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
- Check MCP first - Can this be a tool/resource/prompt?
- Use existing services -
llmService.chat()already exists - Follow agent pattern - Create agent, not standalone function
- Session-aware - Use
sessionIdfor 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
Agentbase class - Always make agents session-aware (pass
sessionId)
If Asked About Persistence
- FoundationDB - Primary (sessions, files, agent state)
- OPFS - Browser cache (draft files, offline mode)
- 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) orlocalhost(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:
- Check theia Documentation
- Look at existing theia extensions in
src/browser/ - Search theia GitHub
If Stuck on MCP:
- Read MCP Specification
- Check
mcp-lmstudio/index.jsfor examples - Review ADR-010
If Stuck on A2A:
- Read A2A Protocol
- Check agent implementations in
src/agents/ - Review ADR-011
If Stuck on Agents:
- Review ADR-013
- Look at
src/agents/base-agent.ts - Study
coordinator-agent.tsexample
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.tsand*-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
- We're building on theia, not from scratch
- Use MCP for tools, A2A for agents
- Everything is session-aware
- Privacy-first: local llms only
- Document major decisions as ADRs
- Eclipse theia = EPL 2.0 = Free commercial use
When in doubt:
- Read ADR-014 (theia decision)
- Check if theia already has the feature
- Build as extension, not standalone
- Follow existing patterns in codebase
Back to: CLAUDE.md | DOCUMENTATION-index.md