api-docs-complete
Skill2 starsChanged 41 days agoMITView on GitHub
Finish an API docblock that already has its happy path — find the status codes the endpoint can ACTUALLY return but that never appear in the handler's body (401 from auth middleware, 429 from a throttle, 403 from an authorization layer, 422 from validation, 500 from the catch-all), and document each with a body captured from a real run rather than invented. Invoke with /api-docs-complete right after annotating a new or changed endpoint, when asked to \"finish the API docs\" or \"check the docs are complete\", or before regenerating generated API reference. Tool-agnostic — Scribe, OpenAPI/Swagger annotations, FastAPI, drf-spectacular. Restraint-gated: an endpoint that genuinely only returns 200 and 401 is complete at two responses; never pad with codes it cannot emit.
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 4 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 66
Write a throwaway test that hits each case, dump the real response, read it, then delete the test:
- Distinctive: line 93
Document a second success response whenever the shape meaningfully varies: an empty collection, a "not entitled" state, a branch returning …
- Distinctive: line 121
inline one level of same-class helpers: before scanning for statuses, or the check is blind to exactly the delegation described in step 3.
- Distinctive: line 123
Keep it honest about its ceiling: it cannot see middleware, guards or validation.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
/api-docs-complete — the responses your first pass didn't write
Writing the 200 is the easy part, and everyone does it. What gets shipped undocumented is everything else — and it is not laziness, it is that the missing codes are not visible where you'd look for them.
This skill runs after a docblock exists. It does not teach annotation syntax — your codebase already has examples. It finds what the first pass left out.
Why a linter or grep can't do this for you
Grep the handler for 4\d\d and you find the codes the method returns itself. The ones that actually break clients come from somewhere else entirely:
| Code | Where it really comes from | Why grepping the handler misses it |
401 | auth middleware on the route/group | It's route config, not method code |
429 | a rate-limit / throttle middleware | Same — and usually inherited from a group, so it isn't even on the route line |
403 | an authorization layer: policy, guard object, decorator | Thrown a call or two away, often in a shared service |
404 | route-model binding, findOrFail, "not yours" branches | Framework-thrown before your code runs |
422 | schema/request validation | Thrown, never returned — no status literal exists anywhere |
500 | the catch-all that flattens unexpected errors | The status is computed, not written |
A static check can enforce "every endpoint has at least one response". It cannot enforce "this endpoint documents the 429 it inherits from a middleware group three files away". That gap is the entire reason to run a checklist.
Real example: a careful hand-written pass produced 77 response examples across 12 endpoints — 200/201, 401, 403, 404, 422, 500, and a domain-specific 402. Every endpoint still missed 429, because the throttle was inherited from a framework-level middleware group and appeared nowhere near the controller. The checklist caught it; the author hadn't.
The pass
1. Read the route definition, not just the handler
Find where the endpoint is registered, and read what's wrapped around it:
- auth middleware →
401is reachable. Always. - throttle / rate-limit middleware →
429is reachable. Check the group too, not just the route: throttles are usually inherited and invisible at the route line. - route-model binding (a typed model parameter) →
404before your code runs. - any other middleware that can short-circuit — maintenance mode, signature verification, tenancy.
2. Walk the handler for what it emits directly
List every exit:
- each error-response helper call — note the status AND any machine-readable error code it carries. That
error/codekey is what clients branch on; a status alone isn't enough. - each explicit response-with-status construction
- each validation call → a
422 - each
abort/throw/guard clause - the final catch → what does it return when something unexpected blows up?
3. Follow the calls that can throw
The step that catches what step 2 misses. For every collaborator the handler calls, ask "can this raise an HTTP status?":
- authorization guards / policies →
403 - domain services raising validation errors →
422 - anything doing a fetch-or-fail →
404 - payment, quota or entitlement checks →
402and friends
If a helper method inside the same class returns a response, its statuses belong on the endpoint too. This is the most-missed case after middleware — a handler that delegates "is the wallet short?" to a private helper looks, to any body-scoped search, like it can only return 200.
4. Capture the real bodies — never hand-write them
Do not invent response JSON. Envelopes differ per project, per base class, and sometimes per middleware. A wrong example is worse than no example: the client codes against it and fails in production.
Write a throwaway test that hits each case, dump the real response, read it, then delete the test:
function dumpShape(label, response):
print("===== {label} [{response.status}] =====")
print(pretty_json(response.body))
test "capture shapes":
dumpShape("401", GET /endpoint) # before authenticating
authenticate_as(user)
dumpShape("200", GET /endpoint)
dumpShape("422", POST /endpoint, {}) # empty/invalid body
dumpShape("403", GET /endpoint?target=someone_elses_id)
# ...one per case found in steps 1-3This routinely catches envelope surprises. Two seen in practice:
- an unauthenticated call returning a custom envelope, not the framework default that the existing docblocks all claimed
- a throttled
429using a different success key (success) than every other response in the same API (status) — so a client checking one field getsnullon rate-limit
Neither is findable by reading code. Both change how a client must be written.
5. Write them, with scenarios
Give each response a scenario label. It matters most where one status carries several meanings — a 422 meaning "already subscribed" is a different client branch from a 422 meaning "your input was malformed". Same code, different recovery.
Document a second success response whenever the shape meaningfully varies: an empty collection, a "not entitled" state, a branch returning a different object. The client has to handle both, so both belong in the docs.
6. Regenerate — and never hand-edit generated output
Run your generator. If the project has more than one doc target (public vs internal, v1 vs v2), pick by audience: an endpoint carrying admin-only or privileged actions does not belong in the integrator-facing set. Check the route is actually matched by that target's include rules — an unmatched route is silently absent, not an error.
7. Verify the generated output, not just the source
Do not trust that what you wrote is what got generated. Annotation blocks are parsed loosely; a malformed one frequently produces wrong output rather than an error.
Seen in practice: a bulk edit inserted a new response block one line off, nesting it inside the previous block's scenario string. The generator emitted a duplicate of the earlier status and dropped the new one — silently, exit code 0. It was only caught by diffing the generated status codes before and after.
So after regenerating, read back the status codes per endpoint from the generated artifact and confirm they match what you intended:
for each endpoint in generated_output:
print(endpoint.method, endpoint.uri, sorted(unique(r.status for r in endpoint.responses)))Counts alone are not enough — a corrupted block can keep the total steady while changing which codes are present.
Pair it with a floor check
A checklist is a human pass and doesn't run in CI. If the project can carry one, add a cheap test that fails when an endpoint has no response example at all, and when a status the handler visibly emits is undocumented. That catches the obvious regressions for everyone, whether or not they run this skill.
Two things worth building into such a test:
- attribute per endpoint, not across the API. A union check ("some endpoint documents 402") lets one endpoint's documented status mask a sibling that emits the same status and documented nothing.
- inline one level of same-class helpers before scanning for statuses, or the check is blind to exactly the delegation described in step 3.
Keep it honest about its ceiling: it cannot see middleware, guards or validation. Those stay this skill's job.
Restraint
Some endpoints really are complete at two responses. A public read that can only succeed or fail auth needs 200 + 401 and nothing else. Do not add a 403 to an endpoint with no authorization, or a 422 to one that takes no input. Padding docs with codes the endpoint cannot emit teaches clients to write dead branches, and trains the reader to stop trusting the docs.
Checklist
401— behind auth middleware?429— any throttle on the route or its group?403— any policy, guard, or authorization service in the call path?404— route-model binding, fetch-or-fail, or a "not found / not yours" branch?422— any validation, on the route or raised by a service? One per distinct error code.- domain codes (
402,409,423…) — every error-response status in the body and in the helpers it calls, each with its machine-readable error key 500— what the catch-all actually returns- a second success response per meaningfully different shape
- every body captured from a real run, not written by hand
- route matched by the right doc target, docs regenerated
- generated output read back and status codes verified per endpoint
Other versions1 project uses a version of this.
Word for word · 1
- AhmedMerza/claude-skills★ 2100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository53 other files it gives its agents.
- animateSkill
- best-optionSkill
- browseSkill
- changelog-generateSkill
- checkpointSkill
- claimSkill
- commitSkill
- courtSkill
- design-driftSkill
- designSkill
- expandSkill
- explainSkill
- fix-reviewSkill
- grill-meSkill
- handover-listSkill
- handover-resumeSkill
- handover-saveSkill
- i18n-syncSkill
- issueSkill
- leadSkill
- mr-approveSkill
- mr-assignSkill
- mr-createSkill
- mr-guideSkill
- mr-listSkill
- mr-mergeSkill
- mr-review-requestSkill
- mr-reviewSkill
- mr-statusSkill
- persona-walkthroughSkill
- ponytailSkill
- prove-the-testSkill
- qa-crawlSkill
- qa-sweepSkill
- reflectSkill
- reviewSkill
- root-causeSkill
- scoutSkill
- second-opinionSkill
- ship-checkSkill
- skill-auditSkill
- skill-compareSkill
- spinoffSkill
- story-siteSkill
- tool-compareSkill
- ui-auditSkill
- ui-polishSkill
- usage-weekSkill
- ux-auditSkill
- validate-planSkill
- video-teardownSkill
- wait-whatSkill
- where-were-weSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

