返回 CodeWhale
ARCHITECTURE.md
根目录 / docs / ARCHITECTURE.md
1 # Codewhale Architecture
2
3 > 阅读简体中文版:[zh_hans/ARCHITECTURE.md](zh_hans/ARCHITECTURE.md)。
4
5 Codewhale Engine is the existing Rust execution runtime. The
6 [Runtime API](RUNTIME_API.md) is its client interface, and
7 [TypeScript mods](EXTENSIONS.md) contribute reviewed extensions.
8
9 Current boundary note (read the workspace version from `Cargo.toml`; this
10 boundary has held since v0.9.1):
11 - `crates/tui` is still the live end-user runtime for the TUI, runtime API, task manager, and tool execution loop.
12 - Other workspace crates are being split out incrementally, but they are not yet the sole runtime source of truth.
13 - The runtime is moving into `crates/runtime` (`codewhale-runtime`) in the
14 order `docs/design/TUI_DECONSTRUCTION.md` records: engine, tools, config,
15 client and stores move there together, never into `crates/core`, and the
16 TUI stays the only crate that writes to the terminal. Until a module has
17 moved, its path under `crates/tui/src` is still where it lives.
18 - The LSP subsystem (`crates/tui/src/lsp/`) is fully wired into the engine's
19 post-tool-execution path (`core/engine/lsp_hooks.rs`), providing inline
20 diagnostics after `File` write, edit, and patch actions.
21 - The swarm agent system was removed in v0.8.5. The active sub-agent surface is
22 the single `agent` tool; persistent RLM sessions are available through the
23 deferred `rlm` action family.
24 No model-visible swarm tool remains in the active codebase.
25
26 ## High-Level Overview
27
28 ```
29 ┌─────────────────────────────────────────────────────────────────┐
30 │ User Interface │
31 │ ┌─────────────────┐ ┌─────────────────┐ ┌────────────────┐ │
32 │ │ TUI (ratatui) │ │ One-shot Mode │ │ Config/CLI │ │
33 │ └────────┬────────┘ └────────┬────────┘ └────────┬───────┘ │
34 └───────────┼─────────────────────┼────────────────────┼──────────┘
35 │ │ │
36 ▼ ▼ ▼
37 ┌─────────────────────────────────────────────────────────────────┐
38 │ Core Engine │
39 │ ┌─────────────────────────────────────────────────────────┐ │
40 │ │ Agent Loop (core/engine.rs) │ │
41 │ │ ┌─────────┐ ┌─────────────┐ ┌──────────────────────┐ │ │
42 │ │ │ Session │ │ Turn Mgmt │ │ Tool Orchestration │ │ │
43 │ │ └─────────┘ └─────────────┘ └──────────────────────┘ │ │
44 │ └─────────────────────────────────────────────────────────┘ │
45 └─────────────────────────────────────────────────────────────────┘
46 │ │ │
47 ▼ ▼ ▼
48 ┌─────────────────────────────────────────────────────────────────┐
49 │ Tool & Extension Layer │
50 │ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌────────────────┐ │
51 │ │ Tools │ │ Skills │ │ Hooks │ │ MCP Servers │ │
52 │ │ (shell, │ │ (plugins)│ │ (pre/ │ │ (external) │ │
53 │ │ file) │ │ │ │ post) │ │ │ │
54 │ └──────────┘ └──────────┘ └─────────┘ └────────────────┘ │
55 └─────────────────────────────────────────────────────────────────┘
56 │ │ │
57 ▼ ▼ ▼
58 ┌─────────────────────────────────────────────────────────────────┐
59 │ Runtime API + Task Management │
60 │ ┌─────────────────────────────┐ ┌──────────────────────────┐ │
61 │ │ HTTP/SSE Runtime API │ │ Persistent Task Manager │ │
62 │ │ (runtime_api.rs) │ │ (task_manager.rs) │ │
63 │ └─────────────────────────────┘ └──────────────────────────┘ │
64 └─────────────────────────────────────────────────────────────────┘
65 │ │
66 ▼ ▼
67 ┌─────────────────────────────────────────────────────────────────┐
68 │ LLM Layer │
69 │ ┌──────────────────────────────────────────────────────────┐ │
70 │ │ LLM Client Layer (client.rs) │ │
71 │ │ ┌──────────────────┐ ┌─────────────────────────────┐ │ │
72 │ │ │ OpenAI-compatible │ │ Anthropic / Responses │ │ │
73 │ │ │ (chat adapter) │ │ (adapters) │ │ │
74 │ │ └──────────────────┘ └─────────────────────────────┘ │ │
75 │ └──────────────────────────────────────────────────────────┘ │
76 └─────────────────────────────────────────────────────────────────┘
77 ```
78
79 ## Module Organization
80
81 ### Entry Point
82
83 - **`crates/cli/src/main.rs`** - The canonical executable entry point. `crates/cli/src/lib.rs` owns its command interface; terminal and headless runtime startup runs in process through the `codewhale_tui` library in `crates/tui/src/lib.rs`.
84
85 ### Core Components
86
87 - **`core/`** - Main engine components
88 - `engine.rs` - Engine state, operation handling, message processing
89 - `engine/turn_loop.rs` - The existing Engine outer turn loop, shared tool
90 planner/executor/result handling, and stream decoder. Its private
91 `turn_loop/` phases contain request preparation (`preparation.rs`), model
92 dispatch and admission (`model_step.rs`), the ordered continuation ladder
93 (`continuation.rs`), inline REPL orchestration (`inline_repl.rs`), and the
94 direct model tool batch (`tool_batch.rs`). They borrow the same Engine and
95 TurnContext; they introduce no runtime, session, prompt, approval, event,
96 or persistence authority. Retry, loop termination, and immediate return
97 stay distinct, and only the existing productive paths advance the step.
98 - `session.rs` - Session state management
99 - `turn.rs` - Turn-based conversation handling
100 - `events.rs` - Event system for UI updates
101 - `ops.rs` - Core operations
102
103 ### Configuration
104
105 - **`config.rs`** - Configuration loading, profiles, environment variables
106 - **`settings.rs`** - Runtime settings management
107
108 ### Workspace Crates
109
110 - **`crates/cli`** - The canonical `codewhale` executable and command interface.
111 It owns commands such as `auth`, `metrics` and `update`, and invokes terminal
112 and headless modes (`run`, `exec`, `doctor`, `sessions`, ...) in process via
113 `codewhale_tui::run(RuntimeOptions, args)`. `crates/tui` is a library; the
114 `codew` and legacy release filename aliases contain the same executable.
115 - **`crates/tools`** - Shared tool invocation primitives, including tool result/error/capability types used by the TUI runtime.
116 - **`crates/agent`** - Model/provider registry (ModelRegistry) for resolving model IDs to provider endpoints.
117 - **`crates/app-server`** - HTTP/SSE + JSON-RPC app server transport for
118 headless agent workflows. The canonical executable dispatches
119 `app-server --http`/`--mobile` in process to the runtime API hosted by the
120 `codewhale_tui` library.
121 - **`crates/config`** - Config loading, profiles, environment variable precedence, CLI runtime overrides.
122 - **`crates/cloud-facts`** - Fetches the signed Codewhale cloud facts channel
123 (`facts/v1`), verifies its Ed25519 envelope, and keeps a verified disk cache;
124 never a startup dependency.
125 - **`crates/command-contract`** - Prototype command capability and dispatch
126 shapes for the staged extraction of TUI commands; shapes only, not yet the
127 production dispatch path.
128 - **`crates/core`** - Provider-neutral request construction (`request.rs`),
129 bounded context fragments, the tool-call parser, and thread/session types.
130 It does **not** own the agent loop: the live turn loop is
131 `Engine::run_turn` in `crates/tui/src/core/engine/turn_loop.rs`, and
132 `crates/tui/src/core/` is a module inside the TUI crate, not this crate. A
133 placeholder `engine/` tree here once suggested otherwise — it had no callers
134 and emitted `TurnComplete` without contacting a model — and was removed in
135 v0.9.11. The source guard follows resolved local phase calls and still
136 rejects unlisted loop owners. ACP stdio now projects the existing Runtime
137 manager and Engine; it keeps no provider/tool round loop or separate history.
138 Recursive RLM and mounted Python RPCs now project captured caller authority
139 onto the same Engine producer and Session; no RLM loop exception remains.
140 Python retains its context and variables, while each round borrows the
141 captured route, Native selection, original code gate, cancellation and
142 deadline. Task guidance is bounded and additive to Core policy. Recursive
143 history is retained whole; overflow refuses rather than compacting it.
144 Persistent `rlm` contexts remain caller-session scoped and `share_session=true`
145 explicitly refuses. Child workers also use their captured admission in the
146 same Engine; neither nested host retains a turn-loop exception.
147 - **`crates/execpolicy`** - Approval/sandbox policy engine for tool execution decisions.
148 - **`crates/hooks`** - Event sinks (stdout, JSONL file, webhook, Unix socket)
149 for response, tool, job and approval lifecycle events, plus the opt-in
150 lifecycle outbox. User-configured shell hooks that run commands around tool
151 calls are a separate system in `crates/tui/src/hooks.rs`.
152 - **`crates/localization`** - Locale registry for user-facing UI chrome strings
153 (`crates/localization/locales/*.json`); it never changes prompts or model
154 output language.
155 - **`crates/mcp`** - MCP client + stdio server for Model Context Protocol tool servers.
156 - **`crates/memory`** - Local, scoped, provenance-bearing memory and
157 resumable state (a library, not a second agent loop).
158 - **`crates/models`** - Provider request/response models and the offline model
159 metadata catalog.
160 - **`crates/palette`** - Colour tokens, themes, and contrast math for the
161 terminal UI. Its `ratatui` feature (on by default) gates everything that
162 renders; theme ids, setting normalizers and hex parsing compile without it,
163 which is how the runtime links it.
164 - **`crates/paths`** - User-scoped runtime path authority (`CODEWHALE_HOME`
165 and platform home resolution).
166 - **`crates/protocol`** - Request/response framing and protocol types.
167 - **`crates/runtime`** - `codewhale-runtime`, the headless runtime being
168 split out of `crates/tui` (`docs/design/TUI_DECONSTRUCTION.md`). Today it
169 holds the leaf modules that moved first (retry status, safe labels, sleep
170 guard, session tree, ...) and `host_terminal`, the one port through which
171 runtime code asks the terminal UI for a terminal effect. It never depends on
172 the TUI, `ratatui` or `crossterm`; `scripts/check-command-crate-boundaries.py`
173 enforces that and ratchets the runtime -> UI references still in `crates/tui`.
174 - **`crates/secrets`** - OS keyring integration for API key storage, plus the
175 shared output sanitizer (`sanitize`) and redaction (`redact`) that UI and
176 runtime code both call.
177 - **`crates/state`** - SQLite thread/session persistence layer.
178 - **`crates/telemetry`** - Anonymous, user-disableable aggregate usage
179 counting; the only crate allowed to build or send a telemetry payload
180 (`docs/TELEMETRY.md`).
181 - **`crates/workflow`** / **`crates/workflow-js`** - Workflow engine and its
182 QuickJS scripting layer (renamed from the whaleflow crates).
183 - **`crates/lane`** - Lane runtime: durable, attachable running instances of
184 Fleet/Workflow work (`codewhale lane list/status/attach/logs/stop`).
185 - **`crates/release`** / **`crates/build-support`** - Release checks and build
186 plumbing.
187
188 ### LLM Integration
189
190 - **`client.rs`** - The live HTTP client layer: OpenAI-compatible, Anthropic,
191 and Responses wire adapters, DeepSeek request-boundary handling, retry
192 policy, and streaming. Provider routes land here through the shared config
193 and catalog layers.
194 - **`llm_client/`** - LLM client trait, retry logic, and error classification
195 (`LlmClient`, `RetryConfig`, `with_retry`) consumed by `client.rs`; `mock.rs`
196 is test-only (`#[cfg(test)]`).
197 - **`crates/models`** (`codewhale_models`) - Data structures for API
198 requests/responses; the TUI crate has no local `models.rs`.
199
200 #### DeepSeek API Endpoints
201
202 DeepSeek exposes OpenAI-compatible endpoints. The first-party route uses:
203 - `https://api.deepseek.com/beta` - default DeepSeek base URL (`provider_defaults.rs`)
204 - `https://api.deepseek.com/beta/models` - live model discovery and health checks
205
206 `https://api.deepseek.com/v1` is accepted for OpenAI SDK compatibility, and
207 can still be configured explicitly to opt out of beta-only features such as
208 strict tool mode, chat prefix completion, and FIM completion. The public
209 DeepSeek docs do not document a Responses API path for this workflow; the engine
210 drives turns through Chat Completions.
211
212 ### Tool System
213
214 - **`tools/`** - Built-in tool implementations
215 - `mod.rs` - Tool registry and common types
216 - `shell.rs` - Shell command execution
217 - `file.rs` - File read/write operations
218 - `todo.rs` - Checklist tools plus legacy todo aliases
219 - `tasks.rs` - Model-visible durable task, gate, background shell, and PR-attempt tools
220 - `git.rs` - Read-only `git_status` / `git_diff` inspection wrappers
221 - `git_tool.rs` - The canonical action-based `Git` tool (`status | diff | log | show | blame`); per-action legacy aliases were removed in v0.9.3
222 - `git_history.rs` - Read-only `git_log` / `git_show` / `git_blame`
223 - `github/` - Unified `github` tool family (read-only context plus guarded
224 comment/closure actions backed by `gh`); deferred by default and
225 discoverable through `tool_search`
226 - `automation.rs` - Model-visible scheduling tools over `AutomationManager`
227 - `plan.rs` - Planning tools
228 - `subagent/` - Sub-agent launch and supervision. `agent` is the one
229 creation surface; `subagent/coord.rs` adds narrow coordination tools
230 (`agents/list`, `agents/message`, `agents/followup`, `agents/interrupt`,
231 `agents/wait`, `agents/coordinate`) over the existing manager. The
232 `agent_open`/`agent_eval`/`agent_close` lifecycle surface was retired
233 (see the `subagent/coord.rs` module doc)
234 - `spec.rs` - Tool specifications
235 - `rlm.rs` - Persistent Recursive Language Model (RLM) sessions — persistent local Python REPL subprocesses (environment-scrubbed, not OS-sandboxed) with semantic helper calls and `var_handle` output support
236
237 ### Extension Systems
238
239 - **`mcp.rs`** - Model Context Protocol client for external tool servers
240 - **`skills/`** - Skill discovery and registry for local `SKILL.md` files, plus install and audit
241 - **`hooks.rs`** - Pre/post execution hooks with conditions
242
243 ### User Interface
244
245 - **`tui/`** - Terminal UI components (ratatui-based; this is a representative
246 list, not exhaustive - the module has grown to 80+ focused files):
247 - `app.rs` - Application state and message handling
248 - `ui.rs` - Event handling, streaming state, and rendering logic
249 - `approval.rs` - Tool approval dialog
250 - `clipboard.rs` - Clipboard handling
251 - `underwater.rs` - Main shell chrome: status chips, mode labels, phase rail
252
253 ### LSP Integration
254
255 - **`lsp/`** - Post-edit diagnostics injection (#136)
256 - `mod.rs` - `LspManager` — lazy per-language transport pool + config
257 - `client.rs` - `StdioLspTransport` — JSON-RPC over stdio with `didOpen`/`didChange`/`publishDiagnostics`
258 - `diagnostics.rs` - Diagnostic types, severity, and HTML-block renderer
259 - `registry.rs` - Language detection and the default server map: `rust-analyzer`,
260 `gopls`, `pyright-langserver`, `typescript-language-server`, `jdtls`,
261 `intelephense` (PHP), `vue-language-server`, `clangd` (`lsp/registry.rs:98-110`)
262 - Wired into the engine via `core/engine/lsp_hooks.rs` — called after every successful edit
263
264 ### Security
265
266 - **`sandbox/`** - platform sandbox policy preparation and denial reporting
267 - `mod.rs` - Sandbox type definitions
268 - `backend.rs` - Pluggable sandbox backend abstraction (routes shell
269 execution to a remote service, e.g. Alibaba OpenSandbox)
270 - `policy.rs` - Sandbox policy configuration
271 - `opensandbox.rs` - Alibaba OpenSandbox HTTP backend adapter
272 - `seatbelt.rs` - macOS Seatbelt profile generation
273 - `bwrap.rs` - opt-in Linux bubblewrap command wrapper
274 - `seccomp.rs` - dormant Linux seccomp implementation; not wired into commands
275 - `process_hardening.rs` - Linux kernel-level hardening for the TUI process
276 itself (defense-in-depth; not a child-command sandbox)
277 - `windows.rs` - Windows helper contract; not advertised until a Job
278 Object process-containment helper exists
279
280 ### Utilities
281
282 - **`utils.rs`** - Common utilities
283 - **`logging.rs`** - Logging infrastructure
284 - **`compaction.rs`** - Context compaction for long conversations
285 - **`purge.rs`** - Agent-driven context purging (surgical message removal/rewriting)
286 - **`pricing.rs`** - Cost estimation
287 - **`prompts.rs`** - System prompt templates
288 - **`runtime_api.rs`** - HTTP/SSE runtime API (`codewhale serve --http`)
289 - **`runtime_threads.rs`** - Durable thread/turn/item store + replayable event timeline
290 - **`task_manager.rs`** - Durable queue, worker pool, task timelines and artifacts
291
292 ## Data Flow
293
294 ### Interactive Session
295
296 1. User input received in TUI
297 2. Input processed by `core/engine.rs`
298 3. Message sent to LLM via `client.rs`
299 4. Response streamed back, parsed in `client.rs`
300 5. Tool calls extracted and executed via `tools/`
301 6. Hooks triggered before/after tool execution
302 7. Results aggregated and sent back to LLM
303 8. Final response rendered in TUI
304
305 ### Crash Recovery + Offline Queue
306
307 1. Before sending user input, the TUI writes a checkpoint snapshot to `~/.codewhale/sessions/checkpoints/latest.json`
308 2. Startup remains fresh by default; prior sessions are resumed explicitly via `--resume`/`--continue` (or `Ctrl+R` in TUI)
309 3. While degraded/offline, new prompts are queued in-memory and mirrored to `~/.codewhale/sessions/checkpoints/offline_queue.json`
310 4. Queue edits (`/queue ...`) are persisted continuously so drafts and queued prompts survive restarts
311 5. Successful turn completion clears the active checkpoint and writes a durable session snapshot
312 6. Action-capable turns also take pre/post-turn side-git workspace snapshots under `~/.codewhale/snapshots/<project_hash>/<worktree_hash>/.git`; `/restore N` and `revert_turn` restore file state without changing conversation history or the user's `.git`
313
314 ### Tool Execution
315
316 1. LLM requests tool via `tool_use` content block
317 2. Tool registry looks up handler
318 3. Pre-execution hooks run
319 4. Approval requested when the effective permission posture and policy require it
320 5. Tool executed (possibly wrapped by Seatbelt on macOS or opt-in bubblewrap on Linux)
321 6. Post-execution hooks run
322 7. Result metadata is retained on runtime item records
323 8. **LSP post-edit hook**: after a `File` write, edit, or patch action (including a replay-only legacy alias), the engine runs `run_post_edit_lsp_hook()` when LSP is enabled to collect diagnostics
324 9. **Diagnostics flush**: before the next API request, `flush_pending_lsp_diagnostics()` injects any collected errors as a synthetic user message
325 10. Result returned to agent loop
326
327 ### Background Tasks
328
329 1. Client enqueues task (`/task add ...` or `POST /v1/tasks`)
330 2. `task_manager.rs` persists task + queue entry under `~/.codewhale/tasks`
331 3. Worker picks queued task (bounded pool), transitions to `running`
332 4. Task creates/uses a runtime thread and starts a runtime turn
333 5. `runtime_threads.rs` persists thread/turn/item records + monotonic event sequence
334 6. Timeline/tool summaries/artifact references are persisted incrementally
335 7. Checklist state, verifier gates, PR attempts, and guarded GitHub events are applied from tool metadata to the active task
336 8. Final state (`completed|failed|canceled`) is durable and queryable via TUI/API
337
338 Model-visible durable task tools are a surface over this same manager. They do
339 not introduce a parallel work system: `task_create` enqueues normal tasks,
340 `checklist_*` updates task-local progress, `task_gate_run` and completed
341 `task_shell_wait` attach verification evidence, and automation runs enqueue
342 ordinary durable tasks.
343
344 ### Runtime Thread/Turn Timeline
345
346 1. API/TUI creates or resumes a thread (`/v1/threads*`)
347 2. Turn starts on the thread (`/v1/threads/{id}/turns`)
348 3. Engine events are mapped to item lifecycle events (`item.started|item.delta|item.completed`)
349 4. Interrupt/steer operations apply to the active turn only
350 5. Compaction (auto/manual) is emitted as `context_compaction` item lifecycle
351 6. Purge (agent-driven) is emitted as `context_purge` item lifecycle
352 7. Clients replay history and resume with `/v1/threads/{id}/events?since_seq=<n>`
353
354 ### Durable Schema Gates
355
356 - `session_manager.rs`, `runtime_threads.rs`, and `task_manager.rs` embed `schema_version` on persisted records.
357 - On load, newer schema versions are rejected with explicit errors instead of silently truncating/overwriting data.
358 - This allows safe forward migrations and prevents corruption when binaries and stored state are out of sync.
359
360 ## Extension Points
361
362 ### Adding a New Tool
363
364 1. Create handler in `tools/`
365 2. Register in `tools/registry.rs`
366 3. Add tool specification (name, description, input schema)
367
368 ### Adding an MCP Server
369
370 1. Configure in `~/.codewhale/mcp.json`
371 2. Server auto-discovered at startup
372 3. Tools exposed to LLM automatically
373
374 ### Creating a Skill
375
376 1. Create skill directory with `SKILL.md`
377 2. Define skill prompt and optional scripts
378 3. Place in a Codewhale-owned root (`~/.codewhale/skills/` or
379 `<workspace>/.codewhale/skills/`), or import from a compatible harness root
380 through `/skills`
381
382 See [SKILLS.md](SKILLS.md) for the Skills Manager, audit inventory, and the
383 rule that compatible roots (`.claude`, `.agents`, …) are never mutated in place.
384
385 ### Adding Hooks
386
387 Configure in `~/.codewhale/config.toml`:
388
389 ```toml
390 [[hooks]]
391 event = "tool_call_before"
392 command = "echo 'Running tool: $TOOL_NAME'"
393 ```
394
395 ## Key Design Decisions
396
397 1. **Streaming-first**: All LLM responses stream for responsiveness
398 2. **Tool safety**: Ask and Auto-Review require approval according to tool and
399 managed policy; Full Access removes ordinary prompts but not hard safety
400 holds. Side-effectful MCP tools use the same boundary.
401 3. **Extensibility**: MCP, skills, and hooks allow customization without code changes
402 4. **Cross-platform**: Core works on Linux/macOS/Windows. Sandbox guarantees
403 are platform-specific: macOS uses Seatbelt when available; Linux uses an
404 installed bubblewrap executable only when explicitly enabled; Windows has
405 no advertised OS command sandbox. Seccomp and the Windows helper contract
406 are not wired into command execution.
407 5. **Minimal dependencies**: Careful dependency selection for build speed
408 6. **Local-first runtime API**: HTTP/SSE endpoints are intended for trusted localhost access and are served by the `crates/tui` runtime today
409 7. **Lock poison**: fail-stop by default. A poisoned lock means a holder
410 panicked mid-mutation, so `.expect()` with a message naming the lock is
411 the standard posture — never serve half-updated state. Recover with
412 `into_inner()` only where stale state is safe (caches, idempotent
413 rebuilds), with a comment saying why.
414
415 ## Configuration Files
416
417 - `~/.codewhale/config.toml` - Main configuration (`~/.deepseek/config.toml` is still read as a legacy fallback)
418 - `/etc/deepseek/managed_config.toml` - Optional managed defaults layer (Unix)
419 - `/etc/deepseek/requirements.toml` - Optional allowed-policy constraints (Unix)
420 - `~/.codewhale/mcp.json` - MCP server configuration
421 - `~/.codewhale/skills/` - User skills directory
422 - `~/.codewhale/sessions/` - Session history
423 - `~/.codewhale/sessions/checkpoints/` - Crash checkpoint + offline queue persistence
424 - `~/.codewhale/snapshots/` - Side-git pre/post-turn workspace snapshots for `/restore` and `revert_turn`
425 - `~/.codewhale/tasks/` - Background task records, queue, timelines, artifacts
426 - `~/.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 or `serve` turns write no approvals there. See `docs/RECEIPTS.md` for what a session did
427 - `~/.codewhale/sessions/<id>/approval_receipts.jsonl` - Every approval ask and decision for a session, including who decided
428
428 lines MARKDOWN