Documentation

Architecture

Seven Rust crates, zero dependency cycles, one binary — how Nyzhi is structured internally.

Edit on GitHub

Nyzhi is a single statically-linked binary built from a Rust workspace of seven crates. Each crate has a clear responsibility, and dependencies flow in one direction — no cycles.

Crate Map

CrateWhat it does
crates/cliCLI entrypoint — parses arguments, wires everything together, dispatches to TUI or one-shot mode
crates/tuiTerminal UI — event loop, slash commands, completion, selectors, themes
crates/coreAgent runtime — tools, sessions, MCP, teams, hooks, memory, autopilot, verification
crates/providerProvider abstraction — model registry, streaming adapters, tiering metadata
crates/authCredential resolution — API keys, OAuth tokens, multi-account rotation
crates/configConfig schema — TOML parsing, defaults, three-layer merge logic
crates/indexSemantic index — embeddings, auto-context retrieval, codebase search

The dependency graph looks like this:

nyzhi (cli)
├── nyzhi-tui
├── nyzhi-core
│   ├── nyzhi-provider
│   │   ├── nyzhi-auth
│   │   └── nyzhi-config
│   ├── nyzhi-auth
│   ├── nyzhi-config
│   └── nyzhi-index
└── nyzhi-config

Startup Sequence

When you run nyz, here’s what happens in order:

  1. Parse CLI arguments — flags like --provider, --model, --trust are extracted
  2. Load global config — from ~/.config/nyzhi/config.toml
  3. Detect workspace root — walks up from current directory looking for .nyzhi/, .claude/, or .git
  4. Merge project config — if <project>/.nyzhi/config.toml exists, it’s merged with global config
  5. Create provider — connects to the configured LLM (or defers if no credentials yet)
  6. Build tool registry — registers 50+ built-in tools, then discovers and registers MCP tools
  7. Dispatch — either launches the interactive TUI (nyz) or runs a single prompt (nyz run/nyz exec)

Turn Execution

Every time the agent processes a prompt, it follows this flow:

  1. Build system prompt — combines workspace rules, custom instructions, and MCP tool summaries
  2. Inject memory — loads user and project memory when auto_memory is enabled
  3. Add auto-context — retrieves relevant code snippets from the semantic index
  4. Stream model response — sends the full context to the LLM and streams tokens back
  5. Execute tool calls — runs any tools the model requests, with permission checks
  6. Emit events — updates the UI/CLI with AgentEvent messages
  7. Persist session — saves the conversation (unless --ephemeral is set)

Tool Execution Boundaries

Tools go through several gates before they can run:

  • Role filtering — subagents may only have access to a subset of tools via allowed_tools
  • Trust policy — the user’s trust mode (off, limited, autoedit, full) controls which tools need approval
  • Sandbox level — restricts file system access (read-only, workspace-write, full-access)
  • Explicit approval — tools marked NeedsApproval require user confirmation unless trust mode allows them

Good to know: Read-only tools (like read, grep, git_status) can execute in parallel. Mutating tools (like write, bash, git_commit) always execute sequentially.

Subagent Architecture

In the interactive TUI, Nyzhi can spawn child agents managed by an AgentManager:

  • spawn_agent — creates a new agent with a specific role and task
  • send_input — sends follow-up instructions to a running agent
  • wait — blocks until one or more agents finish
  • close_agent — shuts down an agent and frees its slot
  • resume_agent — reopens a completed agent for more work

Each agent has a status lifecycle: pending_initrunningcompleted (or errored / shutdown).

The manager enforces limits from your config:

[agent.agents]
max_threads = 4   # max concurrent subagents
max_depth = 2     # max nesting depth (agent spawning an agent)

Team Collaboration

Teams extend subagents with structured communication:

  • Team config — stored as JSON at ~/.nyzhi/teams/<team>/config.json
  • Inboxes — per-member message files for direct and broadcast messaging
  • Task board — shared tasks with status tracking and ownership

Team-aware tools like send_team_message, read_inbox, and spawn_teammate use team_name, agent_name, and is_team_lead from the tool context.

Workspace and Rule Resolution

Nyzhi detects your project root by walking up the directory tree and checking for (in order):

  1. .nyzhi/ directory
  2. .claude/ directory
  3. .git marker

Rules (instructions injected into the system prompt) are loaded with this priority:

  1. AGENTS.md
  2. .nyzhi/rules.md
  3. .nyzhi/instructions.md
  4. CLAUDE.md
  5. .cursorrules

Additional local preferences (NYZHI.local.md, .nyzhi/local.md) and modular rules from .nyzhi/rules/*.md are also loaded.

Tip: Use nyz init to scaffold a .nyzhi/ directory with sensible defaults.

Where Data Lives

WhatLocation
Sessions~/.local/share/nyzhi/sessions/*.json
User memory~/.nyzhi/MEMORY.md
Project memory~/.local/share/nyzhi/projects/<hash>/memory/
Team configs~/.nyzhi/teams/<team>/config.json
Team inboxes~/.nyzhi/teams/<team>/inboxes/*.json
Team tasks~/.nyzhi/tasks/<team>/
Autopilot state<project>/.nyzhi/state/autopilot.json

Design Principles

  • Terminal-first — the TUI is the primary interface, with full non-interactive parity via run/exec
  • Safety boundaries — trust modes, sandbox levels, and approval workflows prevent unintended changes
  • Provider-agnostic — swap models without changing your workflow
  • Transparent state — everything is files (sessions, memory, teams) — inspectable and version-controllable
  • Composable agents — main agent, subagents, and team meshes share the same runtime

Next Steps

  • Configuration — full config reference with examples
  • Tools — the complete tool inventory
  • Teams — how multi-agent collaboration works