Documentation

Architecture

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

Edit on GitHub

Nyzhi is a Rust workspace with six crates. Each crate has a single responsibility; dependencies flow downward from the binary to leaf crates with no cycles.

Crate Dependency Graph

The following diagram shows how the crates depend on each other. The CLI (nyz) sits at the top and depends on the TUI, core, and provider crates. Both TUI and provider depend on auth and config.

                    ┌──────────────┐
                    │  nyzhi (cli) │
                    │   bin: nyz   │
                    └──────┬───────┘

         ┌─────────────────┼─────────────────┐
         │                 │                 │
         ▼                 ▼                 ▼
   ┌───────────┐    ┌───────────┐    ┌─────────────┐
   │ nyzhi-tui │    │ nyzhi-core│    │nyzhi-provider│
   └─────┬─────┘    └─────┬─────┘    └──────┬──────┘
         │                │                  │
         │         ┌──────┴──────┐           │
         │         │             │           │
         ▼         ▼             ▼           ▼
   ┌───────────┐  ┌─────────────┐     ┌───────────┐
   │ nyzhi-auth│  │nyzhi-provider│     │ nyzhi-auth│
   └─────┬─────┘  └──────┬──────┘     └─────┬─────┘
         │               │                   │
         ▼               ▼                   ▼
   ┌─────────────────────────────────────────────┐
   │              nyzhi-config                    │
   └─────────────────────────────────────────────┘

Crate Summary

CratePackageRole
crates/clinyzhiBinary entry point (nyz). CLI parsing via clap, command dispatch, MCP server setup, tool registry assembly.
crates/corenyzhi-coreAgent loop, 50+ tool implementations, session management, workspace detection, MCP client, planning, teams, hooks, skills, verification, analytics, and more.
crates/providernyzhi-providerLLM provider abstraction. Implements streaming chat completions for OpenAI, Anthropic, and Gemini with SSE, thinking/reasoning support, and a model registry. See Providers.
crates/tuinyzhi-tuiTerminal UI. ratatui-based app loop with theming, syntax highlighting, tab completion, input history, session export, and component rendering. See TUI.
crates/authnyzhi-authAuthentication. OAuth2 PKCE and device-code flows, API key resolution, token storage in auth.json, multi-account support with rate-limit rotation.
crates/confignyzhi-configConfiguration. TOML loading and merging across global, project, and local config files. Defines all config types and built-in provider definitions. See Configuration.

nyzhi-core Module Map

The core crate contains 39 modules covering all agent logic. This section groups them by responsibility.

Agent Loop

The agent loop drives each turn: streaming from the LLM, executing tools, and handling approval and retries.

ModulePurpose
agentMain agent turn loop. Streams LLM responses, executes tool calls, handles approval, retries, auto-compaction, and team context injection.
agent_filesFile context management for agent turns.
agent_managerManages multiple concurrent agent instances (sub-agents, teammates).
agent_rolesRole definitions for agent specialization (worker, explorer, planner, reviewer, etc.).

Conversation and Sessions

ModulePurpose
conversationMessage sequence management (thread type).
sessionSession persistence: save, load, list, delete, rename, and search in JSON format.
replayEvent-level session replay.
streamingStream accumulation for SSE responses.

Workspace and Context

ModulePurpose
workspaceProject root detection, project type classification (Rust/Node/Python/Go), rules loading (AGENTS.md, .nyzhi/rules.md, etc.), and .nyzhi/ scaffolding.
worktreeGit worktree management for team isolation.
contextToken estimation and context window management.
context_filesFile mention extraction and resolution (e.g., @file).
promptSystem prompt construction with environment, tools, rules, skills, and MCP summaries.

Tools

The tool system implements a registry with deferred loading and role-based filtering. See Tools for the full catalog.

ModulePurpose
toolsTool trait, registry, context, and result types. Deferred tool loading and role-based filtering.
tools/bashShell command execution with live output streaming.
tools/read, write, editFile read, write, and edit operations.
tools/glob, grepFile pattern matching and content search.
tools/gitGit status, diff, log, show, branch, commit, checkout.
tools/filesystemlist_dir, directory_tree, file_info, delete, move, copy, create_dir.
tools/verifyBuild/test/lint execution with structured evidence.
tools/lspLSP diagnostics, goto definition, find references, hover, AST search.
tools/webweb_fetch and web_search.
tools/browserBrowser automation (open, screenshot, evaluate).
tools/prPR creation and review via gh.
tools/taskSub-agent delegation.
tools/todoTodo list management.
tools/notepadNotepad read/write.
tools/memoryPersistent memory read/write.
tools/teamTeam creation, messaging, task management. See Teams.
tools/semantic_searchSemantic code search.
tools/fuzzy_findFuzzy file finder.
tools/apply_patch, batchStructured patch application and batch operations.
tools/instrumentDebug instrumentation injection/removal.
tools/thinkExplicit thinking/reasoning tool.
tools/update_planPlan update tool.
tools/load_skillLazy skill loading.
tools/tool_searchDeferred tool discovery.
tools/tail_fileFile tail for log monitoring.

Features

ModulePurpose
mcpMCP server management (stdio/HTTP), tool adaptation, hot-connect. See MCP.
planningPlanner/critic loop with persistent plans in .nyzhi/plans/.
autopilot5-phase autonomous execution (expansion, planning, execution, QA, validation).
teamsTeam configuration, task board with file-locking, mailbox messaging system. See Teams.
commandsCustom slash command loading from .nyzhi/commands/ and config.
hooksAfter-edit, after-turn, pre/post-tool hook execution with pattern matching. See Hooks.
skillsSkill persistence, templates, and lazy loading.
verifyAuto-detection of build/test/lint checks per project type.
routingPrompt complexity classification and model tier selection. See Routing.
analyticsToken usage and cost tracking in JSONL format.
memoryProject-scoped and user-scoped persistent memory.
notifyExternal notifications (webhook, Telegram, Discord, Slack). See Notifications.
updaterSelf-update with SHA256 verification, backup, rollback, integrity manifests.
pluginsPlugin manifest and loader.
deepinitAGENTS.md generation from project analysis.
diagnosticsSystem diagnostic info collection.
sandboxSandboxed execution environment.
indexSemantic indexing for code search.
keywordsKeyword extraction from prompts.
judgingQuality assessment.
checkpointCheckpoint management.
persistenceGeneral persistence utilities.

Data Flow

Interactive Mode (TUI)

The following diagram shows how user input flows through the system in interactive mode.

User Input


nyzhi (cli) ── parse CLI args ── load config ── detect workspace


nyzhi-tui::App::run()

    ├─ Build ToolRegistry (50+ tools + MCP tools)
    ├─ Create Provider (resolve credentials via nyzhi-auth)
    ├─ Start MCP servers (nyzhi-core::mcp)


Event Loop

    ├─ User types message
    │   │
    │   ▼
    │   nyzhi-core::agent::run_turn()
    │       │
    │       ├─ Build system prompt (workspace, rules, tools, skills)
    │       ├─ Check context window, auto-compact if needed
    │       ├─ Provider::chat_stream() ── HTTP/SSE to LLM API
    │       │   │
    │       │   ├─ ThinkingDelta events ── displayed in TUI
    │       │   ├─ TextDelta events ── displayed in TUI
    │       │   └─ ToolCall events ── execute tools
    │       │       │
    │       │       ├─ ReadOnly tools: execute in parallel
    │       │       ├─ NeedsApproval tools: prompt user
    │       │       └─ Results fed back for next LLM turn
    │       │
    │       ├─ Retry on 429/5xx (exponential backoff)
    │       ├─ Run hooks (after_edit, after_turn)
    │       └─ Log analytics (token counts, cost)

    ├─ Auto-save session
    └─ Render updated UI

Non-Interactive Mode (nyz run)

The same flow applies, but the TUI event loop is skipped. Output streams directly to stdout. Trust mode defaults apply for tool approval. See Configuration for [agent.trust].


Tool Registry Design

The tool registry uses a deferred loading pattern to keep the initial prompt size small.

  1. Core tools are registered normally. Their full schemas are sent to the LLM in every request.
  2. Deferred tools are registered but only indexed (name and description). They are not included in the ChatRequest tool definitions.
  3. When the LLM needs a deferred tool, it calls tool_search to discover it by name or description.
  4. On first use, the deferred tool is expanded — its full schema is included in subsequent requests.

This keeps the prompt under budget while making 50+ tools available. See Tools for the full list.

Permission Model

Each tool declares a permission level:

LevelBehavior
ReadOnlyAlways auto-approved. Can run in parallel with other read-only tools.
NeedsApprovalRequires user confirmation (or auto-approved in full trust mode, or if matching allow_tools/allow_paths in limited mode). See Configuration for trust settings.

Agent Turn Lifecycle

A single agent turn (run_turn) follows this sequence:

  1. Push user message onto the conversation thread.
  2. Build tool definitions (filtered by role if applicable).
  3. For up to max_steps iterations:
    • Inject unread teammate messages (if in a team).
    • Micro-compact the thread if any individual message is oversized.
    • If context usage exceeds auto_compact_threshold (default 85%), run full auto-compaction: summarize history, keep recent messages.
    • Build the chat request with thinking config.
    • Stream response via the provider’s chat_stream().
    • On retryable error (429, 5xx): exponential backoff, try rate-limit account rotation.
    • Execute tool calls: read-only in parallel, others sequentially.
    • For NeedsApproval tools: emit an approval request, wait for user response.
    • Offload large tool results to context files.
    • Accumulate token usage, emit usage event.
  4. If the LLM stops calling tools (no tool_use in response), the turn is complete.
  5. Run after-turn hooks.
  6. Emit turn complete event.