oc-api-dev — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited oc-api-dev (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
On first invocation, read `references/orchestrator.md` and follow its welcome protocol.
Tri-agent first-party API harness: Designer authors the contract (OpenAPI / GraphQL schema) → Builder scaffolds typed handlers, validation, and an SDK against it → Conformance hits the running server, validates responses against the spec, and diffs the new spec against the previously-shipped one to flag undeclared breaking changes.
This is the producer-side counterpart to oc-integrations-engineer. If you're consuming someone else's API (Stripe, Slack, Salesforce, OAuth providers), use oc-integrations-engineer. If you're designing/building the API your own clients, customers, or partners consume, use this skill.
API DEVELOPER COMMANDS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TRI-AGENT HARNESS
/oc-api design Author the API contract (Designer agent)
/oc-api build Scaffold + conformance loop (Builder → Conformance)
/oc-api test Run Conformance against an existing server
AUTHOR
/oc-api spec Generate / update OpenAPI or GraphQL schema from data model
/oc-api scaffold Generate typed handlers + validation middleware from spec
/oc-api lint Run spectral / redocly lint on the spec
LIFECYCLE
/oc-api version Plan a new version (URL or header strategy)
/oc-api deprecate Mark endpoints deprecated; emit Sunset/Deprecation headers
/oc-api docs Render human-readable docs from the spec
/oc-api sdk Generate TypeScript / Python / Go SDK from the spec
UTILITIES
/oc-api list Show all endpoints with version + deprecation status
/oc-api drift Compare spec to running code; report mismatches
/checkpoint Show checkpoint status
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Type any command to begin. /oc-api to see this again.API DESIGN INTENT
(from oc-app-architect 02-architecture.md API Design section)
│
▼
┌──────────────────┐
│ API │ Authors contract: OpenAPI / GraphQL schema.
│ DESIGNER │ Decides versioning, pagination, error envelope,
│ │ idempotency, rate-limit policy declarations.
└────────┬─────────┘
│
▼
┌──────────────────────────────────────────────┐
│ BUILD LOOP (per API surface) │
│ │
│ ┌────────────┐ contract ┌─────────────┐ │
│ │ API │◄─negotiate──►│ API │ │
│ │ BUILDER │ │ CONFORMANCE │ │
│ │ │──code──────►│ │ │
│ │ Scaffolds │ │ Hits live │ │
│ │ handlers │◄──failures──│ server + │ │
│ │ + SDK │ │ diffs spec │ │
│ └────────────┘ └─────────────┘ │
│ │ │ │
│ │ All checks pass? │ │
│ └───────────────────────────┘ │
└──────────────────────────────────────────────┘
│
└──► Drift monitoring (ongoing)the code, they "agree" because nothing forces disagreement. In practice handlers drift from OpenAPI within hours: a field gets renamed, an optional becomes required, an enum gains a value. Conformance hits the running server with schema-validating fuzz and asserts response shapes match the published spec.
backwards-compatible" without checking that removing nullability on a response field is a breaking change for consumers. Conformance diffs the new spec against the previously-shipped one and labels every change (additive / behavior / breaking) per the taxonomy in references/versioning-and-deprecation.md.
the spec; that doesn't prove the SDK round-trips successfully against the running server. Conformance runs an end-to-end SDK call for each operation.
/oc-api design)The Designer is a senior API architect who has shipped public APIs to thousands of consumers. Key behaviors:
03-data-model.md (or the ORM schema if itexists) and design resources around the actual entities, not invented ones.
"REST-ish but with one GraphQL endpoint over here." Mixed styles double the surface area.
controls end-to-end. For external consumers, opaque cursors (see references/pagination-and-filtering.md).
status code. Don't ship two error shapes.
every POST/PATCH/DELETE that mutates state. See references/error-and-idempotency.md.
/v1/) or header(API-Version: 2026-04-27) before shipping the first endpoint. Adding versioning retroactively is a migration project.
02-architecture.md API Design section, 03-data-model.md,oc-stack-forge's chosen framework + typed-pipeline tooling, oc-reverse-spec inventory (if retrofitting).
api/openapi.yaml (or api/schema.graphql) and present for approval.openapi: 3.1.0
info:
title: [Project] API
version: '1'
description: |
Versioning: URL-based (/v1/, /v2/). Sunset headers on deprecation.
Errors: RFC 9457 problem+json. Pagination: opaque cursor.
servers:
- url: https://oc-api.example.com/v1
security:
- bearerAuth: []
paths:
/widgets:
get:
operationId: listWidgets
parameters:
- { in: query, name: cursor, schema: { type: string } }
- { in: query, name: limit, schema: { type: integer, default: 50, maximum: 200 } }
responses:
'200':
description: Page of widgets
content:
application/json:
schema:
$ref: '#/components/schemas/WidgetPage'
default: { $ref: '#/components/responses/Problem' }
post:
operationId: createWidget
parameters:
- { in: header, name: Idempotency-Key, required: true, schema: { type: string } }
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/WidgetCreate' }
responses:
'201':
description: Created
content:
application/json:
schema: { $ref: '#/components/schemas/Widget' }
default: { $ref: '#/components/responses/Problem' }
components:
securitySchemes:
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
schemas:
Widget:
type: object
required: [id, name, created_at]
properties:
id: { type: string, format: uuid }
name: { type: string }
created_at: { type: string, format: date-time }
WidgetCreate:
type: object
required: [name]
properties:
name: { type: string, minLength: 1, maxLength: 200 }
WidgetPage:
type: object
required: [data]
properties:
data: { type: array, items: { $ref: '#/components/schemas/Widget' } }
next_cursor: { type: [string, 'null'] }
Problem:
type: object
required: [type, title, status]
properties:
type: { type: string, format: uri }
title: { type: string }
status: { type: integer }
detail: { type: string }
instance: { type: string }
responses:
Problem:
description: Error response (RFC 9457)
content:
application/problem+json:
schema: { $ref: '#/components/schemas/Problem' }Present the spec. Confirm resources, auth, error envelope, pagination shape, and versioning strategy with the user. Write checkpoint: phase designed.
/oc-api build)Builder proposes:
## API Build Contract
### Deliverables
- Typed handlers per operationId, generated from the OpenAPI spec
- Request validation middleware (Zod / Pydantic / equivalent for chosen stack)
- RFC 9457 problem+json error formatter applied uniformly
- Idempotency-Key middleware backed by KV / Redis (24h TTL by default)
- Generated SDK (TypeScript via openapi-typescript + openapi-fetch)
- Reference docs (Redoc or Stoplight Elements) at /docs
### Testable Criteria
1. Every operationId has a handler and a request-validation test
2. Every error path returns problem+json with correct `type` URI and `status`
3. Repeated POST with the same Idempotency-Key returns the original response
4. Generated SDK round-trips against the live server for every operation
5. `spectral lint` and `openapi-diff` (vs previous version) report no errorsConformance reviews and pushes back if:
Builder reads the chosen stack from oc-stack-forge's checkpoint and uses the typed-pipeline tooling that oc-stack-forge already recommended:
| Stack (from oc-stack-forge) | Spec authoring | Server validation | SDK generation |
|---|---|---|---|
| Hono + D1 + Workers | @hono/zod-openapi (Zod → OpenAPI) | Hono middleware | openapi-typescript + openapi-fetch |
| FastAPI + Postgres | Pydantic → built-in OpenAPI | FastAPI middleware | openapi-typescript |
| Django + DRF | drf-spectacular | DRF serializers | openapi-typescript |
| Express / Fastify + TS | zod-to-openapi | Zod middleware | openapi-typescript |
| Rails | rswag | Rails strong params | openapi-typescript |
Don't reinvent the toolchain. Read oc-stack-forge/references/typed-pipeline.md for detailed implementation per stack and pick from that menu.
Conformance has isolated context — it reads the spec and runs against the live server without seeing the Builder's implementation choices.
Conformance Persona. A QA engineer who specialises in API contract testing. Key behaviors:
every response against the OpenAPI schema. Mocks are forbidden in this phase.
openapi-diff <prev> <new> — any breaking change must bedeclared (new major version, or explicit Sunset on the old endpoint).
live server and assert the typed response matches.
response must be valid problem+json with the correct type and status.
The second response must be byte-identical to the first.
spectral lint with the project's ruleset must pass clean.Conformance Report saved to api/conformance-round-M.md:
## API Conformance — Round [M]
### Spec → Code Drift
| Operation | Spec status codes | Code status codes | Drift? |
|---|---|---|---|
| listWidgets | 200, 4xx, 5xx | 200, 4xx, 5xx | None |
| createWidget | 201, 4xx, 5xx | 200, 4xx, 5xx | DRIFT — code returns 200 |
### Spec Diff vs Previous Version
- Additive: 2 (new optional fields on Widget)
- Behavior: 0
- Breaking: 1 — `WidgetPage.next_cursor` nullability changed
### SDK Round-Trip
| Operation | SDK call | Response valid | Latency |
|---|---|---|---|
| listWidgets | PASS | PASS | 47ms |
| createWidget | FAIL | — | — |
### Error Envelope
| Status | Triggered? | problem+json valid? |
|---|---|---|
| 400 | Yes | PASS |
| 422 | Yes | FAIL — missing `type` URI |
### Idempotency
| Operation | Repeat returns same body | Status |
|---|---|---|
| createWidget | Yes | PASS |
### Lint
- spectral: 0 errors, 2 warnings
- openapi-diff: 1 breaking change UNDECLARED
### Verdict: PASS / FAIL
[If FAIL: specific failures for Builder to fix]oc-monitoring-ops, hand off to oc-deploy-ops.
Max iterations: 3.
/oc-api version — plan a new versionRead references/versioning-and-deprecation.md. Pick URL (/v2/) or header (API-Version: 2026-04-27) — match what's already in production; never mix. Output: a new spec file (api/v2/openapi.yaml) plus a migration guide template under api/migrations/v1-to-v2.md.
/oc-api deprecate — mark endpoints deprecatedFor each deprecated endpoint:
deprecated: true in the spec.Deprecation: <date> (RFC 9745) and Sunset: <date> (RFC 8594) responseheaders.
Link header pointing at the migration guide.api/deprecations.md with the sunset date,the replacement endpoint, and the consumer-notification plan.
/oc-api docs — render human-readable docsDefault: Redoc, served at /docs from the spec file. The Builder must wire the docs route during scaffolding so the rendered docs are always in sync with the shipped spec.
/oc-api sdk — generate SDKTypeScript via openapi-typescript + openapi-fetch is the default; other languages on request. SDK version tracks the API version (v1.x SDK ↔ /v1 API). Publish to a registry only after Conformance round-trip passes.
/oc-api drift — code-vs-spec drift reportRun between commits, in CI, or on demand. Outputs:
oc-deploy-ops gates production deploys on this command returning zero drift.
| Concern | Owner | Why |
|---|---|---|
| OAuth flow / API-key handling for consuming a third-party | oc-integrations-engineer | Consumer side |
| Webhook receivers tied to a single integration | oc-integrations-engineer | Lives only because of that third-party |
| Stack/framework recommendation, typed-pipeline tooling | oc-stack-forge | Recommends; oc-api-dev materialises |
Discovery-level "API design" intent in 02-architecture.md | oc-app-architect Phase 2 | Intent; oc-api-dev elaborates |
| Rate-limit infrastructure and capacity math | oc-scale-ops | oc-api-dev declares the policy in the spec; oc-scale-ops sizes / implements |
| Threat model of the API surface | oc-security-auditor | oc-api-dev emits the surface; oc-security-auditor reviews |
| Per-endpoint SLO implementation + alert pipelines | oc-monitoring-ops | oc-api-dev emits SLO targets + drift-rule manifest; oc-monitoring-ops wires alerts |
| Secret rotation procedures | oc-integrations-engineer /oc-integrate secrets | Already owned |
oc-api-dev's outputs (rate-limit policy, CORS policy, SLO targets, drift manifest) are declarations in the spec. Sibling skills implement them.
oc-stack-forge ships a pack per language under skills/oc-stack-forge/packs/<id>/pack.yml declaring the canonical testRunner, buildCmd, lintCmd, and a langRef. oc-api-dev's Builder phase reads the build-time codegen output src/generated/api-dev-adapters.json to template the right commands into the generated scaffolds.
The codegen runs in prebuild after gen-stack-packs (so the pack contract is already validated) and before gen-flags. Adding a new language pack auto-extends oc-api-dev — no oc-api-dev code changes needed once the pack lands.
{
"id": "python",
"displayName": "Python",
"status": "stable",
"testRunner": "pytest",
"buildCmd": "python -m build",
"lintCmd": "ruff check .",
"langRef": "language.md"
}status: stable → the adapter is on by default (the coverage flag skills.coverage.<id>.enabled defaults to true). beta / experimental / deprecated packs still appear in the adapter list but are gated by the flag.
oc-api-dev's Builder writes generated source — test stubs, mock servers, CI config fragments. Those need the test/build commands templated in, not looked up at runtime. Codegen produces a stable JSON artifact oc-api-dev can import once and template across many files in one Builder pass. (oc-deploy-ops takes the opposite trade-off — runtime read, because it makes a single dispatch decision per deploy. See oc-deploy-ops/SKILL.md § Pack-aware dispatch.)
api-dev-adapters.json lagsthe packs/ tree. Builder generates scaffolds for the previously-committed baseline. CI catches this via tests/api-dev-adapters.test.js snapshot.
gen-stack-packs fails first;gen-api-dev-adapters never runs. Builder never sees a partial adapter set.
Frameworks and mobile packs are out of oc-api-dev's surface (frameworks pick up the same language adapter; mobile dispatches through oc-stack-forge's release-checklist path, not oc-api-dev).
{project-dir}/.checkpoints/oc-api-dev.checkpoint.json
| Event | What to Save |
|---|---|
| Contract authored | Style (REST/GraphQL), versioning strategy, auth, operation count |
| Build contract negotiated | Deliverables, criteria, chosen toolchain |
| Builder completes | Files generated, SDK published version, docs URL |
| Conformance runs | Per-operation pass/fail, spec diff classification, lint results |
| Version planned | New version number, breaking changes list, sunset dates |
| Endpoint deprecated | Operation, deprecation date, sunset date, replacement |
{
"style": "rest+openapi3.1",
"versioning": "url",
"current_version": "v1",
"auth": "bearer-jwt",
"operations": 14,
"spec_path": "api/openapi.yaml",
"sdk": { "language": "typescript", "version": "1.3.0" },
"last_conformance": {
"round": 2,
"verdict": "PASS",
"drift_operations": 0,
"spec_diff": { "additive": 1, "behavior": 0, "breaking": 0 }
},
"deprecations": [
{ "operation": "listWidgetsLegacy", "sunset": "2026-10-01" }
]
}| Reads from | Why |
|---|---|
| oc-app-architect | 02-architecture.md API Design + 03-data-model.md → discovery baseline |
| oc-stack-forge | Chosen framework + typed-pipeline tooling |
| oc-reverse-spec | Existing-endpoint inventory when retrofitting |
| oc-integrations-engineer | 04-integrations.md carve-outs (inbound webhook receivers stay there) |
| Read by | Why |
|---|---|
| oc-code-auditor | Audits scaffolded handlers against the spec |
| oc-security-auditor | Reads CORS + rate-limit policy as posture inputs |
| oc-monitoring-ops | Ingests SLO targets + drift-alert manifest |
| oc-deploy-ops | Drift gate — oc-api-dev /oc-api drift must report zero before prod |
| oc-integrations-engineer | When a sibling app integrates this API, the published spec is the source of truth |
API changes have ripple effects: SDK consumers need lead time on breaking changes; deprecations need calendar visibility; spec drift is a deploy-blocker. v1.2 routes those signals through the PM tool so they're not buried in a checkpoint. See oc-integrations-engineer for the canonical PM-MCP patterns.
When /oc-api version proposes a major-version bump (or /oc-api lint detects a breaking change in a non-major version), file:
list of breaking endpoints + migration guide.
surface. Consumer registry comes from .opchain/api-consumers.yaml if present, or from the SDK download / API-key telemetry if oc-monitoring-ops is wired.
Each consumer ticket has the suggested upgrade path + the deadline matching the deprecation policy in .opchain/pm.yaml (deprecation_lead_time: 90d etc.).
When /oc-api deprecate <endpoint> is invoked:
the PM-MCP) noting the deprecation date.
sunset date with the cleanup checklist.
sunset date, oc-monitoring-ops opens an incident ticket parent-linked to the deprecation reminder.
/oc-api drift is a oc-deploy-ops pre-condition. When drift is detected:
implementation diverge in {endpoint}. Deploy gate will refuse until reconciled.`
api-drift-labelled bug-typedchild ticket if it persists across a re-run (one-shot drifts often resolve in the next commit; persistent drift gets a ticket).
When /oc-api sdk produces a new SDK release, post a comment on every linked PM ticket that contributed to the version: SDK {language} v{version} released; includes your change ({endpoint}).
.opchain/api-consumers.yaml → skip the per-consumer fan-out;parent ticket only.
parent ticket only with a query link rather than commenting on each.
fan-out by default; opt-in via /oc-api version --pm-broadcast.
truth. Generate types and SDK from it. Don't write them by hand and hope they agree.
against a live process, not a unit test. Mocks ≠ real.
double the surface area for consumers.
operations." Every POST/PATCH/DELETE.
a new major version with Sunset headers and a migration guide.
SLO targets live in the spec. Sibling skills (oc-scale-ops, oc-monitoring-ops) implement the runtime.
isn't done. Round-trip the SDK against the live server.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.