native-agent-router
Native Agent Runtime Router (NAR)
English | 简体中文
Route coding tasks from an orchestrator agent (Codex / opencode / Claude Code) to native CLI worker agents (ZCode, any ACP-compatible agent) through a small, deterministic, model-free kernel.
The kernel never calls a model. It handles task state, bounded waiting, workspace locking, fixed verification, one pre-authorized repair, cancellation with confirmation, budgets, recovery, usage accounting and per-agent scoring — so the orchestrator spends its tokens on judgment, not on polling and log-shuffling.
Orchestrator (Codex / opencode / Claude Code)
| MCP (5 stable tools) or CLI (`nar`)
v
Model-free kernel: tasks, locks, verification, repair, budget, recovery
v
Pluggable native adapters
├── zcode-native (ZCode app-server protocol 0.16, verified live on 0.16.5)
├── acp-generic (Agent Client Protocol, verified live on opencode 1.18.15)
└── your adapter (small class, see docs/BACKENDS.md)More native agents are being supported…
MCP:
nar-mcpexposes exactly five tools:agents,run,wait,inspect,cancel. New backends are added by config, not by new tools.CLI:
narshares the same kernel (debugging, scripting, humans).Token discipline: compact results by default; full logs/diffs on disk, paged via
inspect; deterministic scoring per task (zero tokens) feeds routing.
Install
Requires Python >= 3.10. For the ZCode adapter: Node.js >= 22 and the ZCode
desktop app (or its CLI on PATH). For ACP agents: any ACP server binary.
pip install native-agent-router # or: pipx install native-agent-router
# from a clone:
pip install -e .Verify environment and discovery:
nar doctornar doctor prints what it found (ZCode bundle, node, git) and what to do if
something is missing. It never prints credentials.
Quickstart
Create the config (optional — auto-discovery works without it):
mkdir -p ~/.native-agent-router
cp config.example.json ~/.native-agent-router/agents.jsonList agents, submit a complete work unit, wait, inspect:
nar agents
nar run zcode "Implement parse_flag() in flags.py per the docstring; only modify flags.py" \
/abs/path/to/project --mode build --policy allow --scope flags.py --verify "python -m pytest -q" --wait 600
nar wait <task_id>
nar inspect <task_id> summary
nar inspect <task_id> diagnose # sanitized, shareable error reportContinue the SAME native session for follow-up work on the same module:
nar run zcode "Now handle the --verbose edge case we discussed" /abs/path/to/project \
--session-ref <previous_task_id> --mode build --policy allow --verify "python -m pytest -q"Configuration (the teaching section)
Config file lookup order: --config flag → NAR_CONFIG env →
<home>/agents.json (home = NAR_HOME env or ~/.native-agent-router) →
built-in defaults + auto-discovery.
Top-level settings
Key | Default | Meaning |
| 120 | default bounded block for |
| 3600 | cap on a single |
| 1800 | default per-turn timeout |
| 600 | timeout per verification command |
| 12000 | result summary budget returned to the orchestrator |
| true | one pre-authorized targeted repair per task |
| false | verify commands run without a shell (argv / |
| false | fail-closed: refuse to run a worker in a non-git workspace so changes are always auditable |
Agents
Every task must name an agent_id explicitly. There is no global
"selected backend" that other calls could silently change.
Key | Applies to | Meaning |
| all |
|
| all | set false to hide an agent |
| acp-generic | argv that starts the ACP server, e.g. |
| acp-generic | some ACP servers want |
| both | model selection (see below) |
| acp-generic | CLI-arg model injection template, e.g. |
| zcode-native | ZCode provider id from your own |
| zcode-native | e.g. |
| zcode-native |
|
| both |
|
| zcode-native | native tool-set restriction, e.g. |
| zcode-native |
|
| zcode-native |
|
| both | extra env for the agent subprocess (do NOT put secrets in here; they land in config files) |
Model selection
ZCode (
zcode-native): setprovider+model(+ optionalthought_level). NAR builds ZCode 0.16'sruntimeModelpayload from your own~/.zcode/v2/config.jsonand passes it inside the protocol only. No credential is ever copied to disk by default, no provider/base URL/billing channel is changed, and coldsession/resumeworks (verified live on 0.16.5).ACP agents (
acp-generic): NAR first tries the ACP-native path —session/set_config_option/session/set_model(works with opencode, whosesession/newadvertises amodelconfig option) — then falls back tomodel_argsCLI substitution (e.g.gemini --experimental-acp --model X).
ZCode discovery (how zcode.cjs is found)
Order: ZCODE_BIN env → zcode on PATH → Windows registry uninstall entries
(InstallLocation) → %LOCALAPPDATA%\Programs\ZCode → Program Files\ZCode on
every drive. If none match, nar doctor tells you exactly what to set. The
desktop app does not add its CLI to PATH — that is normal.
Credentials, honestly
credentials: "auto" reads (read-only) the provider you already configured in
the ZCode desktop app and passes the same provider/model/base-URL/key to the
headless app-server in the protocol payload only. NAR never logs keys,
never uploads them anywhere, never switches billing channels, and never
bypasses authentication or plan limits. If you prefer a private session store,
set zcode_home: "isolated" (documents trade-offs in docs/SECURITY.md).
MCP integration
Run nar-mcp over stdio. Examples:
Codex (~/.codex/config.toml):
[mcp_servers.native-agent-router]
command = "nar-mcp"
args = []opencode (opencode.json in your project or ~/.config/opencode/):
{ "mcp": { "native-agent-router": { "type": "local", "command": ["nar-mcp"], "enabled": true } } }Claude Code (.mcp.json):
{ "mcpServers": { "native-agent-router": { "command": "nar-mcp" } } }Then ask your orchestrator, in one sentence:
"Run agents, then run this task to zcode with scope and verify, and
wait for it." See skill/native-agent-router/SKILL.md for the delegation
rules you can drop into any agent's skill folder.
The five MCP tools
Tool | Purpose |
| configured agents + capabilities + score stats (routing data) |
| submit one complete work unit (goal/scope/forbid/verify/budget/mode/session_ref) |
| bounded block until terminal/blocked; never busy-polls |
| paged on-demand reads: status/summary/diff/verify/log/raw/usage/diagnose |
| request stop and report whether it was confirmed |
run returning means submitted, not done. Only
succeeded|failed|cancelled|blocked|interrupted are final. On blocked the
kernel keeps the workspace lock and watches the native session until a real
terminal event arrives (or you cancel/kill).
CLI reference
nar agents | doctor | list
nar run <agent_id> <goal> <workspace> [--scope ...] [--verify "cmd"] [--mode build]
[--policy allow|deny] [--session-ref TASK] [--timeout N] [--wait N]
[--budget N] [--idempotency-key K] [--no-repair]
nar wait <task_id> [--timeout N]
nar inspect <task_id> [status|summary|diff|verify|log|raw|usage|diagnose] [--offset N] [--limit N]
nar cancel <task_id>
nar kill <task_id> --yes # force: terminate agent + release lock (user boundary)
nar stats [agent_id] # deterministic per-agent score statisticsTests
pip install -e ".[dev]"
pytest -q # 64 tests, no model calls, no network
pytest -q -m real # opt-in: hits your real installed agents (spends tokens!)Docs
ARCHITECTURE.md · BACKENDS.md · VERIFY.md · BENCHMARK.md · SECURITY.md · ROLLBACK.md · Skill
Status & honesty
Verified live on this machine: ZCode 0.16.5 (read-only, native resume, edit+verify, permission handling, real usage), opencode 1.18.15 over ACP (handshake, model switch, resume). Evidence paths in docs/VERIFY.md.
Not yet verified here: Gemini CLI (not installed), Claude Code as ACP (installed but currently unusable per user), Codex as orchestrator client.
No claim of "optimal" or fixed savings percentage: see BENCHMARK.md for what was measured and what wasn't.
MIT licensed. Independent community project; not affiliated with Z.AI/ZCode, OpenAI Codex, or SST/opencode.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/BerineYang/native-agent-router'
If you have feedback or need assistance with the MCP directory API, please join our Discord server