中文 · English
Claude plans. ZCode codes. Git verifies.
A plugin for Claude Code and other coding agents that hands a well-specified development task to the local ZCode agent (GLM), runs it in an isolated git worktree, guards every write with a hard-rule check plus a model-based review, and lets you verify the result with git diff and tests instead of trusting the agent's own report.
Claude Code is good at thinking a task through. ZCode grinds out the code at a fraction of the cost. Left alone, either one will happily go off-script. This plugin puts the two in their places:
- The task file is the contract. Claude writes
tasks/T-xxx.md; the message to ZCode is just a doorbell. - The worktree is the sandbox. ZCode works in
~/.zcode-executor/worktrees/<repo>, never in your main checkout. - The gate decides who gets asked. Every tool call ZCode wants to make passes hard rules, model review, and a human if needed. Optional Jev pre-screening can allow early; otherwise the original ZCode
fast+lowscreen runs, followed by slow review only when needed. The models can only allow or ask; they never deny on your behalf. - Evidence beats narrative. You accept with
git diffand your test suite.
Paste this to your agent (Claude Code, Codex, or anything with a shell):
Read https://github.com/kyomio/zcode-executor/blob/main/README.md and install zcode-executor by following its Install section, then run zcode-executor doctor.
You don't drive the CLI yourself. You describe the task to your agent, and it runs the skill: writes a task file, adds a worktree, dispatches to ZCode, waits, then checks the result with git diff and your tests before telling you it's done. If ZCode asks for something the gate won't pass on its own, the agent stops and asks you.
Two ways to trigger it:
Call the skill directly
/zcode-executor add a --json flag to the status command, keep the tests green
(The full name is /zcode-executor:zcode-executor; the short form works unless another plugin claims it.)
Or just say so in plain language
Hand the lib/queue.mjs refactor off to zcode.
Either way, say what "done" looks like — which command should pass, which file should exist, what output you expect. The agent turns that into the acceptance criteria in the task file, and the task file is the contract; the message sent to ZCode is only a doorbell.
- Workflow layer — dispatch and acceptance: task file → isolated worktree → local session id → background runner →
git diffand tests. This is what the CLI commands and the skill are about. - Safety layer — automatic handling of ZCode's permission requests. Its logic follows Claude Code's auto mode: a fixed table of hard rules that nothing can override, then optional Jev pre-screening → ZCode fast screen → slow review if needed, then a human when review cannot pass. Jev adds an early-pass path; it does not replace the ZCode fast screen. The reviewers can allow or ask; they can never deny on your behalf.
Sequence diagram rendered with archify from assets/how-it-works.en.json.
One runner process per session, always in the background; the CLI only reads files under ~/.zcode-executor/runs/<id>/. Nothing costs tokens except send and the review calls.
The workload below is what it took to build this project: 35 task files, 4 executor sessions, 957M prompt tokens and 2.39M output tokens on the executor side. The same tokens priced three ways at public API list prices, with the cache-read rate fixed at 95% for both models:
| Executor | New input | Cache read | Output | Total | vs Sonnet 5 |
|---|---|---|---|---|---|
| Claude Sonnet 5 | $119.6 | $181.9 | $23.9 | $325 | 1× |
| GLM-5.3-Flash, list price | $7.2 | $27.3 | $1.2 | $35.7 | 1/9.1, saves 89% |
| GLM-5.3-Flash via ZCode (67% of list) | $4.8 | $18.3 | $0.8 | $23.9 | 1/13.6, saves 93% |
Prices used (USD per million tokens): Sonnet 5 $2.50 cache write / $0.20 cache read / $10 output; GLM-5.3-Flash $0.15 / $0.03 / $0.50. Sonnet's new input is billed at the cache-write rate because Claude Code writes every turn into the cache. Cache reads dominate: in an agent loop the whole context is re-read every turn, so the cache-read price is what decides the gap. The measured cache-read rate was actually 99.3%; at that rate the ratio is 7.5× and 11.2×. The planner's cost is the same in every scenario and is left out. Prices as of September 2026: Claude, Z.ai.
This repository is both the plugin and its own marketplace.
claude plugin marketplace add kyomio/zcode-executor # or a local path
claude plugin install zcode-executor@zcode-executor --scope userbin/zcode-executor is added to Bash's PATH while the plugin is enabled; the skill appears as /zcode-executor:zcode-executor. Saying "let zcode do it" triggers it.
The plugin also ships a Claude Code mod (a module of function hooks, hooks/): type /zcode to open the watch pane, a live view of this project's zcode sessions. It also opens by itself when Claude sends a task, and adds a status-line summary and toasts. Nothing to configure; it needs a Claude Code version with function-hook mods (the API is in early access).
The repo root ships a native kimi.plugin.json (skills only; the Claude Code mod above is Claude-only and not included). Register it into the personal market once, then install from the 个人 tab:
kimi-daimon kimi-plugin register-personal /path/to/zcode-executorLike the agents below, Kimi Work does not put the plugin's bin/ on PATH — the skill falls back to bin/zcode-executor relative to the plugin root, or npx zcode-executor. Saying 「让 zcode 去做」「派给 zcode」 triggers the skill.
codex plugin marketplace add kyomio/zcode-executor # or a local path
codex plugin add zcode-executor@zcode-executorTwo differences from Claude Code: Codex does not put a plugin's bin/ on PATH (the skill tells the agent where the binary lives), and the default workspace-write sandbox blocks writes to ~/.zcode-executor — add it to [sandbox_workspace_write] writable_roots in ~/.codex/config.toml or approve when prompted.
This repository doubles as a Copilot CLI plugin marketplace.
copilot plugin marketplace add kyomio/zcode-executor
copilot plugin install zcode-executor@zcode-executorA gemini-extension.json at the repo root makes it a Gemini CLI extension; the bundled skills/ are discovered automatically.
gemini extensions install https://github.com/kyomio/zcode-executorAntigravity is Gemini CLI under its new name (agy) and reuses the same extension manifest.
agy plugin install https://github.com/kyomio/zcode-executorpi reads the pi field in package.json and installs the package directly.
pi install npm:zcode-executorNo manifest needed — link the skill into its user skills directory:
ln -s "$(npm root -g)/zcode-executor/skills/zcode-executor" ~/.openclaw/skills/zcode-executorThe repo root ships a Hermes plugin.yaml; install, then enable:
hermes plugins install kyomio/zcode-executor
hermes plugins enable zcode-executor.grok-plugin/ carries its marketplace manifests, and the skill itself is one symlink away (it also reads ~/.agents/skills/):
ln -s "$(npm root -g)/zcode-executor/skills/zcode-executor" ~/.grok/skills/zcode-executorNone of the seven agents above puts the plugin's bin/ on PATH the way Claude Code does — run npm install -g zcode-executor once, or let the skill fall back to npx zcode-executor; the SKILL.md covers both.
npm install -g zcode-executor # zero dependencies, nothing to build
zcode-executor doctor # zero-token self-checkOr run it without installing: npx zcode-executor doctor. The skill ships in the package at $(npm root -g)/zcode-executor/skills/zcode-executor/; copy or symlink it into your agent's skills directory. The CLI itself has no Claude-specific dependency.
SKILL=$(npm root -g)/zcode-executor/skills/zcode-executor
mkdir -p ~/.claude/skills && ln -s "$SKILL" ~/.claude/skills/zcode-executorSwap in your own agent's directory from this table:
| Agent | User skills directory |
|---|---|
| Claude Code | ~/.claude/skills |
| Codex | ~/.codex/skills |
| Gemini CLI / Antigravity | ~/.gemini/skills |
| Grok Build | ~/.grok/skills |
| Hermes | ~/.hermes/skills |
| OpenClaw | ~/.openclaw/skills |
| opencode | ~/.config/opencode/skills |
| Shared (several agents read it) | ~/.agents/skills |
git clone https://github.com/kyomio/zcode-executor && cd zcode-executor
npm link && zcode-executor doctorln -s "$PWD/skills/zcode-executor" ~/.claude/skills/zcode-executorSwap in your agent's directory from the table in the npm section above.
- macOS or Linux. Windows is not supported yet. The ZCode app bundle is looked up where each platform puts it (
/Applications/…,/opt/ZCode/…,/usr/share/zcode/…); installed anywhere else, pointZCODE_BINatzcode.cjs. - Node ≥ 22 (ZCode's app-server needs
node:sqlite). - ZCode desktop app ≥ 3.12.2 installed and logged in (3.11 and earlier are not supported). Both login styles work: an account (OAuth) Coding Plan — the CLI decrypts the platform key the App stores in
~/.zcode/v2/credentials.json(individual and team plans; only the four keys it needs are ever read, pluszcodejwttokenfor off-peak sends) — or an API-key provider in~/.zcode/v2/config.json. Both files are read-only; nothing is ever written back.
This is how zcode-executor itself was built:
- Plan with Claude Fable. The strongest reasoning model does the grilling, writes the spec, and turns it into task files with machine-checkable acceptance criteria.
- Execute with ZCode. Each task goes to a GLM session in its own worktree through
zcode-executor; the permission gate handles the routine approvals. - Fable does a coarse pass, Opus does the review. Fable checks
git diffand runs the tests; if they hold, it dispatches an Opus subagent for a line-by-line code review. Findings go back to the same ZCode session as a follow-up task file. - Merge on evidence. Nothing lands until the tests and the review both pass.
The split keeps the expensive model on judgment and the cheap one on typing.
In Claude Code (terminal or the desktop Code tab), type /zcode to open a live pane showing what this project's zcode sessions are doing:
- Needs you: pending permission requests (full command and reason), questions, runners that died;
- Running: the executor's latest message rendered as Markdown, the tool it is running with its arguments, recently finished tools (failures in red), and queue position for off-peak sends;
- Finished: sessions that ended in the last 10 minutes show the outcome and their last message; older ones take one line each.
A message longer than two lines is folded to its first two; press Expand reply to read it in full and Collapse to fold it again.
The pane opens by itself when Claude sends a task. The status line sums up running turns and pending requests, and a toast pops on a pending request, a finished turn, or a dead runner. The pane is read-only: pending requests still go through Claude.
It reads zcode-executor watch --json (read-only, long-running, no quota) and shows only sessions of the repository the Claude session is in. If the pane says node cannot be found, set nodePath in the plugin's settings.
Other agents ignore the pane and keep using the skill and the CLI.
| Command | What it does |
|---|---|
doctor [--offpeak] [--json] |
Self-check that spends no quota: finds zcode.cjs and the bundled zcode-builtin.json (ZCode App ≥ 3.12.2), reports both provider sources, does one real handshake, reports model tiers and the review pipeline for a newly started runner (it does not call Jev), and checks the off-peak interface — that step goes online and leaves one self-check session in zcode's own session store. --offpeak runs only that step |
quota [--json] |
How many off-peak tickets this tool took today and whether the server would hand one out now; no quota spent, no app-server |
models [--json] |
Lists available models with thought levels and tier assignment |
new --cwd <abs> [--title T] [--tier fast|strong] [--thought L] [--deny "Tool…"] [--provider id] [--json] |
Registers a session (returns a local id x_…); the ZCode session is created on first send |
send <id> <text|-> [--task file] [--wait] [--timeout s] [--steer] [--stream] [--json] |
Queues a message; --wait follows until done or blocked; --task is the task file the review uses as your authorization; --steer injects into a running turn — it takes effect at the next tool boundary, or after the turn ends if there is none |
send <id> <text|-> --offpeak [--task file] [--wait] [--timeout s] [--stream] [--json] |
Off-peak send: takes a ticket on the spot and runs the turn on the Coding Plan's free off-peak capacity once the ticket is ready (see below) |
send <id> --offpeak --resume [--wait] [--stream] [--json] |
Restarts the runner for an off-peak send left unfinished after the turn exited or the runner died |
follow <id> [--timeout s] [--stream] [--json] |
Follows a background runner until a result or a pending request |
status <id> [--tools N] [--json] |
Read-only snapshot: phase, recent tools (with command or path), queue, pending, last result |
list [--project kw] [--json] |
Registered sessions with phase, tier and last outcome; --json adds the owning repository |
watch [--json] |
Read-only, long-running: prints a session snapshot whenever one changes; feeds the watch pane |
cancel <id> |
Denies any pending request, stops the turn, clears the queue |
approve <id> / deny <id> |
Answers the pending permission request (allow is allow_once only) |
answer <id> [--] <values…> |
Answers the pending question by index, value or label; multi-select comma-separated |
Exit codes: 0 done · 1 usage / cannot start · 2 refused (whitelist, unknown session, bad tier; an off-peak send refused before or while taking a ticket) · 3 --wait timed out (turn cancelled) · 4 turn failed / cancelled · 5 blocked, waiting for a human (permission or question).
An off-peak send runs the turn on the Coding Plan subscription's free off-peak capacity instead of your plan quota. The server decides when it starts: send --offpeak takes a ticket and queues, and the turn runs once the ticket is ready. Acceptance is the same as a normal send. Requirements: an individual Coding Plan account login in the ZCode app, and a session model on the off-peak model list. The session must be idle; while an off-peak send is queued or running, normal sends to that session are refused, so use a separate session for off-peak work. Expired tickets are retaken automatically (up to three tickets per send), cancel settles the ticket at any stage, and quota shows today's usage (roughly three tickets a day observed). Normal sends stay the default; the skill tells you when off-peak is available and only switches when you ask.
~/.zcode-executor/config.json (override the directory with ZCODE_EXECUTOR_HOME). Every field is optional.
| Field | Default | Meaning |
|---|---|---|
allowedRoots |
["~/.zcode-executor/worktrees"] |
Directories new --cwd may point into (symlinks resolved) |
waitTimeoutSec |
1800 |
send --wait timeout; the turn is stopped when it fires |
preferredProvider |
account individual plan › account team plan › config.json coding plan |
Which provider to pick when the same model exists under several, e.g. account:bigmodel-team-coding-plan |
tiers |
auto by name | Override which model is fast / strong |
review |
{enabled, model, thought:"low", fastMaxTokens:300, slowMaxTokens:2000, timeoutMs:60000} |
Model review: on/off, ZCode model (default: the fast tier), thought level, token budgets, per-call timeout |
review.jev.apiKey |
absent | A non-blank key enables Jev pre-screening ahead of ZCode fast + review.thought (default low); absent or all-whitespace keeps the original ZCode chain |
environment / sensitive |
[] |
Extra facts and sensitive locations shown to ZCode review calls (not sent to Jev) |
Jev is TypeSafe's structured decision model: it returns probabilities rather than explanations. It does not execute tasks or replace the original ZCode fast screen. It only tries to pass actions early when the evidence is sufficient:
After hard-rule and allow_once checks
→ Jev pre-screen: pass early, otherwise continue
→ ZCode fast screen (default fast + low): pass, otherwise continue
→ ZCode slow review: allow or ask a human
- Five risk checks cover task-boundary conflicts, writes outside the workspace, credential exposure or sensitive-data exfiltration, destructive/external side effects, and unrelated actions. The current model is pinned to
jev-1.13.0; all five probabilities must be at most0.20for early approval. This is a screening threshold, not a safety guarantee. - Write/Edit/MultiEdit bodies are not sent to Jev; these actions currently skip pre-screening locally. Missing intent, truncated required input, or credentials that cannot be reliably redacted also cause a local skip, with no Jev HTTP request. Command complexity alone is not a reason to skip.
- Jev flags, timeouts, network errors, and invalid responses go to the original ZCode fast screen—not directly to denial or mandatory slow review. A failed ZCode fast-screen call still asks a human.
- Early passes can save subsequent review calls; other requests add serial latency. Jev currently has a 10-second total budget, separate from ZCode's
review.timeoutMs. Actual speed and cost benefits depend on the pass rate.
Obtain your own API key from TypeSafe (see the official quick start). It is separate from your ZCode provider key; do not edit ZCode App's configuration for this.
Edit ~/.zcode-executor/config.json. Merge the review.jev field into your existing configuration; keep allowedRoots, provider settings, and other fields rather than replacing the whole file. If you set ZCODE_EXECUTOR_HOME, edit config.json in that directory instead.
Never put a real key in a command argument, shell environment, checked-in example, issue, or log. The value below is only a placeholder; real keys need not use that prefix:
{
"review": {
"jev": {
"apiKey": "jev_REPLACE_WITH_YOUR_KEY"
}
}
}The file must already exist. Restrict its permissions (adjust the path if you use a custom configuration directory):
chmod 600 ~/.zcode-executor/config.jsonWhen review.jev.apiKey is set, config.json must be a regular, non-symlink file owned by the current UID and accessible only by that owner (0600 or stricter). Otherwise zcode-executor refuses to load it. There is no environment-variable fallback and no Jev mode or shadow setting. Remove apiKey (or leave it all-whitespace) to use only the original ZCode review chain. Setting review.enabled to false disables all model review, including Jev; hard rules still apply and other permission requests wait for a human.
zcode-executor doctor --jsonWith review enabled and a key configured, the output should include:
"review": {
"enabled": true,
"fastScreen": "jev",
"jevConfigured": true,
"pipeline": ["jev", "zcode-fast", "zcode-slow"]
}doctor does not call Jev. It confirms configuration and the selected chain, not TypeSafe key validity, account credit, or network connectivity. This excerpt is part of the full JSON response; fastScreen is a compatibility field, not an indication that ZCode's fast screen was replaced.
Newly started runners read the configuration; existing runners do not hot-reload it. Let the current runner exit before sending another turn to pick up changes. Actual approvals record pass / flag / error / skip and filtered diagnostics in executor.gate.preScreen, never the key or full Jev state.
To disable only Jev: remove review.jev.apiKey, keeping the original ZCode fast and slow review chain. Do not use review.enabled:false for this—it disables all model review.
- Hard rules are code constants, never configuration: any path-bearing tool writing outside the worktree stops for a human. The rule table follows the categories of Claude Code's auto mode (credentials, exfiltration, destructive git, deletion, supply chain, persistence, deploys, shared resources, external writes).
- The reviewers never deny. Their only final outputs are allow and ask. Jev flag/error/skip returns to the ZCode fast screen, then slow review if needed. A ZCode fast-call failure still asks a human.
- Allow only when allowed. Automatic approval and
approveboth require anallow_onceoption; there is no "always allow". - Secrets are tightly scoped. ZCode's provider key still goes only to the app-server path. The optional Jev key is the one deliberate persistent secret: it lives only in owner-protected
config.json, is sent only as Jev authorization, and is never copied to events, pending state, runner logs or the app-server process. - Answers are bound to requests. Every
approve/deny/answercarries the request id; stale answers are discarded.
npm test # 728 cases against a scripted mock app-server and mock off-peak server, plus a doc-version drift check; no tokens spent
node --check lib/**/*.mjsReleases are tag-driven: npm version patch bumps package.json, syncs the version into both READMEs and every host's plugin manifest, and commits and tags; git push --follow-tags triggers the workflow that runs the tests, publishes to npm (Trusted Publishing, no token) and creates the GitHub Release. Commit messages are the changelog.
Pure .mjs, zero runtime dependencies, no build step. Design documents live in docs/: PRD, SPEC, CONTEXT (glossary), RULES (coding rules), decisions, verified (facts measured against the real app-server). Agent-facing entry point: AGENTS.md.
Does it work with agents other than ZCode? No, by design. The executor side is ZCode only; the planning side can be Claude Code, Codex or anything that runs a shell.
Why not just let Claude edit the code? Cost and isolation. ZCode's GLM coding plan is credit-based and far cheaper than frontier-model tokens (inside ZCode it is billed at a 67% discount, with a free off-peak quota on top), and the worktree keeps two agents from editing the same files.
How much does a task cost? Measured in tokens, a one-file change is roughly 30–65k input on ZCode's side (its system prompt is heavy); the review adds about 5k input and 2 seconds per fast screen. Billed against the coding plan's credits at ZCode's discounted rate, that is a small fraction of doing the same edit with a frontier model.
What if Jev cannot decide? Flag, timeout, error or invalid response returns to the original ZCode fast screen. A non-passing or unparseable fast result goes to slow review; a failed fast call asks you directly (exit code 5).
Jev is skipped locally, with no HTTP request, when action bodies are omitted, intent is missing, or required input is truncated. Command complexity alone is not a reason to skip or reject.
doctor --json reports review.pipeline: ['jev','zcode-fast','zcode-slow'] with a key, the last two without one, [] when disabled, and null on configuration failure. The legacy fastScreen field does not mean Jev replaces ZCode.
Apache-2.0. Ported code keeps its original notices; see NOTICE.

