Skip to content

Latest commit

 

History

History
1196 lines (953 loc) · 40.8 KB

File metadata and controls

1196 lines (953 loc) · 40.8 KB

CLI Architecture

Comprehensive architecture guide for the coding-agent CLI

The CLI (coding-agent-cli) is a conversational REPL interface that makes AI-assisted coding natural and transparent. Built on design principles of transparency, minimal friction, clean aesthetics, progressive disclosure, workflow-native integration, and self-healing.

High-Level Architecture

The CLI follows a layered architecture where each layer has clear responsibilities:

┌─────────────────────────────────────────────────────────────┐
│                    User Interface Layer                     │
│  (Terminal I/O, Spinners, Context Bar, Status Bar)         │
└─────────────────────────┬───────────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────────┐
│                    REPL Orchestration                       │
│  (Input Handling, Command Routing, Conversation Flow)      │
└─────────────────────────┬───────────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────────┐
│                    Agent Layer                              │
│  (AgentManager, FixAgent, Tool Execution, Self-Healing)    │
└─────────────────────────┬───────────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────────┐
│                    Integration Layer                        │
│  (SpecStory, Git, Obsidian, Claude API)                    │
└─────────────────────────┬───────────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────────┐
│                    Core State Machine                       │
│  (coding-agent-core: Pure state transitions)               │
└─────────────────────────────────────────────────────────────┘

Project Structure

crates/
├── coding-agent-core/     # State machine (shared library)
└── coding-agent-cli/      # Terminal application
    └── src/
        ├── main.rs        # Entry point, panic handler
        ├── cli/           # REPL orchestration
        │   ├── repl.rs              # Main REPL loop
        │   ├── startup.rs           # Welcome screen
        │   ├── input.rs             # Multi-line input, double-enter
        │   ├── terminal.rs          # Raw mode management
        │   ├── output.rs            # Formatted output
        │   └── commands/            # Slash command registry
        │       ├── mod.rs           # Command trait & registry
        │       ├── help.rs          # /help
        │       ├── clear.rs         # /clear (reset context)
        │       ├── status.rs        # /status (active agents)
        │       ├── config.rs        # /config
        │       ├── cost.rs          # /cost (token breakdown)
        │       ├── context.rs       # /context
        │       ├── commit.rs        # /commit (smart git)
        │       ├── diff.rs          # /diff
        │       ├── undo.rs          # /undo
        │       ├── spec.rs          # /spec (planning mode)
        │       ├── document.rs      # /document (Obsidian)
        │       └── model.rs         # /model (switch AI model)
        ├── ui/              # Visual components
        │   ├── theme.rs             # Color definitions
        │   ├── spinner.rs           # Animated spinners
        │   ├── thinking.rs          # Thinking messages
        │   ├── fun_facts.rs         # Long-wait entertainment
        │   ├── context_bar.rs       # Token usage visualization
        │   ├── status_bar.rs        # Multi-agent progress
        │   ├── progress.rs          # Progress bars
        │   ├── syntax.rs            # Code syntax highlighting
        │   └── components.rs        # Reusable UI pieces
        ├── agents/          # Multi-agent orchestration
        │   ├── manager.rs           # Spawn, track, cancel agents
        │   ├── status.rs            # Agent state machine
        │   └── fix_agent.rs         # Self-healing agent
        ├── tools/           # Tool execution pipeline
        │   ├── executor.rs          # Run tools with retries
        │   ├── recovery.rs          # Error recovery strategies
        │   ├── diagnostics.rs       # Parse error messages
        │   └── definitions.rs       # Tool schemas for Claude
        ├── permissions/     # Permission system
        │   ├── trusted.rs           # Trusted path logic
        │   ├── checker.rs           # Permission checking
        │   └── prompt.rs            # Interactive prompts
        ├── integrations/    # External services
        │   ├── specstory.rs         # Session persistence
        │   ├── git.rs               # Git operations
        │   └── obsidian.rs          # Obsidian vault
        ├── tokens/          # Token tracking
        │   ├── counter.rs           # tiktoken-rs wrapper
        │   ├── pricing.rs           # Cost calculation
        │   └── context.rs           # Context window mgmt
        └── config/          # Configuration
            └── settings.rs          # ~/.config/coding-agent/

Core Architectural Patterns

1. Event-Driven State Machine

The CLI orchestrates an event-driven state machine from coding-agent-core:

  • State machine is pure - No I/O, synchronous, deterministic
  • CLI executes actions - API calls, tool execution, file operations
  • Six states: WaitingForUserInput → CallingLlm → ProcessingLlmResponse → ExecutingTools → Error → ShuttingDown
  • Bounded retries - Exponential backoff (1s, 2s, 3s) with max 3 retries

2. Command Registry Pattern

Slash commands follow a trait-based extensible pattern:

pub trait Command {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn execute(&self, args: &str, ctx: &mut CommandContext) -> Result<()>;
}

pub struct CommandContext<'a> {
    pub repl: &'a mut Repl,
    pub agent_manager: Arc<AgentManager>,
    pub session: &'a mut Session,
    pub config: &'a Config,
}

Commands register themselves in CommandRegistry on startup. Adding new commands requires implementing the trait and registering in mod.rs.

3. Multi-Agent Orchestration

The AgentManager coordinates parallel agent execution:

  • Spawn agents - Background tasks for self-healing, search, refactoring
  • Track state - queued → running → complete/failed
  • Display progress - Status bar updates in real-time
  • Cancel agents - User can abort long-running operations

4. Self-Healing Pipeline

Tool execution includes automatic error recovery:

Tool Call → ToolExecutor → Error? → Categorize
                                        │
                                        ├─ Code Error → FixAgent
                                        ├─ Network Error → Retry with backoff
                                        ├─ Permission Error → Prompt user
                                        └─ Resource Error → Suggest alternatives

5. Permission System

Three-tier permission model:

  • Trusted paths - Auto-approved (from config)
  • Interactive prompts - Y/n/Always/Never for untrusted writes
  • Session cache - Decisions remembered during session

6. Streaming UI Updates

All long-running operations provide real-time feedback:

  • Spinners - Tool execution progress
  • Progress bars - Multi-step operations
  • Thinking messages - Rotated during API calls
  • Fun facts - Displayed after 10+ second waits
  • Context bar - Token usage updated after each exchange

Execution Flow

Startup Flow

main.rs
    │
    ├─► Install panic handler (ensure terminal cleanup)
    ├─► Load config from ~/.config/coding-agent/config.toml
    ├─► Load .env for ANTHROPIC_API_KEY
    │
    ▼
cli::run()
    │
    ├─► Terminal::enable_raw_mode()
    │   └─► Drop guard ensures restoration on panic/exit
    │
    ├─► StartupScreen::show()
    │   ├─ Display ASCII logo
    │   ├─ [n] New session
    │   ├─ [r] Resume last ──► SessionManager::load_last()
    │   │   └─► Parse .specstory/history/<session>.md
    │   ├─ [h] Help
    │   └─ [c] Config
    │
    ├─► Repl::new(config)
    │   ├─ Initialize SessionManager
    │   ├─ Initialize TokenCounter (tiktoken-rs)
    │   ├─ Initialize AgentManager (Arc for sharing)
    │   ├─ Initialize ToolExecutor (with retry logic)
    │   ├─ Initialize PermissionChecker (trusted paths)
    │   ├─ Initialize ContextBar
    │   ├─ Initialize CommandRegistry
    │   └─ Load conversation history if resuming
    │
    └─► Repl::run() (main loop)

Main REPL Loop

loop {
    ┌─────────────────────────────────────────────┐
    │  1. Display Context Bar                     │
    │     - Show token usage at bottom of screen  │
    │     - Color-coded: green/yellow/red         │
    └─────────────────────────────────────────────┘
                       │
    ┌──────────────────▼──────────────────────────┐
    │  2. Display Status Bar (if agents active)   │
    │     - Show running agents with progress     │
    │     - Update in real-time                   │
    └─────────────────────────────────────────────┘
                       │
    ┌──────────────────▼──────────────────────────┐
    │  3. Read User Input                         │
    │     - InputHandler::read_input()            │
    │     - Multi-line with double-enter submit   │
    │     - Ctrl+C clears, Ctrl+D exits           │
    └─────────────────────────────────────────────┘
                       │
              ┌────────▼────────┐
              │  Slash command? │
              └────────┬────────┘
                Yes │       │ No
        ┌───────────▼       ▼───────────────┐
        │                                    │
    ┌───▼────────────────────┐  ┌──────────▼────────────┐
    │ CommandRegistry::      │  │ Process as message    │
    │  execute()             │  │  to Claude            │
    │                        │  └──────────┬────────────┘
    │ - Parse command & args │             │
    │ - Look up in registry  │  ┌──────────▼────────────┐
    │ - Execute with context │  │ Add to conversation   │
    └────────────────────────┘  │  history              │
                                │                       │
                                │ Call Claude API       │
                                │  (ureq HTTP client)   │
                                └──────────┬────────────┘
                                           │
                                ┌──────────▼────────────┐
                                │ Process response      │
                                │                       │
                                │ Text? → Display       │
                                │ Tool call? → Execute  │
                                └──────────┬────────────┘
                                           │
                                ┌──────────▼────────────┐
                                │ Tool Execution        │
                                │  (if tool calls)      │
                                │                       │
                                │ - ToolExecutor::      │
                                │    execute()          │
                                │ - Show spinner        │
                                │ - Check permissions   │
                                │ - Run tool            │
                                │ - Handle errors       │
                                │ - Return result       │
                                │                       │
                                │ Send results back     │
                                │  to Claude            │
                                └──────────┬────────────┘
                                           │
                                ┌──────────▼────────────┐
                                │ Update State          │
                                │                       │
                                │ - Count tokens        │
                                │ - Update context bar  │
                                │ - Save session        │
                                │   (.specstory/)       │
                                └───────────────────────┘
                                           │
                                           │
    } ←────────────────────────────────────┘

Key Subsystems

Input Handling

The InputHandler operates in terminal raw mode (via crossterm):

Key Bindings:

  • Enter - Add newline to buffer
  • Enter + Enter - Submit input
  • Ctrl+C - Clear current input buffer
  • Ctrl+D - Exit REPL
  • Backspace - Remove last character

Raw Mode Details:

  • All input processed character-by-character
  • \n only moves cursor down, must use \r\n for proper newline
  • Terminal restored on drop via RAII guard (handles panics)
  • Panic handler installed to ensure cleanup

Multi-line Input:

  • Buffer accumulates characters and newlines
  • Double consecutive Enter triggers submission
  • Cursor tracking for proper display in raw mode

Command System

Command Categories:

Category Commands Purpose
Navigation /help, /clear, /exit, /status REPL control
Code & Files /undo, /diff, /context File operations
Git /commit, /commit --pick Smart git integration
Workflow /model, /cost, /spec, /document Productivity tools
Session /history, /config Session management

Key Commands:

  • /clear - Saves session first, then resets conversation context and clears display
  • /commit - Agent analyzes changes, groups related files, generates purpose-focused message
  • /status - Shows active agents, running tools, current operations
  • /cost - Detailed token breakdown with pricing by model

Claude API Integration

Architecture:

// Claude API call via ureq (synchronous HTTP)
let response = ureq::post("https://api.anthropic.com/v1/messages")
    .set("x-api-key", &api_key)
    .set("anthropic-version", "2023-06-01")
    .send_json(request)?;

Request Flow:

  1. Build request with conversation history
  2. Include available tools (read, write, edit, list, bash, search)
  3. Send to Claude API via ureq
  4. Parse response (text or tool calls)
  5. Execute tools if requested
  6. Send tool results back to Claude
  7. Repeat until final text response

Environment:

  • Requires ANTHROPIC_API_KEY in environment or .env
  • Auto-loads via dotenvy crate on startup
  • API key never logged or displayed

Tool Execution Pipeline

Available Tools:

Tool Purpose Permission
read_file Read file contents Always allowed
write_file Create/overwrite files Requires permission
edit_file Targeted file edits Requires permission
list_files Directory listing Always allowed
bash Execute shell commands Requires permission
code_search Search via ripgrep Always allowed

Execution Flow:

Tool Request from Claude
    │
    ▼
ToolExecutionSpinner::start()
    │
    ▼
PermissionChecker::check() ──► Untrusted? ──► Prompt user
    │                                              │
    │ Trusted/Approved                            │
    │ ◄───────────────────────────────────────────┘
    ▼
ToolExecutor::execute()
    │
    ├─► Success ──► finish_success()
    │
    └─► Error ──► Categorize ──► Auto-fixable? ──► FixAgent::spawn()
                                      │
                                      │ Fixed?
                                      │
                                      └─► Retry original tool

Self-Healing Error Recovery

Error Categories:

Category Strategy
Code Error Spawn FixAgent to diagnose and repair
Network Error Retry with exponential backoff
Permission Error Prompt user for permission
Resource Error Suggest alternatives

FixAgent Flow:

1. Detect code error (e.g., missing dependency, syntax error)
2. Spawn FixAgent with error context
3. FixAgent analyzes error message
4. Generate fix (e.g., add to Cargo.toml, fix import)
5. Apply fix to codebase
6. Generate regression test
7. Verify fix compiles/passes tests
8. Retry original operation
9. Report success/failure to user

Auto-Fixes:

  • Missing dependency → Add to Cargo.toml or package.json
  • Missing import → Add import statement
  • Type mismatch → Suggest type annotation
  • Syntax error → Attempt correction

Session Persistence (SpecStory)

Format:

Conversations saved as markdown in .specstory/history/:

---
title: Adding auth flow
created: 2024-02-13T14:30:00Z
updated: 2024-02-13T15:45:00Z
model: claude-3-opus
version: 1
---

# Adding auth flow

## User
How do I add authentication?

## Agent
Here's how to implement auth...

Operations:

  • Auto-save - After each message exchange
  • Load - Parse markdown back to conversation
  • List - Show all sessions with metadata
  • Resume - Restore full conversation context

Token Tracking

Implementation:

  • Uses tiktoken-rs with cl100k_base tokenizer (Claude-compatible)
  • Counts tokens for all messages in conversation
  • Adds overhead: +4 tokens per message, +3 tokens system overhead
  • Cached globally via OnceLock for performance

Context Bar:

Context: ████████████░░░░░░░░░░░░░░░░░░  38% │ 76k / 200k
  • Position: Bottom of screen, always visible
  • Color-coded: Green (0-60%), Yellow (60-85%), Red (85%+)
  • Updates after each message exchange

Permission System

Trusted Paths:

Configured in ~/.config/coding-agent/config.toml:

[permissions]
trusted_paths = [
    "/Users/username/coding-agent",
    "~/Documents/Personal/",
]

Permission Prompt:

Write to untrusted path: /tmp/test.txt

Allow this operation?
  [y] Yes, this time
  [n] No
  [a] Always for this path
  [v] Never

Behavior:

  • "Always" - Adds to trusted_paths in config
  • "Never" - Caches denial for session
  • Read operations - Always allowed everywhere

Multi-Agent Status Bar

Displayed above input when agents are active:

┌─────────────────────────────────────────────┐
│  AGENTS ─────────────────────────────────── │
│  ● search-agent    Searching...       ██░░  │
│  ● refactor-agent  Analyzing...       ███░  │
│  ○ test-agent      Queued                   │
└─────────────────────────────────────────────┘

States:

  • ○ Queued - Waiting to start
  • ● Running - Active with progress bar
  • ✓ Complete - Successfully finished
  • ✗ Failed - Error state

Git Integration

Smart Commits:

/commit flow:
1. Read git status (staged/unstaged changes)
2. Group related files (same dir, test+impl, etc.)
3. Analyze changes to understand purpose
4. Generate 3-sentence commit message focused on "why"
5. Show preview, allow edit
6. Commit with message

File Grouping Logic:

  • Files in same directory → group together
  • Test files + implementation → group together
  • Unrelated changes → suggest separate commits

Commit Message Style:

Add JWT token validation to login flow

Users can now stay logged in across sessions with
secure token refresh. This improves UX by eliminating
repeated login prompts.

Obsidian Integration

Operations:

  • Search vault - Find notes by content
  • Create note - Suggest location, generate template
  • Update note - Show diff, apply changes
  • Link notes - Add backlinks and metadata

Vault Path:

Configured in ~/.config/coding-agent/config.toml:

[integrations.obsidian]
vault_path = "~/Documents/Personal/"

Configuration

Location: ~/.config/coding-agent/config.toml

Full Configuration:

[permissions]
trusted_paths = [
    "/Users/username/coding-agent",
    "~/Documents/Personal/",
]
auto_read = true

[model]
default = "claude-3-opus"
available = ["claude-3-opus", "claude-3-sonnet"]
context_window = 200000

[theme]
style = "minimal"  # minimal | colorful | monochrome

[persistence]
enabled = true
format = "specstory"
path = ".specstory/history/"

[behavior]
streaming = true
tool_verbosity = "standard"  # minimal | standard | verbose
show_context_bar = true
fun_facts = true
fun_fact_delay = 10  # seconds

[fun_facts_api]
enabled = true
sources = ["uselessfacts", "jokes", "quotes"]
cache_size = 100
refresh_interval = 3600

[error_recovery]
auto_fix = true
generate_tests = true
max_retry_attempts = 3

[integrations.obsidian]
vault_path = "~/Documents/Personal/"

[integrations.git]
auto_stage = false
commit_style = "purpose"  # purpose | conventional | simple

Theme System

Colors centralized in ui/theme.rs:

Element Color Purpose
User input White Neutral
Agent response Cyan Distinguish from user
Tool calls Yellow Action happening
Success Green Completion
Error Red Problems
Warning Orange Caution
Muted/secondary Gray Less important
Cost/tokens Magenta Resource usage
Context bar Green→Yellow→Red Usage level

Accessibility:

  • Respects NO_COLOR environment variable
  • Falls back to plain text if colors unsupported

Dependencies

Core:

Crate Purpose
ureq HTTP client for Claude API
dotenvy Load .env files
serde + serde_json Serialization
toml Config file parsing

Terminal & UI:

Crate Purpose
crossterm Cross-platform terminal control
console Terminal styling
indicatif Spinners, progress bars
syntect Syntax highlighting

Tools & Integrations:

Crate Purpose
walkdir Directory traversal
git2 Git operations
tiktoken-rs Token counting

Async:

Crate Purpose
tokio Async runtime (for future streaming)
reqwest Async HTTP (for fun facts API)

Design Decisions

Why Synchronous API Calls?

  • Simpler control flow in REPL
  • Easier error handling
  • ureq is lightweight and sufficient
  • Can add async/streaming later without major refactor

Why Raw Mode?

  • Full control over input handling
  • Enables double-enter submission
  • Enables multi-line input buffer
  • Better UX than line-buffered input

Why SpecStory Format?

  • Human-readable markdown
  • Version controllable
  • No database required
  • Easy to backup/sync
  • Searchable with standard tools

Why Trait-Based Commands?

  • Easy to extend
  • Type-safe
  • Compile-time guarantees
  • No runtime reflection needed

Why Separate Agent Manager?

  • Enables parallel execution
  • Clear cancellation model
  • Progress tracking
  • Future: distributed agents

Testing Strategy

Unit Tests:

  • Pure functions (token counting, parsing)
  • Config loading/saving
  • Command parsing
  • Error categorization

Integration Tests:

  • Git operations (commit, status, diff)
  • SpecStory save/load
  • Permission checking
  • Tool execution

End-to-End Tests:

  • Full REPL sessions (PTY-based with expectrl)
  • Mock Claude API (with wiremock)
  • Terminal output snapshots (with insta)

Advanced System Architectures

Agent Lifecycle and Coordination

The AgentManager orchestrates multiple background agents that can run in parallel to handle complex tasks.

Agent States:

Queued → Running → Complete
                 ↓
              Failed

Agent Lifecycle:

  1. Creation - Agent spawned via AgentManager::spawn_agent()

    • Receives unique ID and configuration
    • Added to active agents map
    • Initial state: Queued
  2. Execution - Moved to Running state

    • Assigned to tokio task
    • Progress updates sent to manager
    • Can be cancelled by user
  3. Completion - Final state transition

    • Success → Complete with result
    • Error → Failed with error details
    • Removed from active agents after display

Coordination:

  • Parallel Execution - Multiple agents run concurrently via tokio
  • Status Tracking - AgentManager::get_all_statuses() provides snapshot
  • Progress Updates - Agents report progress percentage (0-100)
  • Cancellation - AgentManager::cancel_agent(id) stops running agent
  • Result Aggregation - Results collected from completed agents

Integration Points:

  • /status command queries manager for display
  • StatusBar polls manager for UI updates
  • FixAgent uses manager for spawning sub-agents
  • REPL waits for agent completion before proceeding

Error Recovery Flow

The system implements multi-layered error recovery to handle failures gracefully.

Error Categorization:

pub enum ErrorCategory {
    Code,        // Missing deps, syntax errors, type errors
    Network,     // API timeouts, connection failures
    Permission,  // Access denied, insufficient permissions
    Resource,    // Disk full, memory exhausted, file not found
}

Recovery Pipeline:

Tool Execution → Error Detected → Categorize
                                      │
        ┌─────────────────────────────┼─────────────────────────────┐
        │                             │                             │
    Code Error                  Network Error               Permission Error
        │                             │                             │
        ▼                             ▼                             ▼
  FixAgent::spawn()          Retry with backoff          PermissionPrompt
        │                             │                             │
   Diagnose error            Attempt 1 (1s delay)           User decision
        │                             │                             │
   Generate fix              Attempt 2 (2s delay)         [y] Allow once
        │                             │                  [n] Deny
   Apply fix                 Attempt 3 (3s delay)         [a] Always (→ config)
        │                             │                  [v] Never (→ cache)
   Generate test             Give up if all fail              │
        │                             │                             │
   Verify fix                        │                             │
        │                             │                             │
        └─────────────────────────────┴─────────────────────────────┘
                                      │
                                      ▼
                          Retry Original Operation
                                      │
                              ┌───────┴────────┐
                              │                │
                          Success          Failed
                              │                │
                         Report OK      Report Error

FixAgent Workflow:

  1. Detection - ToolError::is_auto_fixable() returns true

  2. Analysis - Parse error message with DiagnosticsParser

    • Extract error type (missing dep, import, etc.)
    • Identify file and location
    • Determine fix strategy
  3. Fix Generation - Create fix based on error type

    • Missing dependency: Add to Cargo.toml or package.json
    • Missing import: Insert import statement
    • Type mismatch: Suggest type annotation
    • Syntax error: Apply correction
  4. Application - Apply fix to codebase

    • Write file changes
    • Verify syntax correctness
    • Preserve formatting
  5. Test Generation - Create regression test

    • Test that fix resolves issue
    • Prevent future recurrence
    • Written to tests/auto_fix/
  6. Verification - Ensure fix works

    • Re-run compiler/tests
    • Verify no new errors introduced
    • Confirm original operation now succeeds
  7. Retry - Re-execute original tool

    • Use same parameters
    • Report success or new error

Retry Logic:

  • Exponential Backoff: 1s, 2s, 3s delays between attempts
  • Max Attempts: 3 retries before giving up
  • Transient Only: Only network/resource errors retry automatically
  • User Feedback: Show attempt number and delay to user

Loop Prevention:

  • Track fix attempts per error
  • Max 2 fix attempts per unique error
  • Detect if fix introduces same error
  • Abort if no progress after fix

Tool Execution Pipeline

The tool execution system provides a robust framework for running Claude's tool calls with error handling, retries, and progress feedback.

Pipeline Stages:

1. Tool Request (from Claude)
         │
         ▼
2. Parse & Validate
   - Extract tool name
   - Parse input JSON
   - Validate schema
         │
         ▼
3. Permission Check
   - Read operations → Allow
   - Write operations → Check trusted paths
   - Untrusted → Prompt user
         │
         ▼
4. Spinner Start
   - Show tool name + target
   - Begin elapsed time tracking
         │
         ▼
5. Execute Tool Function
   - Call tool implementation
   - Handle tool-specific errors
   - Capture output
         │
         ▼
6. Error Handling
   - Success → Format result
   - Error → Categorize & recover
         │
         ▼
7. Spinner Finish
   - Show success/failure
   - Display elapsed time
   - Log result
         │
         ▼
8. Return Result
   - Send back to Claude
   - Update conversation history

Tool Registration:

// In ToolExecutor initialization
executor.register_tool("read_file", read_file_tool);
executor.register_tool("write_file", write_file_tool);
executor.register_tool("edit_file", edit_file_tool);
executor.register_tool("list_files", list_files_tool);
executor.register_tool("bash", bash_tool);
executor.register_tool("code_search", code_search_tool);

Execution with Context:

pub struct ToolExecutionResult {
    pub tool_id: String,
    pub tool_name: String,
    pub result: Result<String, ToolError>,
    pub duration: Duration,
    pub retry_count: u32,
}

impl ToolExecutor {
    pub fn execute(
        &self,
        id: String,
        name: &str,
        input: Value,
    ) -> ToolExecutionResult {
        let start = Instant::now();
        let mut retry_count = 0;

        loop {
            match self.run_tool(name, &input) {
                Ok(output) => {
                    return ToolExecutionResult {
                        tool_id: id,
                        tool_name: name.to_string(),
                        result: Ok(output),
                        duration: start.elapsed(),
                        retry_count,
                    };
                }
                Err(error) if error.is_retryable() && retry_count < MAX_RETRIES => {
                    retry_count += 1;
                    thread::sleep(exponential_backoff(retry_count));
                    continue;
                }
                Err(error) => {
                    return ToolExecutionResult {
                        tool_id: id,
                        tool_name: name.to_string(),
                        result: Err(error),
                        duration: start.elapsed(),
                        retry_count,
                    };
                }
            }
        }
    }
}

Integration with REPL:

The REPL integrates the tool pipeline in process_conversation():

  1. Receive tool call from Claude response
  2. Create ToolExecutionSpinner for visual feedback
  3. Call ToolExecutor::execute() with tool details
  4. Handle result (success or error)
  5. For errors, trigger error recovery if applicable
  6. Send result back to Claude for next turn
  7. Update context bar with token usage

Performance Considerations:

  • Lazy Loading - Tools loaded on first use
  • Result Caching - Identical reads cached per session
  • Parallel Execution - Independent tools can run concurrently
  • Timeout Protection - Long-running tools have configurable timeouts

Phase 14: Integrated Advanced Features

Completed Integration (Phase 14.1-14.6):

All advanced features have been fully integrated into the main execution flow:

Core Infrastructure (14.1)

  • AgentManager - Fully integrated into REPL as Arc<AgentManager>

    • Spawns and tracks background agents
    • Accessible from all commands via CommandContext
    • Powers /status command for live agent monitoring
  • Permission System - Activated with interactive prompts

    • PermissionPrompt wired into PermissionChecker
    • "Always" responses update config file automatically
    • "Never" responses cached per session
    • Seamless integration with all write operations

Tool Execution Enhancement (14.2)

  • ToolExecutor - Centralized tool execution with retry logic

    • Replaces ad-hoc tool execution
    • Automatic retry for transient errors (network, etc.)
    • Exponential backoff: 1s, 2s, 3s (max 3 attempts)
  • ToolExecutionSpinner - Enhanced visual feedback

    • Shows tool name and target (e.g., "Reading src/main.rs...")
    • Displays success/failure with elapsed time
    • Replaces simple "● Running..." messages

Self-Healing Error Recovery (14.3)

  • FixAgent - Automatic error diagnosis and repair

    • Spawned for auto-fixable code errors
    • Analyzes compiler/runtime errors
    • Applies fixes (missing deps, imports, etc.)
    • Generates regression tests
    • Retries original operation after fix
  • Error Categorization - Intelligent error routing

    • Code errors → FixAgent
    • Network errors → Retry with backoff
    • Permission errors → Interactive prompt
    • Resource errors → Alternative suggestions

UI Enhancements (14.4)

  • StatusBar - Multi-agent progress visualization

    • Displays above input when agents active
    • Real-time progress bars for each agent
    • States: Queued, Running, Complete, Failed
  • LongWaitDetector - Entertainment during delays

    • Monitors operation duration
    • Triggers fun facts after 10s threshold
    • Configurable via fun_fact_delay setting
  • ToolResultFormatter - Enhanced result display

    • Syntax highlighting for code in results
    • Collapsible sections for long outputs
    • Line numbers for file reads

Advanced Git Features (14.5)

  • FileGrouper - Intelligent commit grouping

    • Groups related files (same dir, test+impl)
    • Suggests logical commit splits
    • Shows grouping rationale to user
  • Smart Commit Messages - Purpose-focused generation

    • Analyzes all files in group
    • Focuses on "why" not "what"
    • 3-sentence format with context
    • Preview with edit option
    • Multi-commit workflow support

Obsidian Integration (14.6)

  • ObsidianVault - Full vault operations

    • Search by content with relevance scoring
    • Create notes in suggested locations
    • Update with diff preview
    • Template system with metadata
  • Note Templates - Structured note generation

    • Different types: meeting, concept, reference
    • Includes date, tags, backlinks
    • Context-aware suggestions

Future Enhancements

Potential Future Features:

  • Voice input (Whisper integration)
  • Plugin system (custom commands via Lua/Rust)
  • Split pane view (code preview alongside conversation)
  • Vim keybindings
  • Custom themes (user-definable color schemes)
  • Session branching (fork conversations)
  • Web UI mode (optional browser interface)
  • Fuzzy file picker (fzf-style)
  • Snippets (save/reuse prompts)

Common Patterns for New Features

Adding a New Command

  1. Create new file in src/cli/commands/
  2. Implement Command trait
  3. Register in src/cli/commands/mod.rs
  4. Add to /help output
  5. Write unit tests
  6. Update documentation

Adding a New Tool

  1. Define tool schema in src/tools/definitions.rs
  2. Implement tool function (takes serde_json::Value)
  3. Register in ToolExecutor
  4. Add permission check if needed
  5. Add to tool documentation
  6. Write integration tests

Adding a New UI Component

  1. Create in src/ui/
  2. Use Theme for colors
  3. Handle terminal resize
  4. Handle NO_COLOR
  5. Write snapshot tests
  6. Document in architecture

Troubleshooting

Terminal Not Restoring:

  • Check panic handler installed in main.rs
  • Verify Terminal struct has proper Drop impl
  • Test with intentional panics

API Key Not Loading:

  • Check .env file exists in project root
  • Verify ANTHROPIC_API_KEY set in environment
  • Check dotenvy loaded before API call

Context Bar Not Updating:

  • Verify TokenCounter::count() called after each message
  • Check ContextBar::update() called
  • Verify terminal width for proper rendering

Permission Prompt Not Showing:

  • Check path not in trusted_paths
  • Verify PermissionChecker::check() called
  • Check session cache not caching decision

Tools Not Executing:

  • Verify tool registered in ToolExecutor
  • Check Claude API includes tool in request
  • Verify tool schema matches Claude's format
  • Check logs for parse errors

References

  • Spec: specs/command-line-interface.md - Full CLI specification
  • State Machine: docs/STATE_MACHINE.md - Core state machine docs
  • CLAUDE.md: /Users/charliposner/coding-agent/CLAUDE.md - Project overview