- Created solid.md to document the SOLID principles for clean code practices. - Created tdd.md to outline Test Driven Development principles and practices. - Added kana-rust-backend-best-practice.md as a reference guide for building a Rust backend using Axum and SeaORM. - Established push-flow-convention.md to enforce pre-commit and pre-push hooks with versioning rules. - Introduced AGENTS.md to provide guidance on best practices and available commands for Kilo. - Configured kilo.json to include new skills and agents for enhanced functionality. - Added lefthook.yml for managing git hooks to ensure code quality and adherence to conventions.
10 KiB
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 |
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 |
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 —
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 destructive git commands (shell_filter::git::check_git_destructive, called fromtool/shell.rs::Bash::run). It also contains acheck_credential_readdetector for credential-file reads, but that one is intentionally NOT wired intoBash::runtoday — see the doc comment onBash::runfor 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_scopemodule): tool access is granted per node via one of three tiers (read/write/full, seetool_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 aCognitiveCyclePlan { 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'sScopedAgentarm 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_mindtool (src/tool/workflow.rs) is the manual entry point: the calling LLM supplies its owncyclesarray 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 todocs/runs/<timestamp>-<slug>.md. - Live node progress in TUI panel (
view/workflow.rs): shows node designation + 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, retrying once on failure and escalating to a blocking (ESCALATED:-prefixed,ToastKind::Error) notice if the retry also fails.
Best Practices (Kana Engineering Standards)
This project follows Kana Engineering Best Practices. The following skills are loaded and enforced:
| Skill | Location | Purpose |
|---|---|---|
clean-code |
.claude/skills/clean-code/SKILL.md |
Clean Code principles (naming, functions, classes, comments) |
commit-convention |
.claude/skills/commit-convention/SKILL.md |
Conventional Commits (Bahasa Indonesia) |
push-flow-convention |
.claude/skills/push-flow-convention/SKILL.md |
Pre-commit/pre-push hooks via lefthook |
kana-rust-backend-best-practice |
.claude/skills/kana-rust-backend-best-practice/SKILL.md |
Rust clean-architecture patterns (Axum, SeaORM, etc.) |
Layering Rules
domain/ → application/ → infrastructure/ → interfaces/ → gateway/
(inward) (outward)
- Domain (Layer 0): Pure entities, value objects, repository/service traits. ZERO external framework deps.
- Application (Layer 1): Use-case services (one per file), port traits. Depends ONLY on domain.
- Infrastructure (Layer 2): Concrete implementations of domain traits (SQLite, JSON files, LLM clients, LSP servers, MCP).
- Interfaces (Layer 3): Presentation adapters — TUI (ratatui), API (Axum), WebSocket, daemon, gRPC, web.
- Gateway: Composition root — the only place that wires all layers together.
Critical: Domain must NEVER import application, infrastructure, or interfaces. Application must NEVER import infrastructure or interfaces.
Commit Convention (Bahasa Indonesia)
All commits follow Conventional Commits in Bahasa Indonesia:
feat(tool): add batch file delete
fix(ipc): reconnect loop on socket timeout
chore: bump reqwest to 0.13
docs: add architecture diagram to README
refactor(harness): flatten guard pipeline
Types: feat, fix, chore, docs, refactor, test, style, perf, ci. All types produce a release (patch minimum). Add BREAKING CHANGE: for major bumps.
Clean Code Principles
- Functions under ~40 lines, one level of abstraction, extracted till you drop.
- No flag arguments — split
render(true)intorenderForSuite()/renderForSingleTest(). - Command-Query Separation — function either does or answers, never both.
- No switch/if-else on type — replace with factory + polymorphism.
- No null returns — use
Option<T>or empty collections. - No magic numbers — extract named constants.
- DRY — no duplication.
- Tell, Don't Ask — don't fetch state then decide; tell the object to work.
- Boy Scout Rule — leave every module cleaner than you found it.
Error Handling
anyhow::Resultandanyhow::bail!throughout (except domain layer typed errors).tracing::warn!/tracing::error!for logging. NEVER stderr (corrupts TUI).- Never
.unwrap()or.expect()in production code — use?or proper error handling. - Log expected failures at
warn!, unexpected errors aterror!.
Testing
#[cfg(test)] mod testsblocks inline in production files.- Tests are F.I.R.S.T. — Fast, Independent, Repeatable, Self-validating, Timely.
- Use
Result<()>as test return type for?propagation. - Mock at boundaries only; prefer fakes for owned abstractions.
Compiler Bypasses
NEVER use #[allow(...)], #[expect(...)], or #[allow(dead_code)]. Fix the underlying code instead.
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
- 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.