Skip to content

Commit 2848d04

Browse files
authored
feat(cli): zerion setup skills/mcp + handoff doc (#20)
* docs: handoff doc for zerion-agent split — manual rename steps remaining * feat(cli): add zerion setup skills + zerion setup mcp wrappers `zerion setup skills` shells out to `npx -y skills add zeriontech/zerion-agent` (passes through --agent, -g, -y, --dry-run). Delegates agent detection to vercel-labs/skills (45+ hosts). `zerion setup mcp --print` emits the canonical Zerion hosted-MCP config fragment. `zerion setup mcp --agent <cursor|claude-code|claude-desktop>` merges the Zerion server into the agent's config file. Preserves existing mcpServers entries. Project scope by default; --global / -g writes to the user-wide config. Also extends router help to surface the new subcommands and adds a "Manual operations — agent skills & MCP setup" section to cli/README.md. 12 unit tests in tests/unit/cli/commands/setup.test.mjs; full suite at 122 tests, 0 fails.
1 parent 373d95c commit 2848d04

6 files changed

Lines changed: 461 additions & 0 deletions

File tree

cli/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@ zerion config set slippage <percent> Set slippage tolerance (default: 2%)
132132
zerion config unset <key> Remove a config value
133133
```
134134

135+
### Manual operations — agent skills & MCP setup
136+
137+
Convenience wrappers for installing Zerion as agent skills (Claude Code, Codex, Cursor, Gemini CLI, OpenCode, …) or wiring the hosted MCP into a coding agent's config.
138+
139+
```
140+
zerion setup skills Install Zerion skills via `npx skills add` (interactive)
141+
zerion setup skills --agent claude-code -y Non-interactive install into Claude Code
142+
zerion setup skills -g Install globally (cross-project)
143+
zerion setup mcp --print Print the canonical Zerion MCP config fragment
144+
zerion setup mcp --agent cursor Merge Zerion server into project .cursor/mcp.json
145+
zerion setup mcp --agent claude-code -g Merge into ~/.claude/settings.json (global)
146+
zerion setup mcp --agent claude-desktop -g Merge into Claude Desktop's app config
147+
```
148+
149+
`setup skills` delegates to [vercel-labs/skills](https://github.com/vercel-labs/skills) and installs from [`zeriontech/zerion-agent`](https://github.com/zeriontech/zerion-agent). For the full plugin (skills + slash commands + MCP) inside Claude Code, use `/plugin install zerion-agent@zerion` instead.
150+
135151
### Other
136152

137153
```

cli/commands/setup.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import { spawnSync } from "node:child_process";
2+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3+
import { dirname, join } from "node:path";
4+
import { homedir } from "node:os";
5+
import { print, printError } from "../lib/util/output.js";
6+
7+
const ZERION_AGENT_REPO = "zeriontech/zerion-agent";
8+
9+
const ZERION_MCP_SERVER = {
10+
type: "sse",
11+
url: "https://developers.zerion.io/mcp",
12+
headers: { Authorization: "Bearer ${ZERION_API_KEY}" },
13+
};
14+
15+
const HELP = {
16+
usage: "zerion setup <skills|mcp> [options]",
17+
subcommands: {
18+
"setup skills":
19+
"Install Zerion agent skills via `npx skills add` (delegates to vercel-labs/skills, supports 45+ agents).",
20+
"setup mcp":
21+
"Write the Zerion hosted-MCP config fragment into a detected agent's config file.",
22+
},
23+
flags: {
24+
"--global, -g": "Install globally instead of project scope",
25+
"--agent <name>": "Target a specific agent (e.g. claude-code, cursor, claude-desktop)",
26+
"--print": "Print the MCP config fragment to stdout instead of writing (mcp only)",
27+
"--dry-run": "Print the underlying command/target without executing",
28+
"--yes, -y": "Skip prompts (skills only — passes through to npx skills)",
29+
},
30+
examples: {
31+
"zerion setup skills": "Interactive install across detected agents",
32+
"zerion setup skills --agent claude-code -y": "Non-interactive install into Claude Code",
33+
"zerion setup skills -g": "Install globally",
34+
"zerion setup mcp --print": "View the canonical Zerion MCP fragment",
35+
"zerion setup mcp --agent cursor": "Merge Zerion MCP into project .cursor/mcp.json",
36+
"zerion setup mcp --agent claude-desktop -g": "Merge into Claude Desktop's global config",
37+
},
38+
source: `https://github.com/${ZERION_AGENT_REPO}`,
39+
};
40+
41+
const MCP_TARGETS = {
42+
cursor: {
43+
global: () => join(homedir(), ".cursor", "mcp.json"),
44+
project: () => join(process.cwd(), ".cursor", "mcp.json"),
45+
},
46+
"claude-code": {
47+
global: () => join(homedir(), ".claude", "settings.json"),
48+
project: () => join(process.cwd(), ".claude", "settings.json"),
49+
},
50+
"claude-desktop": {
51+
global: () => {
52+
if (process.platform === "darwin") {
53+
return join(
54+
homedir(),
55+
"Library",
56+
"Application Support",
57+
"Claude",
58+
"claude_desktop_config.json"
59+
);
60+
}
61+
if (process.platform === "win32") {
62+
return join(homedir(), "AppData", "Roaming", "Claude", "claude_desktop_config.json");
63+
}
64+
return join(homedir(), ".config", "Claude", "claude_desktop_config.json");
65+
},
66+
},
67+
};
68+
69+
export default async function setup(args, flags) {
70+
const [subcommand, ...rest] = args;
71+
72+
if (flags.help || flags.h || !subcommand) {
73+
print(HELP);
74+
return;
75+
}
76+
77+
switch (subcommand) {
78+
case "skills":
79+
return setupSkills(rest, flags);
80+
case "mcp":
81+
return setupMcp(rest, flags);
82+
default:
83+
printError(
84+
"unknown_subcommand",
85+
`Unknown setup subcommand: ${subcommand}`,
86+
{ suggestion: "Run 'zerion setup --help' for usage", subcommand }
87+
);
88+
process.exit(1);
89+
}
90+
}
91+
92+
function setupSkills(_args, flags) {
93+
const npxArgs = ["-y", "skills", "add", ZERION_AGENT_REPO];
94+
if (flags.global || flags.g) npxArgs.push("-g");
95+
if (flags.agent) npxArgs.push("-a", flags.agent);
96+
if (flags.yes || flags.y) npxArgs.push("--yes");
97+
98+
const renderedCommand = `npx ${npxArgs.join(" ")}`;
99+
100+
if (flags["dry-run"]) {
101+
print({ ok: true, dryRun: true, command: renderedCommand, source: ZERION_AGENT_REPO });
102+
return;
103+
}
104+
105+
const res = spawnSync("npx", npxArgs, { stdio: "inherit" });
106+
if (res.status !== 0) {
107+
printError("skills_install_failed", "npx skills add returned non-zero", {
108+
exitCode: res.status,
109+
command: renderedCommand,
110+
});
111+
process.exit(res.status ?? 1);
112+
}
113+
print({ ok: true, action: "setup-skills", source: ZERION_AGENT_REPO });
114+
}
115+
116+
function setupMcp(_args, flags) {
117+
if (flags.print) {
118+
const fragment = { mcpServers: { zerion: ZERION_MCP_SERVER } };
119+
process.stdout.write(JSON.stringify(fragment, null, 2) + "\n");
120+
return;
121+
}
122+
123+
const agent = flags.agent;
124+
if (!agent) {
125+
printError(
126+
"missing_agent",
127+
"Specify --agent <name> (cursor, claude-code, claude-desktop) or use --print to view the fragment.",
128+
{ supportedAgents: Object.keys(MCP_TARGETS) }
129+
);
130+
process.exit(1);
131+
}
132+
133+
const target = MCP_TARGETS[agent];
134+
if (!target) {
135+
printError("unknown_agent", `Unknown agent: ${agent}`, {
136+
supportedAgents: Object.keys(MCP_TARGETS),
137+
});
138+
process.exit(1);
139+
}
140+
141+
const wantGlobal = flags.global || flags.g;
142+
const scope = wantGlobal || !target.project ? "global" : "project";
143+
const path = target[scope]();
144+
145+
if (flags["dry-run"]) {
146+
print({ ok: true, dryRun: true, agent, scope, target: path });
147+
return;
148+
}
149+
150+
let config = {};
151+
if (existsSync(path)) {
152+
try {
153+
config = JSON.parse(readFileSync(path, "utf8"));
154+
} catch (err) {
155+
printError("invalid_config", `Existing config at ${path} is not valid JSON`, {
156+
error: err.message,
157+
});
158+
process.exit(1);
159+
}
160+
} else {
161+
mkdirSync(dirname(path), { recursive: true });
162+
}
163+
164+
config.mcpServers = config.mcpServers || {};
165+
config.mcpServers.zerion = ZERION_MCP_SERVER;
166+
writeFileSync(path, JSON.stringify(config, null, 2) + "\n");
167+
168+
print({ ok: true, action: "setup-mcp", agent, scope, target: path });
169+
}

cli/router.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ function printUsage() {
121121
"defaultChain": "Default chain (default: ethereum)",
122122
"slippage": "Default slippage % for swaps (default: 2)",
123123
},
124+
setup: {
125+
"setup skills": "Install Zerion agent skills via `npx skills add zeriontech/zerion-agent` (45+ hosts)",
126+
"setup mcp --agent <name>": "Write the Zerion hosted-MCP fragment into a detected agent's config (cursor, claude-code, claude-desktop)",
127+
"setup mcp --print": "Print the canonical MCP fragment to stdout",
128+
},
124129
chains: [
125130
"ethereum", "base", "arbitrum", "optimism", "polygon",
126131
"binance-smart-chain", "avalanche", "gnosis", "scroll",

cli/zerion.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ register("agent", "delete-policy", agentDeletePolicy);
9292
import configCmd from "./commands/config.js";
9393
registerSingle("config", configCmd);
9494

95+
// --- Setup (skills + mcp installer wrappers) ---
96+
97+
import setupCmd from "./commands/setup.js";
98+
registerSingle("setup", setupCmd);
99+
95100
// --- Dispatch ---
96101

97102
try {
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Handoff — zerion-agent split, 2026-04-26 evening
2+
3+
Spec: `docs/superpowers/specs/2026-04-26-zerion-agent-split-design.md`
4+
Plan: `docs/superpowers/plans/2026-04-26-zerion-agent-split.md`
5+
6+
## What landed tonight
7+
8+
### `zeriontech/zerion-agent` (new private repo)
9+
10+
- Created private under `zeriontech` org
11+
- Content migrated: 4 skills, 8 MCP tool catalog files, 5 example dirs, demo SVG, root `.mcp.json`
12+
- Claude Code plugin manifests authored (`.claude-plugin/plugin.json` + `marketplace.json`) — marketplace name is `zerion`, install command will be `/plugin install zerion-agent@zerion`
13+
- README rewritten for agent-integration audience, three install paths documented
14+
- release-please + lint workflows in CI
15+
- **v0.2.0 released** (release-please bumped 0.1.0 → 0.2.0 to absorb feat commits)
16+
- SKILL.md homepage URLs updated to `https://github.com/zeriontech/zerion-cli` (will resolve once rename happens)
17+
18+
### `zeriontech/zerion-ai` (still named zerion-ai)
19+
20+
- PR #19 merged (`chore: split agent assets into zeriontech/zerion-agent`)
21+
- Removed: `skills/`, `mcp/`, `examples/`, `assets/`, root `.mcp.json`
22+
- Removed: 4 unit tests that read those dirs (`skills.test.mjs`, `examples.test.mjs`, `mcp-tools.test.mjs`, `consistency.test.mjs`) — content lives with content in zerion-agent
23+
- README rewritten for CLI-only audience, links out to zerion-agent
24+
- Pre-existing `package-lock.json` issue from `chore: clear npm audit` commit fixed in the same PR
25+
- All 92 unit tests pass
26+
- CHANGELOG untouched — release-please will pick up the chore commit
27+
28+
### `zerion setup skills` / `zerion setup mcp` (Chunk 9)
29+
30+
Implemented in `cli/commands/setup.js`. Sits on PR branch `chore/handoff-doc` (open as PR #20 when convenient). Behavior:
31+
32+
- `zerion setup skills` shells out to `npx -y skills add zeriontech/zerion-agent`, supports `--agent <name>`, `-g`, `-y` passthrough, and `--dry-run` for inspection.
33+
- `zerion setup mcp --print` emits the canonical hosted-MCP config fragment.
34+
- `zerion setup mcp --agent <cursor|claude-code|claude-desktop>` merges the Zerion server into the agent's config file (project scope by default, `-g` for global). Preserves any existing `mcpServers` entries.
35+
- 12 new tests in `tests/unit/cli/commands/setup.test.mjs`; full suite at 122 tests, 0 fails.
36+
37+
### Verified
38+
39+
- `npx skills add /Users/graysonho/Documents/GitHub/zerion-agent` discovers + installs all 4 skills into `.claude/skills/` (test run in `/tmp`, cleaned up)
40+
- Plugin manifests passed `plugin-dev:plugin-validator` review
41+
42+
## What's blocked, needs Grayson
43+
44+
### 1. Rename `zerion-ai``zerion-cli` on GitHub
45+
46+
**Why blocked:** the `graysonhyc` GitHub account does not have admin permission on `zeriontech/zerion-ai`. API call returned `permissions.admin: False`. `gh repo rename` returned 404 (gh treats permission denial as 404).
47+
48+
**Action:** rename via the web UI at <https://github.com/zeriontech/zerion-ai/settings> → "Repository name" field, change to `zerion-cli`, click "Rename". Or grant admin to graysonhyc and run:
49+
50+
```bash
51+
gh repo rename zerion-cli --repo zeriontech/zerion-ai --yes
52+
```
53+
54+
**After rename:**
55+
56+
```bash
57+
cd /Users/graysonho/Documents/GitHub/zerion-ai
58+
git remote set-url origin https://github.com/zeriontech/zerion-cli.git
59+
git remote -v # confirm
60+
# Optional: rename the local dir
61+
cd /Users/graysonho/Documents/GitHub
62+
mv zerion-ai zerion-cli
63+
```
64+
65+
### 2. Update `zerion-cli` `package.json` URLs (after rename)
66+
67+
Open a small PR:
68+
69+
```bash
70+
cd /Users/graysonho/Documents/GitHub/zerion-cli # or zerion-ai if not renamed locally
71+
git checkout -b chore/update-repo-urls
72+
```
73+
74+
Edit `package.json` — change three URLs:
75+
76+
- `repository.url`: `git+https://github.com/zeriontech/zerion-ai.git``git+https://github.com/zeriontech/zerion-cli.git`
77+
- `bugs.url`: `https://github.com/zeriontech/zerion-ai/issues``https://github.com/zeriontech/zerion-cli/issues`
78+
- `homepage`: `https://github.com/zeriontech/zerion-ai#readme``https://github.com/zeriontech/zerion-cli#readme`
79+
80+
Commit with `chore: update package.json URLs to zerion-cli` and PR. After merge, the next release-please run pushes a new npm version that has the corrected URLs in package metadata (`npm view zerion-cli repository`).
81+
82+
### 3. Flip `zerion-agent` to public when ready
83+
84+
```bash
85+
gh repo edit zeriontech/zerion-agent --visibility public --accept-visibility-change-consequences
86+
```
87+
88+
Tonight it stays private (your call). After flip:
89+
90+
- `npx skills add zeriontech/zerion-agent` works without GitHub auth
91+
- `/plugin marketplace add zeriontech/zerion-agent` works for any user
92+
- External announcement (release notes link, dev-rel, partner heads-up) becomes appropriate
93+
94+
## Status of Plan chunks
95+
96+
| Chunk | Status |
97+
|-------|--------|
98+
| 1: Scaffold zerion-agent | ✅ Done |
99+
| 2: Migrate skills | ✅ Done |
100+
| 3: Migrate mcp/examples/assets | ✅ Done |
101+
| 4: Author plugin manifests | ✅ Done (validator approved) |
102+
| 5: README + release tooling + CI | ✅ Done |
103+
| 6: Push + verify install paths | ✅ Done (npx skills verified locally) |
104+
| 7: Clean up zerion-ai + rename | 🟡 Cleanup merged; rename pending admin |
105+
| 8: Cross-link READMEs + memory | ✅ Done |
106+
| 9: `zerion setup skills/mcp` | ✅ Done — implemented + 12 tests pass; ships in next CLI release |
107+
108+
## Useful commands
109+
110+
Quick install verification once rename + flip-to-public are done:
111+
112+
```bash
113+
mkdir /tmp/install-test && cd /tmp/install-test
114+
npx -y skills add zeriontech/zerion-agent --yes --agent claude-code
115+
find . -name SKILL.md # expect 4 files under .claude/skills/
116+
```
117+
118+
Local tail of recent CLI activity:
119+
120+
```bash
121+
git -C /Users/graysonho/Documents/GitHub/zerion-ai log --oneline -10
122+
git -C /Users/graysonho/Documents/GitHub/zerion-agent log --oneline -10
123+
```

0 commit comments

Comments
 (0)