Skip to content

Latest commit

 

History

History
507 lines (398 loc) · 14.9 KB

File metadata and controls

507 lines (398 loc) · 14.9 KB

CHAD Architecture Deep Dive

This document provides a detailed explanation of CHAD's architecture and design decisions.

System Overview

CHAD is a desktop application built with:

  • Electron — Cross-platform desktop framework
  • TypeScript — Type-safe JavaScript
  • Open WebUI — Vite + Svelte frontend
  • Ollama — Local AI model inference

Architecture Layers

┌──────────────────────────────────────────────────────────┐
│                      USER INTERFACE                       │
│                  Open WebUI (Svelte/Vite)                 │
│           Running on http://127.0.0.1:5173                │
└───────────────────────┬──────────────────────────────────┘
                        │ window.chad API
                        │ (IPC via contextBridge)
┌───────────────────────┴──────────────────────────────────┐
│              ELECTRON MAIN PROCESS (Node.js)              │
│                                                            │
│  ┌──────────────────────────────────────────────────┐    │
│  │              IPC HANDLERS (src/ipc.ts)           │    │
│  │  • chad:chat      • chad:tool:execute            │    │
│  │  • chad:model:*   • chad:task:*                  │    │
│  └────────────────────┬──────────────────────────────┘   │
│                       │                                    │
│  ┌────────────────────┴─────────────────────────────┐    │
│  │        ORCHESTRATOR (src/orchestrator.ts)        │    │
│  │  • Task management                               │    │
│  │  • Tool approval flow                            │    │
│  │  • Model delegation                              │    │
│  │  • Conversation state                            │    │
│  └──────┬──────────────────────────┬─────────────────┘   │
│         │                          │                      │
│  ┌──────┴─────────┐        ┌──────┴──────────────┐      │
│  │  AI CLUSTER    │        │   TOOL REGISTRY     │      │
│  │                │        │                     │      │
│  │  Planner       │        │  Filesystem         │      │
│  │  Coder         │        │  Terminal           │      │
│  │  Architect     │        │  Web                │      │
│  │  Vision        │        │  Custom...          │      │
│  │                │        │                     │      │
│  │  (cluster.ts)  │        │  (registry.ts)      │      │
│  └────────┬───────┘        └──────┬──────────────┘      │
│           │                       │                      │
└───────────┼───────────────────────┼──────────────────────┘
            │                       │
    ┌───────┴────────┐     ┌────────┴──────────┐
    │  Ollama API    │     │  OS APIs           │
    │  localhost:11434│     │  • fs, child_process│
    └────────────────┘     └────────────────────┘

Component Details

1. Electron Main Process (src/main.ts)

Responsibilities:

  • Application lifecycle management
  • Window creation and management
  • Starting the Open WebUI dev server
  • Setting up IPC handlers
  • Initializing AI cluster and tools

Startup Sequence:

  1. app.whenReady() fires
  2. Initialize tool registry
  3. Create splash window (loading.html)
  4. Start Vite dev server for Open WebUI
  5. Wait for server readiness with progress updates
  6. Create main window (ONLY after server is ready) ← KEY FIX
  7. Setup IPC handlers
  8. Load Open WebUI URL
  9. Show main window, close splash

Why this order matters:

  • Creating the main window too early causes Open WebUI's "OI" splash to appear
  • Strict sequencing prevents flicker and race conditions
  • The splash screen provides smooth UX during startup

2. AI Cluster (src/ai/cluster.ts)

Design Pattern: Specialized models, not monolithic

Each model has a clear role:

Planner (mistral-small)

  • Why this model? Strong instruction following, reliable structured output
  • Role: Central coordinator
  • Responsibilities:
    • Parse user requests
    • Decompose into steps
    • Select appropriate tools
    • Delegate to execution models
    • Synthesize results
  • Does NOT: Write code directly

Coder (qwen2.5-coder:14b)

  • Why this model? Fast, excellent at React/TypeScript, efficient on consumer hardware
  • Role: Day-to-day implementation
  • Best for:
    • Components and UI
    • Scripts and utilities
    • Common patterns
    • Quick iterations

Architect (qwen2.5-coder:32b)

  • Why this model? Stronger reasoning, better context handling, fewer hallucinations
  • Role: Complex changes
  • Best for:
    • Large refactors
    • Multi-file reasoning
    • Architecture decisions
    • High-risk changes
  • Trade-off: Slower, used selectively

Vision (llava)

  • Why this model? Can understand images
  • Role: Visual analysis
  • Best for:
    • Screenshot analysis
    • UI mockup interpretation
    • Diagram understanding

Communication Protocol:

Models communicate via:

  1. Tool calls: <tool>toolName</tool><params>{...}</params>
  2. Model delegation: Mentioning @modelName in responses

Example flow:

User: "Add authentication to the app"
  ↓
Planner: Analyzes request, uses fs_search to find relevant files
  ↓
Planner: "@architect, analyze the current structure"
  ↓
Architect: Reviews files, proposes JWT implementation
  ↓
Planner: "@coder, implement the changes"
  ↓
Coder: Uses fs_patch to modify files (with user approval)
  ↓
Response returned to user

3. Tool Registry (src/tools/registry.ts)

Design Pattern: Explicit, permission-based operations

Key Features:

  • Centralized registry of all available tools
  • Parameter validation
  • Approval requirements
  • Execution auditing

Tool Types:

Safe (no approval):

  • Reading files
  • Listing directories
  • Searching content
  • Getting timestamps
  • Web searches

Requires approval:

  • Writing/modifying files
  • Executing commands
  • Deleting data
  • Network requests (POST, etc.)

Why this design?

  • Security: AI can't perform destructive actions without consent
  • Transparency: All actions are explicit and logged
  • Extensibility: New tools can be added without changing AI roles
  • Debugging: Easy to trace what the AI is doing

4. Orchestrator (src/orchestrator.ts)

Role: Manages task execution flow

Task Lifecycle:

1. User Request
   ↓
2. Create TaskContext (ID, messages, status)
   ↓
3. Loop (max iterations):
   a. Send messages to active model
   b. Parse response for tool calls
   c. If tools needed:
      - Check approval requirements
      - Request approval if needed
      - Execute tools
      - Add results to context
      - Continue loop
   d. If model delegation:
      - Switch active model
      - Continue loop
   e. If no tools/delegation:
      - Task complete
   ↓
4. Return final response

State Management:

Each task maintains:

  • id: Unique identifier
  • userRequest: Original request
  • messages: Full conversation history
  • toolResults: Map of executed tools
  • activeModel: Current model handling the task
  • status: planning | executing | awaiting_approval | completed | error

Approval Flow:

Tool requires approval
  ↓
Set status = awaiting_approval
  ↓
Emit approval request (via IPC)
  ↓
Wait for user response
  ↓
If approved: Execute tool
If denied: Add error to context
  ↓
Continue task

5. IPC Bridge (src/ipc.ts + src/preload.ts)

Pattern: Secure, typed communication

Security Model:

  • contextIsolation: true — Renderer can't access Node APIs
  • nodeIntegration: false — No direct Node access
  • contextBridge — Only expose specific APIs

Exposed APIs:

window.chad = {
  chat(request): Promise<ChatResponse>
  model: { chat, list }
  tools: { list, schema, execute, approve, onApprovalRequest }
  tasks: { get, list }
  health(): Promise<HealthStatus>
}

Why IPC?

  • Frontend (renderer) is untrusted
  • Backend (main) has full system access
  • IPC creates a security boundary
  • Only specific operations are allowed

6. Tool Framework

Filesystem Tools (src/tools/filesystem.ts)

fs_read       → Read file contents
fs_write      → Write/create file (approval)
fs_list       → List directory
fs_search     → Search by pattern
fs_patch      → Find & replace (approval)

Terminal Tools (src/tools/terminal.ts)

terminal_powershell  → Execute PowerShell (approval)
terminal_wsl         → Execute WSL command (approval)

Both include:

  • Working directory support
  • Timeout handling
  • stdout/stderr capture
  • Exit code tracking

Web Tools (src/tools/web.ts)

web_search  → Search via Exa API
web_fetch   → Fetch URL content

Design Decisions

Why a Cluster Instead of a Single Model?

Advantages:

  1. Predictability: Smaller models are more consistent
  2. Specialization: Each model excels at its role
  3. Cost: Cheaper to run multiple small models than one huge one
  4. Swappability: Can upgrade models independently
  5. Scaling: Can add more specialized models over time

Inspiration: This mirrors how production AI systems (Cursor, GitHub Copilot, etc.) work internally.

Why Explicit Tools?

Alternatives considered:

  • AI generates code, runs it automatically ❌
  • AI has unrestricted shell access ❌
  • AI can do anything without permission ❌

Why tools are better:

  • Security: Can't do harm without consent
  • Transparency: Know exactly what AI is doing
  • Reliability: Tested, validated operations
  • Auditability: Full log of all actions

Why Electron + Open WebUI?

Electron:

  • Cross-platform (Windows, Mac, Linux)
  • Full Node.js access for tools
  • Native desktop experience
  • Can embed web UIs

Open WebUI:

  • Excellent chat interface
  • Already designed for AI chat
  • Customizable and extensible
  • Active development

Integration:

  • Open WebUI provides the frontend
  • CHAD adds the AI cluster and tools
  • Best of both worlds

Performance Considerations

Model Loading

Models are loaded by Ollama on-demand. First request to each model is slower.

Optimization: Could preload frequently-used models at startup.

Task Iteration Limits

Orchestrator has a max iteration limit (20) to prevent infinite loops.

Reason: If planner gets confused, it could loop forever requesting tools.

IPC Overhead

IPC calls have overhead (serialization, process communication).

Optimization: Batch operations when possible (e.g., read multiple files in one call).

Vite Dev Server

In production, would bundle Open WebUI and serve statically.

Current: Dev mode with hot reload for development.

Production: Run npm run build in open-webui, serve from dist/.

Security Model

Threat Model

Trusted:

  • User
  • Electron main process
  • Tool framework

Untrusted:

  • AI models (could hallucinate harmful commands)
  • Open WebUI renderer (web content, XSS risk)

Protection:

  1. AI can't execute code directly, only request tools
  2. Destructive tools require user approval
  3. Renderer can't access Node APIs
  4. IPC provides security boundary

Approval Bypass

Tools can be executed with approval bypassed IF:

  1. User explicitly approves in UI
  2. Tool is marked as safe (requiresApproval: false)

Never: AI can't bypass approval on its own.

Extensibility

Adding Models

// In src/ai/cluster.ts
this.models.set("newModel", {
  name: "newModel",
  role: "Description",
  model: "ollama-model-name",
  responsibilities: [...]
});

Adding Tools

  1. Create tool file in src/tools/
  2. Define tool with Tool interface
  3. Register in src/tools/index.ts
  4. Tool is automatically available to AI

Custom Integrations

Can add:

  • Database tools (Postgres, MongoDB, etc.)
  • API clients (GitHub, Jira, etc.)
  • Hardware control (Arduino, Raspberry Pi, etc.)
  • Build systems (Webpack, Docker, etc.)

Future Enhancements

Planned

  • Streaming responses: Real-time output from models
  • Tool history: View all tool executions
  • Model swapping UI: Change models without code
  • Task monitoring: Live view of task progress
  • Custom system prompts: Per-model configuration
  • Tool analytics: Most-used tools, success rates

Potential

  • Multi-agent collaboration: Multiple planners working together
  • Tool marketplace: Share custom tools
  • Cloud sync: Sync tasks across devices
  • Voice interface: Speak to CHAD
  • Visual debugger: Step through task execution

Comparison to Other Systems

vs. Cursor

Similarities:

  • Multi-model architecture
  • Tool-driven design
  • Code-focused

Differences:

  • CHAD is fully local
  • CHAD is desktop app, not IDE extension
  • CHAD uses different models

vs. Open WebUI Alone

Similarities:

  • Same frontend

Differences:

  • CHAD adds AI cluster orchestration
  • CHAD adds tool framework
  • CHAD adds desktop integration

vs. Aider

Similarities:

  • AI coding assistant
  • Git integration

Differences:

  • CHAD has GUI (Aider is CLI)
  • CHAD is clustered (Aider is single model)
  • CHAD is more general-purpose

Summary

CHAD is a desktop-native, local, clustered AI system designed for:

  • Coding tasks (primary focus)
  • Hardware automation (future)
  • General automation (future)

Built on:

  • Electron for desktop
  • TypeScript for type safety
  • Open WebUI for UI
  • Ollama for AI inference

Core principles:

  • Clustered models, not monolithic
  • Explicit tools, not unrestricted
  • Local execution, not cloud
  • Extensible design, future-proof

The result is a safe, powerful, customizable AI system that respects user control while providing advanced capabilities.