This document provides a detailed explanation of CHAD's architecture and design decisions.
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
┌──────────────────────────────────────────────────────────┐
│ 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│
└────────────────┘ └────────────────────┘
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:
app.whenReady()fires- Initialize tool registry
- Create splash window (loading.html)
- Start Vite dev server for Open WebUI
- Wait for server readiness with progress updates
- Create main window (ONLY after server is ready) ← KEY FIX
- Setup IPC handlers
- Load Open WebUI URL
- 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
Design Pattern: Specialized models, not monolithic
Each model has a clear role:
- 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
- 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
- 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
- Why this model? Can understand images
- Role: Visual analysis
- Best for:
- Screenshot analysis
- UI mockup interpretation
- Diagram understanding
Communication Protocol:
Models communicate via:
- Tool calls:
<tool>toolName</tool><params>{...}</params> - Model delegation: Mentioning
@modelNamein 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
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
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 identifieruserRequest: Original requestmessages: Full conversation historytoolResults: Map of executed toolsactiveModel: Current model handling the taskstatus: 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
Pattern: Secure, typed communication
Security Model:
contextIsolation: true— Renderer can't access Node APIsnodeIntegration: false— No direct Node accesscontextBridge— 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
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
Advantages:
- Predictability: Smaller models are more consistent
- Specialization: Each model excels at its role
- Cost: Cheaper to run multiple small models than one huge one
- Swappability: Can upgrade models independently
- Scaling: Can add more specialized models over time
Inspiration: This mirrors how production AI systems (Cursor, GitHub Copilot, etc.) work internally.
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
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
Models are loaded by Ollama on-demand. First request to each model is slower.
Optimization: Could preload frequently-used models at startup.
Orchestrator has a max iteration limit (20) to prevent infinite loops.
Reason: If planner gets confused, it could loop forever requesting tools.
IPC calls have overhead (serialization, process communication).
Optimization: Batch operations when possible (e.g., read multiple files in one call).
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/.
Trusted:
- User
- Electron main process
- Tool framework
Untrusted:
- AI models (could hallucinate harmful commands)
- Open WebUI renderer (web content, XSS risk)
Protection:
- AI can't execute code directly, only request tools
- Destructive tools require user approval
- Renderer can't access Node APIs
- IPC provides security boundary
Tools can be executed with approval bypassed IF:
- User explicitly approves in UI
- Tool is marked as safe (requiresApproval: false)
Never: AI can't bypass approval on its own.
// In src/ai/cluster.ts
this.models.set("newModel", {
name: "newModel",
role: "Description",
model: "ollama-model-name",
responsibilities: [...]
});- Create tool file in
src/tools/ - Define tool with Tool interface
- Register in
src/tools/index.ts - Tool is automatically available to AI
Can add:
- Database tools (Postgres, MongoDB, etc.)
- API clients (GitHub, Jira, etc.)
- Hardware control (Arduino, Raspberry Pi, etc.)
- Build systems (Webpack, Docker, etc.)
- 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
- 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
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
Similarities:
- Same frontend
Differences:
- CHAD adds AI cluster orchestration
- CHAD adds tool framework
- CHAD adds desktop integration
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
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.