# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Build & Test ```bash # Build (debug) cargo build # Release build cargo build --release # Run all tests cargo test # Run a single test cargo test test_name # Lint cargo clippy # Lint with warnings-as-errors cargo clippy -- -D warnings ``` Test modules are located inline in production files (not a separate `tests/` dir): - `src/app/harness.rs` — guard/verdict parsing tests - `src/app/runtime/stream/mod.rs` — SSE parser tests - `src/model/memory.rs` — memory CRUD + slugify tests - `src/model/editlog.rs` — edit log append/reload tests - `src/tool/fs/helpers.rs` — tool argument extraction tests Tests use `#[cfg(test)] mod tests` blocks. There are 37 unit tests total. Tracing output goes to `~/.local/share/zesdex/zesdex.log`. Set `RUST_LOG=debug` for verbose logging. ## Architecture Overview Zesdex is an autonomous AI coding agent with a TUI — an OpenAI/Anthropic-compatible LLM client wrapped in a tool-use harness with 28 built-in tools. Detailed architecture documentation is in `docs/CODEMAPS/`: | File | Covers | |------|--------| | [`docs/CODEMAPS/architecture.md`](docs/CODEMAPS/architecture.md) | System layout, process modes, data flow, key files | | [`docs/CODEMAPS/backend.md`](docs/CODEMAPS/backend.md) | Provider, OAuth, IPC, workflow engine, MCP, review, bg bash | | [`docs/CODEMAPS/frontend.md`](docs/CODEMAPS/frontend.md) | TUI render pipeline, 16 overlays, toasts, input handling | | [`docs/CODEMAPS/data.md`](docs/CODEMAPS/data.md) | Persistence, SQLite msglog, memory files, settings/config | | [`docs/CODEMAPS/dependencies.md`](docs/CODEMAPS/dependencies.md) | 23 Rust crates, 5 external services | ### Entry Points `src/main.rs` — three modes: - **Single-process** (default): TUI + agent loop in one process - **Daemon** (`--daemon`): background Unix socket server, handles LLM calls - **Attach** (`--attach `): TUI-only client that connects to a daemon ### Core Flow ``` Controller (key input → Action) → Event Loop → LLM stream → Tool execution → State mutation → TUI render │ │ │ │ src/controller/input.rs │ src/app/runtime/actions/ │ src/tool/ └── maps keys to Action enum │── dispatches Action::* └── 28 tool impls │ matching on Action variant │── applies state mutations ``` ### Key Patterns - **State mutation** — `AppStateRest` is mutable in-place from `actions/mod.rs` and `controller/input.rs`. No generic update function. - **No DI** — modules call `Settings::load()`, `AppConfig::load()`, `all_tools()` directly. - **Logging** — `tracing::warn!` to `~/.local/share/zesdex/zesdex.log` (not stderr, avoids TUI corruption). - **Error handling** — `anyhow::Result` and `anyhow::bail!` throughout. No custom error types. - **Static strings** — MCP tool descriptions use `Box::leak` + `OnceLock` cache. - **Tools** — `trait Tool { fn name() -> &str, fn run() -> Result }`, 28 impls, gated by `Harness`. - **Shell safety** — `tool/shell_filter/` blocks credential leaks and destructive git commands. ### Company Pipeline (Division Architecture) - **5 divisions** in `src/app/subagent/division.rs`: Strategy, Engineering, Quality, Security, Documentation. - **Pipeline orchestrator** in `src/app/workflow/company.rs`: two modes: - `run_company_pipeline()` — full 5-division pipeline - `run_company_pipeline_quick()` — 3-division (Strategy → Engineering → Quality) - **Auto-CEO trigger** in `run_agent_turn()` (`actions/mod.rs`): detects complex requests via `is_complex_request()` heuristics, auto-delegates to pipeline. - **Override** via `/pipeline full|quick|skip` sets `MiscState::pipeline_override`, consumed on next turn. - **Live division progress** in TUI panel (`view/workflow.rs`): shows division name + current tool via `AgentStatus::progress`. - **Auto inline review** after each edit: `src/app/subagent/auto.rs` — `spawn_quick_review()` injects verdict back into LLM conversation. - **Background subagents** (test-gen, arch-review, security-review) fire asynchronously at turn end via `TurnEvent::SystemNote`. ## Code Documentation Every function, struct, enum, trait, module, and significant code block must have a doc comment (`///` or `//!`) that explains: - **What** the function/module does (purpose, not how) - **Flow** — a brief ASCII or prose description of the code flow / data flow above each non-trivial function - **Why** — non-obvious decisions, edge cases, invariants - **Return** — what the caller gets back, especially for `Result` types Examples: ```rust /// Parse an SSE data chunk into one or more StreamEvents. /// /// Flow: buffer → split on '\n' → flush on blank line → JSON parse → match event type /// → return Token / ToolCallDelta / Usage / Done. /// /// Edge case: chunk may split mid-line; remaining bytes stay in buffer /// for the next feed() call. fn feed(&mut self, chunk: &str) -> Vec { ... } /// The single source-of-truth state struct for the entire application. /// /// Mutated in-place from two locations: actions/mod.rs (apply_action) /// and controller/input.rs (key event handlers). Read-only from /// every other module. struct AppStateRest { ... } ``` Rules: - Every `pub fn` needs a doc comment - Every `pub struct` / `pub enum` / `pub trait` needs a doc comment - Non-trivial private functions (≥10 lines) need a doc comment - Write the comment above the code it documents (not inline in the body) - Update comments when code behavior changes — stale docs are worse than no docs