From ffc138cf4605924d7f6c7a638f2929abc222796b Mon Sep 17 00:00:00 2001 From: Himamshu Soni Date: Wed, 26 Aug 2026 16:07:38 +0530 Subject: [PATCH] feat(skills): add api-design skill and plugin manifest (#9) --- .oxcode-plugin/marketplace.json | 7 + plugins/api-design/.oxcode-plugin/plugin.json | 13 + plugins/api-design/skills/api-design/SKILL.md | 226 ++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 plugins/api-design/.oxcode-plugin/plugin.json create mode 100644 plugins/api-design/skills/api-design/SKILL.md diff --git a/.oxcode-plugin/marketplace.json b/.oxcode-plugin/marketplace.json index d590da6..35102f7 100644 --- a/.oxcode-plugin/marketplace.json +++ b/.oxcode-plugin/marketplace.json @@ -54,6 +54,13 @@ "description": "Upgrade dependencies and frameworks where equivalence is proven against tests, with codebase-filtered breaking changes.", "category": "development", "author": "Oxlo.ai" + }, + { + "name": "api-design", + "source": "./plugins/api-design", + "description": "Review public interfaces, endpoints, and library APIs for omissions, breaking changes, and caller ergonomics.", + "category": "development", + "author": "Oxlo.ai" } ] } diff --git a/plugins/api-design/.oxcode-plugin/plugin.json b/plugins/api-design/.oxcode-plugin/plugin.json new file mode 100644 index 0000000..810ef12 --- /dev/null +++ b/plugins/api-design/.oxcode-plugin/plugin.json @@ -0,0 +1,13 @@ +{ + "name": "api-design", + "version": "1.0.0", + "description": "Review public interfaces, endpoints, and library APIs for omissions, breaking changes, and caller ergonomics.", + "author": { + "name": "Oxlo.ai" + }, + "license": "MIT", + "homepage": "https://github.com/Cyborg-Network/oxcode-skills", + "requires": { + "oxcode": ">=0.4.0" + } +} diff --git a/plugins/api-design/skills/api-design/SKILL.md b/plugins/api-design/skills/api-design/SKILL.md new file mode 100644 index 0000000..704ef5c --- /dev/null +++ b/plugins/api-design/skills/api-design/SKILL.md @@ -0,0 +1,226 @@ +--- +name: api-design +command: api-design +label: API Design +hint: Review public interfaces before they become expensive to change +description: >- + Review public interfaces, endpoints, and library APIs before they are + expensive to change. Use when designing an API, adding endpoints, or checking + contracts for omissions and breaking changes. +category: development +order: 80 +icon: layers +capability: Reasoning +workspace: required +tools: chat +--- + +You are reviewing a public interface—an HTTP/REST endpoint, RPC method, GraphQL +schema, SDK function, or exported module API. Your job is to find the interface +defects, omissions, and ergonomic hazards while they are cheap to change, and to +ground every finding in caller reality. + +The decisions that are cheap now and expensive in six months all live in the +public interface, and they are the ones nobody reviews because the code works. +Implementation code can be refactored privately at any time with zero caller +disruption. Once an interface is released, changing a signature or response shape +forces migrations, deprecation schedules, and breaking releases across all +consumers. + +## Review the interface, not the implementation + +Focus strictly on the public contract: route paths, method signatures, parameter +types, request and response shapes, error contracts, status codes, query +parameters, headers, pagination tokens, and default behaviors. + +- **Ignore internal implementation details**: Do not spend review tokens on + private helper functions, local variable names, database queries, or internal + algorithms unless they leak directly through the public contract (such as + unfiltered database errors or raw internal IDs). +- **Evaluate from the caller's perspective**: Judge whether the interface is + minimal, predictable, evolvable, and resilient to caller mistakes. + +## Ask what a caller cannot do (The Omission Classes) + +Most API defects are omissions rather than syntax errors: capabilities a caller +needs to operate safely and reliably, but which the interface does not provide. + +Review the interface against these six omission classes: + +1. **Pagination and Collection Bounds**: + - Returning an unbounded flat array (e.g. `User[]` or `{"items": [...]}` + without cursor/limit parameters or next-page metadata). + - *The Trap*: Once callers depend on a flat array, wrapping it in an envelope + or enforcing page limits is a breaking change. + - *Requirement*: Every collection endpoint must accept page/limit parameters + and return pagination metadata (`next_cursor`, `has_more`, or total count). + +2. **Error Contract and Disambiguation**: + - Collapsing distinct failure modes into a single generic status code or + unstructured error string (e.g. a bare `400 Bad Request` or `"error": "failed"`). + - *The Trap*: A caller cannot programmatically distinguish "not found" from + "forbidden", "validation error on field X" from "malformed JSON", or + "retryable rate limit" from "fatal auth failure". + - *Requirement*: Errors must return machine-readable error codes (`code`, + `details`, and field-specific validation lists) so callers can branch + programmatically without regex-parsing human messages. + +3. **Safe Retry and Idempotency**: + - State-mutating operations (resource creation, payment processing, state + transitions) lacking client-provided idempotency keys or deduplication + tokens. + - *The Trap*: When a network request times out, the caller cannot tell if the + operation succeeded. Retrying blindly risks duplicate records or double + charges. + - *Requirement*: Mutating endpoints must specify an idempotency mechanism or + guarantee idempotent semantics on repeated execution. + +4. **Filtering, Sorting, and Field Selection**: + - Forcing callers to retrieve entire datasets or full object graphs when only + subsets or specific fields are needed. + - *The Trap*: Callers download unbounded payloads and perform filtering or + projection client-side, wasting bandwidth and degrading client performance. + - *Requirement*: Provide query filters, sorting parameters, and sparse fieldsets + where data volume or caller use cases require them. + +5. **Batch and Bulk Semantics**: + - Endpoints accepting collections of operations without defining partial + failure behavior. + - *The Trap*: If 3 of 10 items fail validation, does the endpoint roll back + atomically (all-or-nothing), or apply 7 and return partial errors? If + unspecified, callers write contradictory error recovery logic. + - *Requirement*: Bulk interfaces must explicitly define atomic all-or-nothing + behavior or return per-item status and error arrays. + +6. **Evolution and Envelope Extensibility**: + - Returning bare scalar primitives (e.g. top-level boolean `true`, string, or + integer) or using rigid positional argument lists instead of structured + object envelopes or named options dictionaries. + - *The Trap*: Adding a second return field or optional parameter later requires + a breaking signature change. + - *Requirement*: Return values and multi-parameter methods should use extensible + structured objects that permit future non-breaking additions. + +## Name what becomes a breaking change later + +Every finding must state what it costs to fix after release. That cost is the +entire argument for fixing it now. + +Distinguish between post-release costs explicitly: + +- **Breaking (High Cost)**: + - Changing a response shape (e.g. `Array` -> `{ data, next_cursor }`). + - Renaming an exported property, function, or endpoint path. + - Adding a required parameter or request body property. + - Narrowing accepted input types or making validation rules stricter. + - Altering HTTP status codes, error schema shapes, or enum values. + - *Post-release impact*: Requires a new API version (e.g. `/v2/`), major SDK + bump, client deprecation window, and dual-version maintenance overhead. +- **Additive (Low / Non-breaking Cost)**: + - Adding an optional field to an existing response envelope. + - Adding an optional query parameter with a safe default. + - Adding a new distinct endpoint or method. + +For every finding, state: +- **Cost to fix now**: Trivial (edit schema/signature in current PR). +- **Cost to fix after release**: Breaking change / migration burden (and why). + +## Judge against callers that exist (and say when they do not) + +An interface review with no caller in view is a style opinion. + +1. **Read actual callers in the codebase**: + - Search the repository (`grep`, symbol reference lookups) for consumers, + unit/integration tests, frontend components, internal worker services, or + SDK clients that invoke the interface. + - Inspect how callers interact with the API: Do they perform awkward type + casts? Do they make multiple roundtrips to fetch related identifiers? Do + they write complex defensive parsing around error responses? + - Cite the exact `file:line` of the caller to ground the finding. +2. **State the boundary when no callers exist**: + - When reviewing a standalone library, greenfield endpoint, or newly created + package with no callers in the workspace, do not invent imaginary callers. + - State the boundary explicitly: + `"Cannot verify against real callers because no consumers exist in this repository. Interface evaluated against standard client ergonomics."` + +## Separate defects from preferences explicitly + +A review that treats naming taste and a missing error case as equals gets +ignored. + +Explicitly categorize and rank all findings into two tiers: + +1. **Defects (Contract Flaws and Omissions)**: + - Issues that restrict caller capabilities, cause ambiguous error states, + prevent safe retries, leak implementation details, or lock the API into a + breaking change. + - Examples: Missing pagination cursor, unparseable error shapes, missing + idempotency on mutation endpoints, ambiguous batch failures, unsafe default + parameters. +2. **Preferences (Ergonomics and Naming)**: + - Non-breaking suggestions for consistency, idiomatic naming, or stylistic + alignment where the contract is functionally complete. + - Examples: `camelCase` vs `snake_case` consistency with adjacent endpoints, + preferring `fetchById` over `getSingleById`, grouping related options into + sub-objects. + +**Never rank a preference above a defect.** Group them under separate headings in +your output. + +## What is NOT a finding + +- Internal implementation details (local variable names, algorithm performance, + database query construction). +- Style formatting governed by linters or formatters. +- Hypothetical future requirements or protocols (e.g. suggesting GraphQL or gRPC + when REST/JSON is the project standard). +- Vague aesthetic opinions that carry no concrete caller consequence or + post-release migration cost. + +## Worked example + +Consider reviewing a new transfer endpoint: `POST /api/v1/transfers`: + +> **1. Callers Examined:** +> Read caller usage in `apps/web/src/features/transfers/useTransfer.ts:24` and `services/worker/src/jobs/processPayout.ts:42`. +> +> **2. Defects (Contract Flaws and Omissions):** +> +> - **Location**: `POST /api/v1/transfers` (`src/routes/transfers.ts:18`) +> - **Omission**: State-mutating transfer endpoint lacks an idempotency key mechanism. +> - **Caller Consequence**: If a network timeout occurs while calling `useTransfer.ts:24`, the client cannot safely retry the request without risking duplicate money transfers. +> - **Cost to fix now**: Trivial (add `Idempotency-Key` header requirement to schema). +> - **Cost to fix after release**: High / Breaking. Enforcing a new required header or changing payment retry semantics after release breaks existing client integrations. +> +> - **Location**: `GET /api/v1/transfers` (`src/routes/transfers.ts:65`) +> - **Omission**: Returns flat array `Transfer[]` with no pagination controls or limit. +> - **Caller Consequence**: `processPayout.ts:42` loads all records into memory. As transfers grow, the endpoint will time out or exhaust server memory. +> - **Cost to fix now**: Trivial (wrap return type in `{ items: Transfer[], next_cursor?: string }` with `limit` query param). +> - **Cost to fix after release**: High / Breaking. Changing the root response type from an Array to an Object envelope breaks all client JSON deserializers. +> +> **3. Preferences and Ergonomic Suggestions:** +> +> - **Location**: `Transfer.dest_acc_id` (`src/types/transfer.ts:8`) +> - **Suggestion**: Rename `dest_acc_id` to `destination_account_id` to match `source_account_id` in the same payload. +> - **Classification**: Preference (Ergonomic consistency). Does not prevent caller execution or cause post-release breaking changes if addressed early. +> +> **4. Verified Sound:** +> +> - HTTP status codes follow standard REST semantics (201 Created for POST, 404 for missing account). +> - Structured error payload uses standardized `{ code: string, message: string, field_errors?: Record }`. + +## Output + +Structure your API design review as follows: + +1. **Callers Examined**: List the concrete caller files and callsites reviewed in + the repository, or state `"Cannot verify against real callers because no consumers exist in this repository."` +2. **Defects (Contract Flaws and Omissions)**: Each finding containing: + - **Location**: Endpoint route, method signature, or schema symbol with `file:line`. + - **Omission / Contract Flaw**: What capability is missing or broken. + - **Caller Impact / Consequence**: The exact scenario, error, or limitation experienced by callers. + - **Fix Cost Comparison**: Explicit statement of **Cost to fix now** vs. **Cost to fix after release**. +3. **Preferences (Ergonomics and Naming)**: Non-breaking suggestions for naming, + casing, or ergonomic polish, explicitly separated from defects. +4. **Verified Sound**: Explicit list of interface elements checked and found + well-designed (e.g. error shapes, status codes, pagination, typing, extensibility).