skill-creator
Author a new skill for the selat-skills hub and get it merged, using the
official selat skill CLI. A skill is a declarative directory the selat CLI
executes — never code that calls selat-pay itself. This is the hub's
contribution guide (CONTRIBUTING.md points here); keep
it open while you build.
When To Use
Use when someone wants to add a capability to the hub by composing one or more
paid federated-catalogue endpoints into a named skill, or asks how the
manifest/SKILL.md/evals fit together, how to find a payable endpoint, how to
verify it, or how to submit. Not for editing the CLI or router — this is skill
content only.
Workflow
The whole loop (matches CONTRIBUTING.md):
selat skill new my-skill --dir skills # 1. scaffold
# …edit the files (replace every TODO)… # 2. author
selat skill validate ./skills/my-skill # 3. static SOP check
selat skill verify ./skills/my-skill [--pay] # 4. live-402 check (THE GATE)
selat skill register ./skills/my-skill # 5. add index.json entry
npm run validate # 6. whole-repo check (what CI runs)
selat skill submit ./skills/my-skill # 7. open the PR
- Define + scaffold. One skill = one coherent capability; pick the rail
(
direct Circle nanopayment / routed MPP via the SELAT Router / mixed).
Then selat skill new <name> --dir skills writes skills/<name>/ with
manifest.json, SKILL.md, references/endpoints.md, evals/evals.json.
(No CLI handy? scripts/new-skill.mjs does the same scaffolding offline.)
- Discover endpoints in the federated catalogue and record each merchant's
serviceUrl (NOT the descriptive provider url), method, path, price.
See references/endpoint-discovery.md — this is where most skills break.
- Enrich each endpoint's schema — pin the real request shape before writing
any
body/${param}, from a free source, because a wrong param name or shape
still costs money: the SELAT Router settles the payment before the upstream
validates the body, and a verify probe checks payability, not param
correctness. Pull the gateway's OpenAPI (<serviceUrl-host>/openapi.json), decode
the self-describing bazaar schema in the 402 payment-required header, or read
the upstream's public API docs — then corroborate against the live API, which
is the real source of truth (specs drift: observed tweet_id vs live tweetId,
and "only field X required" when the live API rejects a body without more). Record
every param (name, required, type, enum, format) in references/endpoints.md and
map each manifest ${param} to the real API param name.
See references/schema-enrichment.md.
- Author — replace every
TODO:
manifest.json — name (== folder), maxAmount (cap with
headroom, a filter not a price), params (real defaults), steps[] with
url = serviceUrl + path, ${param} substitution, body for POST.
SKILL.md — frontmatter + sections (When To Use, Workflow, Inputs And
Outputs, Gotchas, Validation, References). No TODO may remain.
references/endpoints.md and evals/evals.json (skill_name == folder).
- Validate (static):
selat skill validate ./skills/<name>.
- Verify (the gate):
selat skill verify ./skills/<name> probes each step's
real 402 price/rail (free) and checks it ≤ maxAmount; --pay makes a capped
real call to confirm it settles 200. Pass required params as flags. This writes
skills/<name>/.selat/verify-receipt.json — the provenance submit attaches to
the PR and that gates merge. Fix any step that's unreachable or over cap;
prefer first-party providers over proxies.
- Register:
selat skill register ./skills/<name> auto-adds/updates the
index.json entry from the manifest.
- Whole-repo check:
npm run validate (exactly what CI runs).
- Submit:
selat skill submit ./skills/<name> (use --dry-run first). It
requires a passing verify receipt, then branches, commits skills/<name> + the
index.json entry, pushes, and opens a PR with the receipt as provenance. No
write access? It prints fork-and-PR commands. A maintainer paid-re-verifies
before merge.
Authoring Voice
A skill's reader is the agent; the agent's audience is often a non-technical
user. Author for that split:
- Command blocks are instructions for the agent to execute — never content
the user is expected to read.
- In Workflow, add a "tell the user" line wherever the agent should report
back — especially before any spend ("this costs about $X — proceed?") and
when relaying results in plain language.
- Keep endpoint URLs, wallet addresses, and raw response JSON out of what the
agent is told to relay; plain language plus the dollar price is the default.
Available Scripts
scripts/new-skill.mjs <name> [--rail …] [--kind …] [--dir skills] — offline
scaffolder equivalent to selat skill new, for environments without the CLI.
Non-interactive; --help for usage.
Inputs And Outputs
| Input |
What you provide |
| Capability |
The one task the skill performs |
| Endpoints |
Catalogue serviceUrl + path + method + price per step |
| Params |
Named inputs with sensible defaults |
Output: a skill that passes validate, has a passing verify receipt, and is
ready for submit.
Gotchas
- Wire steps to the catalogue
serviceUrl, NOT the provider url. A record
has a descriptive url (https://api.tomba.io) and a payable serviceUrl
(https://mpp.orthogonal.com/tomba). The 402 is served only at the serviceUrl;
the provider host yields "no challenge" and a failed verify.
- POST/PUT params go in
body, not the query string — a POST with ?k=v
often returns no challenge.
maxAmount is a spending filter, not the price. Set it with headroom over
the live quote (gateway prices run a few percent above the catalogue) or verify
flags the step as over-cap.
- Give params real defaults so
verify (and users) can exercise each step.
verify is the gate, and the live 402 is the source of truth. The catalogue
lists endpoints the gateway may no longer serve. Never submit a step that doesn't
verify; omit it and re-add when it's served.
- Enrich the schema from a free source before the first paid call — a wrong param
still charges. The Router settles payment before the upstream validates the
body, and a probe checks payability, not param correctness. Pin the shape from the
gateway OpenAPI (
<host>/openapi.json), the 402 bazaar extension, or upstream
docs, then confirm with verify --pay. Specs drift from the live API; the live
API wins (seen: OpenAPI tweet_id vs live tweetId; "only input required" when
the live endpoint also demands model/models/preset).
${param} substitutes as a string — no type coercion. A numeric or array field
wired as "${n}" sends "8" and 4xx's. Keep string-typed fields in the manifest
body; document integer/array fields for a hand-built selat-pay call instead.
- Prefer first-party providers over proxies when equivalent — cheaper/equal,
with real identity and recourse.
- The authoring SOP lives only at the repo root
references/agent-skill-authoring-sop.md;
don't copy it into your skill.
name == folder, kebab-case, consistent across folder, manifest.json, and
SKILL.md frontmatter; evals.json skill_name == folder too.
Validation
Before submit, all must hold:
selat skill validate ./skills/<name> → passes (also the per-skill CI check).
selat skill verify ./skills/<name> → every step reachable and ≤ maxAmount
(writes the verify receipt). --pay confirms a real settled 200.
npm run validate → 0 errors (whole-repo + index.json consistency).
- No
TODO, secrets, or orth/CLI/subprocess calls — the skill is declarative.
Underlying free single-step probe (what verify runs per step):
selat-pay POST "https://mpp.orthogonal.com/<merchant>/<path>" \
--body '{"<param>":"<value>"}' --chain base --probe-only
# success prints: detected mpp=yes, mode=routed-mpp, price=$X on eip155:8453
--chain base is only the flag the probe requires — probing reads a free,
chain-independent quote and never settles. The settlement chain for a paid run
is resolved at runtime from the wallet's funded Gateway balance, so a manifest
does not declare one.
References
CONTRIBUTING.md — repo-level quick reference that points back to this skill.
references/manifest-reference.md — selat-skill/v1 manifest schema, params, rails, examples.
references/endpoint-discovery.md — finding endpoints in the catalogue and the serviceUrl rule.
references/schema-enrichment.md — pinning each endpoint's request schema from OpenAPI / the 402 bazaar extension / upstream docs, and verifying it against the live API.
references/submission-checklist.md — the selat skill command sequence + pre-PR checklist.
../../references/agent-skill-authoring-sop.md — the authoring standard.
1---2name: skill-creator3description: Use this skill when a contributor wants to build, author, scaffold, verify, or submit a new skill to the SELAT skill hub (selat-skills) — e.g. "create a skill", "build a selat skill", "add a skill to the hub", "contribute a skill", "how do I write a manifest.json", "verify my skill", "submit my skill", "wrap an MPP endpoint as a skill". Guides you through the official `selat skill` flow (new → author → validate → verify → register → submit) and encodes the gotchas that make a skill actually pay.4license: Apache-2.05---67# skill-creator89Author a new skill for the **selat-skills** hub and get it merged, using the10official `selat skill` CLI. A skill is a declarative directory the `selat` CLI11executes — **never code that calls `selat-pay` itself**. This is the hub's12contribution guide ([`CONTRIBUTING.md`](../../CONTRIBUTING.md) points here); keep13it open while you build.1415## When To Use1617Use when someone wants to add a capability to the hub by composing one or more18paid **federated-catalogue** endpoints into a named skill, or asks how the19manifest/SKILL.md/evals fit together, how to find a payable endpoint, how to20verify it, or how to submit. Not for editing the CLI or router — this is skill21*content* only.2223## Workflow2425The whole loop (matches `CONTRIBUTING.md`):2627```bash28selat skill new my-skill --dir skills # 1. scaffold29# …edit the files (replace every TODO)… # 2. author30selat skill validate ./skills/my-skill # 3. static SOP check31selat skill verify ./skills/my-skill [--pay] # 4. live-402 check (THE GATE)32selat skill register ./skills/my-skill # 5. add index.json entry33npm run validate # 6. whole-repo check (what CI runs)34selat skill submit ./skills/my-skill # 7. open the PR35```36371. **Define + scaffold.** One skill = one coherent capability; pick the **rail**38 (`direct` Circle nanopayment / `routed` MPP via the SELAT Router / `mixed`).39 Then `selat skill new <name> --dir skills` writes `skills/<name>/` with40 `manifest.json`, `SKILL.md`, `references/endpoints.md`, `evals/evals.json`.41 (No CLI handy? `scripts/new-skill.mjs` does the same scaffolding offline.)422. **Discover endpoints** in the federated catalogue and record each merchant's43 **`serviceUrl`** (NOT the descriptive provider `url`), method, path, price.44 See `references/endpoint-discovery.md` — this is where most skills break.453. **Enrich each endpoint's schema** — pin the real request shape *before* writing46 any `body`/`${param}`, from a **free** source, because a wrong param name or shape47 still costs money: the SELAT Router settles the payment **before** the upstream48 validates the body, and a `verify` probe checks *payability, not param49 correctness*. Pull the gateway's OpenAPI (`<serviceUrl-host>/openapi.json`), decode50 the self-describing `bazaar` schema in the 402 `payment-required` header, or read51 the upstream's public API docs — then **corroborate against the live API**, which52 is the real source of truth (specs drift: observed `tweet_id` vs live `tweetId`,53 and "only field X required" when the live API rejects a body without more). Record54 every param (name, required, type, enum, format) in `references/endpoints.md` and55 map each manifest `${param}` to the real API param name.56 See `references/schema-enrichment.md`.574. **Author** — replace every `TODO`:58 - `manifest.json` — `name` (== folder), `maxAmount` (cap *with59 headroom*, a filter not a price), `params` (real defaults), `steps[]` with60 `url` = `serviceUrl` + path, `${param}` substitution, `body` for POST.61 - `SKILL.md` — frontmatter + sections (When To Use, Workflow, Inputs And62 Outputs, Gotchas, Validation, References). No `TODO` may remain.63 - `references/endpoints.md` and `evals/evals.json` (`skill_name` == folder).645. **Validate (static):** `selat skill validate ./skills/<name>`.656. **Verify (the gate):** `selat skill verify ./skills/<name>` probes each step's66 real 402 price/rail (free) and checks it ≤ `maxAmount`; `--pay` makes a capped67 real call to confirm it settles 200. Pass required params as flags. This writes68 `skills/<name>/.selat/verify-receipt.json` — the provenance `submit` attaches to69 the PR and that **gates merge**. Fix any step that's unreachable or over cap;70 prefer **first-party** providers over proxies.717. **Register:** `selat skill register ./skills/<name>` auto-adds/updates the72 `index.json` entry from the manifest.738. **Whole-repo check:** `npm run validate` (exactly what CI runs).749. **Submit:** `selat skill submit ./skills/<name>` (use `--dry-run` first). It75 requires a passing verify receipt, then branches, commits `skills/<name>` + the76 `index.json` entry, pushes, and opens a PR with the receipt as provenance. No77 write access? It prints fork-and-PR commands. A maintainer paid-re-verifies78 before merge.7980## Authoring Voice8182A skill's reader is the agent; the agent's audience is often a non-technical83user. Author for that split:8485- Command blocks are **instructions for the agent to execute** — never content86 the user is expected to read.87- In **Workflow**, add a "tell the user" line wherever the agent should report88 back — especially before any spend ("this costs about $X — proceed?") and89 when relaying results in plain language.90- Keep endpoint URLs, wallet addresses, and raw response JSON out of what the91 agent is told to relay; plain language plus the dollar price is the default.9293## Available Scripts9495- `scripts/new-skill.mjs <name> [--rail …] [--kind …] [--dir skills]` — offline96 scaffolder equivalent to `selat skill new`, for environments without the CLI.97 Non-interactive; `--help` for usage.9899## Inputs And Outputs100101| Input | What you provide |102|---|---|103| Capability | The one task the skill performs |104| Endpoints | Catalogue `serviceUrl` + path + method + price per step |105| Params | Named inputs with sensible defaults |106107Output: a skill that passes `validate`, has a passing `verify` receipt, and is108ready for `submit`.109110## Gotchas111112- **Wire steps to the catalogue `serviceUrl`, NOT the provider `url`.** A record113 has a *descriptive* `url` (`https://api.tomba.io`) and a *payable* `serviceUrl`114 (`https://mpp.orthogonal.com/tomba`). The 402 is served only at the `serviceUrl`;115 the provider host yields "no challenge" and a failed verify.116- **POST/PUT params go in `body`, not the query string** — a POST with `?k=v`117 often returns no challenge.118- **`maxAmount` is a spending filter, not the price.** Set it with headroom over119 the live quote (gateway prices run a few percent above the catalogue) or `verify`120 flags the step as over-cap.121- **Give params real defaults** so `verify` (and users) can exercise each step.122- **`verify` is the gate, and the live 402 is the source of truth.** The catalogue123 lists endpoints the gateway may no longer serve. Never submit a step that doesn't124 verify; omit it and re-add when it's served.125- **Enrich the schema from a free source before the first paid call — a wrong param126 still charges.** The Router settles payment *before* the upstream validates the127 body, and a probe checks payability, not param correctness. Pin the shape from the128 gateway OpenAPI (`<host>/openapi.json`), the 402 `bazaar` extension, or upstream129 docs, then confirm with `verify --pay`. **Specs drift from the live API; the live130 API wins** (seen: OpenAPI `tweet_id` vs live `tweetId`; "only `input` required" when131 the live endpoint also demands `model`/`models`/`preset`).132- **`${param}` substitutes as a string — no type coercion.** A numeric or array field133 wired as `"${n}"` sends `"8"` and 4xx's. Keep string-typed fields in the manifest134 `body`; document integer/array fields for a hand-built `selat-pay` call instead.135- **Prefer first-party providers over proxies** when equivalent — cheaper/equal,136 with real identity and recourse.137- **The authoring SOP lives only at the repo root** `references/agent-skill-authoring-sop.md`;138 don't copy it into your skill.139- **`name` == folder**, kebab-case, consistent across folder, `manifest.json`, and140 `SKILL.md` frontmatter; `evals.json` `skill_name` == folder too.141142## Validation143144Before `submit`, all must hold:145146- `selat skill validate ./skills/<name>` → passes (also the per-skill CI check).147- `selat skill verify ./skills/<name>` → every step reachable and ≤ `maxAmount`148 (writes the verify receipt). `--pay` confirms a real settled 200.149- `npm run validate` → 0 errors (whole-repo + `index.json` consistency).150- No `TODO`, secrets, or `orth`/CLI/`subprocess` calls — the skill is declarative.151152Underlying free single-step probe (what `verify` runs per step):153154```bash155selat-pay POST "https://mpp.orthogonal.com/<merchant>/<path>" \156 --body '{"<param>":"<value>"}' --chain base --probe-only157# success prints: detected mpp=yes, mode=routed-mpp, price=$X on eip155:8453158```159160`--chain base` is only the flag the probe requires — probing reads a free,161chain-independent quote and never settles. The settlement chain for a paid run162is resolved at runtime from the wallet's funded Gateway balance, so a manifest163does not declare one.164165## References166167- [`CONTRIBUTING.md`](../../CONTRIBUTING.md) — repo-level quick reference that points back to this skill.168- `references/manifest-reference.md` — `selat-skill/v1` manifest schema, params, rails, examples.169- `references/endpoint-discovery.md` — finding endpoints in the catalogue and the `serviceUrl` rule.170- `references/schema-enrichment.md` — pinning each endpoint's request schema from OpenAPI / the 402 `bazaar` extension / upstream docs, and verifying it against the live API.171- `references/submission-checklist.md` — the `selat skill` command sequence + pre-PR checklist.172- [`../../references/agent-skill-authoring-sop.md`](../../references/agent-skill-authoring-sop.md) — the authoring standard.