
Openapi Spec Generation
Generate and refine OpenAPI specs code-first from FastAPI or TypeScript services, then validate, lint, and drive SDK generation for solo API products.
Overview
OpenAPI Spec Generation is an agent skill most often used in Build (also Validate, Ship) that guides code-first OpenAPI creation from FastAPI and TypeScript APIs plus validation, linting, and SDK tooling.
Install
npx skills add https://github.com/wshobson/agents --skill openapi-spec-generationWhat is this skill?
- Code-first OpenAPI patterns for Python FastAPI with Pydantic models and tagged operations
- TypeScript/tsoa-oriented generation and contract discipline
- Validation, linting, and SDK-generation workflow guidance
- Server URLs, enums, and field metadata for publishable API descriptions
- Templates for production-grade request/response models and error shapes
- Includes Template 2: Code-First Generation (Python/FastAPI) with worked FastAPI app scaffold
Adoption & trust: 11.5k installs on skills.sh; 36.5k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your API behavior lives in code but your OpenAPI document is missing, stale, or too painful to keep aligned with every model change.
Who is it for?
Solo builders on FastAPI or TypeScript HTTP services who plan to publish SDKs, partner integrations, or contract-tested releases.
Skip if: GraphQL-only backends, static sites with no API, or teams that already enforce design-first OpenAPI with no code-first workflow.
When should I use this skill?
User needs OpenAPI from FastAPI or TypeScript code, spec validation/linting, or SDK generation from a code-first API.
What do I get? / Deliverables
You export an accurate OpenAPI contract from FastAPI or tsoa-style sources and can lint it and feed SDK generators without hand-maintaining parallel spec files.
- OpenAPI 3.x document aligned with code
- Lint-ready spec and notes for SDK generator integration
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
OpenAPI from running code is core backend construction before clients and docs can trust your contract. Backend is the canonical shelf because the skill centers FastAPI/tsoa models, routes, and automatic schema export—not marketing docs alone.
Where it fits
Draft enums and resource shapes in FastAPI models to see if the MVP API fits in one OpenAPI document.
Add tags, servers, and Field descriptions so /openapi.json is partner-ready from day one.
Regenerate the spec after route changes and run lint plus SDK gen before tagging a release.
How it compares
Pair with backend implementation skills for routes and models—this skill is contract and tooling generation, not deployment.
Common Questions / FAQ
Who is openapi-spec-generation for?
Developers building HTTP APIs who want OpenAPI generated from FastAPI or TypeScript code and maintained through validation and SDK pipelines.
When should I use openapi-spec-generation?
In Validate when scoping an API surface for a prototype; in Build while implementing FastAPI/tsoa models and tags; in Ship before generating SDKs or running contract tests against partners.
Is openapi-spec-generation safe to install?
Check the Security Audits panel on this Prism page; the skill is documentation and codegen guidance and does not by itself move funds or secrets, but generated SDK scripts should be reviewed like any build output.
SKILL.md
READMESKILL.md - Openapi Spec Generation
# OpenAPI Code-First Generation and Tooling Advanced patterns for generating OpenAPI specs from code (Python/FastAPI, TypeScript/tsoa), validation, linting, and SDK generation. ## Template 2: Code-First Generation (Python/FastAPI) ```python # FastAPI with automatic OpenAPI generation from fastapi import FastAPI, HTTPException, Query, Path, Depends from pydantic import BaseModel, Field, EmailStr from typing import Optional, List from datetime import datetime from uuid import UUID from enum import Enum app = FastAPI( title="User Management API", description="API for managing users and profiles", version="2.0.0", openapi_tags=[ {"name": "Users", "description": "User operations"}, {"name": "Profiles", "description": "Profile operations"}, ], servers=[ {"url": "https://api.example.com/v2", "description": "Production"}, {"url": "http://localhost:8000", "description": "Development"}, ], ) # Enums class UserStatus(str, Enum): active = "active" inactive = "inactive" suspended = "suspended" pending = "pending" class UserRole(str, Enum): user = "user" moderator = "moderator" admin = "admin" # Models class UserBase(BaseModel): email: EmailStr = Field(..., description="User email address") name: str = Field(..., min_length=1, max_length=100, description="Display name") class UserCreate(UserBase): role: UserRole = Field(default=UserRole.user) metadata: Optional[dict] = Field(default=None, description="Custom metadata") model_config = { "json_schema_extra": { "examples": [ { "email": "user@example.com", "name": "John Doe", "role": "user" } ] } } class UserUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=100) status: Optional[UserStatus] = None role: Optional[UserRole] = None metadata: Optional[dict] = None class User(UserBase): id: UUID = Field(..., description="Unique identifier") status: UserStatus role: UserRole avatar: Optional[str] = Field(None, description="Avatar URL") metadata: Optional[dict] = None created_at: datetime = Field(..., alias="createdAt") updated_at: Optional[datetime] = Field(None, alias="updatedAt") model_config = {"populate_by_name": True} class Pagination(BaseModel): page: int = Field(..., ge=1) limit: int = Field(..., ge=1, le=100) total: int = Field(..., ge=0) total_pages: int = Field(..., ge=0, alias="totalPages") has_next: bool = Field(..., alias="hasNext") has_prev: bool = Field(..., alias="hasPrev") class UserListResponse(BaseModel): data: List[User] pagination: Pagination class ErrorDetail(BaseModel): field: str message: str class ErrorResponse(BaseModel): code: str = Field(..., description="Error code") message: str = Field(..., description="Error message") details: Optional[List[ErrorDetail]] = None request_id: Optional[str] = Field(None, alias="requestId") # Endpoints @app.get( "/users", response_model=UserListResponse, tags=["Users"], summary="List all users", description="Returns a paginated list of users with optional filtering.", responses={ 400: {"model": ErrorResponse, "description": "Invalid request"}, 401: {"model": ErrorResponse, "description": "Unauthorized"}, }, ) async def list_users( page: int = Query(1, ge=1, description="Page number"), limit: int = Query(20, ge=1, le=100, description="Items per page"), status: Optional[UserStatus] = Query(None, description="Filter by status"), search: Optional[str] = Query(None, min_length=2, max_length=100), ): """ List users with pagination and filtering. - **page**: Page number (1-based) - **limit**: Number of items per page (max 100) - **status**: Filter by user status - **search**: Se