| name | plan-api-contracts |
| description | Request/response types, endpoint definitions per WP |
| argument-hint | Invoked by Planner Coordinator - do not call directly |
plan-api-contracts
Phase: 2 (Contract Generation)
Common contract: .github/skills/PLAN-SKILL-CONTRACT.md
Spec refs: FR-043, FR-044, FR-045, FR-039
This skill is dispatched by the Planner Coordinator during Phase 2. It reads the plan accumulator and generates language-specific API contract files scoped per work package.
Input Contract (FR-023)
| # | Input | Description |
|---|
| 1 | skill_path | Path to this SKILL.md file |
| 2 | plan_dir | Path to .sdd/plans/ directory |
| 3 | contracts_dir | Path to .sdd/plans/contracts/ directory |
| 4 | spec_path | Path to the source spec file |
| 5 | spec_artifacts_dir | Path to spec companion artifacts |
| 6 | research_summary | Key findings from the research phase |
| 7 | target_language | Programming language for contract generation |
| 8 | patterns | Active plan-domain patterns to avoid |
| 9 | phase | Phase indicator (always 2 for this skill) |
Execution Sequence (FR-024)
- Read SKILL.md - Load this file for API contract generation instructions
- Read plan state - Read README and all WP files to identify which WPs have API endpoints
- Read spec + artifacts - Read the spec and the companion artifact
api-contracts.<ext> from spec_artifacts_dir. Read spec and artifact files in parallel.
- Write contract files - Write
api-contracts.<ext> to contracts_dir/<WP-slug>/ per applicable WP
Step 1 - Identify API-Bearing WPs
Read the plan accumulator. For each WP, determine if it:
- Introduces new API endpoints (REST, GraphQL, gRPC, etc.)
- Modifies existing endpoint signatures
- Adds new request/response types
Skip WPs that:
- Do not expose or modify API endpoints
- Only consume APIs (client-side)
- Are pure backend business logic without a public API surface
Step 2 - Read Spec Companion Artifact (FR-044)
Check if spec_artifacts_dir contains an api-contracts.<ext> file. If it exists:
- Parse the spec-level API contract definitions
- These are canonical -- WP-level contracts MUST match endpoint paths, request/response types
- Scope each WP's contract to only the endpoints that WP introduces
If the spec artifact does NOT exist:
- Generate from the spec's API design section and FR descriptions
- Note in a comment that these were derived from spec prose
Step 3 - Generate API Contract Files (FR-043)
For each applicable WP, generate <contracts_dir>/<WP-slug>/api-contracts.<ext>:
3a. Manifest Header (FR-039)
// Generated by: plan-api-contracts skill
// Source spec: <spec_path>
// Work package: WP<NN>-<slug>
// Target language: <target_language>
// DO NOT EDIT MANUALLY -- regenerated on plan revision
3b. Endpoint Path Constants (FR-043.3)
export const API_PATHS = {
GET_USERS: '/api/v1/users',
GET_USER_BY_ID: '/api/v1/users/:id',
CREATE_USER: '/api/v1/users',
UPDATE_USER: '/api/v1/users/:id',
DELETE_USER: '/api/v1/users/:id',
} as const;
class ApiPaths:
GET_USERS = '/api/v1/users'
GET_USER_BY_ID = '/api/v1/users/{id}'
CREATE_USER = '/api/v1/users'
UPDATE_USER = '/api/v1/users/{id}'
DELETE_USER = '/api/v1/users/{id}'
3c. Request Type Definitions (FR-043.1)
For each endpoint that accepts a request body:
export interface CreateUserRequest {
email: string;
name: string;
password: string;
role?: 'admin' | 'user';
}
export interface UpdateUserRequest {
email?: string;
name?: string;
role?: 'admin' | 'user';
}
Requirements:
- All fields MUST be typed
- Required vs optional MUST be explicit
- Validation constraints from the spec MUST be included as comments or decorators
- Query parameters for GET endpoints MUST be typed as a separate interface
3d. Response Type Definitions (FR-043.2)
For each endpoint:
export interface UserResponse {
id: string;
email: string;
name: string;
role: 'admin' | 'user';
createdAt: string;
}
export interface UserListResponse {
data: UserResponse[];
pagination: PaginationMeta;
}
3e. Auth Requirement Declarations (FR-043.4)
Annotate each endpoint with its auth mechanism:
export const AUTH_REQUIREMENTS = {
[API_PATHS.GET_USERS]: { type: 'bearer', roles: ['admin'] },
[API_PATHS.GET_USER_BY_ID]: { type: 'bearer', roles: ['admin', 'user'] },
[API_PATHS.CREATE_USER]: { type: 'none' },
[API_PATHS.UPDATE_USER]: { type: 'bearer', roles: ['admin', 'self'] },
[API_PATHS.DELETE_USER]: { type: 'bearer', roles: ['admin'] },
} as const;
Step 4 - Error Response Types (FR-045)
For each endpoint, include all applicable error response types:
export interface ApiErrorResponse {
error: {
code: string;
message: string;
details?: unknown;
};
status: number;
}
export const ENDPOINT_ERRORS = {
[API_PATHS.CREATE_USER]: {
400: 'VALIDATION_ERROR',
401: 'AUTH_REQUIRED',
403: 'FORBIDDEN',
409: 'USER_ALREADY_EXISTS',
422: 'UNPROCESSABLE_ENTITY',
500: 'INTERNAL_ERROR',
},
[API_PATHS.GET_USER_BY_ID]: {
401: 'AUTH_REQUIRED',
403: 'FORBIDDEN',
404: 'USER_NOT_FOUND',
500: 'INTERNAL_ERROR',
},
} as const;
Applicability rules (not all codes apply to every endpoint):
- 400 (Bad Request): Endpoints with request body or query params
- 401 (Unauthorized): Endpoints requiring authentication
- 403 (Forbidden): Endpoints with role-based access control
- 404 (Not Found): Endpoints accessing a specific resource by ID
- 409 (Conflict): Endpoints creating resources with uniqueness constraints
- 422 (Unprocessable Entity): Endpoints with complex validation beyond basic types
- 500 (Internal Server Error): All endpoints
Step 5 - 800-Line Block Compliance (FR-013)
If a WP's API contract file exceeds 800 lines, split generation across multiple writes.
Constraints
- Output MUST be valid syntax in the target language
- Do NOT include route handler implementations or middleware logic
- Do NOT modify WP markdown files or spec artifacts -- read only
- Only write to
<contracts_dir>/<WP-slug>/api-contracts.<ext>
- Error response types MUST reference error codes -- do not invent new codes not in the spec
- Use plain ASCII hyphens and straight quotes only -- no em dashes, smart quotes, or curly apostrophes