7.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Test
# 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 testssrc/app/runtime/stream/mod.rs— SSE parser testssrc/model/memory.rs— memory CRUD + slugify testssrc/model/editlog.rs— edit log append/reload testssrc/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 |
System layout, process modes, data flow, key files |
docs/CODEMAPS/backend.md |
Provider, OAuth, IPC, workflow engine, MCP, review, bg bash |
docs/CODEMAPS/frontend.md |
TUI render pipeline, 16 overlays, toasts, input handling |
docs/CODEMAPS/data.md |
Persistence, SQLite msglog, memory files, settings/config |
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 <id>): 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 —
AppStateRestis mutable in-place fromactions/mod.rsandcontroller/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::Resultandanyhow::bail!throughout. No custom error types. - Static strings — MCP tool descriptions use
Box::leak+OnceLockcache. - Tools —
trait Tool { fn name() -> &str, fn run() -> Result<String> }, 28 impls, gated byHarness. - 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 pipelinerun_company_pipeline_quick()— 3-division (Strategy → Engineering → Quality)
- Auto-CEO trigger in
run_agent_turn()(actions/mod.rs): detects complex requests viais_complex_request()heuristics, auto-delegates to pipeline. - Override via
/pipeline full|quick|skipsetsMiscState::pipeline_override, consumed on next turn. - Live division progress in TUI panel (
view/workflow.rs): shows division name + current tool viaAgentStatus::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.
Commit Convention
Gunakan Conventional Commits untuk semua commit. Format:
<type>(<scope>): <description>
Type & efek ke versi:
| Type | Bump | Kapan pakai |
|---|---|---|
feat |
minor | Fitur baru |
fix |
patch | Perbaikan bug |
chore |
patch | Maintenance, update deps, dll |
docs |
patch | Perubahan dokumentasi/comment |
refactor |
patch | Refactor kode tanpa perubahan fungsional |
test |
patch | Nambah/ubah test |
style |
patch | Formatting, whitespace, lint |
perf |
patch | Optimasi performa |
ci |
patch | Perubahan CI/CD |
Catatan:
- Semua type menghasilkan release (patch minimal). Tidak ada commit yang "skip release".
- Tambahkan
BREAKING CHANGE:di body commit untuk bump major. - Scope opsional, tapi direkomendasikan (misal
feat(agent):,fix(ipc):).
Contoh
feat(tool): add batch file delete
chore: bump reqwest to 0.12
refactor(harness): flatten guard pipeline
fix(ipc): reconnect loop on socket timeout
docs: add architecture diagram to README
BREAKING CHANGE: IPC frame header changed from 4-byte to 8-byte length
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
Resulttypes
Examples:
/// 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<StreamEvent> { ... }
/// 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 fnneeds a doc comment - Every
pub struct/pub enum/pub traitneeds 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