Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture Overview

Cargo workspace (Edition 2024, resolver 3) with 21 crates + binary root.

Requires Rust 1.94+. Native async traits are used throughout. async-trait is retained only in crates blocked by upstream dependencies (zeph-core, zeph-mcp, zeph-acp — blocked by rmcp).

Workspace Layout

zeph (binary) — thin CLI/channel dispatch, AppBuilder bootstrap, vault/skill/memory subcommands
├── Layer 0 — Primitives
│   └── zeph-common         Shared primitives: Secret, VaultError, common types
├── Layer 1 — Configuration & Secrets
│   ├── zeph-config         Pure-data configuration types, TOML loader, env overrides, migration
│   └── zeph-vault          VaultProvider trait + env and age-encrypted backends
├── Layer 2 — Core Domain Crates
│   ├── zeph-db             Database abstraction (SQLite + PostgreSQL)
│   ├── zeph-llm            LlmProvider trait, Ollama/Claude/OpenAI/Gemini/Candle backends, router
│   ├── zeph-memory         SQLite + Qdrant, SemanticMemory, summarization, document loaders
│   ├── zeph-tools          ToolExecutor trait, ShellExecutor, FileExecutor, TrustLevel
│   ├── zeph-skills         SKILL.md parser, registry, embedding matcher, hot-reload
│   └── zeph-index          AST-based code indexing, hybrid retrieval, repo map (always-on)
├── Layer 3 — Agent Subsystems
│   ├── zeph-context        Context assembly, budget, compaction (extracted from zeph-core)
│   ├── zeph-sanitizer      Content sanitization, PII filter, exfiltration guard
│   ├── zeph-experiments    Autonomous experiment engine, LLM-as-judge evaluation
│   ├── zeph-subagent       Subagent lifecycle, grants, transcripts, hooks
│   └── zeph-orchestration  DAG-based task orchestration, planner, router, aggregator
├── Layer 4 — Agent Core & Commands
│   ├── zeph-core           Agent loop, context builder, metrics
│   └── zeph-commands       Slash command handlers, CommandHandler registry
├── Layer 5 — Protocol & I/O
│   ├── zeph-channels       Telegram, Discord, Slack adapters
│   ├── zeph-mcp            MCP client via rmcp, multi-server lifecycle (optional)
│   ├── zeph-acp            ACP server — IDE integration (optional)
│   ├── zeph-a2a            A2A protocol client + server (optional)
│   ├── zeph-gateway        HTTP webhook gateway (optional)
│   └── zeph-scheduler      Cron task scheduler (optional)
└── Layer 6 — UI
    └── zeph-tui            ratatui TUI dashboard with real-time metrics (optional)

See Crates Overview for the full layered architecture with dependencies.

Dependency Graph

The layered architecture enforces a strict dependency direction: higher layers depend on lower layers, never the reverse. zeph-core (Layer 4) orchestrates all subsystems. Protocol crates (Layer 5) are feature-gated and wired by the binary. Sub-agent lifecycle state is defined in zeph-subagent (Layer 3) to keep zeph-core focused on the agent loop.

Agent Loop

The agent loop processes user input in a continuous cycle:

  1. Read initial user message via channel.recv()
  2. Build context from skills, memory, and environment (summaries, cross-session recall, semantic recall, and code RAG are fetched concurrently via try_join!)
  3. Stream LLM response token-by-token
  4. Execute any tool calls in the response
  5. Drain queued messages (if any) via channel.try_recv() and repeat from step 2

Queued messages are processed sequentially with full context rebuilding between each. Consecutive messages within 500ms are merged to reduce fragmentation. The queue holds a maximum of 10 messages; older messages are dropped when full.

Key Design Decisions

  • Generic Agent: Agent<C: Channel> — generic over channel only. The provider is resolved at construction time (AnyProvider enum dispatch). Tool execution uses Box<dyn ErasedToolExecutor> for object-safe dynamic dispatch, eliminating the former T: ToolExecutor generic parameter. Internal state is grouped into domain sub-structs: MessageState (message buffer, image staging), MemoryState (semantic memory, graph, summaries), SkillState (registry, matcher, prompt), RuntimeConfig (security, hooks, persona config), McpState (MCP tools, manager), IndexState (code retriever, indexer), DebugState (dumper, trace, anomaly detector), SecurityState (sanitizer, quarantine, exfiltration guard), and ToolState (schema filter, dependency graph, iteration bookkeeping). Logic is decomposed into streaming.rs, persistence.rs, and three dedicated subsystems: ContextManager (budget / compaction), ToolOrchestrator (doom-loop detection / iteration limit), and LearningEngine (self-learning reflection state). Concurrency uses parking_lot locks throughout (no poison handling)
  • TLS: rustls everywhere (no openssl-sys)
  • Bootstrap: AppBuilder in the binary’s bootstrap/ module (split into mod.rs, config.rs, health.rs, mcp.rs, provider.rs, skills.rs) handles config/vault resolution, provider creation, memory setup, skill matching, tool executor composition, and graceful shutdown wiring. main.rs (thin entry point) delegates to runner.rs for channel/mode dispatch
  • Binary structure: zeph binary is decomposed into focused modules — runner.rs (dispatch), agent_setup.rs (tool executor + MCP + feature extensions), tracing_init.rs, tui_bridge.rs, channel.rs, cli.rs (clap args), acp.rs, daemon.rs, scheduler.rs, commands/ (vault/skill/memory subcommands), tests.rs
  • Errors: thiserror for all crates with typed error enums (ChannelError, AgentError, LlmError, etc.); anyhow only for top-level orchestration in runner.rs
  • Lints: workspace-level clippy::all + clippy::pedantic + clippy::nursery; unsafe_code = "deny"
  • Dependencies: versions only in root [workspace.dependencies]; crates inherit via workspace = true
  • Feature gates: optional crates (zeph-mcp, zeph-a2a, zeph-tui) are feature-gated in the binary; zeph-index is always-on with all tree-sitter language grammars (Rust, Python, JS/TS, Go) compiled unconditionally
  • Context engineering: proportional budget allocation, semantic recall injection, message trimming, runtime compaction, environment context injection, progressive skill loading, ZEPH.md project config discovery
  • Graceful shutdown: Ctrl-C triggers ordered teardown — the agent loop exits cleanly, MCP server connections are closed, and pending async tasks are drained before process exit
  • LoopbackChannel: headless Channel implementation using two linked tokio mpsc pairs (input_tx/input_rx for user messages, output_tx/output_rx for LoopbackEvent variants). Auto-approves confirmations. Used by daemon mode to bridge the A2A task processor with the agent loop
  • Streaming TaskProcessor: ProcessorEvent enum (StatusUpdate, ArtifactChunk) replaces the former synchronous ProcessResult. The TaskProcessor::process method accepts an mpsc::Sender<ProcessorEvent> for per-token SSE streaming to connected A2A clients