14 KiB
Architecture Notes - Roo Code Extension
Date: 2026-02-16
Phase: 0 - Archaeological Dig
Goal: Map the codebase structure for hook system injection
Executive Summary
This document maps the Roo Code extension architecture to identify injection points for the Intent-Code Traceability hook system. The hook system will enforce a two-stage state machine (Reasoning Loop) and maintain .orchestration/ directory for intent tracking.
1. Tool Execution Flow
1.1 Entry Point: presentAssistantMessage()
File: src/core/assistant-message/presentAssistantMessage.ts
Function: presentAssistantMessage(cline: Task) (line 61)
Flow:
- LLM generates assistant message with tool calls
- Function processes content blocks sequentially
- For each
ToolUseblock, routes to specific tool handler viaswitch (block.name)(line 678) - Tools are executed with callbacks:
askApproval,handleError,pushToolResult
Key Tool Handlers:
write_to_file→WriteToFileTool.handle()(line 681)execute_command→ExecuteCommandTool.handle()(line 750)edit_file→EditFileTool.handle()(line 721)- Custom tools →
customToolRegistry.get(block.name)(line 419)
Hook Injection Point:
- Pre-Hook: Before
tool.handle()call (line 681, 721, etc.) - Post-Hook: After
tool.execute()completes, beforepushToolResult()
1.2 Tool Base Architecture
File: src/core/tools/BaseTool.ts
Class: BaseTool<TName extends ToolName> (line 29)
Key Methods:
abstract execute(params, task, callbacks): Promise<void>- Main execution logicasync handlePartial(task, block): Promise<void>- Streaming supportresetPartialState(): void- Cleanup
Tool Instances: All tools are singleton instances imported at module level:
writeToFileToolfromWriteToFileTool.tsexecuteCommandToolfromExecuteCommandTool.tseditFileToolfromEditFileTool.ts- etc.
Hook Injection Strategy:
- Wrap
execute()method calls - Intercept in
presentAssistantMessage()before tool.handle() - Store active intent context in
Taskinstance
1.3 Tool Registration
File: src/core/task/build-tools.ts
Function: buildNativeToolsArrayWithRestrictions() (line 82)
Process:
- Filters native tools based on mode
- Loads MCP tools from
mcpHub - Loads custom tools from
.roo/tools/directories viacustomToolRegistry - Returns combined tool array for LLM
Custom Tool Registry:
- File:
packages/core/src/custom-tools/custom-tool-registry.ts - Class:
CustomToolRegistry(line 31) - Methods:
register(),get(),has(),getAllSerialized()
Hook Injection Point:
- Add
select_active_intentto native tools array - Register via custom tool registry OR add to native tools list
2. System Prompt Construction
2.1 Prompt Builder
File: src/core/prompts/system.ts
Main Function: SYSTEM_PROMPT() (line 112)
Called From: Task.getSystemPrompt() (line 3745 in Task.ts)
Construction Flow:
- Gets mode configuration and role definition
- Builds sections: formatting, tool use, capabilities, modes, rules, system info
- Adds custom instructions and rooignore rules
- Returns complete prompt string
Key Sections:
roleDefinition- Mode-specific role (line 65)getSharedToolUseSection()- Tool cataloggetToolUseGuidelinesSection()- Tool usage rulesgetRulesSection()- Workspace rulesgetObjectiveSection()- Task objectives
Hook Injection Point:
- Modify
getToolUseGuidelinesSection()or add new section - Add Reasoning Loop instructions before tool guidelines
- Enforce: "You MUST call select_active_intent before writing code"
2.2 Prompt Usage
File: src/core/task/Task.ts
Method: getSystemPrompt() (line 3745)
Called During:
- Initial task creation
- Each LLM request (via
recursivelyMakeClineRequests())
Hook Injection Point:
- Intercept prompt before sending to LLM
- Inject active intent context if
select_active_intentwas called - Add
<intent_context>XML block to prompt
3. Task Lifecycle
3.1 Task Class
File: src/core/task/Task.ts
Class: Task (line 163)
Key Properties:
taskId: string- Unique task identifiercwd: string- Working directoryproviderRef: WeakRef<ClineProvider>- Extension provider referenceapi: ApiHandler- LLM API handlerclineMessages: Anthropic.Message[]- Conversation history
Key Methods:
startTask(text, images)- Initialize taskrecursivelyMakeClineRequests()- Main LLM request loopgetSystemPrompt()- Get system promptsay(),ask()- User interaction methods
Hook Storage Point:
- Add
activeIntentId?: stringproperty to Task - Store intent context loaded from
.orchestration/active_intents.yaml
4. Extension Architecture
4.1 Extension Host
File: src/extension.ts
Function: activate(context: vscode.ExtensionContext) (line 120)
Initialization:
- Creates
ClineProviderinstance - Registers commands and webview
- Sets up MCP hub if enabled
- Initializes code index manager
Provider:
- File:
src/core/webview/ClineProvider.ts - Class:
ClineProvider - Manages tasks, state, and webview communication
4.2 Webview Communication
Flow:
- Webview (UI) sends messages via
postMessage webviewMessageHandler.tsroutes messages- Provider creates/updates tasks
- Tasks execute tools and send results back
Hook Injection Point:
- Intercept webview messages before task creation
- Validate intent selection before allowing tool execution
5. File System Operations
5.1 Write Operations
Tools:
WriteToFileTool- Full file writeEditFileTool- Partial file editsApplyDiffTool- Diff-based editsSearchReplaceTool- Search/replace operations
Common Pattern:
- Validate parameters
- Check
rooIgnoreControllerfor access - Show diff view (if enabled)
- Request approval via
askApproval() - Save changes via
diffViewProvider.saveChanges() - Track file context
- Push tool result
Hook Injection Points:
- Pre-Hook: Before
askApproval()- Check intent scope - Post-Hook: After
saveChanges()- Log toagent_trace.jsonl
6. Hook System Architecture (Planned)
6.1 Hook Engine Location
Proposed File: src/core/hooks/HookEngine.ts
Responsibilities:
- Intercept tool execution requests
- Enforce Pre-Hook and Post-Hook logic
- Manage intent context injection
- Validate scope and constraints
Integration Points:
- Wrap tool execution in
presentAssistantMessage() - Inject into
BaseTool.execute()wrapper - Store hook state in
Taskinstance
6.2 Orchestration Directory
Location: .orchestration/ in workspace root
Files:
active_intents.yaml- Intent specificationsagent_trace.jsonl- Append-only trace ledgerintent_map.md- Spatial mappingAGENT.md- Shared knowledge base
Access:
- Read/write via Node.js
fsAPIs - Initialize on first task creation
- Validate on extension activation
7. Implementation Strategy
7.1 Phase 1: The Handshake
Steps:
- Create
SelectActiveIntentToolextendingBaseTool - Add tool to native tools array in
build-tools.ts - Create
HookEngineclass with Pre-Hook/Post-Hook methods - Modify
presentAssistantMessage()to call hooks - Create
.orchestration/directory structure - Implement
OrchestrationDataModelfor YAML/JSONL access - Modify system prompt to enforce Reasoning Loop
- Implement context injection for
select_active_intent
7.2 File Structure (Planned)
src/
core/
hooks/
HookEngine.ts # Main hook middleware
PreHook.ts # Pre-execution hooks
PostHook.ts # Post-execution hooks
OrchestrationDataModel.ts # Data model access
tools/
SelectActiveIntentTool.ts # New intent selection tool
orchestration/
ActiveIntentsManager.ts # YAML management
AgentTraceLogger.ts # JSONL logging
IntentMapManager.ts # Markdown mapping
8. Key Dependencies
8.1 External Libraries
@anthropic-ai/sdk- LLM APIyaml- YAML parsing (need to add)crypto- SHA-256 hashing (built-in)fs/promises- File system operations
8.2 Internal Dependencies
@roo-code/types- Type definitions@roo-code/core- Core utilitiesTaskclass - Task lifecycleBaseTool- Tool base class
9. Testing Strategy
9.1 Unit Tests
- Hook engine interception logic
- Orchestration data model read/write
- Intent context injection
- Scope validation
9.2 Integration Tests
- End-to-end tool execution with hooks
- Intent selection → context injection → code write
- Trace logging verification
- Parallel agent collision detection
10. Open Questions
-
Tool Registration: Should
select_active_intentbe a native tool or custom tool?- Decision: Native tool (simpler, always available)
-
Hook Timing: Should hooks be synchronous or async?
- Decision: Async (allows for file I/O and user prompts)
-
Error Handling: How to handle hook failures?
- Decision: Fail-safe - log error, allow execution to continue with warning
-
State Persistence: Where to store active intent ID?
- Decision: Task instance property +
.orchestration/active_intents.yaml
- Decision: Task instance property +
11. Next Steps
- ✅ Complete Phase 0 (this document)
- ⏳ Implement Phase 1: The Handshake
- Create
SelectActiveIntentTool - Build
HookEngineinfrastructure - Implement
.orchestration/data models - Modify system prompt
- Create
- ⏳ Implement Phase 2: Hook Middleware & Security
- ⏳ Implement Phase 3: AI-Native Git Layer
- ⏳ Implement Phase 4: Parallel Orchestration
Complete execution flow diagram ┌─────────────────────────────────────────────────────────────┐ │ 1. LLM Response (Streaming) │ │ Anthropic API → Task.recursivelyMakeClineRequests() │ └──────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 2. Tool Call Parsing │ │ Task.ts:2989-3016 │ │ - Receives "tool_call" chunk │ │ - Parses via NativeToolCallParser │ │ - Creates ToolUse object │ │ - Adds to assistantMessageContent[] │ └──────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 3. Message Presentation Router │ │ presentAssistantMessage.ts:63 │ │ - Checks lock (prevents concurrent execution) │ │ - Gets current block from assistantMessageContent │ │ - Routes by block.type → "tool_use" │ └──────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 4. Tool Routing (SWITCH STATEMENT) │ │ presentAssistantMessage.ts:691 │ │ switch (block.name) { │ │ case "write_to_file": │ │ case "execute_command": │ │ ... │ │ } │ └──────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 5. Tool Execution │ │ tool.handle(task, block, callbacks) │ │ BaseTool.ts:113 │ │ - Parses block.nativeArgs → params │ │ - Calls tool.execute(params, task, callbacks) │ └──────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 6. Actual Tool Logic │ │ WriteToFileTool.execute() or ExecuteCommandTool.execute()│ │ - Validates parameters │ │ - Checks permissions │ │ - Asks user approval │ │ - Performs operation │ │ - Calls pushToolResult() │ └──────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 7. Result Back to LLM │ │ pushToolResult() → task.pushToolResultToUserContent() │ │ - Creates tool_result block │ │ - Adds to userMessageContent[] │ │ - LLM receives result in next request │ └─────────────────────────────────────────────────────────────┘
End of Architecture Notes