Based on: plan.md strategic vision and current codebase analysis
Target Audience: Core developers, contributors, and technical stakeholders
Last Updated: $(date)
Codebase Version: 1.99.3 (VS Code fork)
This guide translates the strategic vision from plan.md into actionable technical implementation steps. Code Mavi IDE aims to become the first open-source, agent-first IDE that combines Cursor's intelligence with Void's openness, while avoiding the architectural pitfalls that limited Void's success.
"Void neden öldü? Provider eklediler, UI yaptılar, ama agent beyni yoktu.
Cursor'u öldürmek için provider sayısı değil — daha iyi agent mimarisi gerekiyor."
This insight drives our entire implementation strategy.
-
Void Fork Foundation
- Working VS Code fork with Code Mavi IDE branding
- Basic UI components and services
- Development environment established
-
Agent System Design
- Triple agent architecture fully documented
- Detailed system prompts for Orchestrator, Executor, Verifier
- Tool framework interfaces defined
- Communication protocols specified
-
Documentation Infrastructure
- Comprehensive architecture documentation
- Development guidelines
- User guides framework
- No Semantic Search (Phase 2 incomplete)
- No Agent Execution (Phase 3 not started)
- No Provider System (Phase 5 not started)
- No Build Pipeline (Phase 6 not started)
| Phase | Status | Completion | Critical Items |
|---|---|---|---|
| 0: Void Fork + Orientation | ✅ Complete | 100% | Codebase analysis done |
| 1: Branding + Stabilization | 70% | Telemetry removal pending | |
| 2: Codebase Intelligence | ❌ Not Started | 0% | Semantic search missing |
| 3: Agent Loop | 30% | No implementation | |
| 4: System Prompt + Rules | ✅ Foundation | 50% | UI components missing |
| 5: Provider + Auto Dev | ❌ Not Started | 0% | Stub implementations only |
| 6: Release Preparation | ❌ Not Started | 0% | No build pipeline |
Implement semantic search and code understanding capabilities that Void lacked but Cursor mastered.
Cursor's Three-Layer Architecture (from plan.md):
1. Understanding Layer → Semantic codebase indexing
2. Execution Layer → Main agent + sub-agents
3. Application Layer → Separate "apply model"
Goal: Language-aware code analysis
// File: src/vs/workbench/contrib/mavi/common/mavi-logic/services/ast-service.ts
export class ASTService {
private parsers: Map<string, Parser> = new Map();
async initialize(): Promise<void> {
// Load tree-sitter grammars for supported languages
await this.loadGrammar('javascript');
await this.loadGrammar('typescript');
await this.loadGrammar('python');
await this.loadGrammar('rust');
}
async parseFile(uri: URI): Promise<ASTNode> {
const content = await this.readFile(uri);
const language = this.detectLanguage(uri);
return this.parseWithTreeSitter(content, language);
}
async extractSymbols(ast: ASTNode): Promise<CodeSymbol[]> {
// Extract functions, classes, interfaces, imports, exports
return this.walkAST(ast);
}
}Deliverables:
- tree-sitter integration for 4 core languages
- AST parsing service with symbol extraction
- Code chunking algorithm (50 lines with 10-line overlap)
Goal: Efficient similarity search with SQLite + vec0
// File: src/vs/workbench/contrib/mavi/common/mavi-logic/services/vector-db-service.ts
export class VectorDBService {
private db: Database;
private readonly DIMENSIONS = 768; // nomic-embed-text dimensions
async initialize(dbPath: string): Promise<void> {
this.db = new Database(dbPath);
// Enable vec0 extension
await this.db.exec('LOAD vec0');
// Create chunks table
await this.db.exec(`
CREATE TABLE IF NOT EXISTS code_chunks (
id TEXT PRIMARY KEY,
uri TEXT NOT NULL,
content TEXT NOT NULL,
language TEXT NOT NULL,
line_start INTEGER NOT NULL,
line_end INTEGER NOT NULL,
embedding BLOB NOT NULL,
created_at INTEGER NOT NULL
);
CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts
USING vec0(embedding, dimensions=${this.DIMENSIONS});
`);
}
async searchSimilar(
queryEmbedding: number[],
topK: number = 10
): Promise<SearchResult[]> {
const results = await this.db.all(`
SELECT c.*,
vec0_distance(c.embedding, ?) as distance
FROM code_chunks c
JOIN chunks_fts f ON c.id = f.rowid
ORDER BY distance ASC
LIMIT ?
`, [JSON.stringify(queryEmbedding), topK]);
return results.map(r => ({
uri: URI.parse(r.uri),
score: 1 - r.distance, // Convert distance to similarity score
snippet: r.content,
lineStart: r.line_start,
lineEnd: r.line_end
}));
}
}Deliverables:
- SQLite + vec0 database setup
- Chunk storage and retrieval
- Similarity search implementation
Goal: Multiple embedding model support with fallback
// File: src/vs/workbench/contrib/mavi/common/mavi-logic/services/embedding-service.ts
export interface EmbeddingConfig {
provider: 'ollama' | 'openai' | 'local';
model: string;
dimensions: number;
apiKey?: string;
baseUrl?: string;
}
export class EmbeddingService {
private config: EmbeddingConfig;
constructor(config: EmbeddingConfig) {
this.config = config;
}
async generateEmbedding(text: string): Promise<number[]> {
switch (this.config.provider) {
case 'ollama':
return this.callOllama(text);
case 'openai':
return this.callOpenAI(text);
case 'local':
return this.localEmbedding(text);
default:
throw new Error(`Unsupported provider: ${this.config.provider}`);
}
}
private async callOllama(text: string): Promise<number[]> {
// Default: nomic-embed-text (768 dimensions, free, local)
const response = await fetch('http://localhost:11434/api/embeddings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'nomic-embed-text',
prompt: text
})
});
const data = await response.json();
return data.embedding;
}
async batchEmbed(chunks: CodeChunk[]): Promise<EmbeddingResult[]> {
// Batch processing for efficiency
const batchSize = 32;
const results: EmbeddingResult[] = [];
for (let i = 0; i < chunks.length; i += batchSize) {
const batch = chunks.slice(i, i + batchSize);
const embeddings = await Promise.all(
batch.map(chunk => this.generateEmbedding(chunk.content))
);
batch.forEach((chunk, index) => {
results.push({
chunkId: chunk.id,
embedding: embeddings[index]
});
});
}
return results;
}
}Deliverables:
- Ollama embedding integration (default)
- OpenAI embedding fallback
- Batch processing for efficiency
- Configuration UI for model selection
Goal: Complete semantic search system
// File: src/vs/workbench/contrib/mavi/common/mavi-logic/services/semantic-search-service.ts
export class SemanticSearchService {
private astService: ASTService;
private embeddingService: EmbeddingService;
private vectorDB: VectorDBService;
async indexWorkspace(workspaceRoot: URI): Promise<IndexingResult> {
const files = await this.scanWorkspace(workspaceRoot);
let chunksIndexed = 0;
for (const file of files) {
// Parse file to AST
const ast = await this.astService.parseFile(file);
// Extract and chunk code
const chunks = await this.astService.chunkCode(ast, file);
// Generate embeddings
const embeddings = await this.embeddingService.batchEmbed(chunks);
// Store in vector DB
for (let i = 0; i < chunks.length; i++) {
await this.vectorDB.storeChunk(chunks[i], embeddings[i].embedding);
chunksIndexed++;
}
}
return {
filesIndexed: files.length,
chunksIndexed,
durationMs: Date.now() - startTime
};
}
async search(query: string, options: SearchOptions): Promise<SearchResult[]> {
// Generate query embedding
const queryEmbedding = await this.embeddingService.generateEmbedding(query);
// Vector similarity search
const vectorResults = await this.vectorDB.searchSimilar(queryEmbedding, 50);
// Keyword search (fallback)
const keywordResults = await this.keywordSearch(query, 50);
// Hybrid ranking: 70% semantic, 30% keyword
const hybridResults = this.hybridRank(vectorResults, keywordResults);
// Re-rank with cross-encoder (optional)
if (options.reRank) {
return await this.reRank(hybridResults, query, options.topK || 10);
}
return hybridResults.slice(0, options.topK || 10);
}
private hybridRank(
vectorResults: SearchResult[],
keywordResults: SearchResult[]
): SearchResult[] {
// Reciprocal Rank Fusion (RRF)
const scores = new Map<string, number>();
vectorResults.forEach((result, index) => {
const score = scores.get(result.uri.toString()) || 0;
scores.set(result.uri.toString(), score + (1 / (60 + index + 1)));
});
keywordResults.forEach((result, index) => {
const score = scores.get(result.uri.toString()) || 0;
scores.set(result.uri.toString(), score + (1 / (60 + index + 1)));
});
// Convert to array and sort
return Array.from(scores.entries())
.map(([uri, score]) => ({
uri: URI.parse(uri),
score,
snippet: '', // Would need to retrieve from results
lineStart: 0,
lineEnd: 0
}))
.sort((a, b) => b.score - a.score);
}
}Deliverables:
- Complete semantic search API
- Hybrid search (vector + keyword)
- Re-ranking with cross-encoder
- Integration with agent system
Implement the triple-agent system with self-correction that Void completely missed.
"Cursor'un en büyük sırrı: Ana agent hiç dosya yazmıyor.
Ana model sadece 'semantic diff' üretiyor.
Ayrı bir ucuz/hızlı 'apply model' bunu gerçek koda çeviriyor."
Goal: Agent execution framework
// File: src/vs/workbench/contrib/mavi/common/mavi-logic/agents/agent-system.ts
export interface AgentTask {
id: string;
description: string;
context: AgentContext;
dependencies?: string[];
retryCount: number;
maxRetries: number;
}
export interface AgentContext {
relevantFiles: URI[];
searchResults: SearchResult[];
projectRules: RuleSet;
userPreferences: UserPreferences;
}
export class AgentSystem {
private orchestrator: OrchestratorAgent;
private executors: Map<string, ExecutorAgent> = new Map();
private verifiers: Map<string, VerifierAgent> = new Map();
private taskQueue: TaskQueue;
async initialize(): Promise<void> {
this.orchestrator = new OrchestratorAgent();
// Register specialized executors
this.executors.set('typescript', new TypeScriptExecutor());
this.executors.set('python', new PythonExecutor());
this.executors.set('rust', new RustExecutor());
// Register verifiers
this.verifiers.set('syntax', new SyntaxVerifier());
this.verifiers.set('types', new TypeVerifier());
this.verifiers.set('tests', new TestVerifier());
this.taskQueue = new TaskQueue();
}
async executeUserRequest(request: string): Promise<ExecutionResult> {
// 1. Create checkpoint for safety
const checkpointId = await this.checkpointService.createCheckpoint(
`Before: ${request.substring(0, 50)}...`
);
try {
// 2. Orchestrator analyzes and plans
const plan = await this.orchestrator.analyzeAndPlan(request);
// 3. Execute plan with monitoring
const results = await this.executePlan(plan);
// 4. Generate comprehensive report
const report = this.generateReport(plan, results);
return {
success: true,
checkpointId,
report,
changes: results
};
} catch (error) {
// 5. Rollback on failure
await this.checkpointService.restoreCheckpoint(checkpointId);
return {
success: false,
checkpointId,
error: error.message,
suggestions: this.suggestFix(error)
};
}
}
private async executePlan(plan: ExecutionPlan): Promise<TaskResult[]> {
const results: TaskResult[] = [];
for (const task of plan.tasks) {
let success = false;
let attempt = 0;
while (!success && attempt < task.maxRetries) {
attempt++;
try {
// Delegate to appropriate executor
const executor = this.selectExecutor(task);
const diff = await executor.execute(task);
// Apply changes
await this.applyModel.applyDiff(diff);
// Verify changes
const verification = await this.verifyChanges(task, diff);
if (verification.success) {
success = true;
results.push({
taskId: task.id,
success: true,
diff,
verification
});
} else {
// Self-correction: Update task with error context
task.context = this.enhanceContextWithError(
task.context,
verification.errors
);
task.retryCount++;
}
} catch (error) {
task.retryCount++;
// Continue to next attempt
}
}
if (!success) {
throw new MaxRetriesExceededError(task.id, attempt);
}
}
return results;
}
}Deliverables:
- Agent system core framework
- Task queue and execution pipeline
- Checkpoint integration
- Error handling infrastructure
Goal: Orchestrator, Executor, and Verifier agents
// File: src/vs/workbench/contrib/mavi/common/mavi-logic/agents/orchestrator-agent.ts
export class OrchestratorAgent extends BaseAgent {
readonly role = 'orchestrator';
readonly capabilities = ['analyze', 'plan', 'delegate', 'monitor'];
async analyzeAndPlan(request: string): Promise<ExecutionPlan> {
// 1. Semantic search for context
const searchResults = await this.semanticSearch.search(
request,
{ topK: 20, reRank: true }
);
// 2. Read relevant files
const relevantFiles = await this.gatherContext(searchResults);
// 3. LLM-based planning (using system prompt from orchestrator-prompt.md)
const plan = await this.llmService.generatePlan({
request,
context: {
files: relevantFiles,
searchResults: searchResults.slice(0, 5),
rules: this.ruleService.getActiveRules()
},
systemPrompt: this.loadSystemPrompt('orchestrator')
});
// 4. Validate and optimize plan
return this.validatePlan(plan);
}
private async gatherContext(searchResults: SearchResult[]): Promise<FileContext[]> {
const contexts: FileContext[] = [];
for (const result of searchResults.slice(0, 10)) {
const content = await this.fileService.readFile(result.uri);
const symbols = await this.astService.extractSymbols(result.uri);
contexts.push({
uri: result.uri,
content: content.substring(0, 5000), // Limit context
symbols,
relevance: result.score
});
}
return contexts;
}
}// File: src/vs/workbench/contrib/mavi/common/mavi-logic/agents/executor-agent.ts
export class TypeScriptExecutor extends BaseAgent {
readonly role = 'executor';
readonly capabilities = ['edit', 'create', 'refactor'];
async execute(task: AgentTask): Promise<SemanticDiff> {
// 1. Read target files
const files = await Promise.all(
task.context.relevantFiles.map