mcpbeat

Openapi Spec Writer

curiositech/openapi-spec-writer

Expert in writing OpenAPI 3.0/3.1 specifications for REST APIs. Specializes in schema design, documentation best practices, API-first development, and tooling integration. Generates comprehensive API documentation that serves as both documentation and contract.

4k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
177
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/curiositech/some_claude_skills --skill openapi-spec-writer

The instruction itself

15 sections, as written by the author

OpenAPI Spec Writer

Overview

Expert in writing OpenAPI 3.0/3.1 specifications for REST APIs. Specializes in schema design, documentation best practices, API-first development, and tooling integration. Generates comprehensive API documentation that serves as both documentation and contract.

When to Use

  • Creating OpenAPI specifications for new APIs
  • Documenting existing REST APIs
  • Designing API contracts before implementation
  • Generating client SDKs from specs
  • Setting up interactive API documentation (Swagger UI, Redoc)
  • Validating API responses against schemas
  • Migrating from OpenAPI 2.0 (Swagger) to 3.x

Capabilities

Specification Writing

  • OpenAPI 3.0 and 3.1 syntax
  • Path and operation definitions
  • Request/response schemas
  • Authentication schemes
  • Server configurations

Schema Design

  • JSON Schema with OpenAPI extensions
  • Reusable component schemas
  • Discriminators for polymorphism
  • oneOf, anyOf, allOf composition
  • Nullable types and defaults

Documentation Quality

  • Meaningful descriptions and examples
  • Markdown in descriptions
  • Request/response examples
  • Error response documentation
  • Deprecation notices

Tooling Integration

  • Swagger UI configuration
  • Redoc customization
  • Spectral linting rules
  • SDK generation setup
  • Mock server configuration

Dependencies

Works well with:

  • api-architect - API design patterns
  • rest-api-design - RESTful conventions
  • typescript-pro - Generated client types
  • github-actions-pipeline-builder - CI validation

Examples

Complete OpenAPI 3.1 Spec

openapi: 3.1.0
info:
  title: Task Management API
  description: |
    RESTful API for managing tasks and projects.

    ## Authentication
    All endpoints require a Bearer token in the Authorization header.

    ## Rate Limiting
    - 1000 requests per hour per API key
    - Rate limit headers included in all responses
  version: 1.0.0
  contact:
    name: API Support
    email: [email protected]
    url: https://docs.example.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.example.com/v1
    description: Production server
  - url: https://staging-api.example.com/v1
    description: Staging server
  - url: http://localhost:3000/v1
    description: Local development

tags:
  - name: Tasks
    description: Task management operations
  - name: Projects
    description: Project management operations

paths:
  /tasks:
    get:
      operationId: listTasks
      summary: List all tasks
      description: Returns a paginated list of tasks with optional filtering.
      tags:
        - Tasks
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/LimitParam'
        - name: status
          in: query
          description: Filter by task status
          schema:
            $ref: '#/components/schemas/TaskStatus'
        - name: project_id
          in: query
          description: Filter by project ID
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskListResponse'
              examples:
                default:
                  $ref: '#/components/examples/TaskListExample'
          headers:
            X-Total-Count:
              schema:
                type: integer
              description: Total number of tasks matching the query
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      operationId: createTask
      summary: Create a new task
      description: Creates a new task and returns the created resource.
      tags:
        - Tasks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTaskRequest'
            examples:
              minimal:
                summary: Minimal task
                value:
                  title: "Complete documentation"
              full:
                summary: Full task with all fields
                value:
                  title: "Complete documentation"
                  description: "Write API docs for v1.0"
                  project_id: "550e8400-e29b-41d4-a716-446655440000"
                  due_date: "2024-12-31"
                  priority: "high"
      responses:
        '201':
          description: Task created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
          headers:
            Location:
              schema:
                type: string
                format: uri
              description: URL of the created resource
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /tasks/{taskId}:
    parameters:
      - $ref: '#/components/parameters/TaskIdParam'

    get:
      operationId: getTask
      summary: Get a task by ID
      tags:
        - Tasks
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      operationId: updateTask
      summary: Update a task
      description: Partially updates a task. Only provided fields are updated.
      tags:
        - Tasks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTaskRequest'
      responses:
        '200':
          description: Task updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      operationId: deleteTask
      summary: Delete a task
      tags:
        - Tasks
      responses:
        '204':
          description: Task deleted successfully
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token obtained from /auth/login

  parameters:
    TaskIdParam:
      name: taskId
      in: path
      required: true
      description: Unique task identifier
      schema:
        type: string
        format: uuid
      example: "550e8400-e29b-41d4-a716-446655440000"

    PageParam:
      name: page
      in: query
      description: Page number for pagination (1-indexed)
      schema:
        type: integer
        minimum: 1
        default: 1

    LimitParam:
      name: limit
      in: query
      description: Number of items per page
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20

  schemas:
    Task:
      type: object
      required:
        - id
        - title
        - status
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier
          readOnly: true
        title:
          type: string
          minLength: 1
          maxLength: 200
          description: Task title
        description:
          type: string
          maxLength: 5000
          description: Detailed task description (supports Markdown)
        status:
          $ref: '#/components/schemas/TaskStatus'
        priority:
          $ref: '#/components/schemas/Priority'
        project_id:
          type: string
          format: uuid
          description: Associated project ID
        due_date:
          type: string
          format: date
          description: Due date (ISO 8601)
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true

    TaskStatus:
      type: string
      enum:
        - pending
        - in_progress
        - completed
        - cancelled
      description: Current task status
      default: pending

    Priority:
      type: string
      enum:
        - low
        - medium
        - high
        - urgent
      default: medium

    CreateTaskRequest:
      type: object
      required:
        - title
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 200
        description:
          type: string
          maxLength: 5000
        project_id:
          type: string
          format: uuid
        due_date:
          type: string
          format: date
        priority:
          $ref: '#/components/schemas/Priority'

    UpdateTaskRequest:
      type: object
      minProperties: 1
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 200
        description:
          type: string
          maxLength: 5000
        status:
          $ref: '#/components/schemas/TaskStatus'
        priority:
          $ref: '#/components/schemas/Priority'
        due_date:
          type: string
          format: date

    TaskListResponse:
      type: object
      required:
        - data
        - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Task'
        pagination:
          $ref: '#/components/schemas/Pagination'

    Pagination:
      type: object
      required:
        - page
        - limit
        - total
        - total_pages
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        total_pages:
          type: integer
        has_next:
          type: boolean
        has_prev:
          type: boolean

    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Machine-readable error code
        message:
          type: string
          description: Human-readable error message
        details:
          type: object
          additionalProperties: true
          description: Additional error details

    ValidationError:
      allOf:
        - $ref: '#/components/schemas/Error'
        - type: object
          properties:
            errors:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string

  responses:
    BadRequest:
      description: Bad request - invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "BAD_REQUEST"
            message: "Invalid query parameters"

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "UNAUTHORIZED"
            message: "Invalid or expired token"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "NOT_FOUND"
            message: "Task not found"

    ValidationError:
      description: Validation failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'
          example:
            code: "VALIDATION_ERROR"
            message: "Request validation failed"
            errors:
              - field: "title"
                message: "Title is required"

  examples:
    TaskListExample:
      value:
        data:
          - id: "550e8400-e29b-41d4-a716-446655440000"
            title: "Complete documentation"
            status: "in_progress"
            priority: "high"
            created_at: "2024-01-15T10:30:00Z"
            updated_at: "2024-01-15T10:30:00Z"
        pagination:
          page: 1
          limit: 20
          total: 42
          total_pages: 3
          has_next: true
          has_prev: false

security:
  - bearerAuth: []

Polymorphic Schemas (Discriminator)

components:
  schemas:
    Notification:
      type: object
      required:
        - id
        - type
        - created_at
      discriminator:
        propertyName: type
        mapping:
          email: '#/components/schemas/EmailNotification'
          sms: '#/components/schemas/SmsNotification'
          push: '#/components/schemas/PushNotification'
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
          enum: [email, sms, push]
        created_at:
          type: string
          format: date-time

    EmailNotification:
      allOf:
        - $ref: '#/components/schemas/Notification'
        - type: object
          required:
            - to
            - subject
          properties:
            to:
              type: string
              format: email
            subject:
              type: string
            body:
              type: string

    SmsNotification:
      allOf:
        - $ref: '#/components/schemas/Notification'
        - type: object
          required:
            - phone_number
            - message
          properties:
            phone_number:
              type: string
              pattern: '^\+[1-9]\d{1,14}$'
            message:
              type: string
              maxLength: 160

Spectral Linting Rules

# .spectral.yaml
extends: ["spectral:oas"]

rules:
  # Enforce operation IDs
  operation-operationId: error

  # Require descriptions
  operation-description: error
  oas3-schema-description: warn

  # Naming conventions
  path-casing:
    given: "$.paths[*]~"
    then:
      function: casing
      functionOptions:
        type: kebab

  # Security requirements
  operation-security-defined: error

  # Response codes
  operation-success-response: error

  # Custom: require examples
  require-examples:
    message: "Responses should have examples"
    given: "$.paths.*.*.responses.*.content.*.schema"
    then:
      field: example
      function: truthy

Best Practices

  • Use components - Extract reusable schemas, parameters, responses
  • Provide examples - Real-world examples for every schema
  • Meaningful descriptions - Markdown-formatted, explain business context
  • Consistent naming - kebab-case paths, camelCase properties
  • Version your API - Include version in URL or header
  • Document errors - Define all error responses with examples
  • Use operationId - Unique, descriptive IDs for SDK generation
  • Validate with linting - Use Spectral to enforce standards
  • Keep spec in sync - Automate validation in CI

Common Pitfalls

  • Missing required fields - Forgetting to mark fields as required
  • Inconsistent naming - Mixing snake_case and camelCase
  • Generic descriptions - "Returns data" instead of specific details
  • No examples - Makes spec hard to understand
  • Outdated spec - Spec doesn't match implementation
  • Overusing anyOf - Makes schemas hard to understand
  • Missing error responses - Only documenting happy path
  • No pagination - List endpoints without pagination info

How to use it

Copy the folder

Take curiositech/openapi-spec-writer from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.