zcode-executor

Claude plans, ZCode codes, git verifies. Hand a development task to the local ZCode (GLM) agent in an isolated git worktree, with a hard-rule + model-review permission gate. 把开发任务派给本机 ZCode 执行,worktree 隔离,红线加模型审批,git diff 验收

Packages

Package details

skill

Install zcode-executor from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:zcode-executor
Package
zcode-executor
Version
0.3.0
Published
Sep 19, 2026
Downloads
186/mo · 173/wk
Author
kyomio
License
Apache-2.0
Types
skill
Size
359.6 KB
Dependencies
0 dependencies · 0 peers
Pi manifest JSON
{
  "skills": [
    "./skills"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

Why

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 + low screen 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 diff and your test suite.

Quick start

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.

How to use

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.

Two layers

  • Workflow layer — dispatch and acceptance: task file → isolated worktree → local session id → background runner → git diff and 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.

How it works

How zcode-executor works: dispatch, permission gate, verify

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.

Measured cost

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:

Execution cost for the same workload

Executor New input Cache read Output Total vs Sonnet 5
Claude Sonnet 5 $119.6 $181.9 $23.9 $325
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.

Install

Claude Code (plugin marketplace)

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 user

bin/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.

Codex

codex plugin marketplace add kyomio/zcode-executor        # or a local path
codex plugin add zcode-executor@zcode-executor

Two 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.

GitHub Copilot CLI

This repository doubles as a Copilot CLI plugin marketplace.

copilot plugin marketplace add kyomio/zcode-executor
copilot plugin install zcode-executor@zcode-executor

Gemini CLI

A 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-executor

Antigravity

Antigravity is Gemini CLI under its new name (agy) and reuses the same extension manifest.

agy plugin install https://github.com/kyomio/zcode-executor

pi

pi reads the pi field in package.json and installs the package directly.

pi install npm:zcode-executor

OpenClaw

No manifest needed — link the skill into its user skills directory:

ln -s "$(npm root -g)/zcode-executor/skills/zcode-executor" ~/.openclaw/skills/zcode-executor

Hermes

The repo root ships a Hermes plugin.yaml; install, then enable:

hermes plugins install kyomio/zcode-executor
hermes plugins enable zcode-executor

Grok Build

.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-executor

None 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 (any agent, or no agent)

npm install -g zcode-executor   # zero dependencies, nothing to build
zcode-executor doctor           # zero-token self-check

Or 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-executor

Swap 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

From source

git clone https://github.com/kyomio/zcode-executor && cd zcode-executor
npm link && zcode-executor doctor
ln -s "$PWD/skills/zcode-executor" ~/.claude/skills/zcode-executor

Swap in your agent's directory from the table in the npm section above.

Requirements

  • 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, point ZCODE_BIN at zcode.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). The CLI reads ~/.zcode/v2/config.json read-only; nothing is ever written back.

Recommended workflow

This is how zcode-executor itself was built:

  1. 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.
  2. Execute with ZCode. Each task goes to a GLM session in its own worktree through zcode-executor; the permission gate handles the routine approvals.
  3. Fable does a coarse pass, Opus does the review. Fable checks git diff and 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.
  4. 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.

Commands

Command What it does
doctor [--json] Zero-token self-check: finds zcode.cjs and the bundled zcode-builtin.json (ZCode App ≥ 3.12.2), confirms the config exists, does one real handshake, reports model tiers and the review pipeline for a newly started runner; it does not call Jev
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
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, queue, pending, last result
list [--project kw] [--json] Registered sessions with phase, tier and last outcome
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) · 3 --wait timed out (turn cancelled) · 4 turn failed / cancelled · 5 blocked, waiting for a human (permission or question).

Configuration

~/.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 coding-plan providers first Which provider to pick when the same model exists under several
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)

To enable Jev, edit the JSON file directly—never put a real key in a command argument, shell environment, checked-in example, issue, or log:

{
  "review": {
    "jev": {
      "apiKey": "jev_REPLACE_WITH_YOUR_KEY"
    }
  }
}

Then protect the file:

chmod 600 ~/.zcode-executor/config.json

When 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.

Safety model

  • 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 approve both require an allow_once option; 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/answer carries the request id; stale answers are discarded.

Development

npm test          # 303 cases against a scripted mock app-server, plus a doc-version drift check; no tokens spent
node --check lib/**/*.mjs

Releases are tag-driven: npm version patch bumps package.json, syncs the version into both READMEs and both plugin manifests, 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.

FAQ

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.

License

Apache-2.0. Ported code keeps its original notices; see NOTICE.