From 00fb28a4cf60a719363dce0de67fafc6301857ce Mon Sep 17 00:00:00 2001 From: Michael Sitarzewski Date: Sun, 12 Jul 2026 11:29:16 -0500 Subject: [PATCH] feat(tools): add ZCode (Z.ai GLM agent harness) (#700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(tools): add ZCode (Z.ai GLM agent harness) ZCode reads per-agent markdown from `.zcode/agents/{slug}.md` (project) and `~/.config/zcode/agents/{slug}.md` (global), with `name` + `description` YAML frontmatter and an optional `tools` list — the same plain-agent-markdown shape as Qwen. - tools.json: add the `zcode` entry (dual-scope, per-agent, format `zcode-md`). - convert.sh: add `convert_zcode` (byte-identical to the qwen converter, output to integrations/zcode/agents/) + register in the dispatch, valid_tools, tools_to_run, and parallel_tools. - install.sh: add `zcode` to ALL_TOOLS, `install_zcode`, `detect_zcode`, and the resolve_dest / bin / is_detected / display / label dispatches. Directories + file format verified against ZCode's published docs. Renderer contract: `zcode-md` output is byte-identical to `qwen-md`, verified by diffing `convert.sh --tool zcode` against `--tool qwen` (243/243 files match). check-tools.sh passes (16 tools consistent across tools.json, install.sh, and convert.sh); bash -n clean on both scripts. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WdX6PvnCfRgYD11yVpXVor * zcode: gitignore generated output + add integration README Bring the ZCode integration in line with the other tools: the 243 generated agent files (integrations/zcode/agents/*.md) are output of `convert.sh`, not source — add a .gitignore rule so they can't be committed, and add integrations/zcode/README.md documenting generate/install (matching the vibe and qwen integration READMEs). Verified: generated agents are now git-ignored, the README is tracked, and check-tools.sh still passes at 16 tools. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WKnDRWM4izsB8WAXKszhsq * zcode: fix user-scope install path to ~/.zcode/agents (per ZCode docs) The user-scope dest was ~/.config/zcode/agents/, but the official ZCode docs state subagents are read from ~/.zcode/agents/.md — so user-scope installs landed where ZCode never looks. (detect.agentsDir and project scope were already correct at .zcode/agents, so this was an internal inconsistency.) Point tools.json dest.user, install_zcode's default, the header comment, and the list display at ~/.zcode/agents; drop the stale ~/.config/zcode detection clause; update the integration README. Keep format `zcode-md` distinct — ZCode's native format supports color/model/permissions, so it will diverge from gemini-md as the converter matures rather than being a permanent alias. Verified: a default user-scope install now writes to ~/.zcode/agents/.md (not ~/.config/zcode); check-tools.sh passes at 16 tools; install.sh syntax and tools.json JSON both valid. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WKnDRWM4izsB8WAXKszhsq --------- Co-authored-by: Claude Opus 4.8 --- .gitignore | 1 + integrations/zcode/README.md | 29 +++++++++++++++++++++++ scripts/convert.sh | 45 +++++++++++++++++++++++++++++++++--- scripts/install.sh | 31 +++++++++++++++++++++++-- tools.json | 3 ++- 5 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 integrations/zcode/README.md diff --git a/.gitignore b/.gitignore index 602fb349..6c27b742 100644 --- a/.gitignore +++ b/.gitignore @@ -84,4 +84,5 @@ integrations/osaurus/agency-*/ integrations/hermes/agency-agents-router/ integrations/vibe/agents/ integrations/vibe/prompts/ +integrations/zcode/agents/ graphify-out/ diff --git a/integrations/zcode/README.md b/integrations/zcode/README.md new file mode 100644 index 00000000..a12071b4 --- /dev/null +++ b/integrations/zcode/README.md @@ -0,0 +1,29 @@ +# ZCode Integration + +[ZCode](https://z.ai) is Z.ai's GLM-based coding agent harness. Each agency +agent is rendered as a standalone Markdown agent file with `name` and +`description` frontmatter, which ZCode discovers from its agents directory. + +The generated files come from `scripts/convert.sh --tool zcode`, which writes +one Markdown file per agency agent into `integrations/zcode/agents/`. Those +generated files are not committed (see `.gitignore`); regenerate them locally. + +## Generate + +From the repository root: + +```bash +./scripts/convert.sh --tool zcode +``` + +## Install + +Run the installer from your target directory: + +```bash +cd /your/project && /path/to/agency-agents/scripts/install.sh --tool zcode +``` + +Agents install to `~/.zcode/agents/.md` (user scope) — the directory +ZCode reads subagents from. Use `--division` / `--agent` to install a subset, +or set `ZCODE_AGENTS_DIR` to override the destination. diff --git a/scripts/convert.sh b/scripts/convert.sh index 719e75a2..af005ff9 100755 --- a/scripts/convert.sh +++ b/scripts/convert.sh @@ -18,6 +18,7 @@ # windsurf — Single .windsurfrules for Windsurf # openclaw — OpenClaw workspaces (integrations/openclaw//SOUL.md) # qwen — Qwen Code SubAgent files (~/.qwen/agents/*.md) +# zcode — ZCode agent files (.zcode/agents/*.md · ~/.config/zcode/agents/*.md) # kimi — Kimi Code CLI agent files (~/.config/kimi/agents/) # codex — Codex custom agent TOML files (~/.codex/agents/*.toml) # osaurus — Osaurus skill files (~/.osaurus/skills//SKILL.md) @@ -425,6 +426,43 @@ HEREDOC fi } +convert_zcode() { + local file="$1" + local name description tools slug outfile body + + name="$(get_field "name" "$file")" + description="$(get_field "description" "$file")" + tools="$(get_field "tools" "$file")" + slug="$(slugify "$name")" + body="$(get_body "$file")" + + outfile="$OUT_DIR/zcode/agents/${slug}.md" + mkdir -p "$(dirname "$outfile")" + + # ZCode agent format (Z.ai GLM harness): .md with YAML frontmatter in + # .zcode/agents/ (project) or ~/.config/zcode/agents/ (global). name and + # description required; tools optional (only if present in source). Byte- + # identical to the qwen-md shape, which the Agency Agents app renders natively. + if [[ -n "$tools" ]]; then + cat > "$outfile" < "$outfile" </dev/null 2>&1; } detect_openclaw() { command -v openclaw >/dev/null 2>&1 || [[ -d "${HOME}/.openclaw" ]]; } detect_windsurf() { command -v windsurf >/dev/null 2>&1 || [[ -d "${HOME}/.codeium" ]]; } detect_qwen() { command -v qwen >/dev/null 2>&1 || [[ -d "${HOME}/.qwen" ]]; } +detect_zcode() { command -v zcode >/dev/null 2>&1 || [[ -d "${HOME}/.zcode" ]]; } detect_kimi() { command -v kimi >/dev/null 2>&1; } detect_codex() { command -v codex >/dev/null 2>&1 || [[ -d "${HOME}/.codex" ]]; } detect_osaurus() { command -v osaurus >/dev/null 2>&1 || [[ -d "${HOME}/.osaurus" ]]; } @@ -397,6 +401,7 @@ is_detected() { aider) detect_aider ;; windsurf) detect_windsurf ;; qwen) detect_qwen ;; + zcode) detect_zcode ;; kimi) detect_kimi ;; codex) detect_codex ;; osaurus) detect_osaurus ;; @@ -419,6 +424,7 @@ tool_label() { aider) printf "%-14s %s" "Aider" "(CONVENTIONS.md)" ;; windsurf) printf "%-14s %s" "Windsurf" "(.windsurfrules)" ;; qwen) printf "%-14s %s" "Qwen Code" "(~/.qwen/agents)" ;; + zcode) printf "%-14s %s" "ZCode" "(~/.zcode/agents)" ;; kimi) printf "%-14s %s" "Kimi Code" "(~/.config/kimi/agents)" ;; codex) printf "%-14s %s" "Codex" "(~/.codex/agents)" ;; osaurus) printf "%-14s %s" "Osaurus" "(~/.osaurus/skills)" ;; @@ -547,7 +553,7 @@ tool_simple_name() { claude-code) echo "Claude Code";; copilot) echo "Copilot";; antigravity) echo "Antigravity";; gemini-cli) echo "Gemini CLI";; opencode) echo "OpenCode";; openclaw) echo "OpenClaw";; cursor) echo "Cursor";; aider) echo "Aider";; windsurf) echo "Windsurf";; - qwen) echo "Qwen Code";; kimi) echo "Kimi Code";; codex) echo "Codex";; osaurus) echo "Osaurus";; *) echo "$1";; + qwen) echo "Qwen Code";; zcode) echo "ZCode";; kimi) echo "Kimi Code";; codex) echo "Codex";; osaurus) echo "Osaurus";; *) echo "$1";; esac } @@ -903,6 +909,26 @@ install_qwen() { warn "Tip: Run '/agents manage' in Qwen Code to refresh, or restart session" } +install_zcode() { + local src="$INTEGRATIONS/zcode/agents" + local dest; dest="$(resolve_dest zcode "${HOME}/.zcode/agents")" + local count=0 + + [[ -d "$src" ]] || { err "integrations/zcode missing. Run convert.sh first."; return 1; } + + mkdir -p "$dest" + + local f + while IFS= read -r -d '' f; do + slug_allowed "$(basename "$f" .md)" || continue + install_file "$f" "$dest/" + incr count + done < <(find "$src" -maxdepth 1 -name "*.md" -print0) + + ok "ZCode: installed $count agents to $dest" + warn "ZCode: set ZCODE_AGENTS_DIR=.zcode/agents (in a project) to install there instead." +} + install_kimi() { local src="$INTEGRATIONS/kimi" local dest; dest="$(resolve_dest kimi "${HOME}/.config/kimi/agents")" @@ -1126,6 +1152,7 @@ install_tool() { aider) install_aider ;; windsurf) install_windsurf ;; qwen) install_qwen ;; + zcode) install_zcode ;; kimi) install_kimi ;; codex) install_codex ;; osaurus) install_osaurus ;; diff --git a/tools.json b/tools.json index 998919f8..cd4ea042 100644 --- a/tools.json +++ b/tools.json @@ -15,6 +15,7 @@ "openclaw": {"id":"openclaw","label":"OpenClaw","short":"openclaw","kebab":"openclaw","accent":"#E11D48","icon":null,"order":12,"scope":{"user":true,"project":false},"detect":{"dirs":[".openclaw"],"agentsDir":".openclaw/agency-agents"},"version":{"bin":"openclaw","args":["--version"]},"format":"openclaw-workspace","installKind":"per-agent","slugFrom":"name","dest":{"user":[".openclaw/agency-agents/{slug}/SOUL.md",".openclaw/agency-agents/{slug}/AGENTS.md",".openclaw/agency-agents/{slug}/IDENTITY.md"],"project":[]}}, "windsurf": {"id":"windsurf","label":"Windsurf","short":"Windsurf","kebab":"windsurf","accent":"#09B6A2","icon":"windsurf","order":13,"scope":{"user":false,"project":true},"detect":{"dirs":[".codeium"],"agentsDir":null},"version":{"bin":"windsurf","args":["--version"]},"format":"windsurf-rules","installKind":"roster","slugFrom":null,"dest":{"user":[],"project":[".windsurfrules"]}}, "hermes": {"id":"hermes","label":"Hermes","short":"Hermes","kebab":"hermes","accent":"#7C3AED","icon":null,"order":14,"scope":{"user":true,"project":false},"detect":{"dirs":[".hermes"],"agentsDir":".hermes/plugins"},"version":{"bin":"hermes","args":["--version"]},"format":"hermes-router-plugin","installKind":"plugin","slugFrom":null,"dest":{"user":[".hermes/plugins/agency-agents-router"],"project":[]}}, - "vibe": {"id":"vibe","label":"Mistral Vibe","short":"Vibe","kebab":"vibe","accent":"#FA520F","icon":null,"order":15,"scope":{"user":true,"project":true},"detect":{"dirs":[".vibe"],"agentsDir":".vibe/agents"},"version":{"bin":"vibe","args":["--version"]},"format":"vibe-toml","installKind":"per-agent","slugFrom":"name","dest":{"user":[".vibe/agents/{slug}.toml",".vibe/prompts/{slug}.md"],"project":[".vibe/agents/{slug}.toml",".vibe/prompts/{slug}.md"]}} + "vibe": {"id":"vibe","label":"Mistral Vibe","short":"Vibe","kebab":"vibe","accent":"#FA520F","icon":null,"order":15,"scope":{"user":true,"project":true},"detect":{"dirs":[".vibe"],"agentsDir":".vibe/agents"},"version":{"bin":"vibe","args":["--version"]},"format":"vibe-toml","installKind":"per-agent","slugFrom":"name","dest":{"user":[".vibe/agents/{slug}.toml",".vibe/prompts/{slug}.md"],"project":[".vibe/agents/{slug}.toml",".vibe/prompts/{slug}.md"]}}, + "zcode": {"id":"zcode","label":"ZCode","short":"ZCode","kebab":"zcode","accent":"#4263EB","icon":"zcode","order":16,"scope":{"user":true,"project":true},"detect":{"dirs":[".zcode"],"agentsDir":".zcode/agents"},"version":{"bin":"zcode","args":["--version"]},"format":"zcode-md","installKind":"per-agent","slugFrom":"name","dest":{"user":[".zcode/agents/{slug}.md"],"project":[".zcode/agents/{slug}.md"]}} } }