Files
asepharyana 55677dd671 feat: Add SOLID principles and TDD reference documentation
- 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.
2026-07-21 07:10:17 +07:00

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 mutationAppStateRest 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.
  • Loggingtracing::warn! to ~/.local/share/zesdex/zesdex.log (not stderr, avoids TUI corruption).
  • Error handlinganyhow::Result and anyhow::bail! throughout. No custom error types.
  • Static strings — MCP tool descriptions use Box::leak + OnceLock cache.
  • Toolstrait Tool { fn name() -> &str, fn run() -> Result<String> }, 28 impls, gated by Harness.
  • Shell safetytool/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.rsspawn_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) into renderForSuite() / 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::Result and anyhow::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 at error!.

Testing

  • #[cfg(test)] mod tests blocks 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 Result types

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 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.