skills/api-artifacts/SKILL.md
Templates and rules for generating OpenAPI specs, Postman collections, AsyncAPI specs, and GraphQL schemas from architecture manifests
npx skillsauth add navraj007in/architecture-cowork-plugin api-artifactsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate ready-to-use API documentation and testing artifacts from the system manifest. These artifacts let developers import specs directly into tools like Swagger UI, Postman, and AsyncAPI Studio.
Generate one OpenAPI spec per REST API service in the manifest.
openapi: 3.1.0
info:
title: "{{service-name}} API"
description: "{{service-description}}"
version: "0.1.0"
servers:
- url: http://localhost:{{port}}
description: Local development
- url: https://{{service-name}}.{{domain}}
description: Production
security:
- bearerAuth: []
paths:
# Generate from service responsibilities + shared types
/health:
get:
summary: Health check
operationId: getHealth
tags: [system]
security: []
responses:
"200":
description: Service is healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: "ok"
service:
type: string
example: "{{service-name}}"
/{{resource}}:
get:
summary: "List {{resource}}"
operationId: "list{{Resource}}"
tags: [{{resource}}]
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
"200":
description: "List of {{resource}}"
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/{{Resource}}"
pagination:
$ref: "#/components/schemas/Pagination"
"401":
$ref: "#/components/responses/Unauthorized"
post:
summary: "Create {{resource}}"
operationId: "create{{Resource}}"
tags: [{{resource}}]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Create{{Resource}}"
example:
# Derive from shared type fields
responses:
"201":
description: "{{Resource}} created"
content:
application/json:
schema:
$ref: "#/components/schemas/{{Resource}}"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
/{{resource}}/{id}:
get:
summary: "Get {{resource}} by ID"
operationId: "get{{Resource}}"
tags: [{{resource}}]
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{{Resource}} details"
content:
application/json:
schema:
$ref: "#/components/schemas/{{Resource}}"
"404":
$ref: "#/components/responses/NotFound"
put:
summary: "Update {{resource}}"
operationId: "update{{Resource}}"
tags: [{{resource}}]
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Update{{Resource}}"
responses:
"200":
description: "{{Resource}} updated"
content:
application/json:
schema:
$ref: "#/components/schemas/{{Resource}}"
delete:
summary: "Delete {{resource}}"
operationId: "delete{{Resource}}"
tags: [{{resource}}]
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"204":
description: "{{Resource}} deleted"
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
# Derive from shared types in manifest
{{Resource}}:
type: object
properties:
id:
type: string
format: uuid
# ... fields from shared type
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
required: [id]
Create{{Resource}}:
type: object
properties:
# ... writable fields only (exclude id, timestamps)
required: [# ... required fields]
Update{{Resource}}:
type: object
properties:
# ... writable fields, all optional
Pagination:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
totalPages:
type: integer
Error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: object
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: "VALIDATION_ERROR"
message: "Invalid request body"
details: {}
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: "UNAUTHORIZED"
message: "Authentication required"
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: "NOT_FOUND"
message: "Resource not found"
ticket-management → /tickets, user-management → /users.domain.entities[] — Read domain.entities[] as the primary source; each entity becomes a component schema. For SDL location: check solution.sdl.yaml first; if absent, check sdl/ directory and read sdl/README.md then the relevant module file (typically sdl/data.yaml). Fall back to shared.types[] in the manifest if domain.entities[] is absent in both SDL formats./health with no auth.Generate one Postman collection per REST API service. Use Postman Collection v2.1 format.
{
"info": {
"name": "{{service-name}} API",
"description": "{{service-description}}",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{auth_token}}",
"type": "string"
}
]
},
"variable": [
{
"key": "base_url",
"value": "http://localhost:{{port}}"
},
{
"key": "auth_token",
"value": ""
}
],
"item": [
{
"name": "Health",
"item": [
{
"name": "Health Check",
"request": {
"method": "GET",
"url": "{{base_url}}/health",
"auth": { "type": "noauth" }
}
}
]
},
{
"name": "{{Resource}}",
"item": [
{
"name": "List {{resource}}",
"request": {
"method": "GET",
"url": {
"raw": "{{base_url}}/{{resource}}?page=1&limit=20",
"host": ["{{base_url}}"],
"path": ["{{resource}}"],
"query": [
{ "key": "page", "value": "1" },
{ "key": "limit", "value": "20" }
]
}
}
},
{
"name": "Get {{resource}} by ID",
"request": {
"method": "GET",
"url": "{{base_url}}/{{resource}}/{{resource_id}}"
}
},
{
"name": "Create {{resource}}",
"request": {
"method": "POST",
"url": "{{base_url}}/{{resource}}",
"header": [
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "raw",
"raw": "// JSON body with example values from shared types"
}
}
},
{
"name": "Update {{resource}}",
"request": {
"method": "PUT",
"url": "{{base_url}}/{{resource}}/{{resource_id}}",
"header": [
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "raw",
"raw": "// JSON body with example values"
}
}
},
{
"name": "Delete {{resource}}",
"request": {
"method": "DELETE",
"url": "{{base_url}}/{{resource}}/{{resource_id}}"
}
}
]
}
]
}
base_url and auth_token as variables so the user can switch environments.auth_token variable.Generate one AsyncAPI spec for event-driven / message queue connections in the manifest.
asyncapi: 2.6.0
info:
title: "{{project-name}} Events"
version: "0.1.0"
description: "Event channels for {{project-name}} architecture"
servers:
development:
url: localhost:6379
protocol: redis
description: Local Redis for BullMQ
production:
url: "{{redis-url}}"
protocol: redis
description: Production Redis
channels:
{{queue-name}}:
description: "{{queue-description}}"
publish:
operationId: "publish{{EventName}}"
summary: "{{event-summary}}"
message:
$ref: "#/components/messages/{{EventName}}"
subscribe:
operationId: "consume{{EventName}}"
summary: "{{consumer-summary}}"
message:
$ref: "#/components/messages/{{EventName}}"
components:
messages:
{{EventName}}:
name: {{EventName}}
title: "{{event-title}}"
contentType: application/json
payload:
$ref: "#/components/schemas/{{EventPayload}}"
schemas:
{{EventPayload}}:
type: object
properties:
eventId:
type: string
format: uuid
eventType:
type: string
enum: [{{event-types}}]
timestamp:
type: string
format: date-time
data:
type: object
properties:
# Derive from shared types and event contracts
communication entries with pattern: message-queue or pattern: event-bus.shared.contracts with type: event-schema to define payloads.eventId, eventType, timestamp, and data.Generate for services with type: graphql in the manifest.
type Query {
"""List {{resource}} with pagination"""
{{resource}}s(page: Int = 1, limit: Int = 20): {{Resource}}Connection!
"""Get a single {{resource}} by ID"""
{{resource}}(id: ID!): {{Resource}}
}
type Mutation {
"""Create a new {{resource}}"""
create{{Resource}}(input: Create{{Resource}}Input!): {{Resource}}!
"""Update an existing {{resource}}"""
update{{Resource}}(id: ID!, input: Update{{Resource}}Input!): {{Resource}}!
"""Delete a {{resource}}"""
delete{{Resource}}(id: ID!): Boolean!
}
type {{Resource}} {
id: ID!
# ... fields from shared types
createdAt: DateTime!
updatedAt: DateTime!
}
input Create{{Resource}}Input {
# ... writable fields
}
input Update{{Resource}}Input {
# ... writable fields, all optional
}
type {{Resource}}Connection {
edges: [{{Resource}}!]!
pageInfo: PageInfo!
totalCount: Int!
}
type PageInfo {
page: Int!
limit: Int!
totalPages: Int!
hasNextPage: Boolean!
}
scalar DateTime
Always write generated artifacts to these paths — the scaffolder reads from here for contract-first generation:
| Artifact | Path |
|---|---|
| OpenAPI spec (REST) | architecture-output/contracts/<service-name>.openapi.yaml |
| AsyncAPI spec (events) | architecture-output/contracts/<service-name>.asyncapi.yaml |
| GraphQL schema | architecture-output/contracts/<service-name>.graphql |
| Postman collection | architecture-output/contracts/<service-name>.postman.json |
| Index of all contracts | architecture-output/contracts/_index.md |
The _index.md file must list every generated contract file, its service name, and its type. The scaffolder reads this index to discover all contracts before generating route handlers.
When generating artifacts in the blueprint, present each one in a fenced code block with the appropriate language tag alongside the canonical path:
```yaml with filename comment # architecture-output/contracts/{{service-name}}.openapi.yaml```json with filename comment at top```yaml with filename comment # architecture-output/contracts/{{service-name}}.asyncapi.yaml```graphql with filename comment # architecture-output/contracts/{{service-name}}.graphqlAlways include a usage note after each artifact explaining how to import it into the relevant tool.
| Manifest Condition | Artifacts to Generate |
|---|---|
| Service with type: rest-api | OpenAPI spec + Postman collection |
| Service with type: graphql | GraphQL schema |
| Communication with pattern: message-queue or pattern: event-bus | AsyncAPI spec |
| Service with type: websocket | AsyncAPI spec (WebSocket protocol) |
| Any combination | Generate all applicable artifacts |
If no services have APIs (e.g., agent-only project), skip this deliverable and note why.
development
# Trade-Off Analysis Skill Quantifies exact trade-offs when switching between architecture options. Shows users precisely what they gain and lose when choosing Option A over Option B. ## When to Use Use this skill to help users decide between options by showing: 1. **Cost difference** — how much more/less per month? 2. **Performance difference** — how much faster/slower? 3. **Complexity difference** — how much harder to build/maintain? 4. **Scalability difference** — when does this option hit
testing
# Stage Detection Skill Detects the current project stage (concept → mvp → growth → enterprise) based on `_state.json` field presence and completeness. Used by `/architect:next-steps`, `/architect:check-state`, and roadmap commands. ## When to Use Invoke this skill when you need to determine what stage a project is at based on its state file. Stage detection drives: - Command recommendations (what to run next) - Required fields validation (what should exist at this stage) - Risk assessment (w
development
# Stack Swap Simulator Skill Estimates cost and effort to switch from one tech stack to another. Helps answer: "Can we migrate later if needed?" ## When to Use Use this skill to understand: 1. **Cost of switching stacks** — engineer weeks + downtime risk 2. **Timeline to switch** — how long is the project? 3. **Risk of switching** — what can go wrong? 4. **ROI of switching** — does it save money long-term? 5. **Backwards compatibility** — can we do a gradual migration? ## Input Provide sour
tools
# Stack Compatibility Skill Verifies that chosen technologies integrate well together. Prevents "I picked these tools and they don't work well together" regrets. ## When to Use Use this skill to verify: 1. **Chosen tools work together** — React + Node + MongoDB = good? 2. **No hidden incompatibilities** — will I hit issues in production? 3. **Team can support it** — do we have expertise for this combo? 4. **Licenses compatible** — can we use these together commercially? 5. **Performance assum