Skip to content
william0wangPublic

About

ACP adapter for ZCode — drive GLM-5.3 and GLM-5.3-Flash from IDEA, VS Code, Zed or any ACP client; pair with zcode-acp-remote for phone/web access

Topics

Resources

Contributing

Security policy

Stars

88 stars

Watchers

0 watching

Forks

Latest commit

 

History

512 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zcode-acp-server

CI License: Apache-2.0

English | 简体中文

A standalone Agent Client Protocol (ACP) server that bridges the headless ZCode app-server to ACP-compatible editors such as Zed and JetBrains IDEs.

The server launches the ZCode headless app-server (zcode app-server --stdio) as a subprocess, translates its internal event stream into ACP session/update notifications, and bridges ZCode's interaction channel to ACP — preferring elicitation/create when the client supports it, and falling back to session/request_permission otherwise — so an editor gets a first-class, native coding-agent experience.

Why zcode-acp

  • Native editor experience — streaming diffs, permission prompts and plan mode in Zed / JetBrains' own agent panel. No side-by-side terminal.
  • The official harness, not a reimplementation — drives the real zcode app-server: native tools, skills, MCP and slash commands, auto-compaction, session resume/fork.
  • Beyond the editor — an interactive terminal chat (zcode-acp, a Martty-powered TUI, works over SSH), phone/web access to the same sessions (zcode-acp-remote), opt-in writes-only sandbox. Credentials stay in ~/.zcode.

Because it drives the real ZCode client, your GLM Coding Plan comes along untouched — current perks (the 150% quota bonus, priority routing over raw API) and the plan's flat-rate economics apply exactly as in the official app. No API keys in editor settings.

Status

In active development. Core bridging, slash commands and ZCode extensions, auto-compaction, remote access for mobile/web clients, and the quota APIs are in place; see the project board for what's next.

Prompt attachments

ACP embedded resources preserve the supplied content: text is included in the prompt, and PDF/image bytes are forwarded as native attachments even when their URI is not a readable local file. Other binary resources are staged privately under $ZCODE_HOME/v2/acp-attachments (default ~/.zcode/v2/acp-attachments). Resource links remain references; the bridge does not download remote URIs.

Prompts accept at most 100 blocks and 50 MiB of decoded content, with a 10 MiB limit per image. Staged files use private permissions and persist for native tool reads and session resume; remove files there manually when those sessions no longer need them. Invalid conversions roll back files created by that request. Pause an active goal loop before sending binary attachments; its queued prompts support text only. Audio transcription is not supported.

Requirements

  • Node.js ≥ 22 (the bridge uses node:sqlite for tasks-index sync; the ZCode CLI runtime also requires Node ≥ 22)
  • The ZCode CLI: auto-discovered from the desktop app bundle, or on PATH, or pointed at via ZCODE_BIN (see below)
  • ZCode credentials at ~/.zcode/v2/config.json (created by the ZCode app)

Install

npm install -g zcode-acp-server

This installs both bins: zcode-acp-server (what your editor launches) and zcode-acp (the unified CLI). Configure your ACP client to launch it — see Configure Zed below or your editor's ACP docs.

Install from source instead
git clone https://github.com/william0wang/zcode-acp.git
cd zcode-acp-server
pnpm install
pnpm build

The compiled entry point is dist/index.js (also exposed as the zcode-acp-server bin).

Configure Zed

Add the server to Zed as a custom agent server. In ~/.config/zed/settings.json (%APPDATA%\Zed\settings.json on Windows):

{
  "agent_servers": {
    "ZCode": {
      "type": "custom",
      "command": "zcode-acp-server",
      "env": {
        // Only needed for custom installs — the CLI is auto-discovered from
        // the desktop app bundle or PATH (see the table below).
        "ZCODE_BIN": "/Applications/ZCode.app/Contents/Resources/glm/zcode.cjs",
      },
    },
  },
}

Running from source instead? Use "command": "node" with "args": ["/absolute/path/to/zcode-acp-server/dist/index.js"].

Restart Zed and pick ZCode from the agent dropdown.

Runtime: Bun (optional, lower memory)

The bridge and hub run on Node by default. If a Bun >= 1.4 install is found (~/.bun/bin/bun, Homebrew, or PATH), they automatically re-exec into bun --smol — idle RSS drops from ~81 MB to ~48 MB per process, which adds up when running many concurrent sessions. Nothing to configure; install Bun and restart the editor/CLI. Bun < 1.4 is ignored (no benefit over Node).

Force the old behavior (troubleshooting) with:

"env": { "ZCODE_ACP_RUNTIME": "node" } // in the editor config, or export it

Note: the zcode backend subprocess always needs real Node (it uses node:sea, which Bun does not implement) — installing Bun changes the runtime of the bridge/hub only, and Node >= 22 remains a requirement.

ZCODE_BIN per platform

The CLI is resolved in this order: ZCODE_BIN → a zcode found on PATH → the zcode.cjs bundled inside the ZCode desktop app (the app does not add it to PATH). The auto-discovery covers the standard install locations below, so most setups need no ZCODE_BIN at all — set it only for custom installs:

Platform bundled zcode.cjs path
macOS /Applications/ZCode.app/Contents/Resources/glm/zcode.cjs
Windows %LOCALAPPDATA%\Programs\ZCode\resources\glm\zcode.cjs
Linux Inside the extracted app directory: <install-dir>/resources/glm/zcode.cjs

If the path doesn't match your install, locate it with:

# macOS / Linux
find / -name zcode.cjs -path '*resources/glm*' 2>/dev/null
# Windows (PowerShell)
Get-ChildItem -Path $env:LOCALAPPDATA,$env:APPDATA,'C:\Program Files' -Recurse -Filter zcode.cjs -ErrorAction SilentlyContinue

User config file

All user preferences can be maintained in one place: ~/.config/zcode-acp/config.json (or $XDG_CONFIG_HOME/zcode-acp/config.json). Per-field precedence is config file > environment variable > built-in default — every env var keeps working as a fallback, but the file is the recommended surface (GUI-launched editors and the hub daemon don't inherit your shell's env). Reads are live: an edit takes effect on the next use, no restart needed. The one exception is interaction.timeoutMs, resolved once at bridge start just like its env var.

{
  "lang": "zh", // user-facing strings: "zh" | "en"
  "debug": false, // verbose diagnostics (ZCODE_ACP_DEBUG=1)
  "session": {
    "mode": "yolo", // initial mode: plan|build|edit|guarded|yolo|auto (guarded: 3.15.1+, falls back on older backends)
    "showCompletionStatus": true, // successful turn-end assistant status (default true)
  },
  "autoCompact": { "threshold": 240000 }, // compact once N tokens are used (unset = off)
  "goal": {
    "maxTurns": 100, // goal/auto loop round budget
    "mode": "backend", // "backend" restores the legacy /goal routing
  },
  "interaction": { "timeoutMs": 0 }, // permission wait cap in ms (0 = wait forever)
  "sandbox": { "enabled": false }, // global Seatbelt switch (per-project: sandbox.json)
  "remote": {/* see Remote Access */},
  "quota": {
    "autoResume": true, // wait out usage caps and continue (workflows + /auto)
    /* quota card credentials */
  },
}

Invalid values are warned about on stderr and dropped — the env fallback applies — and the file is never rewritten by the bridge.

For clients such as T3 Code that display the last assistant message as the final response, set session.showCompletionStatus to false (or ZCODE_ACP_SHOW_COMPLETION_STATUS=0). This omits the successful completion/cache status line so the answer stays visible. Error and cancellation warnings still appear; structured usage updates and prompt-response usage are unchanged.

Deliberately NOT file-configurable: per-process plumbing (ZCODE_ACP_RESUME_SESSION, ZCODE_ACP_REMOTE_ORIGIN, ZCODE_ACP_REMOTE_PIN_CWD, ZCODE_ACP_TUI_CLI_PID) and startup-time bootstrap variables (ZCODE_BIN, ZCODE_NODE, ZCODE_HOME, ZCODE_PROVIDER, ZCODE_MODEL, ZCODE_DISALLOWED_TOOLS) — those carry per-run state or are resolved once before any config would be readable.

Environment variables

Every ZCODE_ACP_* preference variable in this table has a config-file field (see User config file); the file value wins.

Variable Default Purpose
ZCODE_BIN (auto-discovered) Path to the ZCode CLI binary or its .cjs entry. Resolution order: this variable → zcode on PATH → the desktop-app bundle
ZCODE_NODE (discovered) Explicit Node binary to run ZCODE_BIN with (must support node:sqlite)
ZCODE_PROVIDER (first enabled) Pin the provider id from config.json (e.g. builtin:zai-coding-plan). Credentials are read from that provider only, and the model dropdown lists only its models. Unset keeps the default "first enabled provider wins". Set together with ZCODE_MODEL to pin the exact model: each new session is switched to ZCODE_PROVIDER/ZCODE_MODEL right after it is created, and session creation fails if the backend refuses that pair.
ZCODE_HOME ~/.zcode Directory that replaces ~/.zcode as the ZCode data root. Everything the bridge reads from there follows it: credentials/provider config (<dir>/v2/config.json), the lazy-session alias store (<dir>/v2/acp-lazy-sessions.json), the desktop app's settings and tasks index (<dir>/v2/setting.json, <dir>/v2/tasks-index.sqlite), user skills (<dir>/skills), and the CLI config with plugin/skill/MCP enablement (<dir>/cli/config.json + plugin cache). Set it before starting the bridge — the credentials and tasks-index paths are resolved once at startup.
ZCODE_MODEL (from config) Override the active model id
ZCODE_DISALLOWED_TOOLS (Cron tools) Space- or comma-separated tool names removed from every session the bridge creates or resumes (sent as the backend's per-session toolDenylist — a registry-level removal, so the tools are neither offered to the model nor executable), merged with the built-in default that disallows CronCreate CronList CronUpdate CronDelete (the bridge cannot serve the backend's automation/* client requests, so those tools are advertised-but-broken — see #192). Rule forms like Bash(git *) remove the whole tool. Matching is by exact tool name — no wildcards (mcp__* matches nothing); list MCP tools by their full mcp__<server>__<tool> name. A backend too old for toolDenylist gets one warning and runs without the policy.
ZCODE_ENABLE_AUTOMATION_TOOLS (unset) Set to 1 to stop disallowing the Cron* tools — only useful for a host that actually implements the backend's automation/* port.
ZCODE_ACP_AUTO_COMPACT_THRESHOLD (unset) Absolute token count that triggers automatic context compaction. After each successful turn (end_turn), if contextUsed >= threshold, the server invokes session/compact to free up context before the next prompt. Set to 0 or leave unset to disable (default). Example: 240000 triggers compaction at 240K tokens. The compaction target itself is decided by the ZCode backend.
ZCODE_ACP_QUOTA_AUTO_RESUME 1 Wait out GLM usage-cap exhaustion (business codes 1308 …) and continue automatically: a quota-stopped /auto goal loop re-enters its rounds after the window reset, and quota-stopped workflow runs are resumed from the journal once the quota card reports the reset. Set 0 to restore pause-for-a-human. The bridge performs the wait (timers + a periodic journal scan), so it works while the editor/app is asleep or detached.
ZCODE_ACP_MODE yolo Mode a newly created session starts in. Values are the backend's own modes — plan, build, edit, yolo, auto. Unset keeps yolo (unrestricted), the bridge's historical default. Only affects session creation; the mode dropdown still switches it per session.
ZCODE_ACP_DEBUG (unset) Set to 1 to enable verbose diagnostic logs (event flow, probe loops, status updates). Default is quiet — only warnings (backend pipe errors, command/permission failures, lock timeouts) are emitted. Enable this when diagnosing bridge issues; the logs appear in Zed.log prefixed with [zcode-acp].
ZCODE_ACP_REMOTE (unset) Set to 1 to enable remote access — serve the same sessions to additional ACP clients over WebSocket.
ZCODE_ACP_REMOTE_TOKEN (unset) Auth token for remote access. Mandatory when ZCODE_ACP_REMOTE=1; remote stays disabled without it.
ZCODE_ACP_HUB_PORT 8377 Port of the machine-level hub daemon. Map exactly this one port in your tunnel.
ZCODE_ACP_HUB_HOST 127.0.0.1 Hub bind address. 0.0.0.0 exposes a token-only, unencrypted surface — only for a containerized tunnel agent on a private interface (see Remote Access).
ZCODE_ACP_REMOTE_PORT 8378 First loopback port for the bridge's ACP endpoint. Each bridge (each editor window) auto-increments to the next free port.
ZCODE_ACP_SANDBOX (unset) Set to 1 to confine the agent's file writes with a macOS Seatbelt sandbox globally; per-project, set "enabled": true in <workspace>/.zcode/acp/sandbox.json instead (see Sandbox).
ZCODE_ACP_LANG (inherited) Language of the bridge's user-facing strings (popups, status/hint lines, command menu descriptions): zh or en. When unset, the bridge inherits the ZCode app's language (localePreference/locale in ~/.zcode/v2/setting.json), then falls back to the LC_ALL/LC_MESSAGES/LANG locale, defaulting to English.
ZCODE_ACP_SHOW_COMPLETION_STATUS 1 Emit successful turn-end status as assistant text. Set 0 or false to omit it; session.showCompletionStatus overrides the env. Error and cancellation warnings remain visible.

Sandbox

Optional macOS Seatbelt confinement for everything the agent writes: dual switch (ZCODE_ACP_SANDBOX=1 globally, or "enabled": true in <workspace>/.zcode/acp/sandbox.json per project — auto-created only while the sandbox's global switch is on; otherwise the bridge writes nothing into the workspace), allow/reject popups for out-of-whitelist writes persisted visibly in that config, and automatic backend restart + task continuation after an allow. Full manual: docs/SANDBOX.md.

Remote Access

With ZCODE_ACP_REMOTE=1 the bridge additionally serves the same sessions over WebSocket through a machine-level hub daemon — a phone or browser can watch, drive, and even create sessions in any known project while Zed stays the primary client. Discovery API, tunnels, auth, and semantics: docs/REMOTE.md; the client integration contract: docs/REMOTE-CLIENTS.md.

Unified CLI (zcode-acp)

One command for every surface: an interactive terminal chat TUI (zcode-acp, powered by Martty), plan quota cards (zcode-acp quota, GLM + Opencode Go + Ollama Cloud), the remote hub daemon (zcode-acp hub), and the stdio server editors invoke (zcode-acp server). TUI keys and quota setup: docs/CLI.md.

Manual Coding Plan account setup

With a supported ZCode CLI installed, run this command in your own terminal:

zcode-acp setup --provider zai       # or: bigmodel

Enter your individual Coding Plan API key at the hidden prompt. Do not put a key in command arguments or environment flags. Setup saves an owner-only ~/.zcode/v2/acp-accounts.json file (ZCODE_HOME relocates the .zcode root), using atomic replacement and an exclusive setup lock. It never modifies the Desktop's config.json, setting.json, or provider_config.json.

An explicitly configured bridge account overrides that family's Desktop key and enablement in memory. Other providers and their order are preserved; use ZCODE_PROVIDER=builtin:zai-coding-plan (or builtin:bigmodel-coding-plan) to select a specific account for model discovery and quota queries. The installed public catalog supplies the plan's models. Runtime account headers, model discovery, and quota use the same merged credential source. Saving does not verify plan membership or key validity; the first provider request does. Restart connected clients after setup. To return to Desktop-only credentials, remove the selected family entry from the private account file, preserving version 1 and the other account entries.

This is manual terminal setup, not an interactive ACP authentication method. T3 Code and other clients can continue using the agent-handled authentication already advertised by the bridge. No OAuth/captcha flow or alternative remote login mechanism is added.

If setup is killed while saving, it may leave an acp-accounts.json.lock directory. After confirming no setup process is running, remove that empty lock directory and retry. It may also leave an acp-accounts.json.<id>.tmp file. That file is owner-only but can hold the key, so delete it. Setup refuses a malformed, linked, or broadly readable account file and never overwrites it. The bridge ignores such a file with a warning and keeps using Desktop credentials. Fix or remove the file, then run setup again.

ACP Registry

This server is compatible with the ACP Registry. It advertises a single agent-type auth method at initialize time — credentials come from Desktop configuration or a private bridge account created by manual terminal setup, so no editor-side credentials are required.

The registry submission assets live under registry/zcode-acp/ (agent.json + icon.svg). Once the package is published to npm, copy that directory into a fork of agentclientprotocol/registry and open a PR — the CI validates the agent.json schema, icon, and that initialize returns a non-empty authMethods.

Develop

pnpm install
pnpm build       # tsc → dist/
pnpm typecheck   # tsc --noEmit
pnpm lint        # eslint (warnings advisory; errors fail CI)
pnpm test        # vitest
pnpm format      # prettier on src/

CI runs typecheck, lint, build, and test on every push and pull request — run them locally before pushing (see CONTRIBUTING.md).

Tip (Node version): this repo pins Node 22 via a root .node-version file. Pair it with fnm or nvm to auto-switch on cd. pnpm itself is managed by your local environment (corepack).

Architecture

The server is organised in layers that mirror the ACP protocol:

  • backend/ — ZCode subprocess client: spawn, reader-loop multiplexer, event-stream listener, sync request/response
  • translators/ — turn ZCode events into ACP session/update notifications (event streaming + snapshot diff)
  • interaction/ — bridge ZCode interaction/* server requests to ACP, preferring elicitation/create and falling back to session/request_permission (tool auth, ExitPlanMode, AskUserQuestion)
  • handlers/ — ACP method handlers (session/new, session/prompt, ...) and the turn engine
  • config/ — model / mode / thought-level configOptions and runtime model switching
  • remote/ — opt-in remote access: loopback ACP endpoint, multi-client broadcast, hub registration
  • quota/ — GLM Coding Plan / Opencode Go / Ollama Cloud usage API client (/quota command, zcode-acp quota subcommand)
  • server.ts — shared state and handler registration
  • index.ts — stdio wiring via the ACP SDK

See docs/ARCHITECTURE.md for the full architecture documentation.

Version Compatibility

ZCode CLI version Support Notes
>= 0.16.0 Full Steer/rewind removed upstream (moved to the v4 conversation API); bridge dropped the session/steer, session/rewind, session/rewindCascade extensions and the /steer, /rewind slash commands. Mid-turn steering is back via the cross-adapter _session/steering extension (v4/command sendText; see docs/PROTOCOL.md)
>= 0.15.0 Full All extension methods available
>= 0.14.8 Full Event-stream push, all extension methods
< 0.14.8 Incompatible Event-stream subscription unavailable

Documentation

  • Architecture — event stream, dual-path deduplication, module responsibilities
  • Protocol — ZCode JSON-RPC protocol details
  • Sandbox — full sandbox manual (switches, whitelist, popups, verification)
  • Remote Access — hub, discovery API, tunnels, remote session-create
  • Unified CLI — interactive TUI, quota cards, hub/server subcommands
  • Remote Clients — remote access integration contract (discovery, transport, recovery)
  • Replay Guide — building a client UI on tail replay
  • Development — local development, debugging, adding extension methods
  • Troubleshooting — common-issue troubleshooting

Contributing

Contributions are welcome! See CONTRIBUTING.md for setup, code style, commit conventions, and the PR checklist. Notable changes are recorded in CHANGELOG.md.

Thanks to everyone who has contributed (updated automatically from the contributors graph):

Contributors

Related Projects

  • glm-acp-agent — a self-contained ACP agent that calls the GLM API directly; zcode-acp instead bridges the real zcode app-server, inheriting its full official harness.
  • claude-agent-acp / codex-acp — official ACP adapters for the Claude and Codex CLIs; zcode-acp is the same idea for the ZCode CLI.
  • zcode-open-bridge — a community Python implementation that bridges ZCode to the MCP/ACP ecosystem. The design of this server references its bridge architecture and several handling strategies.

Acknowledgements

Privacy

No telemetry or tracking — the server reports nothing to anyone. The only runtime dependency beyond the ACP SDK is zod.

Your prompts, code, and file contents are relayed between the editor and the ZCode backend over local pipes; that data reaches the GLM cloud API only because the ZCode backend itself sends it there for inference — this server adds no extra destinations.

Concern What & why
Network Only one outbound request in the whole codebase: the quota GET (open.bigmodel.cn / api.z.ai), carrying just your API key — needed to fetch your usage numbers, sends no user content
Credentials Desktop credentials or owner-only ~/.zcode/v2/acp-accounts.json authenticate native requests and quota queries. Manual setup writes only the private bridge file; Desktop settings are preserved. Never logged. OAuth remains handled by ZCode
Disk No new files unless you run zcode-acp setup. Setup writes the owner-only (0600) ~/.zcode/v2/acp-accounts.json by atomic replacement, with a transient acp-accounts.json.lock directory and .tmp file while it saves. Otherwise writes only to the existing ~/.zcode/v2/tasks-index.sqlite — this syncs sessions to the ZCode app so they appear in its history list and full-text search (stores the session title and first prompt)
Logging Diagnostics to stderr for troubleshooting bridge issues. Even with ZCODE_ACP_DEBUG=1, no prompts/code/keys are ever logged

License

Apache-2.0. This project follows the same license as the upstream ACP specification.

Disclaimer

This is an independent community project and is not affiliated with, endorsed by, or sponsored by Zhipu Z.AI. ZCode is a product of Zhipu Z.AI.

About

ACP adapter for ZCode — drive GLM-5.3 and GLM-5.3-Flash from IDEA, VS Code, Zed or any ACP client; pair with zcode-acp-remote for phone/web access

Topics

Resources

Contributing

Security policy

Stars

88 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages