18 interconnected systems powering a multi-provider AI coding agent CLI with terminal UI, P2P mesh, preference learning, and autonomous operation. Fork of Anthropic's Claude Code.
Uses Commander.js with ~70+ options. Custom sorted help config. run() creates the program with preAction hook for init and .action() for main dispatch. Mode detection branches interactive vs headless vs init-only.
COMMANDS — memoized lazy loader returning 150+ built-in commands. getCommands(cwd) merges bundled skills, built-in plugin skills, skill directory commands, workflow commands, plugin commands, plugin skills, and core COMMANDS(). Resolution: exact match → prefix match → colon-separated fallback.
setup.ts, 423 lines)initializeFileChangedWatcher(cwd)--worktreeinitSessionMemory(), context collapse (gated)getCommands() + loadPluginHooks() as void promisesSTATE singleton with ~100+ accessor functions exported| Type | Count | Providers |
|---|---|---|
| Dedicated Provider classes | 10 | AnthropicProvider, OpenAIProvider, GoogleProvider, CohereProvider, OpenRouterProvider, KiloCodeProvider, OllamaProvider, ClewGatewayProvider, OpenAICompatibleProvider, ProviderInterface |
| OpenAI-compatible (driven by providers.json) | 23 | deepseek, opencode, opencode-go, groq, xai, mistral, together, fireworks, nvidia, deepinfra, perplexity, cerebras, siliconflow, moonshot, zhipu, huggingface, poe, digitalocean, cline, and custom |
Selection priority chain (getActiveProviderName):
Config persistence: User-level ~/.claude/provider.json, project-level .claude/provider.json (takes priority). Auth resolved via getApiKeyForProvider() — checks session keys → OAuth tokens → persisted config → environment variables.
interface ProviderInterface { readonly providerId: ProviderId; readonly label: string; getProviderId(): ProviderId; getProviderLabel(): string; getProviderApiKeyEnvVar(): string; createClient(options: ProviderInitOptions): Promise<ProviderClient>; listModels(options: ProviderInitOptions): Promise<{ id: string; label: string }[]>; }
Layer 1 — Provider SDK: chat.completions.create({ stream: true }) returns SSE AsyncGenerator.
Layer 2 — AnthropicAdapter: Wraps any provider into Anthropic-compatible BetaRawMessageStreamEvent types via wrapStream(). Converts OpenAI delta chunks → Anthropic events (message_start, content_block_start, content_block_delta, etc.). Supports thinking/reasoning_content blocks.
Stream watchdog: 45s (OpenAI-compatible), 60s (Google), 30s (default). Throws stall error if no chunk arrives.
The src/services/ai/ module also includes: ModelDiscoveryService, BrowserAgent, contentBlockUtils, errorNormalizer, providerMetadata, providerModels, toolCallParser, usageNormalizer, usageTypes (130 lines).
One instance per conversation. Manages mutableMessages, abortController, totalUsage, readFileState (file cache), discoveredSkillNames, loadedNestedMemoryPaths.
Key method: submitMessage() — AsyncGenerator that orchestrates user input → system init → AI loop → post-processing → result.
query() → queryLoop())fetchSystemPromptParts() — default + user context + system context (tools, model, MCP clients, working dirs)CLAUDE_COWORK_MEMORY_PATH_OVERRIDE is setgetTasteInjectionBlock() + evaluated rules with confidence ≥ 55%appendSystemPrompt — additional prompt appendedState.transition controls loop iteration: max_output_tokens_escalate, max_output_tokens_recovery, reactive_compact_retry, collapse_drain_retry, stop_hook_blocking, goal_continuation, token_budget_continuation, brief_mode_retry, completed.
QueryDeps — tests can inject fakes for callModel, microcompact, autocompacttryAutoRunDynamicWorkflow() classifies task complexity, spawns parallel coordinator workflowsquery/config.ts) — snapshots immutable values at query entryStructural type (Tool<Input, Output, P>), not a class. Created via buildTool(def) which fills safe defaults. ~30+ lifecycle/UI/safety methods per tool.
| Category | Tools |
|---|---|
| Filesystem | FileRead, FileEdit, FileWrite, Glob, Grep, NotebookEdit |
| Execution | Bash, PowerShell, REPL, ComputerUse |
| Web | WebSearch, WebFetch, MultiSearch, Browser, BrowserAgent |
| Planning/Mode | EnterPlanMode, ExitPlanMode, EnterWorktree, ExitWorktree, Brief |
| Peer Collaboration (17) | PeerDiscover, PeerSendMessage, PeerSpawn, PeerShare, PeerInfo, PeerRun, PeerJoin, PeerSetName, PeerSetRole, PeerListRoles, PeerPing, PeerDisconnect, PeerBroadcast, PeerListMessages, PeerHelp, ProcessPeer, ListPeers |
| MCP | MCPTool, McpAuthTool, ListMcpResourcesTool, ReadMcpResourceTool |
| Task Management | TaskCreate, TaskGet, TaskUpdate, TaskList, TaskOutput, TaskStop |
| Skill & Taste | Skill, TasteLearn, TasteForget, TasteProfile, TasteSuggest |
| Code/Dev | LSP, PR, PrSubscription, JsonPath, Tungsten, Research |
| Team | TeamCreate, TeamDelete |
| Automation (10) | ScheduleCron, Sleep, RemoteTrigger, Workflow, Monitor, PushNotification, SubscribePR, SuggestBackgroundPR, VerifyPlanExecution, SendUserFile |
| Meta/Search | ToolSearch, SessionSearch, TodoWrite, SyntheticOutput |
| Communication | SendMessage, AskUserQuestion, Config, RequestShutdown |
| Agent | AgentTool |
tools.ts)Core tools statically imported. Feature-gated tools (REPLTool, ComputerUseTool, LSPTool, worktree, team, PowerShell, ToolSearchTool) lazy-loaded via helper getters.
Pipeline: getAllBaseTools() → getTools(permissionContext) (filter by SIMPLE mode, isEnabled, deny rules) → assembleToolPool(permCtx, mcpTools) (merge + dedup).
| Module | Role |
|---|---|
| PeerServer | Lightweight HTTP server on 127.0.0.1 (random OS port). Endpoints: GET /peer-info, GET /peer-events (SSE), POST /peer-msg, POST /peer-todo, POST /peer-exec, WebSocket upgrade /peer-chat (currently destroyed) |
| PeerDiscovery | Two-layer: file registry (~/.claude/peers/{pid}.json, 30s heartbeat, 90s stale timeout) + UDP multicast (239.255.37.37:42069, currently disabled for localhost safety) |
| PeerStore | In-memory peer registry with auto-eviction, message queuing (chunked reassembly), liveness pings (60s interval) |
| ProcessPeerProvider | Runs AI tasks as subprocesses — exec mode (spawn with stdin) or PTY mode (node-pty for interactive). Default command: codex |
PeerDiscover, PeerSendMessage, PeerSpawn, PeerShare, PeerInfo, PeerRun, PeerJoin, PeerSetName, PeerSetRole, PeerListRoles, PeerPing, PeerDisconnect, PeerBroadcast, PeerListMessages, PeerHelp, ProcessPeer, ListPeers.
src/services/taste/ — TasteIntegration.ts + 7 subdirectories:
| Subdir | Files | Contents |
|---|---|---|
core/ | 9 | TasteBandit, TasteDecay, TasteMemory, TasteNeuralScorer, TastePolicy, TasteRewardModel, TasteRuntime, TasteSymbolicEngine, TasteTypes |
auto-learn/ | 4 | AutoLearnEngine, PatternDetector, TasteCodebaseAnalyzer |
signals/ | 4 | AcceptRejectTracker, DiffSignalExtractor, EditDistanceReward, TasteSignalCollector |
prompt/ | 2 | TasteConstraintCompiler, TastePromptInjector |
storage/ | — | Profile store, event log |
eval/ | — | Evaluation utilities |
6 arms: minimal, strict_style, architecture_first, test_first, safety_first, refactor_heavy. Exploit (80%): pick highest averageReward. Explore (ε=0.2): pick random arm weighted by inverse pulls. Epsilon decays by 0.99×/update, floor 0.05. Supports future BanditContext extension (file ext, command type, model provider).
Provider-agnostic — uses Jaccard similarity + TF-IDF tokenization. Tokenization: strip punctuation, lowercase, remove 100+ stop words, filter <2 chars. Scoring: Jaccard|tokens∩|/|tokens∪| + tag bonus (0.05/tag). Combined: finalScore = (avgSimilarity × 0.5) + (outputScore × 0.5).
Project ({cwd}/.clew/taste/profile.json), Global (~/.clew/taste/profile.json), Session (RAM ring buffer: 200 events, 100 rules). Load order: Project → Global → new project-level created.
Auto-Learn: PatternDetector — min 5 events, min 3 occurrences to suggest, auto-accept at confidence ≥ 0.7, 30-min cooldown. Decay: half-life 30 days, decayedExcess = excess × 0.5^(daysSinceUse/30), floor at 0.5.
<clew_taste> block (max 8 rules, min confidence 0.55)TastePolicy.evaluate() — symbolic + neural scorer, scores ≥ 0.85 can block editsgetCurrentArm()Services: agentLoop.ts, daemonMode.ts, supervisorIntegration.ts, taskQueue.ts. Supervisor: supervisor.ts, ipcClient.ts. Agent Runtime: 17 files at src/agentRuntime/ — including ultracode.ts, ultracodeBridge.ts, orchestrator.ts, dynamicWorkflow.ts, transcriptClassifier.ts, verifierAgent.ts, workflowRegistry.ts, toolGateway.ts.
Worker spawns child Bun process via Supervisor IPC (main.tsx -p). Max 3 concurrent workers. Task timeout 30 min.
File-backed at ~/.claude/daemon/tasks.json. Key fields: id, priority (critical/high/normal/low), status (pending→in_progress→completed/failed/cancelled/dead_letter), scheduledAt, dependsOn, retryCount/maxRetries (default 3), leaseOwner/leaseExpiresAt (5-min default), projectRoot, tags, errorLog (last 20 lines).
One per user, auto-started. Transport: Windows named pipe or Unix socket. Commands: spawn, attach, stop, respawn, rm, list, logs, shutdown, ping, autonomous_start/stop/status. Auto-exits after 1hr idle. Detects binary upgrades (inode/mtime check every 5min).
base × factor^retryCount (capped at 1h)src/services/mcp/Key files: client.ts (connection management + tool/resource fetching), auth.ts (2207 lines — OAuth + XAA), config.ts (multi-source config), types.ts (state enums + types), useManageMCPConnections.ts (React lifecycle), MCPConnectionManager.tsx (React context), InProcessTransport.ts, SdkControlTransport.ts, claudeai.ts, xaa.ts, xaaIdpLogin.ts, elicitationHandler.ts, mcpStringUtils.ts, channelAllowlist.ts, oauthPort.ts, officialRegistry.ts.
| Transport | Mechanism | Reconnection |
|---|---|---|
| Stdio | Child process spawn | No (process exited) |
| HTTP (StreamableHTTP) | MCP Streamable HTTP spec | Exponential backoff, 5 attempts |
| SSE | Long-lived SSE + POST messages | Same as HTTP |
| WebSocket | Custom transport (Bun + ws package) | — |
| SDK | In-process CLI↔SDK bridge | — |
| In-Process | Linked transport pair (queueMicrotask) | — |
Standard flow: RFC 8414 discovery → localhost callback server (127.0.0.1:random) → browser popup → CSRF state validation → code exchange → OS keychain storage (keyed by serverName|sha256(configHash)[:16]). Token refresh with lockfile-based cross-process coordination, exponential backoff (1s, 2s, 4s).
XAA (SEP-990): Single IdP login across all XAA servers. OIDC + PKCE browser popup → RFC 8693/7523 token exchange (no browser). Silent refresh reuses cached id_token for zero-interaction re-auth.
Step-Up Auth: Detects 403 insufficient_scope, forces PKCE re-auth.
fetchToolsForClient() (memoized) → client.listTools() → wraps each in MCPTool. Tools named mcp__<server>__<toolName>. Dynamic updates via tools.listChanged capability. Resources fetched via fetchResourcesForClient(), with subscription support and skills integration.
Precedence: enterprise > local (.claude/settings.local.json) > project (.mcp.json) > user > dynamic (--mcp-config) > claudeai > managed. Each server validated independently. Supports env var expansion (${VAR_NAME}). Enterprise policy: allowedMcpServers, deniedMcpServers, allowManagedMcpServersOnly.
src/bridge/Key files: bridgeMain.ts (2651 lines — v1 env-based daemon), replBridge.ts (2166 lines — v1 REPL bridge), remoteBridgeCore.ts (861 lines — v2 env-less), initReplBridge.ts, jwtUtils.ts, replBridgeTransport.ts, bridgeApi.ts, bridgeConfig.ts, bridgeMessaging.ts, sessionRunner.ts, inboundMessages.ts, inboundAttachments.ts, createSession.ts, trustedDevice.ts, flushGate.ts, capacityWake.ts, workSecret.ts, types.ts.
v1 (Environment-based): Registers on claude.ai via POST /v1/environments. Poll loop: pollForWork() → WorkSecret (session_ingress_token + api_base_url). Spawns child processes via Session-Ingress WebSocket → HybridTransport. Lifecycle: register → poll → ack → spawn → heartbeat → stop → deregister.
v2 (Env-less, newer): Skips Environments API. Connects via POST /v1/code/sessions (OAuth) → POST /v1/code/sessions/{id}/bridge → worker_jwt. Uses SSETransport (reads) + CCRClient (writes via /worker/*). Token refresh bumps epoch. Gated by tengu_bridge_repl_v2.
createTokenRefreshScheduler — reads JWT exp, sets timer for exp - 5min_buffer. Generation counter per session prevents stale refreshes. Retry: up to 3 failures, 60s delay. Fallback every 30min for long-running sessions.
RemoteServer — HTTP+WS server: GET /health, POST /v1/sessions, GET /ws. Token store: one-time tokens clew-rt-<24-hex>, SHA-256 hashed, 24h expiry. Relay Server (NAT traversal): JSON over WebSocket, pairs listener + connector, forwards data bidirectionally.
Service layer: src/services/plugins/ — pluginOperations.ts, PluginInstallationManager.ts, pluginCliCommands.ts. Builtin: src/plugins/builtinPlugins.ts, src/plugins/bundled/. External: plugins/ directory.
Hook types: command (shell exec), prompt (LLM eval), agent (verifier), http (POST), callback (internal). Events include: Setup, SessionStart, UserPromptSubmit, PreToolUse/PostToolUse/PostToolUseFailure, PermissionRequest/PermissionDenied, Stop/StopFailure, SessionEnd, SubagentStart/Stop, PreCompact/PostCompact, Elicitation, ConfigChange, WorktreeCreate/Remove, FileChanged, CwdChanged, TeammateIdle, TaskCreated/Completed, InstructionsLoaded, MessageDisplay.
Exit codes: 0 = stdout to Claude, 2 = stderr to model (blocking). Supports async: true (background), once: true (auto-remove), if conditions (permission rule syntax).
plugin.json fields: name, version, dependencies, commands, agents, skills, hooks, mcpServers, lspServers, userConfig, settings, strict. Marketplace sources: github, git, url, npm, file, directory. Dependency resolution: DFS with cycle detection. Cross-marketplace deps blocked by default.
commit-commands, code-review, feature-dev, frontend-design, security-guidance, agent-sdk-dev, hookify, plugin-dev, pr-review-toolkit, plus output styles and migrations.
store.ts — generic createStore<T>() returning { getState, setState, subscribe }. Uses Object.is for no-op skip.
AppStateStore.ts — AppState type (~80 fields): settings, MCP connections, plugins, tasks, tool permissions, bridge, speculation, voice, tmux/tungsten, agent definitions, file history, notifications.
AppState.tsx — React glue: AppStateProvider creates store, provides via context. useAppState(selector) uses useSyncExternalStore. useSetAppState() stable updater ref.
onChangeAppState.ts — side-effect orchestrator: syncs permission mode to CCR/SDK, persists model/settings.
selectors.ts — getViewedTeammateTask(), getActiveAgentForInput().
teammateViewHelpers.ts — agent view utilities.
src/ink/, 97 files)A reimplementation of the ink library:
reconciler.ts) — custom React fiber reconciler using react-reconcilerrenderer.ts, render-to-screen.ts, render-node-to-output.ts (virtual tree → ANSI escape sequences)Box, Text, Button, Spacer, Newline, Link, ScrollBox, AlternateScreenuse-input, use-app, use-stdin, use-interval, use-animation-frame, use-terminal-viewport, use-selection, use-search-highlight, use-tab-status, use-terminal-focussrc/components/, 461 files)App.tsx (top-level with AppStateProvider, stats, FPS, Sentry), Messages.tsx, Message.tsx, MessageRow.tsxPromptInput/ directory — input, footer, voice indicator, history search, suggestionsUserPromptMessage, AssistantTextMessage, AssistantThinkingMessage, AssistantToolUseMessage, UserBashInputMessage, UserToolResultMessage, SystemTextMessage + many moreThemedText, ThemedBox, Dialog, Pane, Tabs, Divider, ListItem, ProgressBar, StatusIconsrc/screens/, 3 files)REPL.tsx — main read-eval-print loop. Doctor.tsx — diagnostics screen. ResumeConversation.tsx — session picker with progressive loading.
| Category | Commands |
|---|---|
| Core session | /clear, /compact, /exit, /resume, /session, /status, /version |
| Configuration | /config, /model, /provider-select, /theme, /color, /output-style, /effort, /fast, /thinking, /keybindings, /scroll-speed |
| Collaboration | /buddy, /peer, /bridge, /remote, /teleport, /session |
| Code review | /review, /pr, /diff, /commit, /commit-push-pr, /branch, /autofix-pr |
| Agent management | /agent, /agents, /skill, /skills, /task, /tasks, /daemon |
| Utilities | /help, /doctor, /cost, /usage, /stats, /export, /install, /upgrade, /feedback, /recap |
| MCP/Plugin | /plugin, /mcp, /reload-plugins, /searxng, /tools |
| Voice/UI | /voice, /vim, /desktop, /mobile, /sandbox-toggle |
| Advanced | /ultraplan, /ultracode, /goal, /plan, /research, /workflow, /thinkback, /thinkback-play, /bg, /explorer |
| Auth | /login, /logout, /oauth-refresh |
Also includes: /taste, /taste1, /memory, /context, /rename, /tag, /insights, /guardian, /approve, /brief, /copy, /onboarding, /powerup, /looplock, /passes, /privacy-settings, /permissions, /env, /files, advisory commands, and many more.
addToTotalSessionCost(cost, usage, model) — accepts both Anthropic (snake_case) and generic (camelCase) usage. Accumulates input/output/cache tokens per model. Tracks advisor usage costs. Sends OpenTelemetry metrics.
Session persistence: restoreCostStateForSession(sessionId) reads from project config; saveCurrentSessionCosts() writes back with FPS metrics and per-model usage. Re-exports from bootstrap/state: getTotalCost, getTotalInputTokens, getTotalOutputTokens, getTotalDuration, getTotalAPIDuration, getModelUsage.
Prompt history persists to ~/.claude/history.jsonl:
addToHistory(entry) — deduplicates consecutive identical entries. Large paste contents hashed to pasteStore.getHistory() — async generator: current-session first (newest-first), then cross-session. Max 1000 items.getTimestampedHistory() — for ctrl+R picker: deduplicated by display text, lazy resolve() for paste contents.removeLastFromHistory() — undo last entry (Esc-rewind): fast path pops pending buffer.getSystemContext())gitStatus — Git branch, short status, recent commits (memoized, capped 2000 chars, async exec)capabilities — detected system tools availablecomputerUseHint — prompt injection when computer use enabledcacheBreaker — ephemeral injection (ant-only, cache breaking)getUserContext())claudeMd — parsed CLAUDE.md / memory files from .claude/memory/currentDate — today's date stringtoolPermissionContext lives in AppState (not context.ts). This module provides the context window content for the LLM's workspace understanding. Tool permissions use classifier + rules + prompt approval in the tool execution pipeline. initializeToolPermissionContext() is called with allowed/disallowed tool lists.
isVoiceGrowthBookEnabled() — always true in OSS buildhasVoiceAuth() — requires valid Anthropic OAuth tokens (voice_stream endpoint)hasAlternativeSttKey() — true if OPENAI_API_KEY, GROQ_API_KEY, or WHISPER_API_KEY + WHISPER_API_URL setisVoiceModeEnabled() — full check: hasVoiceAuth() || hasAlternativeSttKey() AND GrowthBook gateSpans into src/commands/voice/ (/voice command), src/services/voice.ts, voiceStreamSTT.ts, voiceKeyterms.ts, and UI components VoiceIndicator, VoiceModeNotice. Supports Anthropic voice streaming + alternative STT (OpenAI, Groq, Whisper).
src/memory/| File | Purpose |
|---|---|
db.ts | SQLite bootstrap: sources, chunks, chunks_fts (FTS5). WAL mode. DB at .claude/index/chunks.db |
store.ts | CRUD: getSource, upsertSource, deleteSource, insertChunks (FTS transaction), searchChunksFTS (sanitized prefix search) |
search.ts | searchMemories(cwd, query, limit) — FTS + scoring: priority (0-1) × recency (0-0.15 for <24h) × lexical. Returns sorted MemorySearchResult[] |
ingest.ts | ingestMemoryWorkspace(cwd, config) — full re-scan, content hash compare, re-chunk changed files, delete removed |
chunker.ts | chunkMarkdown() — splits by word boundary, default 3000 tokens/chunk |
redact.ts | redactSecrets() — strips API keys, tokens before indexing |
types.ts | MemoryType: user, project, feedback, agent, pending, wiki, run, index |
runs/runWriter.ts | Writes conversation summaries to memory |
Truth priority: user=80, feedback=70, project=60, default=50. Content hashing: quick stat-based (relPath + size + mtime) avoids re-indexing. Config: memory dir, wiki dir, index dir, max chunk tokens (3000), auto-capture, auto-sync, exclude globs.
Interactive: main.tsx → showSetupScreens() → LaunchRepl() → Ink TUI → QueryEngine → AI loop → Tool execution → Response
Headless (--print): main.tsx → runHeadless() → headlessStore → QueryEngine → StructuredIO → stdout
Autonomous: Supervisor IPC → daemonMode.ts → agentLoop.ts → taskQueue → spawn workers via IPC → monitor → complete/fail
Peer-to-Peer: /peer share → PeerDiscovery → PeerServer on random port → file registry → HTTP POST/SSE → peers communicate
Bridge: /bridge → initReplBridge() → v1 (env poll loop) or v2 (env-less) → JWT refresh → bidir message relay
| # | System | Depends On | Used By |
|---|---|---|---|
| 1 | Entry Point | — | All |
| 2 | AI Providers | — | QueryEngine, Tools |
| 3 | Query Engine | Providers, Tools, Taste, Context | REPL, Headless, Workers |
| 4 | Tool System | AppState, MCP | QueryEngine |
| 5 | Peer-to-Peer | AppState | Commands, Autonomous |
| 6 | Taste | Storage | QueryEngine |
| 7 | Autonomous | Supervisor, Queue | Daemon, Cron |
| 8 | MCP | Auth | Tools, QueryEngine |
| 9 | Bridge | Providers, Auth | Remote sessions |
| 10 | Plugins | Settings | Commands, Hooks, Agents |
| 11 | AppState | — | All |
| 12 | Ink UI | AppState | REPL, Interactive |
| 13 | Commands | AppState, Plugins | REPL |
| 14 | Cost & History | Bootstrap state | Reporting, Resume |
| 15 | Context | Git, FS | QueryEngine |
| 16 | Voice | OAuth | REPL |
| 17 | Memory | SQLite | QueryEngine |
| File | Lines | Role |
|---|---|---|
main.tsx | 6,475 | Entry — full bootstrap + CLI + lifecycle |
query.ts | 1,623 | Core AI loop |
QueryEngine.ts | 1,219 | Conversation orchestrator |
Tool.ts | 782 | Base tool type + buildTool() |
commands.ts | 740 | Command registrations |
ProviderManager.ts | 369 | Provider selection singleton |
setup.ts | 423 | Init/setup sequence |
context.ts | 195 | System + user context |
history.ts | 451 | Prompt history persistence |
cost-tracker.ts | 350 | Token/cost accounting |
bridgeMain.ts | 2,651 | v1 bridge daemon |
replBridge.ts | 2,166 | v1 REPL bridge |
mcp/auth.ts | 2,207 | MCP OAuth + XAA |
providers.json | 2,197 | AI provider definitions |
remoteBridgeCore.ts | 861 | v2 env-less bridge |