87 lines
6.8 KiB
Markdown
87 lines
6.8 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
Tests use `#[cfg(test)] mod tests` blocks inline in production files (not a separate `tests/` dir).
|
|
|
|
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 37 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 |
|
|
|
|
`docs/runs/` holds an auto-generated audit trail: one markdown file per hive-mind convergence (see below), written deterministically by `app::workflow::docs::write_hive_mind_convergence` — not hand-maintained like `docs/CODEMAPS/`.
|
|
|
|
### 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<String> }`, 28 impls, gated by `Harness`.
|
|
- **Shell safety** — `tool/shell_filter/` blocks destructive git commands (`shell_filter::git::check_git_destructive`, called from `tool/shell.rs::Bash::run`). It also contains a `check_credential_read` detector for credential-file reads, but that one is intentionally NOT wired into `Bash::run` today — see the doc comment on `Bash::run` for why.
|
|
|
|
### Hive-Mind Orchestration (Machine Intelligence)
|
|
|
|
- **A single Core Intelligence spawning anonymous processing nodes.** The Core Intelligence (main agent) compiles a cognitive cycle plan per task: an ordered list of cycles, each cycle a set of processing nodes that run in parallel. Each node's sole identity is its directive (what to do) and an access tier. Cycle count and nodes-per-cycle are entirely Core-Intelligence output.
|
|
- **Access tiers** in `src/app/subagent/division.rs` (`tool_scope` module): tool access is granted per node via one of three tiers (`read` / `write` / `full`, see `tool_scope::tools_for`) picked by the Core Intelligence based on what each node's directive actually needs.
|
|
- **Orchestrator** in `src/app/workflow/hive_mind.rs`: `run_hive_mind()` executes a `CognitiveCyclePlan { cycles: Vec<Vec<NodeDirective>> }` cycle-by-cycle. Node IDs are system-assigned coordinates (e.g. `"Node-0-1"`).
|
|
- **Continuous collective state, not phase-boundary sync**: `engine::execute_primitive`'s `ScopedAgent` arm merges each node's complete output into the shared collective-state channel the instant that node finishes — not after its whole parallel cohort completes — so sibling/later nodes see it in real time.
|
|
- **Consensus synthesis, not a per-node summary**: after all cycles complete, `synthesize_consensus()` spawns one final read-only node whose sole directive is to reconcile the entire collective state into a single consensus assessment — a real reasoning pass, not string concatenation, since node outputs can overlap or conflict.
|
|
- **Auto-trigger** in `run_agent_turn()` (`actions/mod.rs`): `is_complex_request()` heuristics decide only whether to ask the Core Intelligence to compile a plan at all — the plan's shape is fully dynamic.
|
|
- **`hive_mind` tool** (`src/tool/workflow.rs`) is the manual entry point: the calling LLM supplies its own `cycles` array of `{directive, access}` directly.
|
|
- **Guaranteed documentation**: after every convergence, `src/app/workflow/docs.rs::write_hive_mind_convergence()` deterministically (not an LLM step, not skippable) writes every node's full output plus the final consensus to `docs/runs/<timestamp>-<slug>.md`.
|
|
- **Live node progress** in TUI panel (`view/workflow.rs`): shows node designation + 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`, retrying once on failure and escalating to a blocking (`ESCALATED:`-prefixed, `ToastKind::Error`) notice if the retry also fails.
|
|
|
|
Commit convention (Conventional Commits, Bahasa Indonesia): see the `commit-convention` skill.
|
|
|
|
## 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<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 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
|
|
- NEVER use compiler/linter bypass annotations or attributes (such as `#[allow(clippy::too_many_lines, clippy::too_many_arguments, clippy::ref_option)]`, `#[allow(dead_code)]`, etc.) to silence warnings or skip linter checks. Always fix the underlying code issues instead.
|