API Skill Builder — bootstrap a vendor-API CLI + Claude skill with AI-safety baked in
This skill takes you from "I want to drive the <X> REST API safely from a Claude session" to a published alpha that:
- never lets the AI read the API credential,
- classifies every endpoint into a six-tier risk taxonomy and refuses to send a mutation without the matching operator-supplied flag,
- stores the credential in the strongest OS-native secret store available, with file fallback at mode
0600, - writes an append-only audit log of every mutation,
- ships with cross-platform installers, MIT license, full doc set, CI, issue/discussion templates, and a tracked project-memory layer.
The canonical reference implementation is linode-api-skill at https://github.com/aditya-m-bharadwaj/linode-api-skill. Whenever this skill says "mirror the pattern", read the corresponding file there and adapt it. Do not invent variations of the safety contract — copy it.
Hard rules (non-negotiable for every generated skill)
When you generate a new <vendor>-api-skill repo, the resulting tool MUST satisfy all of these. If a target API makes one of them impossible (e.g. mandatory query-string auth), surface the conflict to the operator and stop — do not silently weaken the contract.
- The API credential never enters the AI's context. Not via env, not via
cat, not via argv, not via dialog stdout the AI can see. Entry path is<bin> setup(TTY-only, hidden prompt) or<bin> gui-setup(native OS password dialog, AI-runnable but renders out-of-band of any pipe the AI reads). - Storage is OS-native first, file fallback at mode
0600only. macOS Keychain → Linux Secret Service (libsecret) → file at~/.<vendor>-api-skill/token(mode0600, refuses to read if broader). Single-string-secret backends only — if the vendor uses a key+secret pair, store the pair as one URL-encoded or JSON blob in one keystore entry. - Verify before store. A new credential is validated against a known-good read endpoint (
whoami-equivalent for the API) BEFORE replacing whatever is already in the keystore. A bad credential never overwrites a working one. - Six-tier safety classifier with required-flag matrix. Every mutation passes through
classify(method, path)which returns one of:read,mutating,destructive,billable,financial,privilege. The CLI itself enforces the required flags; the matrix is the same aslinode-api-skill's. Unrecognized endpoints fall through to the strictest applicable default (GET → read, DELETE → destructive, anything else → mutating). - Append-only audit log of every mutation.
~/.<vendor>-api-skill/audit.log, mode0600, one JSON line per mutation, with timestamp / user / action / target / parameter metadata — never the token, never request body values, never generated secrets. - Path / argument hardening. Validate paths against a tight regex; reject
../.traversal segments and URL-encoded%-sequences pre-classification. Refuse--body @filepaths that resolve inside the config dir. Strip a leading API-version prefix (e.g./v4,/v3) at the boundary if the docs canonically include it. - Stdlib-only Python, single file.
bin/<vendor>-api-skillis one Python 3.8+ file using only the stdlib. Norequests, noclick, nopydantic, nokeyring. This eliminates supply-chain risk on a privileged tool. - Every mutation needs human confirmation in chat AND the machine
--yesflag.--yesalone is never enough; the AI must obtain explicit human confirmation in chat before sending. - MIT license, AI-authorship disclosure, commit-trailer convention.
AUTHORS.mddiscloses the model that wrote the code. Commits carryPrompted-By: <operator>+Co-Authored-By: <model>trailers. Seelinode-api-skill/CONTRIBUTING.mdfor the exact format. - Threat model documented.
SECURITY.mdlists what the tool defends and what it does NOT defend; reporting goes through GitHub private security advisories.
The build process
Follow these steps in order. Do not skip "in-flight" steps to land a partial alpha — the safety contract is most useful when complete.
Step 0 — Confirm scope with the operator
Before writing code, agree on:
- API name and slug. Slug is
<vendor>-api-skill(kebab-case, no doubling). Used as the binary name, repo name, and Claude skillname:field. - Auth model. Bearer token?
apikey+secretpair? OAuth? HMAC-signed requests? This shapes the token storage andgui-setupflow. - API base URL and version. e.g.
https://api.linode.com/v4,https://api.porkbun.com/api/json/v3, etc. Note whether the canonical docs paths include the version segment (you'll want to strip it at the boundary if so — see_strip_v4inlinode-api-skill). - The "billable" endpoints. Which paths cost real money when called? Get a list from the operator or the vendor's pricing page. These are the ones that need
--i-understand-billing. - The "financial" and "privilege" prefixes (if any). Some APIs don't have these tiers — that's fine; leave the prefix lists empty.
Step 1 — Init the repo
mkdir ~/Code/<slug>
cd ~/Code/<slug>
git init -b main
Drop in the LICENSE (MIT, copyright "<slug> contributors"), .gitignore (mirror linode-api-skill), and the dir skeleton:
.claude/
├── skills/<slug>/SKILL.md ← the runtime skill (will be authored after the CLI exists)
├── commands/{resume,save}.md ← project-level slash commands
└── settings.json ← graphify PreToolUse hook (installed by `graphify claude install`)
.github/
├── workflows/{ci,codeql}.yml
├── ISSUE_TEMPLATE/{bug_report,feature_request,config}.{md,yml}
├── DISCUSSION_TEMPLATE/{q-and-a,ideas,show-and-tell}.yml
└── FUNDING.yml
bin/<slug> ← the CLI (Python 3.8+, stdlib only)
tests/test_classify.py ← offline classifier tests
docs/
├── README.md
├── progress/{TEMPLATE.md,YYYY-MM-DD-initial-alpha.md}
├── decisions/{TEMPLATE.md,NNNN-*.md}
└── settings.local.json.template ← harness deny-rules template
install.sh
install.ps1
AUTHORS.md
CHANGELOG.md
CLAUDE.md
CONTRIBUTING.md
LICENSE
README.md
SECURITY.md
Step 2 — Design the safety classifier
Author the classifier table in bin/<slug> with five collections (mirror linode-api-skill line ~620+):
_FINANCIAL_PREFIXES— tuple of path prefixes under which any non-GET isfinancial. Leave empty()if the API has no money-movement endpoints._PRIVILEGE_PREFIXES— tuple of path prefixes under which any non-GET isprivilege(token/user/oauth management)._BILLABLE_EXACT— set of(METHOD, normalized_path)tuples that allocate a paid resource._MUTATING_EXACT— set of(METHOD, normalized_path)for explicitly-mutating-but-free endpoints (clearer than relying on the default)._DESTRUCTIVE_EXACT— optional, for non-DELETE destructive endpoints (e.g.POST /…/disable).
Implement _normalize_path(path) — strips the API-version prefix if applicable, then maps numeric segments to {id} for table lookup. Implement classify(method, path) returning (tier, [required_flags], explanation).
Test the classifier offline for every entry. Cross-check each _BILLABLE_EXACT entry against the vendor's pricing page — over-cautious is safe; under-cautious is dangerous.
Step 3 — Implement token storage
Mirror the storage layer from linode-api-skill (look for _kc_get_macos, _kc_set_macos, _kc_get_linux, _file_get, _file_set):
- macOS:
security add-generic-password -U(in-place update, no delete-then-add race). - Linux:
secret-tool store/secret-tool lookup(libsecret). Falls through to file if not present. - Windows / fallback: file at
~/.<slug>/token, mode0600. Refuse to read if POSIX mode is broader than0600.
For multi-part credentials (apikey + secret), serialize as one JSON blob before storage so each backend stays a single