zod-openapi/SKILL.md
Designs a REST API contract using zod-openapi v5 as the schema-first source of truth. Activate when the user says "Generate a OpenAPI document" or specifically wants as output a document in the OpenAPI specification
npx skillsauth add sanurb/skills zod-openapiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill produces one atomic REST API contract for a new or changed HTTP surface. Good APIs are boring, WE DO NOT BREAK USERSPACE, and zod-openapi keeps the schema-first source of truth in Zod while createDocument emits the OpenAPI contract. Use it only when the project already uses zod-openapi as the contract layer.
GlobalMeta extends ZodOpenApiMetadata, register every reusable component with .meta({ id }), model branded IDs, separate input from output schemas, and include the reusable ProblemDetails schema.application/problem+json for every 4xx/5xx, keep title static per error class, put dynamic context in detail, and wire HTTP Retry-After plus retry_after on 429 and 503.createDocument. Read references/zod-openapi-patterns.md. Compose the ZodOpenApiObject with openapi: '3.1.0', info, components.securitySchemes.bearerAuth, security, and paths built from requestParams, requestBody, and responses; include rate-limit headers in response headers; then produce the final Output artifact.Deliver nothing if ANY criterion fails.
application/problem+json.type URI MUST resolve to a url documentation.title; dynamic context goes in detail only.instance MUST be unique per occurrence.errors array of { field, message, code }.Retry-After and the retry_after body field.error_code and error_name MUST come from a central catalog.Idempotency-Key via requestParams.header; DELETE by resource ID MUST NOT require it.next_page or nextCursor.RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset headers.Authorization: Bearer <key> through components.securitySchemes.bearerAuth; OAuth MAY layer on top.?include=<field>.extendZodWithOpenApi and the .openapi() runtime extension (both removed in v5) are forbidden. Metadata flows through native Zod .meta() only.GlobalMeta extends ZodOpenApiMetadata via declare module 'zod/v4' once per module graph..meta({ id: 'Name' }); hand-written $ref strings and implicit __schemaN names are forbidden.z.lazy schema MUST declare an explicit .meta({ id }).z.transform in output schemas is forbidden; use .pipe(), .overwrite(), or manual .meta({ override }).createDocument MUST be the single entry point; hand-written OpenAPI YAML and direct oas31.OpenAPIObject construction are forbidden.openapi: MUST be '3.1.0' or newer unless a concrete downstream constraint requires 3.0.x; if 3.0.x is used, the generator file MUST document why inline.content: { 'application/problem+json': { schema: ProblemDetails } }, and ProblemDetails MUST register via .meta({ id: 'ProblemDetails' }).requestParams: { path | query | header | cookie }; hand-rolled parameters: [...] arrays are forbidden.Table columns: Method, Path (kebab-case plural), Purpose, Success Status, Auth Scope, Rate Limit Tier, Idempotency.
TypeScript block with import * as z from 'zod/v4';, import type { ZodOpenApiMetadata } from 'zod-openapi';, declare module 'zod/v4' { interface GlobalMeta extends ZodOpenApiMetadata {} }, every input/output/reusable schema, branded IDs, and ProblemDetails.
TypeScript block with import { createDocument } from 'zod-openapi';, import type { ZodOpenApiObject, ZodOpenApiPathsObject } from 'zod-openapi';, and a full createDocument({ openapi: '3.1.0', info, components: { schemas, securitySchemes }, security, paths }) call using requestParams, requestBody, responses, and response headers.
Table: error_code, error_name, error_category, status, retryable, owner_action_required, title, type.
One JSON block per failure mode showing the complete RFC 9457 Problem Details body emitted at runtime.
TypeScript block deriving types via z.infer<>, including the input/output split for schemas that diverge and can emit Foo / FooOutput components.
One success curl and one failure curl per endpoint. Every curl MUST include Authorization: Bearer <key>, and every success case MUST show RateLimit-* response headers.
| File | One Job | |---|---| | references/zod-openapi-patterns.md | zod-openapi v5 path modeling, requestParams, createDocument, auth, rate limits | | references/errors.md | RFC 9457 catalog rules and ProblemDetails wiring | | references/typescript-interfaces.md | GlobalMeta augmentation, branded IDs, input/output type split |
development
Sets up an `## Agent skills` block in AGENTS.md/CLAUDE.md and `docs/agents/` so the engineering skills know this repo's issue tracker (GitHub, GitLab, fp, or local markdown), triage label vocabulary, and domain doc layout. Run before first use of `fp-plan`, `fp-implement`, `fp-review`, `to-issues`, `to-prd`, `triage`, `diagnose`, `tdd`, `improve-codebase-architecture`, or `zoom-out` — or if those skills appear to be missing context about the issue tracker, triage labels, or domain docs.
development
Build a throwaway prototype to flush out a design before committing to it. Routes between two branches — a runnable terminal app for state/business-logic questions, or several radically different UI variations toggleable from one route. Use when the user wants to prototype, sanity-check a data model or state machine, mock up a UI, explore design options, or says "prototype this", "let me play with it", "try a few designs".
tools
Control herdr (a terminal-native agent multiplexer) from inside it. Manage workspaces and tabs, split panes, spawn sibling agents, read pane output, and wait for state changes — all via CLI commands that talk to the running herdr instance over a local unix socket. Use when running inside herdr (HERDR_ENV=1). Do not use outside herdr.
documentation
Compact the current conversation into a handoff document for another agent to pick up.