Skip to content

feat(crush): add ZERO-294 Crush adapter#56

Closed
spencercharest wants to merge 1 commit into
mainfrom
spencer/zero-314-crush-charm-adapter-skills-mcp-pretooluse-only-hook
Closed

feat(crush): add ZERO-294 Crush adapter#56
spencercharest wants to merge 1 commit into
mainfrom
spencer/zero-314-crush-charm-adapter-skills-mcp-pretooluse-only-hook

Conversation

@spencercharest

@spencercharest spencercharest commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Subtask: ZERO-314 under ZERO-294.

Adds a Crush adapter for Zero without modifying guides/agent-install.md:

  • adds plugins/zero-crush/ overlay with mergeable crush.json fragment, PreToolUse hook, and manifest
  • builds Crush-specific SKILL.md frontmatter with user-invocable: true while preserving the shared Zero skill body
  • adds scripts/build-crush.sh
  • adds standalone consumer guide guides/crush.md and links it from README
  • adds plugins/zero-crush/manifest.json to MANIFESTS and bumps versioned manifests to 1.4.0 with make minor

Official sources used

Install and update flow

Human in-harness flow:

  1. Run curl -fsSL https://zero.xyz/install.sh | bash once for the shared Zero runner/runtime.
  2. Run scripts/build-crush.sh in this repo.
  3. Copy dist/zero-crush/. into the target project.
  4. Merge dist/zero-crush/crush/crush.zero.json into project crush.json, .crush.json, or global ~/.config/crush/crush.json.
  5. Restart Crush.
  6. Use the command palette (Ctrl+P) and choose project:zero or user:zero, or ask Crush to help set up and test Zero.

Terminal flow:

curl -fsSL https://zero.xyz/install.sh | bash
scripts/build-crush.sh
cp -R dist/zero-crush/. /path/to/your/project/

Update flow:

curl -fsSL https://zero.xyz/install.sh | bash
scripts/build-crush.sh
cp -R dist/zero-crush/. /path/to/your/project/

Crush does not currently have SessionStart/UserPromptSubmit hooks, so runner install/update remains manual through the standalone installer. The PreToolUse hook only handles Zero command gating and context injection on bash tool calls.

Proposed guides/agent-install.md notes

Do not merge these into guides/agent-install.md in this PR. Collect them later during the runbook rewrite.

  • Crush reads project skills from .crush/skills/, .agents/skills/, .claude/skills/, and .cursor/skills/, plus configured options.skills_paths.
  • Mark Zero with user-invocable: true so it appears in the Ctrl+P command palette as project:zero or user:zero.
  • Crush has only PreToolUse hooks today. Configure a crush.json hook with matcher: "^bash$" and command: "./.crush/hooks/zero-pre-tool-use.sh".
  • The hook can return decision: "allow" for read-only Zero runner commands, decision: "deny" for zero fetch without --max-pay, and context as a partial substitute for missing UserPromptSubmit hooks.
  • Remote Zero MCP belongs under mcp.zero with type: "http" and url: "https://mcp.zero.xyz". OAuth can be left to server discovery unless Crush requires explicit OAuth config in a future release.
  • Crush has no SessionStart hook, so runner install/update remains curl -fsSL https://zero.xyz/install.sh | bash; project template updates are manual via scripts/build-crush.sh and copying dist/zero-crush/.

Verification

Local checks:

scripts/build-crush.sh --tar dist/zero-crush.tgz
jq . plugins/zero-crush/manifest.json \
  plugins/zero-crush/crush/crush.zero.json \
  dist/zero-crush/manifest.json \
  dist/zero-crush/crush/crush.zero.json
make version
# generated Crush skill body matches shared Zero skill body after frontmatter stripping
# .crush and .agents generated skill files match
CRUSH_TOOL_INPUT_COMMAND='zero search cdn upload' dist/zero-crush/.crush/hooks/zero-pre-tool-use.sh
CRUSH_TOOL_INPUT_COMMAND='zero auth whoami --json' dist/zero-crush/.crush/hooks/zero-pre-tool-use.sh
CRUSH_TOOL_INPUT_COMMAND='zero fetch https://example.com' dist/zero-crush/.crush/hooks/zero-pre-tool-use.sh
CRUSH_TOOL_INPUT_COMMAND='zero fetch https://example.com --max-pay 0.001' dist/zero-crush/.crush/hooks/zero-pre-tool-use.sh
tar -tzf dist/zero-crush.tgz | sort
git diff --check
git diff -- guides/agent-install.md

Docker copied-auth Crush + Zero smoke test:

ts="$(date -u +%Y%m%dT%H%M%SZ)"
docker run --rm --name zero-314-crush-e2e \
  -v "$PWD":/repo \
  -v "$HOME/.zero":/host-zero:ro \
  --env-file /Users/spencercharest/zeroclick/env \
  -e TEST_TS="$ts" \
  node:22-bookworm-slim bash -lc '
set -euo pipefail
apt-get update >/tmp/apt-update.log 2>&1
apt-get install -y curl jq >/tmp/apt-install.log 2>&1
cd /repo
cp -R /host-zero "$HOME/.zero"
chmod -R go-rwx "$HOME/.zero" || true
npm install -g @zeroxyz/cli@latest @charmland/crush@latest >/tmp/npm-install.log 2>&1
zero --help >/tmp/zero-help.txt
zero auth whoami --json >/tmp/zero-whoami.json
crush --version >/tmp/crush-version.txt
scripts/build-crush.sh --tar dist/zero-crush-docker.tgz >/tmp/build-crush.log
jq . plugins/zero-crush/manifest.json plugins/zero-crush/crush/crush.zero.json dist/zero-crush/manifest.json dist/zero-crush/crush/crush.zero.json >/tmp/jq.log
mkdir -p /tmp/crush-project
cp -R dist/zero-crush/. /tmp/crush-project/
cd /tmp/crush-project
CRUSH_TOOL_INPUT_COMMAND="zero search cdn upload" .crush/hooks/zero-pre-tool-use.sh | jq -e ".decision == \"allow\"" >/tmp/hook-search.log
CRUSH_TOOL_INPUT_COMMAND="zero fetch https://example.com" .crush/hooks/zero-pre-tool-use.sh | jq -e ".decision == \"deny\"" >/tmp/hook-fetch-deny.log
CRUSH_TOOL_INPUT_COMMAND="zero fetch https://example.com --max-pay 0.001" .crush/hooks/zero-pre-tool-use.sh | jq -e "has(\"decision\") | not" >/tmp/hook-fetch-cap.log
cd /repo
zero search "static file CDN upload" >/tmp/zero-search.txt
zero get 1 --formatted >/tmp/zero-get.txt
body="ZERO-314 Crush Docker copied-auth CDN upload check ${TEST_TS}"
data=$(printf "%s" "$body" | base64 | tr -d "\n")
DATA="$data" node -e "const fs=require(\"fs\"); const data=process.env.DATA; const ts=process.env.TEST_TS; fs.writeFileSync(\"/tmp/zero-cdn-body.json\", JSON.stringify({kind:\"file\", slug:\"agent-harness-e2e-crush-docker-\"+ts+\".txt\", data, cacheTtlSeconds:3600}));"
zero fetch --json --capability cdn-withzero-xyz-static-site-file-cdn-upload-a0d9f22f https://cdn.withzero.xyz/api/v1/uploads -d @/tmp/zero-cdn-body.json --max-pay 0.001 >/tmp/zero-fetch.json
node -e "const fs=require(\"fs\"); const r=JSON.parse(fs.readFileSync(\"/tmp/zero-fetch.json\",\"utf8\")); if(!r.ok) throw new Error(JSON.stringify(r)); console.log(JSON.stringify({runId:r.runId,payment:r.payment,body:r.body,crushVersion:fs.readFileSync(\"/tmp/crush-version.txt\",\"utf8\").trim()}, null, 2));"
'

Copied ~/.zero: yes.

Zero result:

No zero review was run.

Claude-style plugin compatibility and simpler install option

Full Claude Code plugin package support: No. Crush reads Agent Skills and can reuse the Zero skill body, but it does not install Claude Code .claude-plugin packages as a full plugin artifact.

What this means for users:

  • The current build/copy flow should be treated as maintainer packaging. Consumers should get a prebuilt zero-crush artifact or use native Crush skill/MCP configuration.

  • Simplest native Crush flow:

    curl -fsSL https://zero.xyz/install.sh | bash
    # add/copy the Zero skill into .crush/skills/zero or .agents/skills/zero
    # add https://mcp.zero.xyz under mcp.zero in crush.json
  • If the custom PreToolUse hook is not worth the support burden, ship only skill + MCP. That is not Claude-style plugin support, but it is likely the lowest-maintenance Crush path.

GitHub Releases / no-build install check

Result: No native Gemini-style GitHub Release install path. Crush supports skills, hooks, and MCP configuration, but I did not find a Crush plugin/package installer that resolves GitHub Release assets for an adapter bundle.

Best no-build consumer path:

curl -fsSL https://zero.xyz/install.sh | bash
# add/copy the Zero skill into .crush/skills/zero or .agents/skills/zero
# add https://mcp.zero.xyz under mcp.zero in crush.json

A GitHub Release tarball can publish ready-to-copy .crush files and crush.zero.json, avoiding scripts/build-crush.sh for users. It should be documented as manual download/extract. If the PreToolUse hook is not worth supporting, skill + MCP is the simpler path.

PR status

Draft. Docker verified Crush installation, adapter copy into a project, hook behavior, copied-auth Zero runner auth/search/get/fetch, and returned CDN file. I did not run a real interactive Crush TUI/model-backed session to verify skill palette loading and MCP discovery inside the product UI.

@spencercharest

Copy link
Copy Markdown
Collaborator Author

Folded into #63 as a matrix entry (crush in plugins/zero/agents.json) — standalone skills (~/.config/crush/skills + ~/.agents/skills) + MCP data for ~/.config/crush/crush.json. No hooks fragment: Crush's only event is still PreToolUse and its dialect (lowercase bash tool name, top-level decision/context envelope) is incompatible with the shared scripts — this branch's zero-pre-tool-use.sh prototype is noted in #63 as the future path if PreToolUse gating is wanted. The adapter-template work here stays available on this branch if we later ship per-host templates.

spencercharest added a commit that referenced this pull request Jul 2, 2026
* feat(zero): add 15 agents/harnesses to the install matrix

Folds the ZERO-294 adapter PRs (#37-#56, excl. #48/#58) into
plugins/zero/agents.json: amp, antigravity, cline, continue-cli, copilot,
crush, cursor, devin, goose, hermes, kilo-code, opencode, qwen-code, trae,
zed. Roo Code (#53) and Replit Agent (#50) are not addable (product shut
down / no local footprint). Existing kiro (#42) and warp (#46) entries were
re-verified and stand as-is.

qwen-code is plugin-installable (verified live: non-interactive marketplace
install with --consent, native --auto-update); everything else is
standalone-only. Hook fragments added where the host has a JSON hook config
whose semantics tolerate our scripts: continue-cli (full Claude-compatible),
devin (SessionStart+UserPromptSubmit), qwen-code (full, ms timeouts),
copilot/cursor/goose (SessionStart only, host dialects).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(version-check): detect manifests by top-level version key, not grep

agents.json now carries host hook-dialect fragments that legitimately
contain a nested "version" field (Copilot/Cursor hooks files); the grep
matched it and lockstep failed on a non-manifest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(zero): drop standalone.mcp from new matrix entries

MCP config targets are only needed for ephemeral environments where auth
session data cannot be written to disk; the new entries are all persistent
hosts. kiro/warp keep their pre-existing blocks. The researched per-host
MCP surfaces remain documented in the closed adapter PRs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(zero): drop standalone.mcp from kiro and warp too

MCP config targets are only for ephemeral environments where auth session
data cannot be written to disk; no matrix entry needs one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant