@moonpay/cli 1.49.0 → 1.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: moonpay-automation-builder
3
+ description: Author new automations for the MoonPay Agents app. Use when the user wants to schedule a recurring task — a daily portfolio email, an hourly price check, a weekly rebalance, a cron-triggered prompt. Automations are JSON entries that fire a prompt or skill on a cron schedule via either the Claude Code or Codex backend. This skill defines the JSON schema, where to write it, and how to pick a sensible cron.
4
+ ---
5
+
6
+ # MoonPay Automation Builder
7
+
8
+ An automation is a saved prompt that the MoonPay Agents app fires on a cron schedule. The first fire spawns a fresh agent session; every subsequent fire `--resume`s the same session so the agent keeps its memory across runs. This is how "every morning, summarize my portfolio" or "every Monday at 9am, run my DCA strategy" actually run.
9
+
10
+ This skill is how new automations get authored.
11
+
12
+ ## When to use this skill
13
+
14
+ - The user wants something to run on a schedule, not just one-shot.
15
+ - The user already has a skill or a prompt that works once and wants to run it on repeat.
16
+ - The user describes the trigger with words like "every day", "every Monday", "hourly", "twice a week", "at 9am".
17
+
18
+ If the user wants a one-shot future action ("remind me at 3pm"), suggest the `schedule` skill instead — that's cloud-side and one-time.
19
+
20
+ ## On-disk format
21
+
22
+ All automations live in a single file:
23
+
24
+ ```
25
+ ~/.moonpay-agents/automations.json
26
+ ```
27
+
28
+ It's a JSON array of automation objects. Each object:
29
+
30
+ ```json
31
+ {
32
+ "id": "<uuid v4>",
33
+ "name": "Morning portfolio check",
34
+ "body": "Run mp portfolio retrieve --json, summarize the top movers since yesterday, and Slack me a 3-bullet update.",
35
+ "cron": "0 9 * * *",
36
+ "backend": "claude",
37
+ "enabled": true,
38
+ "sessionId": null,
39
+ "lastRun": null,
40
+ "lastStatus": null,
41
+ "lastOutput": null,
42
+ "createdAt": "2026-05-14T17:00:00Z"
43
+ }
44
+ ```
45
+
46
+ | field | required | notes |
47
+ |---|---|---|
48
+ | `id` | required | UUID v4. Generate one if creating new. |
49
+ | `name` | required | Short label shown in the Automations view. |
50
+ | `body` | required | The prompt the agent runs on each fire. Write it like a normal user message — the agent sees this verbatim. |
51
+ | `cron` | required | 5-field cron: `min hour dom month dow`. See "Picking a cron" below. |
52
+ | `backend` | required | `"claude"` or `"codex"`. Default to `"claude"` unless the user prefers Codex. |
53
+ | `enabled` | optional | Defaults to `true`. Set `false` to author the automation without firing it. |
54
+ | `sessionId` | optional | Leave `null` — the app fills this in after the first fire. |
55
+ | `lastRun`, `lastStatus`, `lastOutput` | optional | Leave `null` — written by the app after each fire. |
56
+ | `createdAt` | required | ISO-8601 timestamp. Use the current time. |
57
+
58
+ The app reloads `automations.json` on every save, so writing directly to disk works — no IPC needed.
59
+
60
+ ## Picking a cron
61
+
62
+ The format is the standard 5-field Unix cron: `minute hour day-of-month month day-of-week`. **Day-of-week is 0–6 with 0 = Sunday.**
63
+
64
+ | Cadence | Cron | Notes |
65
+ |---|---|---|
66
+ | Every minute | `* * * * *` | Don't. Almost always a bug. |
67
+ | Every 5 minutes | `*/5 * * * *` | Polling. Fine for cheap checks. |
68
+ | Every hour on the hour | `0 * * * *` | |
69
+ | Daily at 9am | `0 9 * * *` | Local time of the device running the app. |
70
+ | Every weekday at 9am | `0 9 * * 1-5` | Mon–Fri. |
71
+ | Every Monday at 9am | `0 9 * * 1` | |
72
+ | First of the month at 9am | `0 9 1 * *` | |
73
+
74
+ The MoonPay Agents app uses a 6-field internal form (`sec min hour dom month dow`) — it prepends `0 ` automatically. Always write 5-field cron in the JSON.
75
+
76
+ ### Cron gotchas
77
+
78
+ - **Day-of-month + day-of-week are OR'd**, not AND'd. `0 9 1 * 1` fires on the 1st of the month AND every Monday — usually not what people want.
79
+ - **App must be running.** The scheduler is in-process; if the app is closed, the automation doesn't fire. (No launchd integration today.)
80
+ - **Time zone** = local machine time. If the user moves time zones, the cron fires at the same local time, not the same UTC time.
81
+
82
+ ## Writing the `body`
83
+
84
+ The body is the prompt the agent gets on every fire. Two things to get right:
85
+
86
+ ### 1. Write it like a normal user message
87
+
88
+ ```
89
+ Pull my Polymarket positions with mp polymarket positions list --json. For each position
90
+ where the current price has moved >5% from entry, draft a Slack message to #me with the
91
+ position name, entry price, current price, and PnL.
92
+ ```
93
+
94
+ Not:
95
+
96
+ ```
97
+ Execute polymarket position summary procedure
98
+ ```
99
+
100
+ The agent reads the body the same way it reads a chat message. Be specific about what data to pull, what to do with it, and where to deliver the result.
101
+
102
+ ### 2. Don't recreate skills inline
103
+
104
+ If the workflow already exists as a skill (`mp skill list`), invoke the skill instead of describing its steps:
105
+
106
+ > "Use the moonpay-portfolio skill. Compute drift from my target allocation and Slack me a one-line summary if drift > 5%."
107
+
108
+ This keeps the automation small and lets skill improvements propagate automatically.
109
+
110
+ ### 3. Pick the right backend
111
+
112
+ - **`"claude"`** for anything that needs nuanced judgment, web research, or long-form output. Default.
113
+ - **`"codex"`** if the workflow is heavily code-modifying (e.g. "regenerate this report HTML and write it to disk") and you want Codex's editing harness.
114
+
115
+ ## Authoring flow (what the agent should do)
116
+
117
+ When the user invokes you:
118
+
119
+ 1. **Ask three things**:
120
+ - What should this automation do? (the body)
121
+ - How often? (the cron — in plain English, you'll convert)
122
+ - Backend? (default to claude unless they specify)
123
+ 2. **Convert the cadence to a 5-field cron** and read it back to the user in plain English ("Every weekday at 9am — `0 9 * * 1-5`") to confirm.
124
+ 3. **Read `~/.moonpay-agents/automations.json`** (create the file as `[]` if missing).
125
+ 4. **Append a new automation object** with a freshly generated UUID v4, the current ISO-8601 timestamp for `createdAt`, the user's body, the cron, the backend, `enabled: true`, and `null` for `sessionId`/`lastRun`/`lastStatus`/`lastOutput`.
126
+ 5. **Write the updated array back** to `~/.moonpay-agents/automations.json`. Pretty-print (2-space indent) — the user may edit it by hand.
127
+ 6. **Tell the user**: when the next fire is, the name + cron, and that they can disable/edit it from the Automations view.
128
+
129
+ ## Important rules
130
+
131
+ - **Never write to `automations.json` without reading it first.** Read → modify → write. Don't blow away other automations.
132
+ - **Always use UUID v4 for `id`** — incrementing IDs collide on import/export.
133
+ - **Use `null`, not `""` or `undefined`**, for the lifecycle fields the app fills in (`sessionId`, `lastRun`, etc).
134
+ - **Don't enable an automation that fires every minute** without warning the user. `*/5 * * * *` is usually the right floor.
135
+ - **Validate the cron** by running it through `cron --validate <expr>` or noting in the response that the app's scheduler will reject invalid expressions on save.
136
+
137
+ ## Common pitfalls
138
+
139
+ - **Cron means local time.** Users who travel get surprises. Mention it on creation if the cadence is time-sensitive.
140
+ - **First fire is at the next match.** A 9am daily automation created at 10am won't fire until 9am tomorrow. Tell the user the expected next-fire time.
141
+ - **Body is too vague.** "Check my portfolio" produces wildly different output each fire. "Run mp portfolio retrieve --json and Slack me a 3-bullet summary of changes since yesterday" produces consistent output.
142
+ - **App-closed silence.** If a user complains an automation didn't fire, first thing to check: was the app actually running at the scheduled time?
143
+
144
+ ## Related
145
+
146
+ - **moonpay-skill-builder** — author the underlying skill before scheduling it. Most good automations are "run this skill on a cron".
147
+ - **moonpay-artifact-builder** — for visual recurring reports, pair an automation that updates a JSON file with an artifact that reads it.
148
+ - **`schedule` skill** (cloud-side) — for one-shot future runs ("at 3pm tomorrow, do X"). Different system, persists across app closure.
@@ -18,7 +18,7 @@ Then drive Playwright through shipping + card details, **show the total**, and o
18
18
 
19
19
  The MoonAgents Card runs on Monavate × Baanx. Before checkout works, the user must have:
20
20
  - Completed Baanx KYC and received a virtual card (`mp card create`)
21
- - Delegated USDC spending from a Solana wallet to the Baanx spender (`mp card delegate`)
21
+ - Delegated USDC spending from a Solana wallet to the Baanx spender (`mp card wallet link`) — runs the SPL Approve + SIWS ownership dance locally
22
22
 
23
23
  If `mp card retrieve` errors with "No MoonCard account", point the user at `mp card onboarding start` first — don't try to checkout until the card exists.
24
24
 
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: moonpay-card-onboarding
3
+ description: Set up a MoonAgents Card from scratch — collect identity, run KYC via Veriff, accept Baanx's Terms + Privacy + E-Sign disclosures, finalize registration, and delegate a Solana wallet for USDC spending. The conversational counterpart to the moon-agents-card Artifact's "Get started" CTA. Run this before moonpay-card-checkout if `mp card retrieve` errors with "No MoonCard account" or if the user has no delegated wallets.
4
+ ---
5
+
6
+ # MoonAgents Card Onboarding
7
+
8
+ ## Goal
9
+
10
+ Walk the user from "I want a MoonAgents Card" to "I can tap-to-pay on Solana USDC." This is a multi-step flow with real KYC, real legal acceptance, and a real on-chain delegation transaction. Don't shortcut any of it.
11
+
12
+ The Artifact (**moon-agents-card** in the MoonPay Agents desktop app) routes here via "Get started" or "Delegate wallet" CTAs depending on which stage the user is in.
13
+
14
+ ## Pre-flight — figure out which stage they're at
15
+
16
+ Always run these two probes first. The answers tell you where to pick up:
17
+
18
+ ```bash
19
+ mp card retrieve --json
20
+ mp card onboarding check --json
21
+ ```
22
+
23
+ Five possible states:
24
+
25
+ | State | Detected by | Jump to step |
26
+ |---|---|---|
27
+ | Never started | `mp card retrieve` errors "No MoonCard account" + `mp card onboarding check` errors with same | **Step 1** |
28
+ | KYC in progress | `mp card onboarding check` returns `veriffUrl` (no `terms` block) | **Step 2** |
29
+ | KYC verified, terms not accepted | `check` returns `terms: { termsAndConditions, privacyPolicy, eSignConsentDisclosure }` | **Step 3** |
30
+ | Card created, no delegation | `mp card retrieve` succeeds, `mp card wallet list` is empty | **Step 4** |
31
+ | Fully ready | both succeed and `mp card wallet list` returns items | **Done** — route to `moonpay-card-checkout` |
32
+
33
+ Surface the current stage to the user so they understand where they are.
34
+
35
+ ## Step 1 — Collect identity details and start onboarding
36
+
37
+ Ask the user for the required fields **one batch at a time** (don't drip out one field per turn — copy-paste-friendly):
38
+
39
+ ```
40
+ - First name
41
+ - Last name
42
+ - Date of birth (YYYY-MM-DD)
43
+ - Country of residence (ISO 3166-1 alpha-2, e.g. US, GB, DE)
44
+ - Country of nationality (same format)
45
+ - Phone country code (numeric, e.g. 1 for US, 44 for UK)
46
+ - Phone number (digits only)
47
+ ```
48
+
49
+ `mp user retrieve --json` may give you their email and name already — use that to pre-fill if available, but always read back to the user for confirmation.
50
+
51
+ Then call:
52
+
53
+ ```bash
54
+ mp card onboarding start \
55
+ --firstName "<first>" \
56
+ --lastName "<last>" \
57
+ --dateOfBirth "<YYYY-MM-DD>" \
58
+ --countryOfResidence "<XX>" \
59
+ --countryOfNationality "<XX>" \
60
+ --phoneCountryCode <code> \
61
+ --phoneNumber "<digits>"
62
+ ```
63
+
64
+ Returns a Veriff KYC session URL. Surface it to the user with a click-through call to action ("Open this URL to complete identity verification: …"). The user opens it in their browser, completes Veriff's webcam + ID flow, comes back.
65
+
66
+ `mp card onboarding start` is **idempotent** — safe to call again with the same fields if the user lost the URL or the session expired. It just returns a fresh URL.
67
+
68
+ ## Step 2 — Poll for KYC verification
69
+
70
+ After the user comes back, run:
71
+
72
+ ```bash
73
+ mp card onboarding check --json
74
+ ```
75
+
76
+ Three things can come back:
77
+ - Still pending → `veriffUrl` again, no `terms` block. Tell the user Veriff hasn't reported back yet, wait 30s, re-check.
78
+ - **Rejected** → check response will indicate failed status. Direct the user to retry the Veriff session (a fresh `mp card onboarding start` returns a new URL).
79
+ - **Verified** → response contains a `terms` block. Jump to Step 3.
80
+
81
+ Don't auto-poll in a tight loop — KYC takes minutes, not seconds. One check, surface status, ask the user to nudge you again when they're done.
82
+
83
+ ## Step 3 — Show terms, collect address, finalize
84
+
85
+ The `check` response contains live URLs Baanx records consent against. **Never hardcode legal URLs** — fetch them fresh each time and surface them to the user:
86
+
87
+ ```
88
+ terms.termsAndConditions — Baanx Terms of Service
89
+ terms.privacyPolicy — Privacy Policy
90
+ terms.eSignConsentDisclosure — US-only E-Sign Act Disclosure
91
+ ```
92
+
93
+ Show all three URLs to the user. Ask them to open each, read, and confirm they accept. Don't paraphrase the legal text — the URLs the user sees must match what Baanx records consent against.
94
+
95
+ Then ask for shipping/billing address:
96
+ ```
97
+ - Address line 1
98
+ - Address line 2 (optional)
99
+ - City
100
+ - ZIP / postal code
101
+ ```
102
+
103
+ Then finalize:
104
+
105
+ ```bash
106
+ mp card onboarding finish \
107
+ --addressLine1 "<address>" \
108
+ --addressLine2 "<line2 or omit>" \
109
+ --city "<city>" \
110
+ --zip "<zip>" \
111
+ --acceptTerms true \
112
+ --acceptESign true # only for US residents; omit otherwise
113
+ ```
114
+
115
+ On success, the user has a Baanx-issued virtual card. `mp card retrieve` now works. Move to Step 4.
116
+
117
+ ## Step 4 — Delegate a Solana wallet
118
+
119
+ The card pulls USDC from a Solana wallet the user explicitly delegates. Two things to collect:
120
+
121
+ 1. **Which local wallet** — `mp wallet list` to see options. Most users have one (e.g. `main`). If they don't, run `mp wallet create --name main --chain solana` first.
122
+ 2. **Spending cap** — the on-chain `approve` amount. User-controlled. Recommend `500` for a starter cap; they can re-link with a higher cap later. **Don't suggest unlimited** — the cap is the blast radius if Baanx is ever compromised.
123
+
124
+ ```bash
125
+ mp card wallet link --wallet <name> --currency USDC --amount <cap>
126
+ ```
127
+
128
+ This runs the 4-step dance locally: builds an SPL Approve tx, signs + broadcasts, fetches a fresh token+nonce from Baanx, signs the SIWS ownership message, registers with Baanx. The user sees the tx in their Solana wallet history.
129
+
130
+ On success, `mp card wallet list` shows the delegation. The user is fully onboarded.
131
+
132
+ ## Wrap-up
133
+
134
+ Tell the user they're done and what's possible now:
135
+
136
+ > "You're set. Your MoonAgents Card is live with `$<cap>` delegated from your `<wallet>` Solana wallet. Tap the **Start shopping** button on the MoonAgents Card artifact whenever you want to spend it — it'll route through me and the **moonpay-card-checkout** skill."
137
+
138
+ ## Important rules
139
+
140
+ - **Never hardcode the Veriff URL or legal URLs** — always fetch fresh from `mp card onboarding check`
141
+ - **Never auto-accept terms** — the user must see all three URLs and explicitly agree
142
+ - **Never suggest an unlimited delegation cap** — the cap is the loss ceiling if anything goes wrong
143
+ - **Never store the user's PII anywhere** — once you've passed it to `mp card onboarding start/finish`, drop it
144
+ - **Idempotency**: `mp card onboarding start` and `finish` are safe to retry with the same arguments — useful when sessions time out
145
+
146
+ ## Related
147
+
148
+ - **moonpay-card-checkout** — runs purchases once onboarding is done. Routes back here if state regresses (e.g., delegation expired).
149
+ - **moon-agents-card** (Artifact) — visual state. Shows "Get started" / "Delegate wallet" / ready states based on what `mp card retrieve` + `mp card wallet list` return.
150
+ - **moonpay-auth** — if `mp` isn't logged in, the user needs to handle that first.
@@ -0,0 +1,157 @@
1
+ ---
2
+ name: moonpay-skill-builder
3
+ description: Author new agent skills for the MoonPay Agents app. Use when the user wants to teach the agent a new workflow, encode a procedure they keep repeating, or wrap a CLI sequence as a single invokable skill. Skills are markdown files with YAML frontmatter that both Claude Code and Codex pick up natively. This skill defines the contract, the save location, and how to write skills that don't suck.
4
+ ---
5
+
6
+ # MoonPay Skill Builder
7
+
8
+ A skill is a markdown file the agent reads when it decides the user's request matches the skill's description. It's not a function call — it's an instruction set the agent follows. Used well, skills turn a 12-step chat into one prompt; used badly, they're just untested documentation.
9
+
10
+ This skill is how new skills get authored.
11
+
12
+ ## When to use this skill
13
+
14
+ - The user has a procedure they've walked the agent through more than twice.
15
+ - The user wants to share an agent workflow with their team.
16
+ - The user wants to wrap a `mp` CLI command sequence (or any other tool sequence) as a single invocable thing.
17
+
18
+ Don't use this skill for one-off requests or things that are already a single `mp` command — those don't need a skill.
19
+
20
+ ## On-disk format
21
+
22
+ A skill is a directory. The directory name is the skill slug (kebab-case, must match the frontmatter `name`).
23
+
24
+ ```
25
+ <slug>/
26
+ ├── SKILL.md # Required. Frontmatter + body.
27
+ ├── scripts/ # Optional. Helper scripts the skill body calls.
28
+ ├── references/ # Optional. Long-form docs the body links to.
29
+ └── templates/ # Optional. Reference files the agent can read or copy.
30
+ ```
31
+
32
+ Only `SKILL.md` is required. Most useful skills stop there.
33
+
34
+ ### `SKILL.md` frontmatter
35
+
36
+ Both Claude Code and Codex are strict — only **two fields** are portable across both engines:
37
+
38
+ ```yaml
39
+ ---
40
+ name: my-skill-slug
41
+ description: One paragraph explaining (a) WHEN the agent should invoke this skill, and (b) WHAT it does. The description is the matching surface — write it like a router, not a summary.
42
+ ---
43
+ ```
44
+
45
+ | key | required | notes |
46
+ |---|---|---|
47
+ | `name` | required | kebab-case slug, matches the directory name |
48
+ | `description` | required | The matching text. See "Writing the description" below — this is the highest-leverage part of the skill |
49
+
50
+ **Do not add other fields** (`tags`, `category`, `version`, `author`, etc). Codex's docs explicitly state "Do not include any other fields in YAML frontmatter." Claude has its own optional fields (`allowed-tools`, `disable-model-invocation`, `model`, `effort`, `paths`, etc.) but those are Claude-specific — using them breaks portability.
51
+
52
+ For app-side metadata that the MoonPay Agents app might want (filter chips, icons, etc.), the app derives those from the skill's filesystem location, not from frontmatter. Built-in skills come from the plugin path; user-authored skills come from `.agents/skills/`. No metadata required from the skill itself.
53
+
54
+ ### Save location
55
+
56
+ Write user-authored skills here:
57
+
58
+ ```
59
+ ~/.moonpay-agents/.agents/skills/<slug>/SKILL.md
60
+ ```
61
+
62
+ (The `.agents/skills/` path is Codex-native. The MoonPay Agents app symlinks `.claude/skills` → `.agents/skills` on startup so Claude Code picks them up too.)
63
+
64
+ Built-in MoonPay skills live under `~/.moonpay-agents/plugins/moonpay/skills/` and are managed by `mp plugin install/update` — don't write there.
65
+
66
+ ## Writing the description
67
+
68
+ The description is the only thing the agent sees when deciding whether to invoke your skill. Write it like routing logic, not like documentation.
69
+
70
+ **Good** (specific triggers, concrete verbs, says what it does):
71
+ > Trade on Polymarket — search markets, buy/sell outcome shares, track positions and PnL. Use when the user names Polymarket explicitly, or wants politics, crypto, news, or general-events markets.
72
+
73
+ **Bad** (vague, no trigger words):
74
+ > Helps with prediction markets.
75
+
76
+ **Bad** (says what NOT to do without saying what to do):
77
+ > Don't use for Kalshi. Don't use for sports betting. Don't use for…
78
+
79
+ A good description answers two questions in one paragraph:
80
+ 1. **When should the agent pick this skill?** (Specific triggers, user phrases, concrete situations.)
81
+ 2. **What will the agent do once it picks it?** (One verb-led sentence: "search…, buy/sell…, track…")
82
+
83
+ If your description doesn't have at least two trigger phrases the user would actually say, rewrite it.
84
+
85
+ ## Writing the body
86
+
87
+ The body is what the agent reads after picking the skill. It's read-only context, not executable — the agent decides what to actually do based on what the body says.
88
+
89
+ ### Structure that works
90
+
91
+ ```markdown
92
+ # <Skill Title>
93
+
94
+ One sentence: what this skill does and the one thing it's good for.
95
+
96
+ ## When to use
97
+
98
+ Bullet list of concrete situations. Be specific. "When the user mentions X" beats "When relevant."
99
+
100
+ ## Setup (if any)
101
+
102
+ Commands to run once before the skill's main flow. Skip the section entirely if there's no setup.
103
+
104
+ ## The flow
105
+
106
+ Numbered steps. Each step:
107
+ - States the goal of the step in one line
108
+ - Shows the exact command(s) with example argv
109
+ - Says what to surface to the user between steps
110
+
111
+ ## Important rules
112
+
113
+ Bullets of must / never. Use these for things that look optional but aren't (e.g. "Always pass --json", "Never click Pay Now").
114
+
115
+ ## Related
116
+
117
+ Links to other skills the agent should bounce to.
118
+ ```
119
+
120
+ ### Body rules
121
+
122
+ - **Write commands literally**, with realistic example arguments. The agent will copy-paste them. `mp wallet list` is useful; `mp <whatever wallet command>` is not.
123
+ - **Don't paraphrase tool output.** If the skill processes the output of `mp foo --json`, name the actual fields (`data.items[0].balance`, not "the balance field").
124
+ - **Surface intermediate state to the user.** Between steps, the agent should tell the user what just happened in one line. Write that line in the skill body so the agent doesn't have to invent it.
125
+ - **Pause for confirmation before irreversible actions** — send money, sign tx, push to remote, click Pay. Spell out the pause in the body.
126
+ - **Bail to another skill** if pre-flight fails. Example: `moonpay-card-checkout` bails to `moonpay-card-onboarding` if there's no card yet.
127
+
128
+ ### Body anti-patterns
129
+
130
+ - **"This skill is helpful for…"** — that's the description's job. The body is for the agent, not the user.
131
+ - **Explaining concepts at length.** If you find yourself writing two paragraphs of background, move it to `references/<topic>.md` and link to it.
132
+ - **Branching trees.** If the skill has 6 if/else paths, it's probably 2 skills.
133
+ - **No examples.** Every command needs at least one concrete example argv.
134
+
135
+ ## Authoring flow (what the agent should do)
136
+
137
+ When the user invokes you:
138
+
139
+ 1. **Ask what the skill should do** — one paragraph from the user describing the workflow, including the triggers ("when I say X").
140
+ 2. **Propose the slug + description back to the user** for confirmation. The description is the highest-leverage part; don't move past this until the user says yes.
141
+ 3. **Draft the body** following the structure above. Use real `mp` commands where possible — search `mp --help` if you're unsure.
142
+ 4. **Save** to `~/.moonpay-agents/.agents/skills/<slug>/SKILL.md` (create the directory if needed).
143
+ 5. **Show the user the saved path** and remind them they may need to restart the chat for the agent to pick up the new skill.
144
+
145
+ ## Common pitfalls
146
+
147
+ - **Skill is too broad.** "moonpay-helper" with description "helps with MoonPay stuff" will never be selected reliably. Each skill should do one thing.
148
+ - **Skill is too narrow.** "moonpay-buy-eth-on-monday" should just be an automation, not a skill.
149
+ - **Skill description is the same as an existing skill.** Run `mp skill list` first; if there's overlap, edit the existing skill instead of adding a new one.
150
+ - **Skill calls `mp` commands that don't exist.** Run them in a shell first to confirm flags + output shape.
151
+ - **Skill body is a wall of prose.** The agent will read it, but the user won't review it. Keep it tight.
152
+
153
+ ## Related
154
+
155
+ - **moonpay-artifact-builder** — sibling skill for authoring HTML artifacts (the visual side; this one is the procedural side).
156
+ - **moonpay-automation-builder** — sibling skill for scheduling existing skills on a cron.
157
+ - **`mp skill list`** — see what's already installed before authoring a new one.