From c7bb486b2485b89c561beb478de6d501efbcfd3e Mon Sep 17 00:00:00 2001 From: Spencer Charest Date: Sun, 14 Jun 2026 16:38:26 -0700 Subject: [PATCH] feat(amp): add ZERO-294 Amp adapter --- Makefile | 3 +- README.md | 7 +- guides/amp.md | 61 +++++++++++++++ plugins/zero-amp/README.md | 35 +++++++++ plugins/zero-amp/hooks/zero-context.sh | 6 ++ plugins/zero-amp/manifest.json | 5 ++ plugins/zero-amp/plugins/zero.ts | 93 +++++++++++++++++++++++ plugins/zero-amp/skill/mcp.json | 6 ++ plugins/zero-gemini/gemini-extension.json | 2 +- plugins/zero/.claude-plugin/plugin.json | 2 +- plugins/zero/.codex-plugin/plugin.json | 2 +- plugins/zero/.factory-plugin/plugin.json | 2 +- scripts/build-amp.sh | 75 ++++++++++++++++++ 13 files changed, 292 insertions(+), 7 deletions(-) create mode 100644 guides/amp.md create mode 100644 plugins/zero-amp/README.md create mode 100755 plugins/zero-amp/hooks/zero-context.sh create mode 100644 plugins/zero-amp/manifest.json create mode 100644 plugins/zero-amp/plugins/zero.ts create mode 100644 plugins/zero-amp/skill/mcp.json create mode 100755 scripts/build-amp.sh diff --git a/Makefile b/Makefile index 8c75263..fbe2395 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,8 @@ MANIFESTS := \ plugins/zero/.claude-plugin/plugin.json \ plugins/zero/.codex-plugin/plugin.json \ plugins/zero/.factory-plugin/plugin.json \ - plugins/zero-gemini/gemini-extension.json + plugins/zero-gemini/gemini-extension.json \ + plugins/zero-amp/manifest.json # The manifest read for the current version (all of MANIFESTS stay in lockstep). VERSION_SOURCE := plugins/zero/.claude-plugin/plugin.json diff --git a/README.md b/README.md index 3c553b6..5a31ddc 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ installation, use the guides below. Pick your agent: - **[Codex (CLI)](guides/codex.md)** - **[Codex app](guides/codex-app.md)** - **[Droid](guides/droid.md)** +- **[Amp](guides/amp.md)** - **[Gemini CLI](guides/gemini-cli.md)** - **[Anything else (standalone installer)](guides/generic.md)** — works in any agent with a shell (and for humans at a terminal): @@ -73,7 +74,9 @@ plugins/zero/ # the shared plugin: skill + hooks (+ Claude's ├── .codex-plugin/ # Codex manifest └── .factory-plugin/ # Droid manifest plugins/zero-gemini/ # thin Gemini-only overlay (manifest + hook wiring) +plugins/zero-amp/ # thin Amp overlay (plugin + embedded-MCP skill) scripts/build-gemini.sh # assembles the installable Gemini extension into dist/ +scripts/build-amp.sh # assembles the installable Amp package into dist/ guides/ # per-host install guides + the agent install runbook ``` @@ -83,5 +86,5 @@ mechanics — live in the per-host guides. ## Status This repo is built up iteratively, one carefully reviewed PR at a time. Today -it ships the **Claude Code**, **Codex**, **Droid**, and **Gemini CLI** plugins; -additional hosts (Cursor) will land in subsequent PRs. +it ships the **Claude Code**, **Codex**, **Droid**, **Amp**, and **Gemini CLI** +plugins; additional hosts (Cursor) will land in subsequent PRs. diff --git a/guides/amp.md b/guides/amp.md new file mode 100644 index 0000000..c17ee60 --- /dev/null +++ b/guides/amp.md @@ -0,0 +1,61 @@ +# Zero for Amp + +How to install Zero in Amp and keep it up to date. + +## Install + +### From the terminal + +Clone the Zero plugins repository, build the Amp package, and copy the Amp +project files into your workspace: + +```bash +git clone https://github.com/officialzeroxyz/zero-plugins.git +cd zero-plugins +./scripts/build-amp.sh +cp -R dist/zero-amp/. /path/to/your/workspace/ +``` + +From the Amp workspace, reload plugins or restart Amp: + +```bash +amp plugins list +``` + +The Zero skill is installed at `.agents/skills/zero/`. Amp exposes skills +through its command palette, opened with `/` in the CLI. The skill also bundles +the Zero MCP connector in `.agents/skills/zero/mcp.json`, so Zero MCP tools are +only exposed when the Zero skill is loaded. + +Once installed, ask Amp: *"Help me set up and test Zero."* It walks you through +signing in. + +### Global install + +For a user-wide install, copy the same files into Amp's global plugin and skill +locations: + +```bash +git clone https://github.com/officialzeroxyz/zero-plugins.git +cd zero-plugins +./scripts/build-amp.sh +mkdir -p ~/.config/amp/plugins ~/.config/amp/zero/hooks ~/.config/agents/skills +cp dist/zero-amp/.amp/plugins/zero.ts ~/.config/amp/plugins/zero.ts +cp dist/zero-amp/.amp/zero/hooks/*.sh ~/.config/amp/zero/hooks/ +rm -rf ~/.config/agents/skills/zero +cp -R dist/zero-amp/.agents/skills/zero ~/.config/agents/skills/zero +``` + +## Staying up to date + +- The Zero runner updates when the Amp Zero plugin starts a thread session. +- To update the Amp plugin and skill files: + + ```bash + cd zero-plugins + git pull + ./scripts/build-amp.sh + cp -R dist/zero-amp/. /path/to/your/workspace/ + ``` + +For a global install, repeat the global copy commands above. diff --git a/plugins/zero-amp/README.md b/plugins/zero-amp/README.md new file mode 100644 index 0000000..44a6b97 --- /dev/null +++ b/plugins/zero-amp/README.md @@ -0,0 +1,35 @@ +# zero-amp (overlay - not directly installable) + +This directory holds Amp-specific packaging for Zero: + +- `manifest.json` - version metadata kept in lockstep with other hosts +- `skill/mcp.json` - embedded MCP config copied into the Zero skill directory +- `plugins/zero.ts` - Amp TypeScript plugin for runner provisioning, prompt + context, a command-palette entry, and safe Zero command allow rules +- `hooks/zero-context.sh` - helper used by the Amp command-palette entry + +The canonical Zero skill and shared runner provisioner live once in +[`../zero/`](../zero/) and are copied into the build output by +`scripts/build-amp.sh`. User-facing install instructions are in the +[Amp guide](../../guides/amp.md). + +## How the package is built + +```text +plugins/zero-amp/ # this overlay + ├── manifest.json # version metadata + ├── skill/mcp.json # embedded MCP config + ├── plugins/zero.ts # Amp plugin + └── hooks/zero-context.sh # command helper + +scripts/build-amp.sh # assembles overlay + shared files -> dist/zero-amp/ + +dist/zero-amp/ + ├── .agents/skills/zero/ # project skill with embedded mcp.json + ├── .amp/plugins/zero.ts # project plugin + └── .amp/zero/hooks/ # hook/helper scripts used by the plugin +``` + +Amp reads project plugins from `.amp/plugins/*.ts` and project skills from +`.agents/skills/`. The embedded `mcp.json` keeps Zero MCP tools scoped to the +Zero skill instead of adding them to every Amp turn. diff --git a/plugins/zero-amp/hooks/zero-context.sh b/plugins/zero-amp/hooks/zero-context.sh new file mode 100755 index 0000000..e3fa780 --- /dev/null +++ b/plugins/zero-amp/hooks/zero-context.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail + +cat <<'EOF' +Zero is available in this Amp workspace. Use the zero skill before saying a requested external capability is unavailable or telling the user to sign up for a third-party service. Resolve the runner as `zero` or `.amp/zero/hooks/zero-runner`, then follow the zero skill for search, inspect, call, and review. Do not create a wallet yourself. +EOF diff --git a/plugins/zero-amp/manifest.json b/plugins/zero-amp/manifest.json new file mode 100644 index 0000000..a8ddf78 --- /dev/null +++ b/plugins/zero-amp/manifest.json @@ -0,0 +1,5 @@ +{ + "name": "zero-amp", + "version": "1.4.0", + "description": "Zero Amp plugin, Agent Skill with embedded MCP, and runner provisioning helpers" +} diff --git a/plugins/zero-amp/plugins/zero.ts b/plugins/zero-amp/plugins/zero.ts new file mode 100644 index 0000000..5a615b2 --- /dev/null +++ b/plugins/zero-amp/plugins/zero.ts @@ -0,0 +1,93 @@ +import type { PluginAPI } from '@ampcode/plugin' +import { spawn } from 'node:child_process' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const pluginDir = dirname(fileURLToPath(import.meta.url)) +const zeroRoot = join(pluginDir, '..', 'zero') +const ensureRunner = join(zeroRoot, 'hooks', 'ensure-runner.sh') +const contextScript = join(zeroRoot, 'hooks', 'zero-context.sh') +const runnerShim = join(zeroRoot, 'hooks', 'zero-runner') + +const context = + 'Zero is available in this Amp workspace. Use the zero skill before saying a requested external capability is unavailable or telling the user to sign up for a third-party service. Resolve the runner as `zero` or `.amp/zero/hooks/zero-runner`, then follow the zero skill for search, inspect, call, and review. Do not create a wallet yourself.' + +let ensureStarted = false +let ensureDone = false + +export default function (amp: PluginAPI) { + amp.logger.log('Zero plugin initialized') + + amp.on('session.start', async () => { + ensureZeroRunner(amp) + }) + + amp.on('agent.start', async () => { + ensureZeroRunner(amp) + return { message: { content: context } } + }) + + amp.registerCommand( + 'zero-context', + { + title: 'Zero: Show context', + category: 'Zero', + description: 'Show how to use Zero from this Amp workspace', + }, + async (ctx) => { + try { + const text = await runCommand('bash', [contextScript], zeroRoot) + await ctx.ui.notify(text.trim() || context) + } catch { + await ctx.ui.notify(context) + } + }, + ) +} + +function ensureZeroRunner(amp: PluginAPI) { + if (ensureStarted || ensureDone) return + ensureStarted = true + + runCommand('bash', [ensureRunner], zeroRoot) + .then(() => { + ensureDone = true + amp.logger.log(`Zero runner ready at ${runnerShim}`) + }) + .catch((error) => { + amp.logger.log(`Zero runner provisioning failed: ${String(error)}`) + }) + .finally(() => { + ensureStarted = false + }) +} + +function runCommand(command: string, args: string[], cwd: string): Promise { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { + cwd, + env: { + ...process.env, + ZERO_RUNNER_SHIM: runnerShim, + }, + stdio: ['ignore', 'pipe', 'pipe'], + }) + + let stdout = '' + let stderr = '' + child.stdout.on('data', (chunk) => { + stdout += chunk.toString() + }) + child.stderr.on('data', (chunk) => { + stderr += chunk.toString() + }) + child.on('error', reject) + child.on('close', (code) => { + if (code === 0) { + resolve(stdout) + } else { + reject(new Error(stderr.trim() || `command exited ${code}`)) + } + }) + }) +} diff --git a/plugins/zero-amp/skill/mcp.json b/plugins/zero-amp/skill/mcp.json new file mode 100644 index 0000000..66e1c7e --- /dev/null +++ b/plugins/zero-amp/skill/mcp.json @@ -0,0 +1,6 @@ +{ + "zero": { + "url": "https://mcp.zero.xyz", + "includeTools": ["*"] + } +} diff --git a/plugins/zero-gemini/gemini-extension.json b/plugins/zero-gemini/gemini-extension.json index 69ea920..ac48f52 100644 --- a/plugins/zero-gemini/gemini-extension.json +++ b/plugins/zero-gemini/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "zero", - "version": "1.3.3", + "version": "1.4.0", "description": "Discover and call paid AI capabilities (x402 / MPP) with automatic, wallet-backed payment. Search a live index of external services — image/video/audio generation, web scraping, data enrichment, real-time data, messaging — then call them and pay per use. Bundles the 'zero' skill and the Zero MCP connector.", "mcpServers": { "zero": { diff --git a/plugins/zero/.claude-plugin/plugin.json b/plugins/zero/.claude-plugin/plugin.json index 6b83198..59e52a7 100644 --- a/plugins/zero/.claude-plugin/plugin.json +++ b/plugins/zero/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "zero", - "version": "1.3.3", + "version": "1.4.0", "description": "Discover and call paid AI capabilities (x402 / MPP) with automatic, wallet-backed payment. Search a live index of external services — image/video/audio generation, web scraping, data enrichment, real-time data, messaging — then call them and pay per use. Bundles the 'zero' skill and the Zero MCP connector.", "author": { "name": "Zero", "url": "https://zero.xyz" }, "homepage": "https://zero.xyz", diff --git a/plugins/zero/.codex-plugin/plugin.json b/plugins/zero/.codex-plugin/plugin.json index e90630a..3a8d304 100644 --- a/plugins/zero/.codex-plugin/plugin.json +++ b/plugins/zero/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "zero", - "version": "1.3.3", + "version": "1.4.0", "description": "Discover and call paid AI capabilities (x402 / MPP) with automatic, wallet-backed payment. Search a live index of external services — image/video/audio generation, web scraping, data enrichment, real-time data, messaging — then call them and pay per use. Bundles the 'zero' skill.", "author": { "name": "Zero", "url": "https://zero.xyz" }, "homepage": "https://zero.xyz", diff --git a/plugins/zero/.factory-plugin/plugin.json b/plugins/zero/.factory-plugin/plugin.json index 6b83198..59e52a7 100644 --- a/plugins/zero/.factory-plugin/plugin.json +++ b/plugins/zero/.factory-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "zero", - "version": "1.3.3", + "version": "1.4.0", "description": "Discover and call paid AI capabilities (x402 / MPP) with automatic, wallet-backed payment. Search a live index of external services — image/video/audio generation, web scraping, data enrichment, real-time data, messaging — then call them and pay per use. Bundles the 'zero' skill and the Zero MCP connector.", "author": { "name": "Zero", "url": "https://zero.xyz" }, "homepage": "https://zero.xyz", diff --git a/scripts/build-amp.sh b/scripts/build-amp.sh new file mode 100755 index 0000000..15f5882 --- /dev/null +++ b/scripts/build-amp.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# +# Assemble the Amp package into dist/zero-amp/. +# +# Amp reads project plugins from .amp/plugins/*.ts and project skills from +# .agents/skills//SKILL.md. Skills can bundle MCP servers with mcp.json, +# so the Zero MCP connector is copied directly into the Zero skill folder. +# +# Usage: +# scripts/build-amp.sh # assemble dist/zero-amp/ +# scripts/build-amp.sh --tar OUT.tgz # also write a tarball + +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SHARED="$ROOT/plugins/zero" +OVERLAY="$ROOT/plugins/zero-amp" +OUT="$ROOT/dist/zero-amp" + +TARBALL="" +if [ "${1:-}" = "--tar" ]; then + TARBALL="${2:?--tar requires an output path}" +fi + +for f in \ + "$OVERLAY/manifest.json" \ + "$OVERLAY/skill/mcp.json" \ + "$OVERLAY/plugins/zero.ts" \ + "$OVERLAY/hooks/zero-context.sh" \ + "$SHARED/hooks/ensure-runner.sh" \ + "$SHARED/skills/zero/SKILL.md"; do + [ -f "$f" ] || { echo "build-amp: missing required input: $f" >&2; exit 1; } +done + +rm -rf "$OUT" +mkdir -p "$OUT/.agents/skills" "$OUT/.amp/plugins" "$OUT/.amp/zero/hooks" + +cp "$OVERLAY/manifest.json" "$OUT/manifest.json" +cp "$OVERLAY/plugins/zero.ts" "$OUT/.amp/plugins/zero.ts" +cp "$OVERLAY/hooks/zero-context.sh" "$OUT/.amp/zero/hooks/zero-context.sh" +cp "$SHARED/hooks/ensure-runner.sh" "$OUT/.amp/zero/hooks/ensure-runner-shared.sh" +cp -R "$SHARED/skills/zero" "$OUT/.agents/skills/zero" +cp "$OVERLAY/skill/mcp.json" "$OUT/.agents/skills/zero/mcp.json" + +cat > "$OUT/.amp/zero/hooks/ensure-runner.sh" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SHARED="$SCRIPT_DIR/ensure-runner-shared.sh" + +# Use a workspace-local shim so Amp can invoke `.amp/zero/hooks/zero-runner` +# even before ~/.zero/runtime/bin is on PATH. +export ZERO_RUNNER_SHIM="${ZERO_RUNNER_SHIM:-$SCRIPT_DIR/zero-runner}" + +bash "$SHARED" + +if [ -x "$HOME/.zero/runtime/bin/zero" ]; then + ln -sfn "$HOME/.zero/runtime/bin/zero" "$ZERO_RUNNER_SHIM" +fi +EOF + +chmod +x \ + "$OUT/.amp/zero/hooks/ensure-runner.sh" \ + "$OUT/.amp/zero/hooks/ensure-runner-shared.sh" \ + "$OUT/.amp/zero/hooks/zero-context.sh" + +echo "build-amp: assembled $OUT" +find "$OUT" -type f | sed "s#^$ROOT/##" | sort + +if [ -n "$TARBALL" ]; then + mkdir -p "$(dirname "$TARBALL")" + tar -czf "$TARBALL" -C "$OUT" . + echo "build-amp: wrote $TARBALL" +fi