Skip to content
Back to skills

Api Craft

ASecurity

> LLM-judgment critique of API design quality — the ceiling counterpart to rule-based API checks (OpenAPI-format compliance and webhook-format validation). A linter can confirm a path is documented and a schema validates; only judgment can tell whether the endpoint sits at the right abstraction, whether the HTTP verb is honest, whether a resource name belongs in the URL or a query param, whether a stranger could predict the response shape, and whether the error tells the consumer what to do. ...

  • 20 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 11, 2026
securityrustgonodegitapibackendsecurity

Works with

  • cursor
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add Intense-Visions/harness-engineering --skill api-craft --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Craft?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Api Craft
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/intense-visions-api-craft/badge)](https://www.skillsdirectory.com/skills/intense-visions-api-craft)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# API Craft

> LLM-judgment critique of API design quality — the ceiling counterpart to rule-based API checks (OpenAPI-format compliance and webhook-format validation). A linter can confirm a path is documented and a schema validates; only judgment can tell whether the endpoint sits at the right abstraction, whether the HTTP verb is honest, whether a resource name belongs in the URL or a query param, whether a stranger could predict the response shape, and whether the error tells the consumer what to do. Emits 3-axis findings (tier × impact × confidence per ADR 0019).

## When to Use

- During PR review on a new or substantially-changed endpoint, resource, or OpenAPI contract
- Before publishing an API (or a new resource family) to consumers, to catch design debt the format floor cannot see
- Periodically, to audit whether a growing API surface has stayed consistent (resource naming, verb use, error shapes, pagination)
- On a project's own OpenAPI/Swagger documents and route/handler definitions — the natural inputs
- As the API critic alongside copy-craft (which owns error-message prose) and the rule-based API floor (OpenAPI/webhook format compliance)
- NOT for whether a schema validates or a path is documented (that is the mechanical floor, not this skill)
- NOT for the wording of a single error string in isolation (use copy-craft — it owns prose-in-code)
- NOT for authentication/authorization vulnerabilities or injection (use security-craft and the security floor)
- NOT for autofix / contract rewriting (this is judgment-only)

## Capability Roles

<!-- Capability seam: this skill participates in a real extension point whose three roles are named and concrete. A seam with only one role filled is accidental single-implementation lock-in. See harness-skill-authoring Phase 1C. -->

- **Defines (Service Definition):** the shared craft critique contract (`packages/cli/src/shared/craft/`) — `LlmProvider` + finding/axes schema + run store — shared across all `*-craft` skills. This skill implements, and does not own, that contract.
- **Provides (Provider):** **this skill** — a API-design critique implemented over the shared contract (`packages/cli/src/api-craft/`).
- **Consumes (Consumer):** `craft-fleet` (the craft-pipeline elevation sweep) and the `harness` natural-language router, which invoke every `*-craft` provider uniformly through the shared critique/finding shape

## Process

### B' precondition check (every invocation)

api-craft is the ceiling; it runs regardless of setup, but its critique sharpens when a project declares its API conventions. Before critiquing, note the state:

| Precondition       | Source                                            | If missing                                                                                                                                                                          |
| ------------------ | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiStyleDeclared` | a project API style guide (e.g. `docs/**/API.md`) | Run with the generic seed rubrics; note in the summary that a style guide would sharpen critique and offer to seed one (progressive upgrade — the same posture as docs-craft's B'). |

When no style guide exists, api-craft still runs with the seed rubrics (degraded, not blocked). It never refuses to critique just because a project has not written its API conventions down.

### Phase 1: DISCOVER — Find API surfaces

1. **Read project configuration.** Shared craft config under `craft.llm.*` selects the judgment backend. `maxFiles` (default 60) caps the surface count.

2. **Discover the API surface.** Two kinds are collected:
   - **OpenAPI / Swagger documents** (YAML or JSON) under the project root and conventional roots (`docs`, `spec`, `specs`, `api`, `openapi`, `src`), matched by filename (`openapi.yaml`, `swagger.json`) or a root `openapi:` / `swagger:` key.
   - **Route / handler definitions** in code under the conventional roots (`src/routes`, `src/api`, `src/controllers`, `src/handlers`, `app/api`, `pages/api`, `routes`, `api`, …), included only when the file carries a route SIGNAL — a `.get(/.post(` call, an `@Get()`/`@Controller()` decorator, an exported `GET`/`POST` handler, etc. `--routes-dir` points route discovery at an explicit directory; `--spec-file` names an explicit OpenAPI document; `--files` overrides discovery entirely.

3. **Exclude non-API surfaces.** Tests / specs, type declarations, barrels and registries (`index.ts`, `_registry.ts`), build / dependency trees (`node_modules`, `dist`), and helper modules under an API root that define no endpoint are skipped — they are not authored API surfaces.

### Phase 2: CRITIQUE — Per (surface, rubric) loop, kind-filtered

9 seed rubrics, each declaring which surface kinds it applies to:

| Rubric     | Title                                              | Applies to |
| ---------- | -------------------------------------------------- | ---------- |
| `API-R001` | Resources model the domain, not the implementation | all        |
| `API-R002` | Resource naming and URL structure are predictable  | all        |
| `API-R003` | HTTP methods are honest                            | all        |
| `API-R004` | Status codes are correct and meaningful            | all        |
| `API-R005` | Error responses tell the consumer what to do       | all        |
| `API-R006` | Response shapes are predictable and consistent     | all        |
| `API-R007` | Collections paginate and filter consistently       | all        |
| `API-R008` | Mutations are idempotency-honest                   | route only |
| `API-R009` | Evolves without breaking consumers                 | all        |

For each (surface, rubric) where the rubric applies to the surface's kind:

1. Build a prompt with the rubric description + surface kind + surface source (truncated to 8000 chars for cost).
2. The LLM returns fenced JSON: `null` (rubric doesn't apply / the surface already clears the bar) OR `{ tier, impact, confidence, message }`.
3. On non-null: emit an `ApiFinding` with `cite.rubricId` populated for ADR 0020 traceability, and a derived `priority` for sorting.

Idempotency (`API-R008`) is a handler-behavior concern a declarative spec rarely captures, so it critiques `route` surfaces only; an OpenAPI document is critiqued against the other eight rubrics. This is the API analogue of cli-ergonomics-craft's leaf/group filter.

A small curated exemplar set anchors the catalog — **Stripe, Linear's GraphQL API, GitHub's REST API, Resend, and the Anthropic API** — each a public reference point for one API-quality dimension (Stripe for idempotent requests, cursor pagination, and dated versioning; Linear for domain-mirroring types; GitHub for a guessable path grammar; Resend for a right-sized resource surface; Anthropic for honest methods and a consistent error contract). The exemplars ground the rubric sources today and seed a future BENCHMARK phase, the direct analogue of docs-craft's exemplar corpus.

### Phase 3: REPORT — Aggregate + cost telemetry

Emit `ApiCraftOutput`:

```ts
{
  findings: ApiFinding[];
  summary: {
    phaseRun: ['critique'];
    mode: 'fast';
    durationMs: number;
    llmCalls: { provider, model, count, costUsd };
    catalog: { rubricsApplied: string[]; exemplarsAvailable: number };
    counts: { filesScanned, filesSkipped };
    runId: string;
  }
}
```

## Harness Integration

- **`harness api-craft`** — CLI entry. `--files <glob>` / `--routes-dir <dir>` / `--spec-file <file>` / `--exclude-dirs <dirs...>` / `--max-files <n>` / `--json` / `--verbose`. Exits non-zero when any `foundational`-tier finding is present.
- **`mcp__harness__api_craft`** — MCP tool. Two modes (see "In-session flow" below).
- **`mcp__harness__api_craft_finalize`** — MCP tool that completes the in-session flow.
- **Cross-cutting API:** `critiqueApiSurfaceFile(file, opts)` exported from `packages/cli/src/api-craft/index.ts`. Another craft skill (or an orchestrator) can critique a single spec or route file without re-walking the project.
- **Shared craft infrastructure:** `LlmProvider`, `MockLlmProvider`, `derivePriority`, and the 3-axis types all live in `packages/cli/src/shared/craft/`.
- **Sibling boundaries:** copy-craft owns error-message and log prose; security-craft owns trust-boundary and least-authority critique; the rule-based API floor owns OpenAPI/webhook format compliance. api-craft owns the SHAPE of the API contract — resource modeling, naming, verbs, status codes, error contracts, response shapes, pagination, idempotency, and compatible evolution.

## Success Criteria

See `docs/changes/api-craft/proposal.md` for the full success criteria. Highlights:

- 9 seed rubrics ship at `catalog/rubrics/<slug>.ts` (file-per-rubric, matching the craft family)
- 3-axis output preserved (tier × impact × confidence, never collapsed)
- `cite.rubricId` populated on every finding (ADR 0020)
- Kind-aware rubric filtering (the idempotency rubric never fires on a static OpenAPI document)
- A curated exemplar set anchors the catalog and grows without a schema change
- Cross-cutting `critiqueApiSurfaceFile` works on a single surface without a project walk
- Graceful degradation: runs with seed rubrics when no API style guide is declared

## Rationalizations to Reject

These are common rationalizations that sound reasonable but lead to incorrect results. When you catch yourself thinking any of these, stop and follow the documented process instead.

| Rationalization                                                                        | Why It Is Wrong                                                                                                                                                                                                                                          |
| -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "This endpoint validates against its OpenAPI schema, so the contract is fine."         | Schema validity is the mechanical floor. api-craft asks whether the SHAPE is right — is the verb honest, does the resource model the domain, does the error tell the consumer what to do. A schema-valid `GET /widgets/delete/:id` still fails API-R003. |
| "It is just an internal API, so I can skip the compatibility critique."                | API-R009 applies wherever there are consumers. Internal callers break exactly the way external ones do when a response shape or field meaning shifts unannounced — the blast radius is smaller, not the rule.                                            |
| "The handler returns a 500 with a message, so errors are covered."                     | API-R004 and API-R005 ask whether the status code is CORRECT for the failure and whether the body tells the consumer what to DO next — not merely that some error came back. A generic 500 on a client-caused failure fails both.                        |
| "I can see the fix, so I will add the idempotency key to the handler while I am here." | api-craft is judgment-only. It emits a finding naming the surface and a concrete suggested change; it never rewrites a contract or handler. Editing here violates the no-autofix gate and hides the finding from the consumer who owns the decision.     |
| "No API style guide is declared, so a critique would not be meaningful."               | The B' check degrades to the seed rubrics — it never blocks. Refusing to critique because a project has not written its conventions down abandons the ceiling role; note the degraded context and run anyway.                                            |

## Examples

### Example: A GET that mutates state

**Input:** `src/routes/widgets.ts` defining `router.get('/widgets/delete/:id', …)` whose handler deletes the record.

**Output (mock LLM):**

```
src/routes/widgets.ts (route)
  API-R003 [foundational/large/high] src/routes/widgets.ts (route)
    `GET /widgets/delete/:id` mutates state — a GET must be safe, and caches or
    prefetchers may replay it. Model this as `DELETE /widgets/:id` so retry and
    caching behavior are predictable from the method alone.
```

### Example: A create with no idempotency path

**Input:** `src/routes/payments.ts` — a `POST /payments` handler that charges a card with no idempotency key and no dedup.

**Output:**

```
src/routes/payments.ts (route)
  API-R008 [foundational/large/high] src/routes/payments.ts (route)
    `POST /payments` charges on every call with no idempotency key — a network
    retry double-charges. Accept an `Idempotency-Key` header and return the
    original result for a repeated key, the way Stripe's charge API does.
```

### Example: A clean OpenAPI document — no findings

**Input:** An `openapi.yaml` with domain-modeled resources, plural paths, honest methods, correct status codes, a consistent typed error schema, cursor pagination, and a version.

**Output:**

```
No API-craft findings.

Summary: 0 findings across 1 API surfaces (0 skipped, 8 rubrics, 5 exemplars, 8 LLM calls, $0.0000, 5ms)
```

## Gates

- **No autofix.** api-craft is judgment-only; it never rewrites a contract or a handler.
- **No floor duplication.** Whether a schema validates or a path is documented is a mechanical concern, not this skill's.
- **No sibling territory.** Error-message wording belongs to copy-craft; trust-boundary and auth-vulnerability critique belongs to security-craft.
- **No POLISH / BENCHMARK phases in v1.** The catalog carries exemplars so a future BENCHMARK phase (score against the Stripe / GitHub tier) lands without a schema change — but v1 is CRITIQUE-only, the same first-version posture as the rest of the non-design craft family.
- **No graph persistence.** v1 returns findings; it does not write craft edges to the graph.
- **No runtime introspection.** v1 reasons from the OpenAPI document and route-definition source, not from calling the live API — a later minor version may add a runtime probe.
- **No B' hard block.** When no API style guide is declared, api-craft runs with the seed rubrics and notes the degraded context — it never refuses.

## Escalation

- **When LLM cost is too high:** drop `--max-files` (default 60), or scope to specific surfaces with `--files` / `--spec-file`. Per-surface cost = applicable rubrics × per-call; source is truncated at 8000 input chars.
- **When a rubric produces a high false-positive rate:** scope away with `--files`, or filter findings by `cite.rubricId` in your consumer. Per-rubric disable is a later minor version.
- **When discovery misses a project's layout:** point route discovery at the right place with `--routes-dir`, name the contract with `--spec-file`, or pass an explicit `--files` list.
- **When no LLM provider is configured:** api-craft is LLM-judgment-based. Configure a craft backend under `craft.llm.*`; do not expect rule-based output.

## Status

**v1 — CRITIQUE phase.** See:

- Spec: `docs/changes/api-craft/proposal.md`
- Roadmap entry: part of the `craft-pipeline` initiative
- Sibling craft skills: `harness-cli-ergonomics-craft` (the structural twin), `harness-docs-craft`, `harness-code-craft`, `harness-design-craft`, `naming-craft`, `spec-craft`, `copy-craft`, `test-craft`, `knowledge-craft`, `security-craft`
- Shared infrastructure: `packages/cli/src/shared/craft/`
- Future: a BENCHMARK phase scoring against the exemplar corpus, a runtime probe against a live API, and a per-rubric disable configuration

Files in this skill

  • SKILL.md15.6 KB
  • skill.yaml2.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…