Help us improve
Share bugs, ideas, or general feedback.
From sdd
Derives API contracts from data models, sequence diagrams, and acceptance criteria into OpenAPI 3.1, gRPC proto, CLI, or public API docs. Runs drift checks and reconciliation.
npx claudepluginhub genkovich/sdd --plugin sddHow this skill is triggered — by the user, by Claude, or both
Slash command
/sdd:apiinheritThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Projects the upstream artifacts into one **interface contract**. By default that's an HTTP/OpenAPI contract; this skill is **interface-kind aware** — and the kind comes from the surface(s) `design` declared in `sad.md` frontmatter `target_surfaces`, **read here, not re-derived** (→ [`../_shared/surfaces.md`](../_shared/surfaces.md)). For a non-HTTP project it produces the matching contract form...
Generates OpenAPI 3.1 contracts with JSON schemas, RFC 9457 error responses, versioning, and examples from API entities, PRDs, or database schemas.
Generates OpenAPI 3.1 specs from use case interaction sequences with traceability to source steps and schema validation. For API contract design from realized use cases.
Generates OpenAPI 3.0/3.1 specs and Pact consumer contracts from API code, designs, or schemas for documentation, testing, and code gen.
Share bugs, ideas, or general feedback.
Projects the upstream artifacts into one interface contract. By default that's an HTTP/OpenAPI contract; this skill is interface-kind aware — and the kind comes from the surface(s) design declared in sad.md frontmatter target_surfaces, read here, not re-derived (→ ../_shared/surfaces.md). For a non-HTTP project it produces the matching contract form (or steps aside):
contracts/openapi.yaml (OpenAPI 3.1) + api-sync-report.md..proto (or the repo's IDL) with the same derive-and-drift discipline.contracts/cli.md — the command/flag/exit-code surface derived from the AC.contracts/public-api.md — the public signatures/types the feature exposes.contracts/events.md (no request/response surface).tasks.Whatever the form, the contract is derived from data-model.md + the sad.md §6 sequences + the spec's AC, never typed by hand — generation that diverges from the model or the sequences is the bug this skill exists to catch. The rest of this file details the HTTP path (the common case); the same derive → drift-check → reconcile loop applies to the other forms with the form-appropriate artifact.
This skill keeps only its own machinery. Question phrasing is shared → ../_shared/ask-style.md. Depth (events doc only when async; one resource vs full surface) follows the size matrix → ../_shared/size-matrix.md. The drift-resolution dialog reuses the shared 4-state actions — keep it short, point the machinery to _shared.
Backend Lead (drives the interface). The PM confirms each endpoint maps to a real user story; a frontend / consumer engineer is the first reader — the contract is locked before they start integration.
<slug> — same feature slug used by every earlier stage.docs/features/<slug>/data-model.md. It is the source of typed fields and constraints; without it the contract would be invented field-by-field. If absent → STOP and point: «run data-model <slug> first — the contract is derived from its entities».docs/features/<slug>/sad.md §6 — the Mermaid sequenceDiagram blocks. Their alt/else branches become the error responses; an async participant (<message-bus> / <external-system>) on a mutating flow marks its endpoint Idempotency-Key-required and seeds events.md. Absent → note the gap (error branches derived from spec.md §5 only — likely misses authorization branches) and still generate.docs/features/<slug>/spec.md — §4 user stories give the endpoint list; §5 acceptance criteria give the shape of each happy + error outcome. The spec deliberately holds no HTTP/status/error-code/SQL detail — that mapping is this skill's job.docs/features/<slug>/.size — depth hint. Absent → default to M (full surface). docs/features/<slug>/adr/*.md — override defaults (versioning, error format, auth scheme) when an ADR mandates it; docs/features/<slug>/CONTEXT.md — glossary terms become schema names verbatim. Existing contracts/openapi.yaml → diff and update in place, never overwrite whole-cloth.test -f docs/features/<slug>/data-model.md → fail = refuse with the pointer above. Determine the interface kind — read sad.md frontmatter target_surfaces FIRST (design already declared it; the surface picks the contract form per ../_shared/surfaces.md: backend-service → OpenAPI / gRPC / events per its sub-kind; cli → contracts/cli.md; worker → contracts/events.md; library-sdk → contracts/public-api.md; a UI surface — web-frontend / mobile-app / desktop-app — consumes the backend contract, it does not author one). Fall back to deriving the kind from docs/architecture-map.md + the spec's capabilities only if the SAD or the field is absent (a greenfield run where design was skipped). HTTP/REST → the OpenAPI path below (the default, detailed here); gRPC/CLI/library/event-only → produce the matching contract form (see the intro) with this same derive→drift→reconcile loop; no external interface (pure internal logic) → skip to tasks with a one-line note in the report. Then read data-model.md (entities, fields, types, constraints), sad.md §6 (flows + alt-branches + async actors), spec.md §4/§5. Surface a one-line "found / missing" note for sad.md and spec.md — never refuse on their absence, only narrow the derivation and record the gap../templates/openapi.yaml → docs/features/<slug>/contracts/openapi.yaml. If async flows exist, also ./templates/events.md → contracts/events.md. Fill info.description from spec.md §1 (why this API exists).data-model.md entity column — copy its constraints across (maxLength/pattern/enum from the model's bounded types). Never invent a field with no origin in any input — ask the user where it comes from. $ref every shared schema; no inline duplication. Lists paginate by cursor (?after=&before=&limit=), wrapped in {items, has_next, has_prev, next_cursor}.alt … else … end branch into a responses entry. The error body is the unified envelope {code, message, details?}; code follows the neutral convention module.error_name (snake_case, e.g. lesson.not_owned, lesson.invalid_state) — a naming rule, not a language artifact. Map status by class (4xx client / 5xx server). This closes the spec's usual blind spot — §5 lists the happy path + a couple of errors; the sequences enumerate the authorization and concurrent-state branches the spec omits.Idempotency-Key-required (state the TTL). For each async message, fill an events.md entry: event name module.action.vN, payload schema, producer, consumers, retry / dead-letter behaviour.<...>@example.test, +380 00 000 00 00, Test User) — never real PII.docs/features/<slug>/contracts/api-sync-report.md — see ./references/drift-check.md. It has a field-origins table (one row per operation.field: path | origin | confidence) and a checklist. The check runs both directions:
spec.md §5 AC maps to ≥1 operation/response; every operation maps to a §4 user story + ≥1 AC; every sad.md §6 alt-branch has a response, and any error/authorization response the contract needs but no §6 flow shows is a sequence gap. A gap here is not an api bug — it's a hole upstream: surface it and offer Fix-the-source-first, which re-opens specify (add the missing AC) or sequences (draw the missing branch) before the contract is finalized.
A core finding failing (or ≥3 flags total) pauses the run — resolve each via the shared 4-state actions (../_shared/ask-style.md): Accept-as-is / Fix-the-contract / Save-as-OQ / Fix-the-source-first. Never silently edit the sources — surface the mismatch and let the human pick the right artifact (the contract, the spec's AC, or the sequence).spectral lint contracts/openapi.yaml (add it to the project's check target if not yet wired). On a clean check, the files are written; propose commit api: <slug> contract. Then emit the stage-handoff block per ../_shared/handoff.md — What I did + Review (contracts/openapi.yaml, api-sync-report.md, + events.md if async) + Run next (/clear, then /sdd:tasks <slug>)./sdd:api <slug> --reconcile. Re-derives after an upstream artifact changed (typically data-model.md arrived or was tightened after a thinner first pass). It re-reads inputs, tightens loose types where the model now has a constraint, refreshes the field-origins confidence column, and — the load-bearing part — surfaces any field that had an inferred origin but now disagrees with the model. That disagreement is real drift, not stale incompleteness. info.version is never bumped silently; the user does that with a CHANGELOG line.
docs/features/<slug>/contracts/openapi.yaml written: OpenAPI 3.1, BearerAuth global with public endpoints declaring explicit security: [], every error response the {code, message, details?} envelope, every operation with examples, all shared types via $ref.api-sync-report.md written alongside: field-origins table + the 4-point drift checklist, every core finding ✓ or explicitly resolved with the user.data-model.md column; every error code exists in the repo's error definitions (checked in the form the repo uses).contracts/events.md present iff the feature has async flows; each event has a payload schema, producer, consumers, retry / DLQ note.data-model.md (keep it with a # stale note and surface it — the human decides).data-model.md; error codes are the neutral module.error_name convention — not a Go/TS/Python idiom and not tied to any driver's error type.{"error": "failed"}), ?v=2 query versioning, nullable: true (3.0 style — use type: [string, null]), offset pagination, or real PII in examples.design already declared it. target_surfaces in sad.md is the primary signal — read it; the architecture-map derivation is the fallback only when the SAD/field is absent (greenfield). Silently re-inferring HTTP-vs-events on every run is the double-derivation this skill's surface-awareness removes.../_shared/ask-style.md — canonical question/option phrasing for the drift-resolution dialog (step 7).../_shared/size-matrix.md — MVP (one resource, events only if async) vs Full surface depth.../_shared/surfaces.md — the declared target_surfaces (read from sad.md) pick the contract form; this skill reads, never re-derives../references/drift-check.md — the field-origins table + 4-point drift checklist, reconcile semantics, conflict table../templates/openapi.yaml — OpenAPI 3.1 scaffold: BearerAuth, cursor page wrapper, {code, message, details?} Error schema../templates/events.md — async event-contract scaffold (producer / consumers / payload / retry / DLQ).