阅读简体中文版:zh_hans/ARCHITECTURE.md。
Codewhale Engine is the existing Rust execution runtime. The Runtime API is its client interface, and TypeScript mods contribute reviewed extensions.
Current boundary note (read the workspace version from Cargo.toml; this
boundary has held since v0.9.1):
crates/tuiis still the live end-user runtime for the TUI, runtime API, task manager, and tool execution loop.- Other workspace crates are being split out incrementally, but they are not yet the sole runtime source of truth.
- The runtime is moving into
crates/runtime(codewhale-runtime) in the orderdocs/design/TUI_DECONSTRUCTION.mdrecords: engine, tools, config, client and stores move there together, never intocrates/core, and the TUI stays the only crate that writes to the terminal. Until a module has moved, its path undercrates/tui/srcis still where it lives. - The LSP subsystem (
crates/tui/src/lsp/) is fully wired into the engine's post-tool-execution path (core/engine/lsp_hooks.rs), providing inline diagnostics afterFilewrite, edit, and patch actions. - The swarm agent system was removed in v0.8.5. The active sub-agent surface is
the single
agenttool; persistent RLM sessions are available through the deferredrlmaction family. No model-visible swarm tool remains in the active codebase.
┌─────────────────────────────────────────────────────────────────┐
│ User Interface │
│ ┌─────────────────┐ ┌─────────────────┐ ┌────────────────┐ │
│ │ TUI (ratatui) │ │ One-shot Mode │ │ Config/CLI │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬───────┘ │
└───────────┼─────────────────────┼────────────────────┼──────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Core Engine │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Agent Loop (core/engine.rs) │ │
│ │ ┌─────────┐ ┌─────────────┐ ┌──────────────────────┐ │ │
│ │ │ Session │ │ Turn Mgmt │ │ Tool Orchestration │ │ │
│ │ └─────────┘ └─────────────┘ └──────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Tool & Extension Layer │
│ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌────────────────┐ │
│ │ Tools │ │ Skills │ │ Hooks │ │ MCP Servers │ │
│ │ (shell, │ │ (plugins)│ │ (pre/ │ │ (external) │ │
│ │ file) │ │ │ │ post) │ │ │ │
│ └──────────┘ └──────────┘ └─────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Runtime API + Task Management │
│ ┌─────────────────────────────┐ ┌──────────────────────────┐ │
│ │ HTTP/SSE Runtime API │ │ Persistent Task Manager │ │
│ │ (runtime_api.rs) │ │ (task_manager.rs) │ │
│ └─────────────────────────────┘ └──────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ LLM Layer │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ LLM Client Layer (client.rs) │ │
│ │ ┌──────────────────┐ ┌─────────────────────────────┐ │ │
│ │ │ OpenAI-compatible │ │ Anthropic / Responses │ │ │
│ │ │ (chat adapter) │ │ (adapters) │ │ │
│ │ └──────────────────┘ └─────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
crates/cli/src/main.rs- The canonical executable entry point.crates/cli/src/lib.rsowns its command interface; terminal and headless runtime startup runs in process through thecodewhale_tuilibrary incrates/tui/src/lib.rs.
core/- Main engine componentsengine.rs- Engine state, operation handling, message processingengine/turn_loop.rs- The existing Engine outer turn loop, shared tool planner/executor/result handling, and stream decoder. Its privateturn_loop/phases contain request preparation (preparation.rs), model dispatch and admission (model_step.rs), the ordered continuation ladder (continuation.rs), inline REPL orchestration (inline_repl.rs), and the direct model tool batch (tool_batch.rs). They borrow the same Engine and TurnContext; they introduce no runtime, session, prompt, approval, event, or persistence authority. Retry, loop termination, and immediate return stay distinct, and only the existing productive paths advance the step.session.rs- Session state managementturn.rs- Turn-based conversation handlingevents.rs- Event system for UI updatesops.rs- Core operations
config.rs- Configuration loading, profiles, environment variablessettings.rs- Runtime settings management
crates/cli- The canonicalcodewhaleexecutable and command interface. It owns commands such asauth,metricsandupdate, and invokes terminal and headless modes (run,exec,doctor,sessions, ...) in process viacodewhale_tui::run(RuntimeOptions, args).crates/tuiis a library; thecodewand legacy release filename aliases contain the same executable.crates/tools- Shared tool invocation primitives, including tool result/error/capability types used by the TUI runtime.crates/agent- Model/provider registry (ModelRegistry) for resolving model IDs to provider endpoints.crates/app-server- HTTP/SSE + JSON-RPC app server transport for headless agent workflows. The canonical executable dispatchesapp-server --http/--mobilein process to the runtime API hosted by thecodewhale_tuilibrary.crates/config- Config loading, profiles, environment variable precedence, CLI runtime overrides.crates/cloud-facts- Fetches the signed Codewhale cloud facts channel (facts/v1), verifies its Ed25519 envelope, and keeps a verified disk cache; never a startup dependency.crates/command-contract- Prototype command capability and dispatch shapes for the staged extraction of TUI commands; shapes only, not yet the production dispatch path.crates/core- Provider-neutral request construction (request.rs), bounded context fragments, the tool-call parser, and thread/session types. It does not own the agent loop: the live turn loop isEngine::run_turnincrates/tui/src/core/engine/turn_loop.rs, andcrates/tui/src/core/is a module inside the TUI crate, not this crate. A placeholderengine/tree here once suggested otherwise — it had no callers and emittedTurnCompletewithout contacting a model — and was removed in v0.9.11. The source guard follows resolved local phase calls and still rejects unlisted loop owners. ACP stdio now projects the existing Runtime manager and Engine; it keeps no provider/tool round loop or separate history. Recursive RLM and mounted Python RPCs now project captured caller authority onto the same Engine producer and Session; no RLM loop exception remains. Python retains its context and variables, while each round borrows the captured route, Native selection, original code gate, cancellation and deadline. Task guidance is bounded and additive to Core policy. Recursive history is retained whole; overflow refuses rather than compacting it. Persistentrlmcontexts remain caller-session scoped andshare_session=trueexplicitly refuses. Child workers also use their captured admission in the same Engine; neither nested host retains a turn-loop exception.crates/execpolicy- Approval/sandbox policy engine for tool execution decisions.crates/hooks- Event sinks (stdout, JSONL file, webhook, Unix socket) for response, tool, job and approval lifecycle events, plus the opt-in lifecycle outbox. User-configured shell hooks that run commands around tool calls are a separate system incrates/tui/src/hooks.rs.crates/localization- Locale registry for user-facing UI chrome strings (crates/localization/locales/*.json); it never changes prompts or model output language.crates/mcp- MCP client + stdio server for Model Context Protocol tool servers.crates/memory- Local, scoped, provenance-bearing memory and resumable state (a library, not a second agent loop).crates/models- Provider request/response models and the offline model metadata catalog.crates/palette- Colour tokens, themes, and contrast math for the terminal UI. Itsratatuifeature (on by default) gates everything that renders; theme ids, setting normalizers and hex parsing compile without it, which is how the runtime links it.crates/paths- User-scoped runtime path authority (CODEWHALE_HOMEand platform home resolution).crates/protocol- Request/response framing and protocol types.crates/runtime-codewhale-runtime, the headless runtime being split out ofcrates/tui(docs/design/TUI_DECONSTRUCTION.md). Today it holds the leaf modules that moved first (retry status, safe labels, sleep guard, session tree, ...) andhost_terminal, the one port through which runtime code asks the terminal UI for a terminal effect. It never depends on the TUI,ratatuiorcrossterm;scripts/check-command-crate-boundaries.pyenforces that and ratchets the runtime -> UI references still incrates/tui.crates/secrets- OS keyring integration for API key storage, plus the shared output sanitizer (sanitize) and redaction (redact) that UI and runtime code both call.crates/state- SQLite thread/session persistence layer.crates/telemetry- Anonymous, user-disableable aggregate usage counting; the only crate allowed to build or send a telemetry payload (docs/TELEMETRY.md).crates/workflow/crates/workflow-js- Workflow engine and its QuickJS scripting layer (renamed from the whaleflow crates).crates/lane- Lane runtime: durable, attachable running instances of Fleet/Workflow work (codewhale lane list/status/attach/logs/stop).crates/release/crates/build-support- Release checks and build plumbing.
client.rs- The live HTTP client layer: OpenAI-compatible, Anthropic, and Responses wire adapters, DeepSeek request-boundary handling, retry policy, and streaming. Provider routes land here through the shared config and catalog layers.llm_client/- LLM client trait, retry logic, and error classification (LlmClient,RetryConfig,with_retry) consumed byclient.rs;mock.rsis test-only (#[cfg(test)]).crates/models(codewhale_models) - Data structures for API requests/responses; the TUI crate has no localmodels.rs.
DeepSeek exposes OpenAI-compatible endpoints. The first-party route uses:
https://api.deepseek.com/beta- default DeepSeek base URL (provider_defaults.rs)https://api.deepseek.com/beta/models- live model discovery and health checks
https://api.deepseek.com/v1 is accepted for OpenAI SDK compatibility, and
can still be configured explicitly to opt out of beta-only features such as
strict tool mode, chat prefix completion, and FIM completion. The public
DeepSeek docs do not document a Responses API path for this workflow; the engine
drives turns through Chat Completions.
tools/- Built-in tool implementationsmod.rs- Tool registry and common typesshell.rs- Shell command executionfile.rs- File read/write operationstodo.rs- Checklist tools plus legacy todo aliasestasks.rs- Model-visible durable task, gate, background shell, and PR-attempt toolsgit.rs- Read-onlygit_status/git_diffinspection wrappersgit_tool.rs- The canonical action-basedGittool (status | diff | log | show | blame); per-action legacy aliases were removed in v0.9.3git_history.rs- Read-onlygit_log/git_show/git_blamegithub/- Unifiedgithubtool family (read-only context plus guarded comment/closure actions backed bygh); deferred by default and discoverable throughtool_searchautomation.rs- Model-visible scheduling tools overAutomationManagerplan.rs- Planning toolssubagent/- Sub-agent launch and supervision.agentis the one creation surface;subagent/coord.rsadds narrow coordination tools (agents/list,agents/message,agents/followup,agents/interrupt,agents/wait,agents/coordinate) over the existing manager. Theagent_open/agent_eval/agent_closelifecycle surface was retired (see thesubagent/coord.rsmodule doc)spec.rs- Tool specificationsrlm.rs- Persistent Recursive Language Model (RLM) sessions — persistent local Python REPL subprocesses (environment-scrubbed, not OS-sandboxed) with semantic helper calls andvar_handleoutput support
mcp.rs- Model Context Protocol client for external tool serversskills/- Skill discovery and registry for localSKILL.mdfiles, plus install and audithooks.rs- Pre/post execution hooks with conditions
tui/- Terminal UI components (ratatui-based; this is a representative list, not exhaustive - the module has grown to 80+ focused files):app.rs- Application state and message handlingui.rs- Event handling, streaming state, and rendering logicapproval.rs- Tool approval dialogclipboard.rs- Clipboard handlingunderwater.rs- Main shell chrome: status chips, mode labels, phase rail
lsp/- Post-edit diagnostics injection (#136)mod.rs-LspManager— lazy per-language transport pool + configclient.rs-StdioLspTransport— JSON-RPC over stdio withdidOpen/didChange/publishDiagnosticsdiagnostics.rs- Diagnostic types, severity, and HTML-block rendererregistry.rs- Language detection and the default server map:rust-analyzer,gopls,pyright-langserver,typescript-language-server,jdtls,intelephense(PHP),vue-language-server,clangd(lsp/registry.rs:98-110)- Wired into the engine via
core/engine/lsp_hooks.rs— called after every successful edit
sandbox/- platform sandbox policy preparation and denial reportingmod.rs- Sandbox type definitionsbackend.rs- Pluggable sandbox backend abstraction (routes shell execution to a remote service, e.g. Alibaba OpenSandbox)policy.rs- Sandbox policy configurationopensandbox.rs- Alibaba OpenSandbox HTTP backend adapterseatbelt.rs- macOS Seatbelt profile generationbwrap.rs- opt-in Linux bubblewrap command wrapperseccomp.rs- dormant Linux seccomp implementation; not wired into commandsprocess_hardening.rs- Linux kernel-level hardening for the TUI process itself (defense-in-depth; not a child-command sandbox)windows.rs- Windows helper contract; not advertised until a Job Object process-containment helper exists
utils.rs- Common utilitieslogging.rs- Logging infrastructurecompaction.rs- Context compaction for long conversationspurge.rs- Agent-driven context purging (surgical message removal/rewriting)pricing.rs- Cost estimationprompts.rs- System prompt templatesruntime_api.rs- HTTP/SSE runtime API (codewhale serve --http)runtime_threads.rs- Durable thread/turn/item store + replayable event timelinetask_manager.rs- Durable queue, worker pool, task timelines and artifacts
- User input received in TUI
- Input processed by
core/engine.rs - Message sent to LLM via
client.rs - Response streamed back, parsed in
client.rs - Tool calls extracted and executed via
tools/ - Hooks triggered before/after tool execution
- Results aggregated and sent back to LLM
- Final response rendered in TUI
- Before sending user input, the TUI writes a checkpoint snapshot to
~/.codewhale/sessions/checkpoints/latest.json - Startup remains fresh by default; prior sessions are resumed explicitly via
--resume/--continue(orCtrl+Rin TUI) - While degraded/offline, new prompts are queued in-memory and mirrored to
~/.codewhale/sessions/checkpoints/offline_queue.json - Queue edits (
/queue ...) are persisted continuously so drafts and queued prompts survive restarts - Successful turn completion clears the active checkpoint and writes a durable session snapshot
- Action-capable turns also take pre/post-turn side-git workspace snapshots under
~/.codewhale/snapshots/<project_hash>/<worktree_hash>/.git;/restore Nandrevert_turnrestore file state without changing conversation history or the user's.git
- LLM requests tool via
tool_usecontent block - Tool registry looks up handler
- Pre-execution hooks run
- Approval requested when the effective permission posture and policy require it
- Tool executed (possibly wrapped by Seatbelt on macOS or opt-in bubblewrap on Linux)
- Post-execution hooks run
- Result metadata is retained on runtime item records
- LSP post-edit hook: after a
Filewrite, edit, or patch action (including a replay-only legacy alias), the engine runsrun_post_edit_lsp_hook()when LSP is enabled to collect diagnostics - Diagnostics flush: before the next API request,
flush_pending_lsp_diagnostics()injects any collected errors as a synthetic user message - Result returned to agent loop
- Client enqueues task (
/task add ...orPOST /v1/tasks) task_manager.rspersists task + queue entry under~/.codewhale/tasks- Worker picks queued task (bounded pool), transitions to
running - Task creates/uses a runtime thread and starts a runtime turn
runtime_threads.rspersists thread/turn/item records + monotonic event sequence- Timeline/tool summaries/artifact references are persisted incrementally
- Checklist state, verifier gates, PR attempts, and guarded GitHub events are applied from tool metadata to the active task
- Final state (
completed|failed|canceled) is durable and queryable via TUI/API
Model-visible durable task tools are a surface over this same manager. They do
not introduce a parallel work system: task_create enqueues normal tasks,
checklist_* updates task-local progress, task_gate_run and completed
task_shell_wait attach verification evidence, and automation runs enqueue
ordinary durable tasks.
- API/TUI creates or resumes a thread (
/v1/threads*) - Turn starts on the thread (
/v1/threads/{id}/turns) - Engine events are mapped to item lifecycle events (
item.started|item.delta|item.completed) - Interrupt/steer operations apply to the active turn only
- Compaction (auto/manual) is emitted as
context_compactionitem lifecycle - Purge (agent-driven) is emitted as
context_purgeitem lifecycle - Clients replay history and resume with
/v1/threads/{id}/events?since_seq=<n>
session_manager.rs,runtime_threads.rs, andtask_manager.rsembedschema_versionon persisted records.- On load, newer schema versions are rejected with explicit errors instead of silently truncating/overwriting data.
- This allows safe forward migrations and prevents corruption when binaries and stored state are out of sync.
- Create handler in
tools/ - Register in
tools/registry.rs - Add tool specification (name, description, input schema)
- Configure in
~/.codewhale/mcp.json - Server auto-discovered at startup
- Tools exposed to LLM automatically
- Create skill directory with
SKILL.md - Define skill prompt and optional scripts
- Place in a Codewhale-owned root (
~/.codewhale/skills/or<workspace>/.codewhale/skills/), or import from a compatible harness root through/skills
See SKILLS.md for the Skills Manager, audit inventory, and the
rule that compatible roots (.claude, .agents, …) are never mutated in place.
Configure in ~/.codewhale/config.toml:
[[hooks]]
event = "tool_call_before"
command = "echo 'Running tool: $TOOL_NAME'"- Streaming-first: All LLM responses stream for responsiveness
- Tool safety: Ask and Auto-Review require approval according to tool and managed policy; Full Access removes ordinary prompts but not hard safety holds. Side-effectful MCP tools use the same boundary.
- Extensibility: MCP, skills, and hooks allow customization without code changes
- Cross-platform: Core works on Linux/macOS/Windows. Sandbox guarantees are platform-specific: macOS uses Seatbelt when available; Linux uses an installed bubblewrap executable only when explicitly enabled; Windows has no advertised OS command sandbox. Seccomp and the Windows helper contract are not wired into command execution.
- Minimal dependencies: Careful dependency selection for build speed
- Local-first runtime API: HTTP/SSE endpoints are intended for trusted localhost access and are served by the
crates/tuiruntime today - Lock poison: fail-stop by default. A poisoned lock means a holder
panicked mid-mutation, so
.expect()with a message naming the lock is the standard posture — never serve half-updated state. Recover withinto_inner()only where stale state is safe (caches, idempotent rebuilds), with a comment saying why.
~/.codewhale/config.toml- Main configuration (~/.deepseek/config.tomlis still read as a legacy fallback)/etc/deepseek/managed_config.toml- Optional managed defaults layer (Unix)/etc/deepseek/requirements.toml- Optional allowed-policy constraints (Unix)~/.codewhale/mcp.json- MCP server configuration~/.codewhale/skills/- User skills directory~/.codewhale/sessions/- Session history~/.codewhale/sessions/checkpoints/- Crash checkpoint + offline queue persistence~/.codewhale/snapshots/- Side-git pre/post-turn workspace snapshots for/restoreandrevert_turn~/.codewhale/tasks/- Background task records, queue, timelines, artifacts~/.codewhale/audit.log- Append-only security events: credential saves and clears, hook environment key names, compaction passes, goal completions, the terminal's approval routing, Auto-Review verdicts, and outbound network decisions when[network]auditing is on. Not an action record: it holds no commands or file changes, and app orserveturns write no approvals there. Seedocs/RECEIPTS.mdfor what a session did~/.codewhale/sessions/<id>/approval_receipts.jsonl- Every approval ask and decision for a session, including who decided