Dispatch and steer ZCode sessions (GLM models) from any external agent — Claude Code, Codex, custom orchestrators — using the official zcode-cli app-server protocol. No GUI interaction, no headless-mode model limits, no hacks.
flowchart TB
AG["🧠 external agent<br/>Claude Code · Codex · any orchestrator"]
subgraph PRE["⚙ preflight — one driver per cwd"]
direction LR
LOCK["cwd lock · PID-checked<br/>collision → exit 3"]
CFG["config · pinned model + reasoning<br/>plan key decrypted in-process (AES-GCM)"]
GATE{"new or<br/>steer?"}
LOCK --> CFG --> GATE
end
subgraph BRIDGE["🔌 app-server bridge — stdio · NDJSON"]
direction LR
MIRROR["provider/updateAccountConfig<br/>entitlement mirror"]
CREATE["session/create<br/>static title pinned"]
RESUME["session/resume<br/>cwd · model · reasoning verified"]
SEND["session/send {content}"]
IACT["runtime prefs + provider headers<br/>answered for own provider/model only"]
POLL["session/usage + turn_usage<br/>polled until terminal"]
MIRROR --> CREATE --> SEND
RESUME --> SEND
SEND --> IACT --> POLL
end
DONE{"turn<br/>outcome"}
JSON["📤 sanitized JSON → --out · incremental<br/>actual model + reasoning verified from the store"]
subgraph DESK["🖥 desktop — persistent · click-through"]
direction LR
NSTART["🚀 STARTED notify<br/>New · Steer"]
NEND["✅ COMPLETED · ❌ FAILED · 🟡 TIMEOUT<br/>click → zcode:// workspace deep link"]
VIS["task-index seeding — show_sessions.py<br/>sidebar 'By project' visibility"]
end
AG -- "prompt file" --> LOCK
GATE -- "new" --> MIRROR
GATE -- "steer · --resume" --> RESUME
SEND -. "turn starts" .-> NSTART
CREATE -. "title = sidebar = notify" .-> VIS
POLL --> DONE
DONE -- "exit 0" --> JSON
DONE -- "exit 4" --> JSON
DONE -- "exit 5 · resumable" --> JSON
DONE --> NEND
JSON -. "polled read-only" .-> AG
classDef neutral fill:#10141c,stroke:#8a97a4,stroke-width:1.5px,color:#e8f0f6
classDef server fill:#10141c,stroke:#4f9cf5,stroke-width:1.5px,color:#e8f0f6
classDef session fill:#0e2a2f,stroke:#4fe3c1,stroke-width:1.5px,color:#e8f0f6
classDef desk fill:#191326,stroke:#f0b95a,stroke-width:1.5px,color:#f4e3c2
classDef result fill:#123a52,stroke:#62c7f5,stroke-width:2px,color:#ffffff
class AG,LOCK,CFG neutral
class MIRROR,IACT,POLL server
class CREATE,RESUME,SEND session
class NSTART,NEND,VIS desk
class JSON result
style PRE fill:#0b0e14,stroke:#22303e,color:#c3cdd6
style BRIDGE fill:#0d2836,stroke:#4fe3c1,stroke-width:2px,color:#eafff8
style DESK fill:#120f1a,stroke:#f0b95a,color:#f4e3c2
zcode-cli -p (headless) cannot select a model on current ZCode releases (no --model flag), and sessions created through the app-server protocol are invisible in the desktop app until extra steps are taken. This dispatcher solves both, documented in docs/PROTOCOL.md:
- explicit model + reasoning selection (
session/create) - account-state mirroring (
provider/updateAccountConfig) so the plan providers materialize - runtime-auth interaction handling (
interaction/requestProviderRuntimeHeaders) with the plan credential decrypted in-process only - visible sessions: task-index seeding + static pinned session titles
- sanitized JSON results with verified (not echoed) model/reasoning/usage
From a release tarball (the exact released file set):
curl -L -o zcode-dispatch.tar.gz \
https://github.com/oss-singularity/zcode-dispatch/releases/latest/download/zcode-dispatch.tar.gz
tar xzf zcode-dispatch.tar.gz
cd zcode-dispatch
./install.sh --target ~/tools/zcode-dispatchinstall.sh copies the scripts and docs, preserves an existing config.json (so re-running it after a release is an update-in-place), and symlinks the commands into ~/.local/bin (--target, --bin, --no-bin to customize). From a git clone you can also run the scripts in place — nothing else is required beyond Python 3.10+ and pip install cryptography.
pip install cryptography # AES-GCM for the credential store
./dispatch.py --setup # auto-detect provider/models/credentials → config.json
./dispatch.py \
--cwd /path/to/exclusive/worktree \
--model GLM-5.3 \
--prompt-file task.md \
--out result.json --timeout 7200(--setup is optional — copying config.example.json to config.json and editing it works just as well.)
Prerequisite: zcode-cli login (Z.AI OAuth) done once — the plan credential is read from the shared ZCode credential store and stays in dispatcher memory only. Full reference (flags, exit codes, result schema, protocol internals, detached launches, recovery): docs/USAGE.md.
| Flag | Meaning |
|---|---|
--cwd |
exclusive working directory (worktree recommended) |
--model |
one of the configured models (default: GLM-5.3, GLM-5.3-Flash) |
--prompt-file |
UTF-8 prompt; sent as one turn (content field) |
--out |
result JSON path (written incrementally — poll for read-only monitoring) |
--resume sess_… |
continue an existing session (cwd/model/reasoning verified against the store) |
--timeout |
seconds (default 300; use 7200 for long runs) |
--mode |
yolo (default) / build / edit / plan |
--reasoning |
low / high / max (default from config, usually max) |
--setup |
detect provider/models/credentials from the installed ZCode runtime, write the config, exit |
Exit codes: 0 completed · 2 arguments · 3 concurrency/resume mismatch · 4 turn failed · 5 timeout (session intact, resumable) · 6 bridge/config error.
| Tool | Purpose |
|---|---|
open_session.sh <sessionId> |
Deep-link a session's workspace into the ZCode desktop app |
show_sessions.py |
Insert unindexed sessions into the desktop app's task index (visibility without deep links) |
notify_click.sh |
Persistent clickable desktop notification (used by the dispatcher) |
fake_app_server.py |
Protocol fake for offline tests of error/timeout paths |
docs/USAGE.md— dispatcher guide: flags, exit codes, result schema, detached launches, failure recoverydocs/PROTOCOL.md— app-server protocol findings (entitlement mirroring, runtime headers, visibility)docs/CLI-REFERENCE.md—zcode-cliterminal reference: headless mode, session store, skills/plugins/MCP configuration
The plan API key is decrypted in dispatcher memory (AES-256-GCM, ZCode's own credential-store scheme) and passed exclusively over the local stdio pipe to the official zcode-cli binary. Keys never appear in argv, logs, results, or evidence files. Header requests for foreign provider/model contexts are declined. No global ZCode settings are modified.
Battle-tested on ZCode Desktop 3.14.0 / CLI 0.16.9 (Linux x64). See docs/PROTOCOL.md for the protocol findings and known upstream limitations.
MIT licensed. Built in the OSS Singularity org.
- Static pinned session titles (start notify = sidebar = completion notify)
- Click-through desktop notifications (STARTED / COMPLETED / FAILED / TIMEOUT)
- Task-index seeding for desktop visibility (By project)
- Social preview typography (overlay rendered from
social-preview-src/) - Lint-clean main (Super-Linter: pylint/ruff/markdown)
- Per-repo
--setupwizard (auto-detect provider, models, credentials) - Release install flow (
install.sh+ release tarball, update-in-place) - Timeline sidebar visibility (blocked upstream: session-registry filter — tracked in ZCT-21013117278467761684)
- Social preview final polish (six-band card, repo footer, 1 MiB-optimized render)
- Social preview artwork by Luna ✨ — the moment in between: a thought is sent out, flows across the bridge as work, and returns as a finished result.
- Protocol findings documented from ZCode Desktop 3.14.0 / CLI 0.16.9 — upstream ticket ZCT-21013117278467761684.
