Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Consolidate the machine-interface contract — global wire conventions, authentication, idempotency, versioning, endpoint catalogue with request/response shapes, event registry, and evolution policy under stable `EP-name` and `EVT-name` IDs. Use when asked to produce an INTERFACES.md, design machine interfaces, document HTTP and event contracts, define wire formats and event schemas, or consolidate API style, endpoints, events, and evolution policy into one artifact.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-08 | ✗→✓ | ▲ Improved | 311% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 342% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 386% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 541% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 542% | 0% |
Produce an INTERFACES.md that serves as the single source of truth for how independently-developed components communicate across machine boundaries: HTTP endpoints, events, and the wire-level conventions that govern both. The document merges what older guidance often split across separate wire-format, API-style, event-registry, and evolution-policy documents, because those four are always read together by the same downstream agents. For every boundary it pins the field-casing, timestamp, ID, enum, null-versus-missing, pagination, filtering, and error-response conventions; names the authentication scheme and idempotency semantics; declares the versioning strategy; catalogues every endpoint under a stable EP-name with exact request/response shapes and the error codes it may emit (cited to ERRORS.md, never inlined); catalogues every event under a stable EVT-name with producer, consumers, delivery guarantee, and payload schema; and commits an evolution policy with compatibility promises and deprecation windows.
INTERFACES.md is the document that decides when code, tests, and other artifacts disagree about the wire. Downstream readers include every IA (for the endpoints and events they realise), /data, /behavior, /security, /quality, /operations, every boundary-touching per-unit /SPEC.md, every /code-review, and /system-verification. The defining discipline — and the commonest failure — is every endpoint and event entry is self-sufficient: an agent implementing either side of the boundary can produce compatible serialisation/deserialisation code from a single entry, without opening another file.
EVT-name from DOMAIN § 7; every endpoint's vocabulary must use glossary canonical forms.WEB_IA.md, CLI_IA.md, MOBILE_IA.md, TUI_IA.md, VOICE_IA.md. Each IA enumerates the EP-name it invokes; every such citation must match an endpoint entry in § 6.EP-name and EVT-name is permanent. New endpoints and events take new unused IDs. Retired IDs remain with (retired) markers.Read set size: 2 required + up to 5 surface IAs + optional existing sources. Read all required inputs and all IAs in scope end-to-end. Truncated reads cause silent contract drift.
Interface-contract construction proceeds in seven phases: boundary identification, global convention extraction, auth/idempotency/versioning policy, endpoint catalogue, event catalogue, evolution policy, validation. Phases are sequential; revisit earlier phases if a later phase reveals an inconsistency.
Enumerate every machine boundary in the system. A boundary exists wherever:
For each boundary capture: descriptive name (Server API ↔ Client, Server ↔ Git Engine, Worker ↔ Message Bus), components on each side (from ARCHITECTURE.md), native casing on each side (the language-native convention — snake_case for Rust, camelCase for TypeScript), and coverage status (new | partially documented in ARCHITECTURE.md | fully documented elsewhere; if fully documented, the row cites the location and the boundary does not repeat the documentation).
Boundaries already fully documented elsewhere appear in § 1's table with a pointer — never re-documented below. The document fills gaps.
For each boundary (or for the system as a whole if conventions are uniform), pin the defaults that apply to every endpoint and event unless explicitly overridden. § 2 carries one subsection per boundary covering every dimension in the Rules section below: field casing on the wire, timestamp format, ID format, enum representation, numeric types and JS safe-range, nullability convention, empty-array-vs-missing, pagination (cursor or offset; default and max page size), filtering and sorting query-parameter conventions, and the canonical error response shape.
The canonical error response shape is pinned in this document (the wire shape is INTERFACES' concern); error codes are cited by string from ERRORS.md (never inlined). State the shape once; every endpoint's error responses conform to it.
A per-endpoint override is legitimate when an external standard governs (OAuth2 endpoints use snake_case per RFC 6749) or when a legacy endpoint predates a convention change (explicitly noted with a deprecation plan). Every override appears both in § 2 (as an exception) and in the endpoint's § 6 entry.
§ 3 Authentication — per boundary: scheme (bearer JWT, session cookie, mTLS, HMAC-signed request, API key), token shape and issuer (JWT issued by IdentityService, 15-min TTL), scope vocabulary (repo:read, repo:write, admin:*), refresh flow if applicable, and the list of endpoints that are explicitly unauthenticated (if any — listed by EP-name).
§ 4 Idempotency — which HTTP methods are idempotent by convention (GET, PUT, DELETE). The idempotency-key header name (Idempotency-Key), accepted formats (ULID, UUID), storage duration (e.g., 15 minutes post-completion), and replay semantics (server returns the stored response for replays within the window; rejects replays with divergent bodies with a specific error code cited from ERRORS.md).
§ 5 Versioning — the chosen strategy: URL path (/v1/...), version header (Api-Version: 2026-04-19), or additive-only (no version identifier; new fields always allowed). State the deprecation signals: Sunset and Deprecation response headers, a docs URL, and the advance-notice window per change class (detailed in § 8). Cite ADR-NN from ARCHITECTURE.md when the decision was architectural.
§ 6 is the endpoint registry. For each endpoint produce one block following the template in references/endpoint-template.md. Read that file and apply it verbatim — field order, heading level, bullet labels, and JSON fence style are the contract that downstream agents parse.
Assignment rules:
EP-{action} in kebab-case naming the action, not the URL path (EP-push-create, EP-repo-read, EP-user-list). Once assigned, the ID is permanent. Retired endpoints keep their ID with a (retired — superseded by EP-{name}) marker in § 6.EP-name alphabetically.UC-NN from USE_CASES.md (via DOMAIN.md). Orphan endpoints reveal either an unneeded endpoint or a missing use case — surface as an open question.ERR_CODE values by string; every cited code must exist in ERRORS.md. Never inline error bodies — the canonical shape lives in § 2, the code registry in ERRORS.md.EVT-names; the events themselves live in § 7.§ 7 is the event registry. If the system uses no events at all (pure request/response), § 7 reads exactly: No events — the system is request/response only. and the events: frontmatter count is 0.
Otherwise, for each event produce one block following the event template in references/endpoint-template.md verbatim. Assignment rules:
EVT-push-accepted, EVT-order-placed, EVT-subscription-renewed). Commands (EVT-place-order, EVT-charge-customer) are forbidden — commands belong to endpoint requests or BEHAVIOR.md.schema-version header; state the current version in the block and the evolution rules (additive-only within a version; breaking change requires EVT-{name}-v2).§ 8 pins the promises the system makes to consumers. Four subsections:
Deprecation and Sunset headers on every affected response from announcement through sunset.ui_message_key mappings changed (per ERRORS.md § 6).Cite ADR-NN where the evolution policy references an architectural decision.
Before finalising, verify:
(tbd), no (n/a) except where the template explicitly permits (none).UC-NN.Events emitted: bullet appears in § 7.EVT-name that also appears in DOMAIN.md § 7 has a matching name (no drift).serde, rename_all, @JsonProperty, Jackson, Gson, Pydantic, validator, zod, io-ts).boundaries, endpoints, events, open_questions.Update frontmatter. status is complete if § 10 reads All questions resolved., has_open_questions otherwise.
These rules govern the output. Violations are detected by the quality checklist.
An agent implementing either side of the boundary must produce compatible code from the entry alone — no inference, no cross-referencing another file except for the ERRORS.md code definitions. Every field carries its wire type, required/optional status, and a one-line description.
EP-name and EVT-name are assigned once and never renumbered, never reused, never silently deleted. Retired IDs remain with (retired — superseded by {new-id}) markers. The IDs outlive regenerations; quotes do not.
The JSON in endpoint and event bodies shows the casing as it travels on the wire, regardless of the language-native casing on either side. If Rust's native snake_case becomes camelCase on the wire, the block shows camelCase. The language-native form is an implementation detail.
Every endpoint lists ERR_CODE values from ERRORS.md. Never inline the message, never restate the HTTP status-to-meaning mapping. The canonical error response shape lives in § 2; the code registry in ERRORS.md. An endpoint entry that enumerates inline error bodies is a rule violation.
When existing type definitions disagree (TypeScript interfaces say userId, Rust structs say user_id, OpenAPI spec says uid), the agent does not silently pick one. The conflict becomes a question in § 10 with options, tradeoffs, and a recommendation. Silent resolution is exactly the failure INTERFACES.md exists to prevent.
No "use serde rename_all = camelCase", no "use @JsonProperty", no "generate with OpenAPI code-gen", no library names, no decorator syntax. INTERFACES.md specifies the wire contract; SPECs specify how each unit implements it.
When a handler receives one shape and emits a different shape (server between client and internal service), both shapes appear in the entry and the transformation is named. Implicit reshaping causes contract drift.
§ 2 pins the defaults; every override appears both in § 2 (as a named exception with rationale) and in the overriding endpoint's § 6 entry. An endpoint that silently diverges from the boundary convention is a bug, not a feature.
EP-push-create, not EP-POST-v1-repos-repoId-push. Action-named IDs survive URL restructuring; path-named IDs churn with every versioning change.
EVT-push-accepted, not EVT-accept-push or EVT-push-accept. Commands (present-tense or imperative) belong to endpoints or BEHAVIOR.md. An imperative event name is a modelling error.
A reader agent cannot open files to resolve ambiguity. Prefer inlining a type note in every field (string — required. ULID format.) over cross-referencing a "types glossary" elsewhere. Duplication of type semantics across entries is acceptable; ambiguity is not.
INTERFACES is about the wire. Domain glossary stays in DOMAIN.md (never restate entity definitions here). Persistence schema stays in DATA.md (never name tables or columns here). UI layouts stay in IAs (never describe how a toast is rendered here). Cross-endpoint orchestration (sagas, state machines) stays in BEHAVIOR.md.
One YAML block at the top with skill, date, status, boundaries, endpoints, events, error_shape_references, open_questions. Never two blocks. Counts match the body exactly.
No "appropriate", "relevant", "as needed", "etc.", "various", "and so on". Use exact IDs, exact field names, exact types, exact HTTP statuses. Unresolvable ambiguity surfaces in § 10 Open Questions.
The per-endpoint block template in § 6 and per-event block template in § 7 are defined in references/endpoint-template.md. The agent must read that file and apply the templates verbatim. Do not paraphrase, do not reorder bullets, do not drop fields.
markdown--- skill: INTERFACES.md date: {YYYY-MM-DD} status: {complete | has_open_questions | blocked} boundaries: {N} endpoints: {N} events: {N} error_shape_references: ERRORS.md open_questions: {N} --- # INTERFACES — {ProductName} > Consolidated machine-interface contract. Every HTTP endpoint, every event, > every wire-level convention, and the evolution policy live here. Downstream > artifacts cite endpoints and events by stable `EP-name` / `EVT-name` IDs. > Error code definitions live in ERRORS.md; this document pins the shape of > error responses and lists which codes each endpoint may emit. ## § 1. Overview & Boundaries | Boundary | Components | Native casing (each side) | Wire casing | Endpoints | Events | Coverage | |----------|-----------|---------------------------|-------------|-----------|--------|----------| | `{boundary name}` | `{Component A}` ↔ `{Component B}` | `snake_case` / `camelCase` | `camelCase` | `{N}` | `{N}` | `new` / `partial (see ARCHITECTURE § X)` / `external (see {path})` | (One row per boundary. Boundaries fully documented elsewhere cite the location and are not re-documented in §§ 6–7.) --- ## § 2. Global Wire Conventions ### `{boundary name}` - **Field casing:** `camelCase` on the wire; servers receive / emit `camelCase` regardless of native representation. - **Timestamp format:** ISO 8601 with timezone, always UTC (`2026-04-19T09:00:00Z`). Numeric epochs are forbidden. - **ID format:** `{kind}` — ULID 26 chars / UUIDv4 / prefixed (`repo_abc123...`). State the format once; every ID-typed field conforms. - **Enum representation:** `lowercase-string` — e.g., `"active"`, `"archived"`. Numeric enums forbidden. - **Numeric types:** integers are JSON `number` and stay within JS safe range (`< 2^53`); larger integers travel as `string`. Decimals name their precision and scale. - **Nullability:** absence of a field means unknown; explicit `null` means "known to be none". State which convention this boundary uses and apply it uniformly. - **Empty arrays vs missing:** empty `[]` means "queried; no items found"; missing field means "not queried / not applicable". - **Pagination:** cursor-based (`cursor`, `limit`; max `limit` = `100`, default `20`). Response carries `nextCursor` (or absent when exhausted). - **Filtering and sorting:** query params `filter[field]=value` and `sort=field` or `sort=-field` for descending. Multiple sort keys comma-separated. - **Error response shape:** every non-2xx response carries the § 2 error shape (field names follow this boundary's wire casing — the example below shows camelCase; snake_case boundaries use `request_id`, `docs_url`): ```json { "code": "string — required. UPPER_SNAKE code from ERRORS.md.", "message": "string — required. Human-readable developer-facing English summary.", "details": "object — optional. Structured payload; schema per code.", "requestId": "string — required. Correlation id.", "docsUrl": "string — optional. Link to docs for this code." } ``` Code-to-meaning mapping lives in ERRORS.md § 3. (Repeat for each boundary. If all boundaries share conventions, one subsection named `All boundaries` is sufficient.) --- ## § 3. Authentication Model ### `{boundary name}` - **Scheme:** `{Bearer JWT | session cookie | mTLS | HMAC-signed request | API key}` - **Token shape:** `{e.g., JWT issued by IdentityService, RS256, 15-min TTL, claims: sub, scopes, iat, exp}` - **Scopes:** `{enumerate — "repo:read", "repo:write", "admin:*"}` - **Refresh:** `{refresh endpoint EP-name or "clients re-authenticate on expiry"}` - **Unauthenticated endpoints:** `EP-{name}`, `EP-{name}` — or `(none)`. (Repeat per boundary.) --- ## § 4. Idempotency - **Idempotent methods (convention):** `GET`, `PUT`, `DELETE`. - **Idempotency-Key header:** `Idempotency-Key` — ULID or UUID accepted. - **Retention window:** `{15 minutes post-completion}` — during this window a replay returns the stored response. - **Replay semantics:** identical body within window → stored response replayed; divergent body within window → `{ERR_CODE_FROM_ERRORS_MD}` (`409`). - **Non-idempotent endpoints:** `POST` endpoints without idempotency keys are safe to retry only after reading the response; state per-endpoint in § 6. --- ## § 5. Versioning - **Strategy:** `{URL path /v1/... | Api-Version header (date) | additive-only}`. See `ADR-{NN}` in ARCHITECTURE.md. - **Current version:** `{v1 | 2026-04-19}`. - **Deprecation signals:** `Deprecation: true` header on affected responses; `Sunset: <date>` header names the removal date; `Link: <docs-url>; rel="deprecation"` points to migration docs. - **Advance notice:** per change class — see § 8. --- ## § 6. Endpoints (One subsection per boundary. Within each boundary, one block per endpoint, sorted alphabetically by `EP-name`. Each block follows the template in `references/endpoint-template.md` verbatim.) ### Boundary: `{boundary name}` {Endpoint blocks per template, one after another.} --- ## § 7. Events (Either the fixed sentence below or one block per event following the template in `references/endpoint-template.md`. Sort alphabetically by `EVT-name`.) `{If none: "No events — the system is request/response only."}` {Otherwise: event blocks per template.} --- ## § 8. Evolution Policy ### Compatibility promise - We will never rename an existing wire field. - We will never change the type of an existing wire field. - We will never remove a field, endpoint, or event without a deprecation cycle per the timeline below. - We will never narrow an enum's values without a deprecation cycle. - Adding optional fields, new endpoints, and new events is always allowed. ### Change classes - **Additive** — new optional fields, new endpoints, new events, new enum values at the *wide* end. Allowed any release. - **Compatible** — loosening a constraint, widening an enum with a default-branch contract. Allowed with release notes. - **Breaking** — removals, renames, narrowings, type changes, status-code changes for existing meanings. Requires the deprecation cycle below. ### Deprecation timeline - **Additive:** immediate. - **Compatible:** ship in the next minor release with RELEASE_NOTES entry. - **Breaking:** minimum `{6 months}` advance notice. From announcement, every affected response carries `Deprecation: true` and `Sunset: <date>`. Sunset date is no earlier than announcement + window. ### Migration guidance - **Additive:** none required. - **Compatible:** update type definitions to accept the new shape; no runtime change. - **Breaking:** update callers to the replacement `EP-name` / `EVT-name`; update switch statements keyed on enum values; adjust retry logic if idempotency semantics differ; refresh UI templates if error `ui_message_key` mappings changed (per ERRORS.md § 6). --- ## § 9. Relationship to Other Artifacts - **DOMAIN.md** owns the ubiquitous language. Every term used in this document is defined there. Every `EVT-name` that also appears in DOMAIN § 7 must match exactly. - **ARCHITECTURE.md** owns components and boundaries. Boundaries in § 1 trace to architecture boundaries; transformation points trace to architecture data-flow sections. - **IAs** (`WEB_IA.md`, `CLI_IA.md`, `MOBILE_IA.md`, `TUI_IA.md`, `VOICE_IA.md`) cite `EP-name` for the endpoints they invoke and `EVT-name` for the events they subscribe to. Every such citation maps to a block here. - **ERRORS.md** owns the error-code registry; this document owns the error response *shape* (§ 2) and the per-endpoint *code citations* (§ 6). - **DATA.md** owns persistence schemas — this document never names tables or columns. - **BEHAVIOR.md** owns state machines and saga-level sequencing across multiple endpoints — this document owns only per-endpoint contracts. - **SECURITY.md** maps `THREAT-NN` entries to endpoints and events where relevant; endpoints cite threat refs via their authentication bullet where material. - **QUALITY.md** owns metric and SLO catalogues; this document does not name metrics. - **SPECs** for boundary-touching units cite the exact `EP-name` they implement and must use the field names from this document verbatim. --- ## § 10. Open Questions - [ ] {Question — e.g., "`EP-repo-read` response includes both `createdAt` (camelCase, ISO 8601) in the spec and `created_at` (snake_case, epoch seconds) in existing Rust types. Which is authoritative for the public boundary?"} - **Option A:** camelCase ISO 8601 — matches § 2 global convention; requires Rust-side transformation. - **Option B:** snake_case epoch — matches current implementation; violates § 2; requires spec exception. - **Recommendation:** Option A; transformation is already required at the boundary for other fields, so adding one field does not change implementation complexity materially. (If none: "All questions resolved.")
EP-name IDs and full per-endpoint blocks (request/response shapes, auth, idempotency, error code citations, events emitted, transformation notes, rate limits)EVT-name IDs and full per-event blocks (kind, producer, consumers, delivery guarantee, ordering, payload, headers, version, evolution rules)/errors. This document pins the shape in § 2 and cites codes in § 6./domain./data./behavior./spec./security./quality./operations./use-cases.skill, date, status, boundaries, endpoints, events, error_shape_references, open_questions)references/endpoint-template.md verbatim — every bullet populated, no blanksEP-name is kebab-case and names the action (EP-push-create), not the URL pathUC-NNResponse errors: lists only ERR_CODE citations (no inline bodies, no status-to-meaning mappings)Events emitted: lists EVT-name values from § 7 — or (none)No events — the system is request/response only. or contains event blocks following the template verbatimEVT-name is kebab-case and past-tense, naming a state change (EVT-push-accepted, never EVT-place-order)EVT-name that appears in DOMAIN.md § 7 matches exactlyserde, rename_all, @JsonProperty, Jackson, Gson, Pydantic, validator, zod, io-ts, openapi-generator)page, screen, button, modal, toast, dashboard)table, column, index, migration, primary key, foreign key)EP-name / EVT-name entries retain their row with (retired — superseded by {new-id}) markersboundaries, endpoints, eventsstatus is complete if § 10 is "All questions resolved." and has_open_questions otherwiseINTERFACES_{context}.md with an INTERFACES_INDEX.mdOther measured skills in the registry, with their headline benchmark lift.