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
| Crate | What it does |
|---|---|
crates/cli | CLI entrypoint — parses arguments, wires everything together, dispatches to TUI or one-shot mode |
crates/tui | Terminal UI — event loop, slash commands, completion, selectors, themes |
crates/core | Agent runtime — tools, sessions, MCP, teams, hooks, memory, autopilot, verification |
crates/provider | Provider abstraction — model registry, streaming adapters, tiering metadata |
crates/auth | Credential resolution — API keys, OAuth tokens, multi-account rotation |
crates/config | Config schema — TOML parsing, defaults, three-layer merge logic |
crates/index | Semantic 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:
- Parse CLI arguments — flags like
--provider,--model,--trustare extracted - Load global config — from
~/.config/nyzhi/config.toml - Detect workspace root — walks up from current directory looking for
.nyzhi/,.claude/, or.git - Merge project config — if
<project>/.nyzhi/config.tomlexists, it’s merged with global config - Create provider — connects to the configured LLM (or defers if no credentials yet)
- Build tool registry — registers 50+ built-in tools, then discovers and registers MCP tools
- 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:
- Build system prompt — combines workspace rules, custom instructions, and MCP tool summaries
- Inject memory — loads user and project memory when
auto_memoryis enabled - Add auto-context — retrieves relevant code snippets from the semantic index
- Stream model response — sends the full context to the LLM and streams tokens back
- Execute tool calls — runs any tools the model requests, with permission checks
- Emit events — updates the UI/CLI with
AgentEventmessages - Persist session — saves the conversation (unless
--ephemeralis 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
NeedsApprovalrequire user confirmation unless trust mode allows them
Good to know: Read-only tools (like
read,grep,git_status) can execute in parallel. Mutating tools (likewrite,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 tasksend_input— sends follow-up instructions to a running agentwait— blocks until one or more agents finishclose_agent— shuts down an agent and frees its slotresume_agent— reopens a completed agent for more work
Each agent has a status lifecycle: pending_init → running → completed (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):
.nyzhi/directory.claude/directory.gitmarker
Rules (instructions injected into the system prompt) are loaded with this priority:
AGENTS.md.nyzhi/rules.md.nyzhi/instructions.mdCLAUDE.md.cursorrules
Additional local preferences (NYZHI.local.md, .nyzhi/local.md) and modular rules from .nyzhi/rules/*.md are also loaded.
Tip: Use
nyz initto scaffold a.nyzhi/directory with sensible defaults.
Where Data Lives
| What | Location |
|---|---|
| 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