The skill.md toolkit: the format specification, a generator, and a validator that returns a fix per finding. Ships as a library, a CLI, and an x402-paid service.
| Route | Price | What lands in the 200 body |
|---|---|---|
POST /generate | $0.01 | The generated skill.md, plus a validation report for it — one call gives you a file you can commit |
GET /rules | free | The whole rule catalogue as JSON: id, severity, title and fix for each of the 23 rules |
GET /spec | free | The SKILL-MD format specification |
POST /validate | $0.002 | The full report: every finding with its rule id, line, what is wrong in this document, and the exact fix |
GET / · /health · /skill.md · /.well-known/x402 · /openapi.json | free | Discovery |
base-sepolia / baseexact · EIP-3009 transferWithAuthorization0x40252CFDF8B20Ed757D61ff157719F33Ec332402solana / solana-devnetexact · SPL transferChecked, fee sponsoredWwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwWBoth rails appear in the accepts array of every 402. Settlement runs through
the x402 facilitator, and the 200 carries an
X-PAYMENT-RESPONSE receipt naming the rail and the transaction.
# as a CLI — free, no wallet needed
npx x402-skill-md generate openapi.json -o skill.md
npx x402-skill-md validate skill.md
# PASS score 100/100 (0 errors, 0 warnings, 0 infos)
# service: x402-domains endpoints: 2 rails: evm + solana
# No findings. This document is conformant.
# as a library
npm i x402-skill-md
import { openapiToSkillMd, validateSkillMd } from "x402-skill-md";
const { skillMd, warnings } = openapiToSkillMd(spec, { baseUrl: "https://api.example.com" });
validateSkillMd(skillMd).valid; // true
validateSkillMd(skillMd).service.dualRail; // true
# in CI — exits 1 on errors
- run: npx x402-skill-md validate skill.md --strict
The file an AI agent reads to learn how to use and pay for an HTTP service — in one fetch, with no SDK and no human. It is Markdown, so a model can read it directly; it has a defined section grammar, so a parser can check it.
OpenAPI already describes shapes. It does not describe what a call costs, in what asset, on which chains, to which address — and for an agent with a wallet and no account, that is the load-bearing information. An agent has to answer three questions before it spends anything: can this service do what I need, what will it cost, and can I pay at all.
A conformant skill.md documents an EVM rail and a Solana rail — rules SM005 and SM006, both error severity. Three reasons:
accepts array. Two entries cost one extra object; the client picks. There is no protocol reason to publish one.The spec also requires the facilitator to be declared per rail, because facilitators are chain-specific: the reference x402.org facilitator settles Base Sepolia only and will not settle a Solana payment. A document naming one facilitator for both rails is telling clients something false.
A validator that only says “invalid” is not worth paying for. Every finding names the rule, where it is, what is wrong in this document, and the remedy:
{
"rule": "SM006",
"severity": "error",
"title": "No Solana payment rail documented",
"detail": "There is no Payment section, so no Solana rail is documented.",
"fix": "Name a Solana network (`solana` or `solana-devnet`) and its `payTo`
address in the Payment section. Every conformant skill.md is dual-rail:
an agent's wallet lives on one chain, and it must be able to tell from
this file alone whether it can pay."
}
23 rules: 10 errors, 10 warnings, 3 infos. valid is true when there are zero errors, independent of score; the score (100 − 12/error − 4/warning − 1/info) is a quality signal, valid is the gate.
The library is free on npm and the CLI does the same work locally, so the honest answer is: the paid routes exist for agents. An agent that has just written an OpenAPI document cannot npm install inside its own reasoning loop; it can make an HTTP request and pay a cent. Humans should use the CLI. GET /rules and GET /spec are free on both paths, because you should be able to see what you are being judged against before paying to be judged.