Skip to main content

System overview

31 tools, three agent tiers, and an in-process coordination bus.
User Input
    |
    v
+---------+     +--------------+     +---------------+
| InputBox |---->|   useChat    |---->|  Forge Agent   |
| (OpenTUI)|     |  (AI SDK)    |     | (orchestrator) |
+---------+     +--------------+     +-------+-------+
                                             | dispatch
                              +--------------+--------------+
                              v              v              v
                        +----------+  +----------+  +----------+
                        |  Explore  |  |   Code   |  |WebSearch |
                        | subagent  |  | subagent |  | subagent |
                        +-----+----+  +----+-----+  +----+-----+
                              |            |              |
                              +------+-----+--------------+
                                     v
                              +--------------+
                              |   AgentBus   |
                              | file cache   |
                              | tool cache   |
                              | findings     |
                              | edit mutex   |
                              +--------------+
                                     |
                    +----------------+----------------+
                    v                v                v
             +-----------+   +-----------+   +-----------+
             |   Tools   |   |Intelligence|   |  Neovim   |
             |  31 tools |   |  Router    |   | (msgpack) |
             +-----------+   +-----+-----+   +-----------+
                                   |
                        +----------+----------+
                        v          v          v
                      LSP    tree-sitter    regex

Three-tier agent architecture

TierAgentStep limitToken limitPurpose
1Forge500Full contextMain orchestrator —plans, dispatches, responds
2Code25150KFile edits, refactoring, implementation
2Explore1580KRead-only research, code analysis
2WebSearchMulti-step web research with scraping

AgentBus

In-process coordination layer for parallel subagents. File Cache —First reader caches the content; concurrent readers get the same Promise. Generation counter prevents stale overwrites after concurrent edits. Tool Result Cache —LRU, max 200 entries. Keyed by toolName:canonicalized-args. Covers: read_code, grep, glob, navigate, analyze, web_search. Persists across dispatches via exportCaches(). Edit Mutex —Promise-chaining serializes edits to the same file. First editor becomes owner; second gets a warning. Findings —Agents call report_finding(label, content) to post to the bus. Each step, prepareStep() drains unseen findings and injects them as peer discovery messages.

Step lifecycle

Each agent step passes through prepareStep():
Step 0: toolChoice = "required" (force immediate tool use)
     |
Each step: capture path map -> sanitize inputs -> inject peer findings -> check budget
     |
Step 1+: semantic pruning (stale reads, canceled plans, old edit args)
     |
Step 3+: age-based tool result summarization (rolling window)
  - read_file/read_code: "[pruned] 245 lines -- exports: Foo, Bar"
  - grep: "[pruned] 42 matches"  |  glob: "[pruned] 25 files"
  - edit_file/write_file/create_file: always preserved
     |
Trim threshold (50K explore, 80K code): inject context recovery
     |
Budget warning (60K explore, 120K code): inject "wrap up soon"
     |
Force-done (70K explore, 135K code): activeTools = ["done"]
     |
Hard stop (80K explore, 150K code): abort

Result pipeline

Subagent finishes
    |
extractDoneResult() -- look for structured done() call
    |  found                    |  not found
formatDoneResult()      buildFallbackResult()
(structured summary)    (extract from tool results, 2K/tool, 8K total)
    |                          |
bus.setResult(text)
    |
Multi-agent: aggregate all results + findings
Single-agent: return directly
    |
toModelOutput() -- compact for parent context

Agent quality pipeline

Schema Enforcement —The dispatch schema requires a targetFiles array on every task. Pre-dispatch validation rejects tasks without real file paths before any subagent runs. Complexity-Tier RoutingdetectTaskTier() classifies tasks as trivial or standard. Trivial tasks route to the trivialModel when configured. De-Sloppify Pass —After code agents finish, a cleanup agent runs in fresh context to remove sloppy patterns: tests of language features, redundant type checks, console.log, commented-out code, over-defensive error handling. Done Tool Contracts —Explore and code done tools demand pasteable code, not prose. If the parent has to re-read files, the done call failed.

Intelligence router

Routes code intelligence operations to the best available backend.
BackendTierCapabilities
LSP1definitions, references, rename, diagnostics, code actions, call hierarchy, type info, formatting
ts-morph2TypeScript/JavaScript —AST definitions, references, rename, extract, unused detection
tree-sitter233 languages —symbol extraction, imports/exports, scopes, outlines
regex3Universal fallback —symbol search, simple definitions, import patterns
For each operation, the router tries backends in tier order. If tier 1 returns null or throws, tier 2 is tried, then tier 3.

LSP integration

Dual-backend architecture —the agent always has LSP access regardless of editor state:
  • Neovim bridge: When the editor is open, routes LSP requests through Neovim’s running servers via Lua RPC. Zero startup cost.
  • Standalone client: When the editor is closed, spawns LSP servers directly as child processes with JSON-RPC over stdin/stdout.
  • Multi-language warmup: On boot, detectAllLanguages() scans project config files and spawns standalone LSP servers for all detected languages in parallel.
  • Server discovery: PATH, ~/.soulforge/lsp-servers/, ~/.local/share/soulforge/mason/bin/

Web search system

web_search tool call
    |
    +-- webSearchModel configured?
    |       |
    |       +-- YES -> spawn ToolLoopAgent (up to 15 steps, 120s)
    |       |         +-- web_search tool -> Brave API -> DDG fallback
    |       |         +-- fetch_page tool -> Jina -> Readability -> fallback
    |       |         +-- synthesize structured summary
    |       |
    |       +-- NO -> direct webSearchScraper -> Brave -> DDG
    |
    +-- return result (cached 5 min)
Search BackendTriggerNotes
Brave Search APIBRAVE_API_KEY setStructured results with snippets
DuckDuckGo HTMLBrave unavailableScrapes html.duckduckgo.com, no API key
Page Fetch BackendTriggerNotes
Jina ReaderAlways tried firstReturns clean markdown
ReadabilityJina fails@mozilla/readability + linkedom
Fallback stripReadability failsRegex HTML to text

Context manager

Assembles the system prompt from multiple sources:
  1. Mode instructions —persona-specific behavior
  2. Project info —detected toolchain, package.json metadata
  3. Git context —branch, recent commits, dirty files
  4. Repo map —PageRank-ranked file/symbol view
  5. Memory —persistent project/global memory from SQLite
  6. Forbidden files —security patterns that block AI access
  7. Outside-CWD gating —write tools require confirmation for paths outside the project
  8. Skills —loaded skill instructions
See also: Multi-agent dispatch for AgentBus coordination details, and User steering for mid-execution redirection.

UI layer

Framework: OpenTUI (React reconciler for terminal UIs).
StorePurpose
stores/ui.tsModal state, active panels, layout flags
stores/errors.tsBackground error log
stores/repomap.tsScan progress, stats, semantic summary status
stores/statusbar.tsMemory usage, polling
ComponentPurpose
App.tsxRoot —wires all state, keybindings, modals
InputBox.tsxMultiline input with paste collapse, fuzzy history, command autocomplete
MessageList.tsxChat messages with markdown, syntax highlighting, tool call progress
ContextBar.tsxLive context usage with green/gray dot indicator
EditorPanel.tsxEmbedded Neovim with screen rendering
CommandPicker.tsxSlash command palette
ToolCallDisplay.tsxReal-time tool execution visualization

File layout

src/
+-- boot.tsx                    # Entry point
+-- index.tsx                   # App initialization
+-- components/                 # OpenTUI components
+-- hooks/                      # React hooks (useChat, useNeovim, useTabs...)
+-- stores/                     # Zustand stores
+-- types/                      # Shared type definitions
+-- config/                     # Config loading/saving
+-- core/
    +-- agents/                 # Forge, Code, Explore, WebSearch agents
    |   +-- agent-bus.ts        # Shared coordination bus
    |   +-- subagent-tools.ts   # Dispatch orchestration
    |   +-- step-utils.ts       # Per-step injection logic
    |   +-- stream-options.ts   # Streaming configuration builder
    +-- context/
    |   +-- manager.ts          # System prompt assembly
    +-- editor/                 # Neovim integration
    +-- intelligence/
    |   +-- repo-map.ts         # PageRank codebase index
    |   +-- router.ts           # Multi-backend operation router
    |   +-- post-edit.ts        # Diagnostic diffing after edits
    |   +-- backends/           # LSP, tree-sitter, regex
    +-- llm/                    # Provider config, model registry
    +-- memory/                 # Persistent memory (SQLite)
    +-- modes/                  # Forge personas
    +-- security/               # Forbidden file patterns
    +-- sessions/               # Session persistence + rebuild
    +-- setup/                  # Prerequisite checks
    +-- tools/                  # All 31 tools