3.1 KiB
3.1 KiB
CLAUDE.md
Rust TUI coding agent. Ratatui + Crossterm + Tokio. See DESIGN.md for architecture decisions and PLAN.md for implementation phases.
Commands
cargo build: Build the projectcargo test: Run all unit and integration testscargo test --lib: Unit tests onlycargo test --test '*': Integration tests onlycargo clippy -- -D warnings: Lint (must pass with zero warnings)cargo fmt --check: Format checkcargo run -- --project-dir <path>: Run against a project directory
Architecture
Six modules with strict boundaries:
src/app/— Wiring, lifecycle, tokio runtime setupsrc/tui/— Ratatui rendering, input handling, vim modes. Communicates with core ONLY via channels (UserAction→ core,UIEvent← core). Never touches conversation state directly.src/core/— Conversation tree, orchestrator loop, sub-agent lifecyclesrc/provider/—ModelProvidertrait + Claude implementation. Leaf module, no internal dependencies.src/tools/—Tooltrait, registry, built-in tools. Depends only onsandbox.src/sandbox/— Landlock policy, path validation, command execution. Leaf module.src/session/— JSONL logging, session read/write. Leaf module.
The channel boundary between tui and core is critical — never bypass it. The TUI is a frontend; core is the engine. This separation enables headless mode for benchmarking.
Code Style
- Use
thiserrorfor error types, notanyhowin library code (anyhowonly inmain.rs/app) - Prefer
impl Traitreturn types over boxing when possible - All public types need doc comments
- No
unwrap()in non-test code — use?or explicit error handling - Async functions should be cancel-safe where possible
- Use
tracingfor structured logging, notprintln!orlog
Conversation Data Model
Events use parent IDs forming a tree (not a flat list). This enables future branching. Every event has: id, parent_id, timestamp, event_type, token_usage. A "turn" is all events between two user messages — this is the unit for token tracking.
Testing
- Unit tests go in the same file as the code (
#[cfg(test)] mod tests) - Integration tests go in
tests/ - TUI widget tests use
ratatui::backend::TestBackend+instasnapshots - Provider tests replay recorded SSE fixtures from
tests/fixtures/ - Sandbox tests use
tempdirand skip Landlock-specific assertions if kernel < 5.13 - Run
cargo testbefore every commit
Key Constraints
- All file I/O and process spawning in tools MUST go through
Sandbox— never usestd::fsorstd::process::Commanddirectly in tool implementations - The
ModelProvidertrait must remain provider-agnostic — no Claude-specific types in the trait interface - Session JSONL is append-only. Never rewrite history. Branching works by writing new events with different parent IDs.
- Token usage must be tracked per-event and aggregatable per-turn
Do Not
- Add MCP support (deferred, but keep tool trait compatible)
- Use
unsafewithout discussion - Add dependencies without checking if an existing dep covers the use case
- Modify test fixtures without re-recording from a real API session