zcode-delegate
Delegate a coding task to the Z.AI ZCode CLI as a background implementer, then review its diff and land it yourself. Use this whenever the user wants to hand implementation work to ZCode — phrasings like "have ZCode do X", "delegate this to ZCode", "run it through ZCode", or "use
Install
npx skills add https://github.com/amElnagdy/delegate-skills/tree/master/skills/zcode-delegate
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install amelnagdy-delegate-skills@llmmart
git clone https://github.com/amElnagdy/delegate-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole amelnagdy/delegate-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
ZCode Delegate
You are the orchestrator. This skill lets you hand a bounded coding task to a separate implementer — the Z.AI ZCode CLI — then review what it produced and land it yourself. You write the brief and own the judgment; ZCode does the typing; you verify and commit.
Nothing here is specific to one orchestrating agent. The loop needs only the ability to run a shell command and read a file. (It is designed for and run on Claude Code; treat other orchestrators as designed-for, not yet proven.)
When NOT to use this
- The task is small enough to just do inline — delegation overhead is not worth it.
- ZCode is not installed, or its CLI has no model provider configured.
- You want to write the code yourself, or you only need a review.
Prerequisites (check once)
- ZCode is installed. The CLI ships inside the desktop app — it is not on PATH and not on
npm. The relay resolves it in this order:
--zcode-path <file>orZCODE_CLIfirst, then PATH, then the installed app bundle. On Linux the app is an AppImage with no fixed install path, so the flag or the environment variable is required there — the relay guesses nothing. - A model provider is configured for the CLI, with a key it can actually reach. Being signed into the desktop app is not enough — see below.
- You are in (or will point
--cdat) the target git repository.
The relay records the CLI version and how it was resolved into result.json, so a surprising
install is visible after the fact.
Authenticating the headless CLI
Signing into the ZCode desktop app does not authenticate the CLI this relay drives. The CLI
keeps its own config at ~/.zcode/cli/config.json, separate from the desktop app's, and nothing
bridges the two. zcode login is the intended path, but where it fails with OAuth response is not valid JSON the way in is a Z.AI API key.
Two pieces are needed, and they are separate:
The provider block must exist in
~/.zcode/cli/config.json. It defines the provider, its endpoint and its models — the environment cannot supply this:{ "provider": { "zai": { "kind": "anthropic", "options": { "apiKeyRequired": true, "baseURL": "https://api.z.ai/api/anthropic" }, "models": { "glm-5.1": { "name": "GLM-5.1" } } } }, "model": { "main": "zai/glm-5.1" } }The key can live either in
provider.zai.options.apiKeyin that file, or in the environment as any one ofZAI_API_KEY,ZCODE_API_KEY, orANTHROPIC_API_KEY. Prefer the environment — it keeps the secret off disk.
If a run fails with Model provider is missing an API key: <provider>, the provider block resolved
but no key was found: set one of those variables and re-run.
Autonomy — read this before dispatching
ZCode's own term is mode. It has four values; only two are usable headlessly.
| mode | Behaviour |
|---|---|
yolo |
Writes. ZCode's own default for --prompt, and this relay's write-capable default. |
plan |
Refuses edits. What --read-only selects. |
build |
Rejected by this relay. No permission client exists headlessly, so tools are blocked and the run exits 0 having done nothing. |
edit |
Rejected for the same reason. |
Two limits stated plainly, because ZCode cannot enforce them:
planmode refused edits in testing, but the relay does not treat that as a guarantee. It takes a Git fingerprint before the run and reports a tri-statereadOnlyViolationafterwards. ConfirmtouchedFilescame back empty rather than assuming no edits.- ZCode has no
--allowed-tools. Only the--disallowed-toolsdenylist exists, and it is genuinely enforced. An explicit allowlisted tool surface is therefore impossible here — do not assume one.
The loop
Run these five steps per task. Steps 1, 4, and 5 are your judgment; 2 and 3 are mechanical.
1. Write the brief
ZCode sees only what you send — no repo memory, no chat history. Everything the task needs goes in the brief: the goal, the current state, what to change, what to leave untouched, the project's actual gate commands (discover them from the repo's CLAUDE.md/AGENTS.md/Makefile — do not assume), and a report contract. Tell ZCode it will not commit. One task per brief. The relay delivers the brief as an attached file, so the command line no longer bounds its length — the model's context window still does. Full guidance and a template: references/writing-the-brief.md.
2. Dispatch
node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo
# read-only (review/diagnosis, no edits): add --read-only
# continue a specific session: add --session <sess_...> (from result.json; send only the delta brief)
# continue the latest session for --cd: add --resume-last
# withhold tools (denylist): add --disallowed-tools "Write,Edit,Bash"
# point at the CLI explicitly: add --zcode-path /path/to/zcode.cjs
# hard time limit (watchdog): add --timeout 2h (default: off)
# see all options: node .../relay.mjs --help
(<skill-dir> is this skill's installed directory — the folder containing this SKILL.md.)
The relay writes its artifacts to a temp dir, so the repo under review stays clean. It never
commits — see step 5. Mechanics, flags, and the result.json shape:
references/dispatch-and-poll.md.
3. Wait for completion
The relay blocks until ZCode finishes, so back it with whatever your orchestrator offers:
- Claude Code: run the Bash call with
run_in_background: true; you are notified on completion. - Plain shell / other agents: foreground for short tasks, or background it and poll the result
file. The run is done when
result.jsonexists with astatus. A pre-run usage error exits 2 and writes no result file, so check the exit code too; a CLI that cannot be found exits 127 but does write aresult.jsonwith statuszcode_unavailable.
Do not trust progress trackers over reality: read the working tree, not a status line.
4. Review — do not trust the self-report
- Re-run the project's gates yourself. Never take "gates passed" on faith.
- Read the diff against the brief: did ZCode do what was asked, nothing more and nothing less?
touchedFilesis your starting point. - On a
--read-onlyrun, checkreadOnlyViolationand confirmtouchedFilesis empty. - Run the relevant guard skills on the diff if you have them installed.
Full checklist: references/review-and-land.md.
5. Land it
The orchestrator commits. Only after the gates pass and the diff holds:
- Commit the verified work yourself, with a clear message.
- If it needs changes, send a delta brief with
--session <sessionId>from the priorresult.json, and review again.
Read-only second opinions
The relay doubles as a way to get an adversarial second opinion with no write risk: dispatch
--read-only with a brief listing the agreed points, then each contested point with both positions,
and ask ZCode to defend or concede each. Because plan mode's guarantee is measured rather than
enforced here, verify touchedFiles came back empty instead of assuming no edits.
Authorization model
Delegation is something the human opts into. Once they have, committing verified, gate-passing work is the agreed contract. Two limits: surface, don't absorb (report ZCode's design decisions and defensible-but-unasked turns rather than silently keeping them) and stop for scope changes (if correct completion needs going beyond the brief, ask). The full treatment is in references/review-and-land.md.
References
- references/writing-the-brief.md — how to write a brief ZCode can execute blind: structure, the report contract, embedding the real gate commands.
- references/dispatch-and-poll.md —
relay.mjsflags, theresult.jsoncontract, how the CLI is resolved, backgrounding, and recovery. - references/review-and-land.md — the review checklist, the commit boundary, and the exact-session rework cycle.
- references/multi-task-queues.md — running a sequential queue: carrying constraints forward, progress tracking, and the end-of-run coherence check.
Files (delegate-skills)
-
references
-
dispatch-and-poll.md 6.4 KB
# Dispatch and poll The relay wraps the ZCode CLI so your job is "run a command, read a file." ```bash node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo cat brief.txt | node "<skill-dir>/scripts/relay.mjs" --cd /path/to/repo ``` ## How the relay finds ZCode ZCode does not install a `zcode` binary on PATH and does not publish one to npm — the CLI ships inside the desktop app. The relay resolves it in this order, first hit wins: 1. `zcode` on **PATH** — if you made a shim or alias, this is used. 2. **`--zcode-path <file>`**, else the **`ZCODE_CLI`** environment variable. 3. The installed **app bundle**: `%LOCALAPPDATA%\Programs\ZCode\resources\glm\zcode.cjs` on Windows, `/Applications/ZCode.app/…` (and `~/Applications/…`) on macOS. Linux ships an AppImage with no fixed install path, so there is nothing to auto-discover there — use option 1 or 2. A resolved `.cjs` bundle is launched under `node`. `result.json` records which route was used in `zcodeSource` (`path` / `flag` / `env` / `bundle`), so a surprising install is visible after the run. If no CLI is found — including when you name one explicitly that does not exist — the relay exits **127** and still writes a `result.json` with `status: "zcode_unavailable"`. ## Options | Flag | Effect | | --- | --- | | `--brief <file>` | Path to the brief. Omitted → read from stdin. | | `--cd <dir>` | Working root for ZCode (default: current directory). | | `--lane <name>` | Fleet lane from `delegate-setup` config. Explicit flags win over lane dials. | | `--mode <mode>` | ZCode's `--mode`. **Only `plan` and `yolo` are accepted** (see below). Default `yolo`. | | `--read-only` | Shortcut for `--mode plan` (review/diagnosis, no edits). | | `--disallowed-tools <list>` | Comma/space-separated denylist, e.g. `"Write,Edit,Bash"`. Enforced by ZCode. | | `--session <id>` | Continue a specific session by `sess_…` id from a prior `result.json`. | | `--resume-last` | Continue the latest session **for `--cd`**. Mutually exclusive with `--session`. | | `--zcode-path <file>` | Point at the CLI explicitly. | | `--timeout <dur>` | Relay-side watchdog (default: off). `30m`, `2h`. ZCode has no timeout flag of its own. | | `--out-dir <dir>` | Where to write run artifacts (default: a fresh dir under the system temp dir). | | `-h, --help` | Show help. | ### Why `build` and `edit` are rejected ZCode documents four modes. Headless runs have no permission client, so under `build` or `edit` the Write and Bash tools are blocked and the run **exits 0 having changed nothing**, with a report explaining that tool permissions were denied. That is a success status for a run that did no work, so the relay refuses those modes up front with a usage error (exit 2) rather than letting them look like a completed task. Use `--mode yolo` to write, or `--read-only` for plan mode. ## The `result.json` contract Speaks `delegate-relay.result.v1`. | Field | Meaning | | --- | --- | | `status` | `completed` \| `failed` \| `timeout` \| `aborted` \| `zcode_unavailable` | | `exitCode` | ZCode's own exit code, or the relay's mapping for a killed run | | `signal` | The signal that killed the child, or `null` | | `finalMessage` | ZCode's final report (its `response` field) | | `sessionId` | The `sess_…` id — pass to `--session` to continue this exact session | | `touchedFiles` | Git porcelain paths. `[]` when the tree is clean, `null` when git cannot report. | | `mode` | The ZCode mode the run actually used | | `readOnlyViolation` | Tri-state. `false` = the tripwire saw no change on a plan run, `true` = it did, `null` = unknown or not applicable | | `usage` | ZCode's token accounting (input, output, total, cache reads) | | `contextWindow` | From ZCode's `projection` | | `zcodeVersion`, `zcodeSource` | Which CLI ran, and how it was found | | `briefPath`, `outputPath`, `finalPath` | Run artifacts on disk | Exit codes: a pre-run usage error (bad args, empty brief, a rejected `--mode`) exits **2** and writes **no** result file. A CLI that cannot be found exits **127** and *does* write one. Otherwise the exit code mirrors ZCode's, and a run killed by the watchdog reports `timeout`. An orchestrator that polls for the file must therefore also check the exit code — a non-zero exit with no file is a usage error, not a crashed run. ## Backgrounding - **Claude Code:** run the Bash call with `run_in_background: true`. - **bash/zsh (incl. Git Bash/WSL):** `… &`, then poll for `result.json`. - **PowerShell:** `Start-Job`. **cmd:** `start /b`. The run is finished when `result.json` exists with a `status` *and* the process has exited. ## Reading the output ZCode's `--json` prints a single JSON document at the end rather than a stream of events, and the relay parses it tolerantly: the bundled AI SDK sometimes prints a warning banner on stdout ahead of the JSON, so leading non-JSON lines are skipped. The raw stdout is preserved at `outputPath` and the final report at `finalPath`, so nothing is lost if parsing degrades. If the document cannot be parsed at all: - with exit 0, the run is still `completed`, `finalMessage` falls back to the raw stdout, and a `parseWarning` field is set — read `outputPath` yourself. - with a non-zero exit, the run is `failed` and `stderrTail` carries the last lines of stderr. ## When a run misbehaves - **`status: "timeout"`** — the watchdog fired. The whole ZCode process tree was killed. Inspect the working tree before re-dispatching; a killed run can leave partial edits. - **`status: "aborted"`** — the relay itself was killed and forwarded the kill. Same advice. - **`status: "zcode_unavailable"`** — no CLI found. Check the three resolution routes above. - **Exit 1 with `Session not found`** — the `--session` id does not exist. Session ids are `sess_`-prefixed; copy them from a prior `result.json`, not from memory. - **`completed` but `touchedFiles` is empty on a write run** — read `finalMessage`. ZCode may have reported that it could not proceed. That is a real outcome, not a relay bug. - **`(no final message captured)` on a resumed plan-mode run** — ZCode has been observed returning `"response": ""` while doing substantial work (658 output tokens across 602 events in one measured run). The relay reports what ZCode sent, so an empty report here is the CLI's, not a parse failure: `parseWarning` will be absent and `usage` non-zero. Read `outputPath` and the working tree rather than concluding nothing happened. -
multi-task-queues.md 3.5 KB
# Multi-task queues A queue is a sequence of bounded tasks dispatched one at a time, each reviewed and landed before the next begins. It is the shape that makes delegation worth the overhead: a migration, a mechanical refactor across many files, a removal sweep. **Run them sequentially.** Parallel dispatches against one working tree produce interleaved edits that no reviewer can untangle, and `touchedFiles` stops meaning anything. ## The loop For each task in the queue: 1. Write the brief for **this task only**. 2. Dispatch. 3. Wait for `result.json`. 4. Review: re-run the gates, read the diff, check scope. 5. Land it — a commit per task, not one commit at the end. 6. Note anything learned that the next brief needs. A commit per task is what makes a queue recoverable. When task 6 of 9 goes wrong, you revert one commit instead of unpicking a nine-task blob. ## Carrying constraints forward Each brief is written cold, so constraints do not survive on their own. Keep a short block and paste it into every brief in the queue: ```markdown # Standing constraints (apply to every task in this queue) - Do not add dependencies. - Do not reformat files you are not otherwise changing. - Public API in src/api/ is frozen; changing it fails review. - Gates: node test/relay-smoke.mjs ``` Add to this block as you learn. If task 3's review caught a drive-by refactor, task 4's brief should forbid it explicitly. The block is how a queue gets *more* reliable as it runs rather than less. ## Fresh session per task, usually Start each task cold — a new dispatch with no `--session`. Independent tasks should not inherit an earlier task's context, which can carry over assumptions you rejected in review. Use `--session` **within** a task, for rework, not **between** tasks. The exception is a genuinely continuous piece of work split across dispatches for length; there, continuing the session preserves context that a cold brief would have to restate. ## Tracking progress Keep a visible checklist — the queue, one line each, marked as landed. Update it after the commit, not after the dispatch. A task is done when it is committed and the gates passed, not when ZCode said it finished. Record the `sessionId` of each task next to its line. If a landed task later turns out to be wrong, that id is the cheapest way back into its context. ## The end-of-run coherence check Individually correct changes can be collectively wrong. When the queue is done, review the whole range as one diff: ```bash git diff <commit-before-the-queue>..HEAD ``` Look for what per-task review structurally cannot catch: - **Drift** — the same problem solved three different ways across tasks. - **Duplication** — a helper invented in task 2 and reinvented in task 7. - **Dead ends** — code added for a task that a later task made unnecessary. - **Half-migrations** — the old and new patterns now both present, with no task left to finish it. Then run the gates once more over the final state. A queue where every task passed its own gates can still end with a broken tree, because task N's gates ran before task N+1 existed. ## When to stop the queue Stop and go back to the human when: - Two consecutive tasks need rework for the same reason — the standing constraints are wrong, not the implementer. - A task reveals the plan was based on a wrong assumption about the codebase. - Correct completion needs a scope change. Ask; do not expand the mandate yourself. Stopping a queue at task 4 with a clear explanation is a better outcome than finishing all nine and handing over a diff you cannot defend. -
review-and-land.md 4 KB
# Review and land ZCode's `result.json` contains its own summary and its own claims about gates. Treat all of it as a hypothesis. You are the reviewer; the commit is yours. ## The checklist 1. **Re-run the project's gates yourself.** Every time. "Gates passed" in `finalMessage` is a claim, not evidence. Run the actual commands from the brief and read their output. 2. **Read the diff against the brief.** Did ZCode do what was asked — nothing more, nothing less? `touchedFiles` tells you where to look; `git diff` tells you what happened. 3. **Check the "Out of scope" list.** Was anything on it touched? 4. **Read the DECISIONS section** of the report. Anything ZCode chose that the brief did not specify is something you now own. Surface it; do not absorb it silently. 5. **On a `--read-only` run**, confirm `touchedFiles` is `[]` and `readOnlyViolation` is `false`. Plan mode refuses edits, but the relay measures rather than assumes — see below. 6. **Run your guard skills** on the diff if you have them installed. This skill produces the work; those skills judge it. 7. For schema or migration changes, round-trip them. For removals, grep for dangling references. ## What `readOnlyViolation` means `plan` mode refused to write in testing, but whether that refusal is enforced by ZCode's tool layer or is model compliance is not established. So the relay fingerprints the repository before the run and compares afterwards: - `false` — no Git-visible change was detected. This is the expected result. - `true` — something changed during a read-only run. **Stop and inspect the tree.** The relay detects and reports; it does not attribute or revert. - `null` — git could not report, so the tripwire has no opinion. Inspect the tree directly. `readOnlyViolation` is `null` on `yolo` runs, where writes are the point. ## The commit boundary **The relay never commits.** Not on success, not on a clean gate run, not ever. Committing belongs to whoever reviewed the diff, and that is you. This is not a limitation to work around. If you find yourself wanting the implementer to commit, the review step is being skipped. ## Rework: the exact-session cycle When the diff needs changes, continue the same session rather than starting cold: ```bash node "<skill-dir>/scripts/relay.mjs" --brief delta-brief.txt --cd /path/to/repo --session sess_3d8fa06c-… ``` - Take `sessionId` from the prior `result.json`. - **Send only the delta** — what was wrong and what to do instead. ZCode still has the earlier turn; re-sending the original brief wastes context and invites it to redo accepted work. - `--resume-last` continues the latest session for `--cd`. It is scoped to that directory rather than being a global "last", which makes it safer than it sounds — but `--session` is still the precise choice when you have the id. - Review the result again. A rework cycle gets the same scrutiny as the first pass. ## Authorization model Delegation is something the human opts into. Once they have — "run this queue", "proceed" — committing verified, gate-passing work is the agreed contract. Two limits on that mandate: **Surface, don't absorb.** Report ZCode's design decisions, its defensible-but-unasked turns, and non-blocking nitpicks. Your reviewer's summary should let the human disagree with a choice they would not have made. Silently keeping such a change makes it yours. **Stop for scope changes.** If correct completion requires going beyond the brief — a schema change the task implies, a dependency the fix needs, a refactor without which the change is unsafe — ask. Do not expand the mandate yourself, and do not let the implementer expand it for you. ## What to tell the human After landing, say what actually happened: - what changed, and why - which gates you ran, and their real output - what ZCode decided that the brief did not specify - anything you left undone, and why If a gate failed, say so with the output. If a step was skipped, say that. A clean report of a messy run is more useful than a confident summary that does not survive contact with the diff. -
writing-the-brief.md 4.9 KB
# Writing the brief ZCode starts every dispatch cold. It has no orchestrator chat history, no memory of the last task, and no idea what you already ruled out. The brief is the entire context, and a vague brief is the single most common cause of a diff you have to throw away. ## How the brief reaches ZCode The relay writes your brief to `brief.md` in its run directory and passes it with ZCode's `--attach` flag, alongside a fixed one-line prompt telling ZCode to follow the attached brief. That matters in two ways: - **The command line stops bounding the brief.** ZCode has no stdin delivery, so a brief passed as prompt text would be limited by the command line (about 32 767 characters on Windows). Attaching sidesteps that entirely — write the brief the task deserves. The configured model's context window still applies, so this buys room, not an unlimited budget. - **The brief is a document, not a chat message.** Structure it with headings. ZCode reads it as a file. ## Structure ```markdown # Goal One or two sentences. What must be true when this is done. # Current state Where the relevant code lives, what it does today, and anything already tried and rejected. Name files with paths. Do not make ZCode hunt. # Change Exactly what to do. Be specific about behaviour, not implementation, unless the implementation is the point. # Out of scope What to leave alone. This is the field that prevents scope creep — spend real effort on it. # Gates The project's ACTUAL commands, copied from its CLAUDE.md / AGENTS.md / Makefile / package.json. Do not invent these. node test/relay-smoke.mjs npx skills add . --list # Constraints Anything non-negotiable: dependency limits, style rules, files that must not be touched, platforms that must keep working. # Report contract End your final message with: - WHAT CHANGED: one line per file, with the reason - GATES: the command you ran and its actual result - DECISIONS: anything you chose that the brief did not specify - UNFINISHED: anything you could not complete, and why # You will not commit Do not run `git commit`, `git push`, or any command that writes to `.git`. The orchestrator reviews the diff and commits. ``` ## The rules that actually matter **Embed the real gate commands.** The most common failure is a brief that says "run the tests" to an implementer with no idea what the test command is. Discover them from the repo first, then paste them. If you did not verify the command yourself, do not put it in the brief. **Spend effort on "Out of scope".** An implementer that is uncertain tends to do more, not less. A brief that says only what to change invites reformatting, drive-by refactors, and dependency additions. Name the things you do not want touched. **One task per brief.** If the brief has an "and then also", split it. Queues are for sequences — see [multi-task-queues.md](multi-task-queues.md). **Ask for a report contract.** You are going to re-verify everything anyway, but a structured report tells you where to look first, and the DECISIONS section is how you catch defensible-but-unasked turns before they reach your commit. **Say it will not commit.** The relay never commits, and ZCode running under `--mode yolo` has a Bash tool. Being explicit costs one line. ## Tool restrictions belong on the command line, not in the brief If the task genuinely must not touch certain tools, do not ask politely in the brief — pass `--disallowed-tools "Write,Edit,Bash"`. That denylist is enforced by ZCode: the named tools are absent from the session entirely. Prose in a brief is not. There is no allowlist counterpart — ZCode has no `--allowed-tools`. You can subtract capability, not enumerate it. ## For a read-only run A `--read-only` dispatch runs in ZCode's `plan` mode, which refuses edits. Briefs for these runs should ask for a deliverable **in the final message**, since no files will change: ```markdown # Goal Give a second opinion on the approach below. Do not change any files. # Agreed ...points both sides accept... # Contested 1. <point> — Position A: ... Position B: ... 2. ... # Report contract For each contested point, defend or concede, and say which evidence moved you. ``` Then verify the result: `touchedFiles` is `[]` and `readOnlyViolation` is `false`. Plan mode's refusal is measured by the relay's Git tripwire, not guaranteed by a sandbox, and `readOnlyViolation` is tri-state — `true` means Git-visible changes were detected, `false` means none were, and `null` means the tripwire could not tell, which calls for inspecting the tree yourself rather than assuming either. ## Delta briefs for rework When you send work back with `--session <sessionId>`, ZCode still has the earlier turn. Send only what changed — the correction, not the whole original brief. Repeating the full brief wastes context and invites it to redo work you already accepted. See [review-and-land.md](review-and-land.md).
-
-
scripts
-
relay.mjs 46.9 KB · in bundle
-
-
SKILL.md 9.4 KB
--- name: zcode-delegate description: >- Delegate a coding task to the Z.AI ZCode CLI as a background implementer, then review its diff and land it yourself. Use this whenever the user wants to hand implementation work to ZCode — phrasings like "have ZCode do X", "delegate this to ZCode", "run it through ZCode", or "use ZCode to implement/fix/refactor" — or to run a queue of coding tasks through ZCode while staying the reviewer. DO NOT USE for tasks small enough to do inline, or when the user wants the code written directly without delegating. license: MIT compatibility: Requires the `zcode` CLI (Z.AI ZCode) with a configured model provider, Node 18+, and git. ZCode ships its CLI inside the desktop app rather than on PATH or npm — see Prerequisites. The orchestrating agent must be able to run shell commands and read files. Shell examples assume bash/zsh (macOS/Linux, or Git Bash/WSL on Windows). metadata: version: 0.5.0 --- # ZCode Delegate You are the **orchestrator**. This skill lets you hand a bounded coding task to a separate **implementer** — the Z.AI ZCode CLI — then review what it produced and land it yourself. You write the brief and own the judgment; ZCode does the typing; you verify and commit. Nothing here is specific to one orchestrating agent. The loop needs only the ability to run a shell command and read a file. (It is designed for and run on Claude Code; treat other orchestrators as designed-for, not yet proven.) ## When NOT to use this - The task is small enough to just do inline — delegation overhead is not worth it. - ZCode is not installed, or its CLI has no model provider configured. - You want to write the code yourself, or you only need a review. ## Prerequisites (check once) 1. **ZCode is installed.** The CLI ships **inside the desktop app** — it is not on PATH and not on npm. The relay resolves it in this order: `--zcode-path <file>` or `ZCODE_CLI` first, then PATH, then the installed app bundle. On Linux the app is an AppImage with no fixed install path, so the flag or the environment variable is required there — the relay guesses nothing. 2. **A model provider is configured for the CLI**, with a key it can actually reach. Being signed into the desktop app is *not* enough — see below. 3. You are in (or will point `--cd` at) the target git repository. The relay records the CLI version and how it was resolved into `result.json`, so a surprising install is visible after the fact. ## Authenticating the headless CLI **Signing into the ZCode desktop app does not authenticate the CLI this relay drives.** The CLI keeps its own config at `~/.zcode/cli/config.json`, separate from the desktop app's, and nothing bridges the two. `zcode login` is the intended path, but where it fails with `OAuth response is not valid JSON` the way in is a Z.AI API key. Two pieces are needed, and they are separate: 1. **The provider block** must exist in `~/.zcode/cli/config.json`. It defines the provider, its endpoint and its models — the environment cannot supply this: ```jsonc { "provider": { "zai": { "kind": "anthropic", "options": { "apiKeyRequired": true, "baseURL": "https://api.z.ai/api/anthropic" }, "models": { "glm-5.1": { "name": "GLM-5.1" } } } }, "model": { "main": "zai/glm-5.1" } } ``` 2. **The key** can live either in `provider.zai.options.apiKey` in that file, or in the environment as any one of `ZAI_API_KEY`, `ZCODE_API_KEY`, or `ANTHROPIC_API_KEY`. Prefer the environment — it keeps the secret off disk. If a run fails with `Model provider is missing an API key: <provider>`, the provider block resolved but no key was found: set one of those variables and re-run. ## Autonomy — read this before dispatching ZCode's own term is **mode**. It has four values; only two are usable headlessly. | mode | Behaviour | | --- | --- | | `yolo` | **Writes.** ZCode's own default for `--prompt`, and this relay's write-capable default. | | `plan` | **Refuses edits.** What `--read-only` selects. | | `build` | **Rejected by this relay.** No permission client exists headlessly, so tools are blocked and the run exits 0 having done nothing. | | `edit` | Rejected for the same reason. | Two limits stated plainly, because ZCode cannot enforce them: - **`plan` mode refused edits in testing, but the relay does not treat that as a guarantee.** It takes a Git fingerprint before the run and reports a tri-state `readOnlyViolation` afterwards. Confirm `touchedFiles` came back empty rather than assuming no edits. - **ZCode has no `--allowed-tools`.** Only the `--disallowed-tools` denylist exists, and it *is* genuinely enforced. An explicit allowlisted tool surface is therefore impossible here — do not assume one. ## The loop Run these five steps per task. Steps 1, 4, and 5 are your judgment; 2 and 3 are mechanical. ### 1. Write the brief ZCode sees **only** what you send — no repo memory, no chat history. Everything the task needs goes in the brief: the goal, the current state, what to change, what to leave untouched, the project's **actual** gate commands (discover them from the repo's CLAUDE.md/AGENTS.md/Makefile — do not assume), and a report contract. Tell ZCode it will **not** commit. One task per brief. The relay delivers the brief as an attached file, so the command line no longer bounds its length — the model's context window still does. Full guidance and a template: [references/writing-the-brief.md](references/writing-the-brief.md). ### 2. Dispatch ```bash node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo # read-only (review/diagnosis, no edits): add --read-only # continue a specific session: add --session <sess_...> (from result.json; send only the delta brief) # continue the latest session for --cd: add --resume-last # withhold tools (denylist): add --disallowed-tools "Write,Edit,Bash" # point at the CLI explicitly: add --zcode-path /path/to/zcode.cjs # hard time limit (watchdog): add --timeout 2h (default: off) # see all options: node .../relay.mjs --help ``` (`<skill-dir>` is this skill's installed directory — the folder containing this `SKILL.md`.) The relay writes its artifacts to a temp dir, so the repo under review stays clean. It **never commits** — see step 5. Mechanics, flags, and the `result.json` shape: [references/dispatch-and-poll.md](references/dispatch-and-poll.md). ### 3. Wait for completion The relay blocks until ZCode finishes, so back it with whatever your orchestrator offers: - **Claude Code:** run the Bash call with `run_in_background: true`; you are notified on completion. - **Plain shell / other agents:** foreground for short tasks, or background it and poll the result file. The run is done when `result.json` exists with a `status`. A pre-run usage error exits 2 and writes **no** result file, so check the exit code too; a CLI that cannot be found exits 127 but *does* write a `result.json` with status `zcode_unavailable`. Do not trust progress trackers over reality: read the working tree, not a status line. ### 4. Review — do not trust the self-report - **Re-run the project's gates yourself.** Never take "gates passed" on faith. - **Read the diff** against the brief: did ZCode do what was asked, nothing more and nothing less? `touchedFiles` is your starting point. - **On a `--read-only` run, check `readOnlyViolation` and confirm `touchedFiles` is empty.** - Run the relevant guard skills on the diff if you have them installed. Full checklist: [references/review-and-land.md](references/review-and-land.md). ### 5. Land it **The orchestrator commits.** Only after the gates pass and the diff holds: - Commit the verified work yourself, with a clear message. - If it needs changes, send a delta brief with `--session <sessionId>` from the prior `result.json`, and review again. ## Read-only second opinions The relay doubles as a way to get an adversarial second opinion with no write risk: dispatch `--read-only` with a brief listing the agreed points, then each contested point with both positions, and ask ZCode to defend or concede each. Because plan mode's guarantee is measured rather than enforced here, verify `touchedFiles` came back empty instead of assuming no edits. ## Authorization model Delegation is something the human opts into. Once they have, committing verified, gate-passing work is the agreed contract. Two limits: **surface, don't absorb** (report ZCode's design decisions and defensible-but-unasked turns rather than silently keeping them) and **stop for scope changes** (if correct completion needs going beyond the brief, ask). The full treatment is in [references/review-and-land.md](references/review-and-land.md). ## References - [references/writing-the-brief.md](references/writing-the-brief.md) — how to write a brief ZCode can execute blind: structure, the report contract, embedding the real gate commands. - [references/dispatch-and-poll.md](references/dispatch-and-poll.md) — `relay.mjs` flags, the `result.json` contract, how the CLI is resolved, backgrounding, and recovery. - [references/review-and-land.md](references/review-and-land.md) — the review checklist, the commit boundary, and the exact-session rework cycle. - [references/multi-task-queues.md](references/multi-task-queues.md) — running a sequential queue: carrying constraints forward, progress tracking, and the end-of-run coherence check.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.