Skip to main content

Development Guide

Comprehensive guide for developing with the Coditect AI IDE (T2) codebase.

Table of Contents

Common Tasks

Add New Agent

// src/agents/my-agent.ts
export class MyAgent extends Agent {
constructor(sessionId: string) {
super(
{
name: 'my-agent',
description: 'What this agent does',
skills: ['skill1', 'skill2'],
mcpTools: ['tool1', 'tool2'],
subAgents: []
},
sessionId
);
}

async execute(task: Task): Promise<Result> {
// Use MCP for tools
const data = await this.useTool('lmstudio', 'lmstudio_chat', {
model: 'qwen/qwq-32b',
messages: [{ role: 'user', content: task.prompt }]
});

// Or collaborate with other agents via A2A
const review = await this.collaborate('code-reviewer', {
action: 'review',
payload: { code: data }
});

return { data, review };
}
}

Add New theia Extension

// src/browser/my-extension/my-module.ts
import { ContainerModule } from '@theia/core/shared/inversify';
import { MyContribution } from './my-contribution';

export default new ContainerModule(bind => {
bind(MyContribution).toSelf().inSingletonScope();
bind(CommandContribution).toService(MyContribution);
});
// src/browser/my-extension/my-contribution.ts
import { injectable } from '@theia/core/shared/inversify';
import { CommandContribution, CommandRegistry } from '@theia/core';

@injectable()
export class MyContribution implements CommandContribution {
registerCommands(commands: CommandRegistry): void {
commands.registerCommand({
id: 'my:command',
label: 'My Command'
}, {
execute: async () => {
// Implementation
}
});
}
}

Add New MCP Tool

// mcp-lmstudio/index.js
server.setRequestHandler('tools/list', async () => ({
tools: [
// ... existing tools
{
name: 'my_new_tool',
description: 'What it does',
inputSchema: {
type: 'object',
properties: {
param1: { type: 'string' },
},
required: ['param1']
}
}
]
}));

server.setRequestHandler('tools/call', async (request) => {
if (request.params.name === 'my_new_tool') {
// Implementation
return { content: [{ type: 'text', text: 'result' }] };
}
});

Adding Features

If Asked to Build IDE Features

STOP - Check if theia already has it:

  • ✅ File explorer → theia has it (@theia/navigator)
  • ✅ editor tabs → theia has it (@theia/editor)
  • ✅ terminal → theia has it (@theia/terminal)
  • ✅ Settings → theia has it (@theia/preferences)
  • ✅ Keybindings → theia has it (@theia/keymaps)

Build as theia extension, don't reinvent.

How to check: Search theia docs and node_modules/@theia/ before building.

If Asked to Add llm Features

  1. Check MCP first - Can this be a tool/resource/prompt?
  2. Use existing services - llmService.chat() already exists
  3. Follow agent pattern - Create agent, not standalone function
  4. Session-aware - Use sessionId for isolation

If Asked About Agents

  • Agents use MCP for tools (llm access, file operations)
  • Agents use A2A for collaboration (agent-to-agent)
  • Always create agents that extend Agent base class
  • Always make agents session-aware (pass sessionId)

If Asked About Persistence

  1. FoundationDB - Primary (sessions, files, agent state)
  2. OPFS - Browser cache (draft files, offline mode)
  3. IndexedDB - Fallback (unsupported browsers)

Don't create new persistence - use fdbService or opfsService.

Working with Protocols

MCP Protocol (Anthropic)

Three core primitives:

1. Tools (Model-controlled):

// Agent decides when to call
await mcpClient.callTool('lmstudio', 'lmstudio_chat', {
model: 'qwen/qwq-32b',
messages: [{ role: 'user', content: 'Hello' }],
temperature: 0.7
});

2. Resources (App-controlled):

// App provides context
file:///workspace/src/main.ts

3. Prompts (User-controlled):

// User triggers templates
code-review({ code, level: 'advanced' })

A2A Protocol (Google/Linux Foundation)

Agent-to-agent communication:

// Agent 1 requests from Agent 2
const review = await a2aClient.requestFromAgent('code-reviewer', {
action: 'review',
payload: { code: generatedCode }
});

Multi-Session Architecture

Each session is isolated:

  • Independent editor tabs
  • Separate llm conversation history
  • Isolated file workspace
  • Dedicated terminal context
  • Session-specific agent state

Saved to FoundationDB, cached in OPFS.

Development Workflows

llm Workflow Modes

1. Single Mode

const result = await llmService.chat('meta-llama-3.3-70b', messages);

2. Parallel Mode

const [result1, result2] = await Promise.all([
llmService.chat('qwen/qwq-32b', messages),
llmService.chatWithClaude(messages)
]);

3. Sequential Mode

const code = await llmService.chat('deepseek-coder', codePrompt);
const review = await llmService.chatWithClaude([
{ role: 'user', content: `Review:\n${code}` }
]);

4. Consensus Mode

const responses = await llmService.consensusMode(prompt, [
'meta-llama-3.3-70b',
'qwen/qwq-32b',
'deepseek-coder'
]);

Environment Setup

Docker (Recommended):

# In /workspace/PROJECTS/t2/
docker-compose up -d
# Access: http://localhost:3000

Local Development:

npm install
npm run dev
# Access: http://localhost:5173

LM Studio Configuration:

  • Host: host.docker.internal (Docker) or localhost (local)
  • Port: 1234
  • API: OpenAI-compatible at /v1
  • Models: 16+ available (qwen, llama, deepseek, etc.)

Agent Hierarchy

Coordinator Agent (Top-level orchestrator)
├── Planning Agent (Task decomposition)
├── Code Generation Agent (LM Studio)
│ ├── TypeScript Sub-Agent
│ ├── Python Sub-Agent
│ └── Rust Sub-Agent
├── Code Review Agent (Claude Code)
│ ├── Security Review Sub-Agent
│ ├── Performance Review Sub-Agent
│ └── Style Review Sub-Agent
└── Testing Agent
├── Unit Test Sub-Agent
├── Integration Test Sub-Agent
└── E2E Test Sub-Agent

Troubleshooting

Common Pitfalls

1. Building Features theia Already Has

Wrong: Creating file explorer from scratch ✅ Right: Using @theia/navigator and extending with contributions

2. Using Global State or Singletons

Wrong: let currentSession = null; export const setSession = ...Right: Inject services via @inject(SessionService) and pass sessionId

3. Calling llms Directly Without MCP

Wrong: fetch('http://localhost:1234/v1/chat/completions', ...)Right: await mcpClient.callTool('lmstudio', 'lmstudio_chat', {...})

4. Copying V4 UI Components

Wrong: Copying React components from src/v4-*/ or src/frontend-original/Right: Using theia widgets and React views within theia framework

5. Storing State in OPFS First

Wrong: await opfsService.write(...); await fdbService.write(...)Right: await fdbService.write(...); await opfsService.cache(...)

6. Creating Agents Without Sessions

Wrong: new CodeGenAgent() (no sessionId) ✅ Right: new CodeGenAgent(sessionId) and pass through all operations

7. Hardcoding Model Names

Wrong: const model = 'qwen/qwq-32b'Right: const model = await llmService.getSelectedModel(sessionId)

8. Ignoring WSL2 File Monitoring Issues

Wrong: Running file-monitor without --poll on WSL2 ✅ Right: Always use --poll --poll-interval 2 on WSL2

9. Using npm Scripts That Don't Exist

Wrong: npm test (shows "Error: no test specified") ✅ Right: Check package.json scripts first - tests don't exist yet

10. Not Checking ADRs Before Architectural Changes

Wrong: Switching from Zustand to Redux without justification ✅ Right: Read ADR-002, understand why Zustand was chosen, create new ADR if changing

Getting Help

If Stuck on theia:

  1. Check theia Documentation
  2. Look at existing theia extensions in src/browser/
  3. Search theia GitHub

If Stuck on MCP:

  1. Read MCP Specification
  2. Check mcp-lmstudio/index.js for examples
  3. Review ADR-010

If Stuck on A2A:

  1. Read A2A Protocol
  2. Check agent implementations in src/agents/
  3. Review ADR-011

If Stuck on Agents:

  1. Review ADR-013
  2. Look at src/agents/base-agent.ts
  3. Study coordinator-agent.ts example

Important Constraints

What NOT to Do

Don't build IDE features from scratch → Use theia ❌ Don't create custom persistence → Use fdbService/opfsService ❌ Don't make agents without sessions → Always pass sessionId ❌ Don't bypass MCP → Use mcpClient for llm access ❌ Don't hardcode llm models → Use model selection ❌ Don't ignore A2A → Use for agent collaboration ❌ Don't commit secrets → Use .env variables

What TO Do

Build theia extensions for new IDE features ✅ Use existing services (llmService, mcpClient, a2aClient) ✅ Follow agent patterns (extend Agent base class) ✅ Make everything session-aware (pass sessionId) ✅ Use MCP for tools (llm, file ops, etc.) ✅ Use A2A for agents (inter-agent communication) ✅ Document decisions (create ADRs for major changes)

Success Criteria

When implementing features:

Works in theia - Extensions integrate properly ✅ Session-aware - All state tied to sessionId ✅ Uses MCP/A2A - Protocols used correctly ✅ Privacy-first - No cloud calls (except optional Claude) ✅ Well-documented - ADRs for major decisions ✅ Type-safe - Full TypeScript coverage

Key Architectural Insights

1. Eclipse theia ≠ VS Code

  • theia is NOT a VS Code fork - it's a framework for building VS Code-like IDEs
  • theia uses dependency injection (InversifyJS) - everything is a service
  • Extensions register via ContainerModule.bind() - no global state
  • Implication: Don't look for main.ts or index.ts - look for *-module.ts and *-contribution.ts

2. MCP Tools vs A2A Messages

  • MCP: AI agent → external tool (llm, file ops, database)
  • A2A: AI agent → AI agent (coordination, delegation)
  • Critical: MCP is for capabilities, A2A is for collaboration
  • Example: Code generation agent uses MCP to call LM Studio, then uses A2A to request review from review agent

3. Session Isolation Architecture

  • Every user action happens in a session context (sessionId)
  • Sessions are NOT browser tabs - they're logical workspaces
  • Multiple sessions can exist in same browser tab
  • Database pattern: All FDB keys prefixed with tenant_id/session_id/...
  • Why: Enables multi-tenancy and parallel project work

4. OPFS vs FoundationDB Split

  • FoundationDB: Source of truth (sessions, files, agent state)
  • OPFS: Browser-side cache for offline mode and performance
  • Sync pattern: Write to FDB, cache to OPFS, read from OPFS with FDB fallback
  • Critical: NEVER use OPFS as primary storage - it can be cleared by browser

5. Agent Execution Model

  • Agents are stateless - all state lives in sessionId context
  • Agent "memory" = FDB queries with session/conversation filters
  • Sub-agents are NOT child processes - they're specialized skill modules
  • Coordinator pattern: Coordinator agent doesn't execute - it only delegates

6. V4 Reference Usage

  • V4 = custom web app with Kubernetes pods
  • T2 = theia extensions (completely different architecture)
  • V4 is useful for: FoundationDB patterns, agent coordination logic, MCP/A2A examples
  • V4 is NOT useful for: UI components, file operations, IDE features (theia has these)

Remember

  1. We're building on theia, not from scratch
  2. Use MCP for tools, A2A for agents
  3. Everything is session-aware
  4. Privacy-first: local llms only
  5. Document major decisions as ADRs
  6. Eclipse theia = EPL 2.0 = Free commercial use

When in doubt:

  1. Read ADR-014 (theia decision)
  2. Check if theia already has the feature
  3. Build as extension, not standalone
  4. Follow existing patterns in codebase

Back to: CLAUDE.md | DOCUMENTATION-index.md