openapi-spec-generation
Generate and maintain OpenAPI 3.1 specifications from code, design-first specs, and validation patterns. Use when creating API documentation, generating SDKs, or ensuring API contract compliance.
Best use case
openapi-spec-generation is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Generate and maintain OpenAPI 3.1 specifications from code, design-first specs, and validation patterns. Use when creating API documentation, generating SDKs, or ensuring API contract compliance.
Teams using openapi-spec-generation should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/openapi-spec-generation/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How openapi-spec-generation Compares
| Feature / Agent | openapi-spec-generation | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Generate and maintain OpenAPI 3.1 specifications from code, design-first specs, and validation patterns. Use when creating API documentation, generating SDKs, or ensuring API contract compliance.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# OpenAPI Spec Generation
Comprehensive patterns for creating, maintaining, and validating OpenAPI 3.1 specifications for RESTful APIs.
## When to Use This Skill
- Creating API documentation from scratch
- Generating OpenAPI specs from existing code
- Designing API contracts (design-first approach)
- Validating API implementations against specs
- Generating client SDKs from specs
- Setting up API documentation portals
## Core Concepts
### 1. OpenAPI 3.1 Structure
```yaml
openapi: 3.1.0
info:
title: API Title
version: 1.0.0
servers:
- url: https://api.example.com/v1
paths:
/resources:
get: ...
components:
schemas: ...
securitySchemes: ...
```
### 2. Design Approaches
| Approach | Description | Best For |
| ---------------- | ---------------------------- | ------------------- |
| **Design-First** | Write spec before code | New APIs, contracts |
| **Code-First** | Generate spec from code | Existing APIs |
| **Hybrid** | Annotate code, generate spec | Evolving APIs |
## Templates
### Template 1: Complete API Specification
```yaml
openapi: 3.1.0
info:
title: User Management API
description: |
API for managing users and their profiles.
## Authentication
All endpoints require Bearer token authentication.
## Rate Limiting
- 1000 requests per minute for standard tier
- 10000 requests per minute for enterprise tier
version: 2.0.0
contact:
name: API Support
email: api-support@example.com
url: https://docs.example.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: https://api.example.com/v2
description: Production
- url: https://staging-api.example.com/v2
description: Staging
- url: http://localhost:3000/v2
description: Local development
tags:
- name: Users
description: User management operations
- name: Profiles
description: User profile operations
- name: Admin
description: Administrative operations
paths:
/users:
get:
operationId: listUsers
summary: List all users
description: Returns a paginated list of users with optional filtering.
tags:
- Users
parameters:
- $ref: "#/components/parameters/PageParam"
- $ref: "#/components/parameters/LimitParam"
- name: status
in: query
description: Filter by user status
schema:
$ref: "#/components/schemas/UserStatus"
- name: search
in: query
description: Search by name or email
schema:
type: string
minLength: 2
maxLength: 100
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/UserListResponse"
examples:
default:
$ref: "#/components/examples/UserListExample"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"429":
$ref: "#/components/responses/RateLimited"
security:
- bearerAuth: []
post:
operationId: createUser
summary: Create a new user
description: Creates a new user account and sends welcome email.
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUserRequest"
examples:
standard:
summary: Standard user
value:
email: user@example.com
name: John Doe
role: user
admin:
summary: Admin user
value:
email: admin@example.com
name: Admin User
role: admin
responses:
"201":
description: User created successfully
content:
application/json:
schema:
$ref: "#/components/schemas/User"
headers:
Location:
description: URL of created user
schema:
type: string
format: uri
"400":
$ref: "#/components/responses/BadRequest"
"409":
description: Email already exists
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
security:
- bearerAuth: []
/users/{userId}:
parameters:
- $ref: "#/components/parameters/UserIdParam"
get:
operationId: getUser
summary: Get user by ID
tags:
- Users
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
$ref: "#/components/responses/NotFound"
security:
- bearerAuth: []
patch:
operationId: updateUser
summary: Update user
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateUserRequest"
responses:
"200":
description: User updated
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
security:
- bearerAuth: []
delete:
operationId: deleteUser
summary: Delete user
tags:
- Users
- Admin
responses:
"204":
description: User deleted
"404":
$ref: "#/components/responses/NotFound"
security:
- bearerAuth: []
- apiKey: []
components:
schemas:
User:
type: object
required:
- id
- email
- name
- status
- createdAt
properties:
id:
type: string
format: uuid
readOnly: true
description: Unique user identifier
email:
type: string
format: email
description: User email address
name:
type: string
minLength: 1
maxLength: 100
description: User display name
status:
$ref: "#/components/schemas/UserStatus"
role:
type: string
enum: [user, moderator, admin]
default: user
avatar:
type: string
format: uri
nullable: true
metadata:
type: object
additionalProperties: true
description: Custom metadata
createdAt:
type: string
format: date-time
readOnly: true
updatedAt:
type: string
format: date-time
readOnly: true
UserStatus:
type: string
enum: [active, inactive, suspended, pending]
description: User account status
CreateUserRequest:
type: object
required:
- email
- name
properties:
email:
type: string
format: email
name:
type: string
minLength: 1
maxLength: 100
role:
type: string
enum: [user, moderator, admin]
default: user
metadata:
type: object
additionalProperties: true
UpdateUserRequest:
type: object
minProperties: 1
properties:
name:
type: string
minLength: 1
maxLength: 100
status:
$ref: "#/components/schemas/UserStatus"
role:
type: string
enum: [user, moderator, admin]
metadata:
type: object
additionalProperties: true
UserListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
$ref: "#/components/schemas/User"
pagination:
$ref: "#/components/schemas/Pagination"
Pagination:
type: object
required:
- page
- limit
- total
- totalPages
properties:
page:
type: integer
minimum: 1
limit:
type: integer
minimum: 1
maximum: 100
total:
type: integer
minimum: 0
totalPages:
type: integer
minimum: 0
hasNext:
type: boolean
hasPrev:
type: boolean
Error:
type: object
required:
- code
- message
properties:
code:
type: string
description: Error code for programmatic handling
message:
type: string
description: Human-readable error message
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
requestId:
type: string
description: Request ID for support
parameters:
UserIdParam:
name: userId
in: path
required: true
description: User ID
schema:
type: string
format: uuid
PageParam:
name: page
in: query
description: Page number (1-based)
schema:
type: integer
minimum: 1
default: 1
LimitParam:
name: limit
in: query
description: Items per page
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: VALIDATION_ERROR
message: Invalid request parameters
details:
- field: email
message: Must be a valid email address
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: User not found
RateLimited:
description: Too many requests
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
headers:
Retry-After:
description: Seconds until rate limit resets
schema:
type: integer
X-RateLimit-Limit:
description: Request limit per window
schema:
type: integer
X-RateLimit-Remaining:
description: Remaining requests in window
schema:
type: integer
examples:
UserListExample:
value:
data:
- id: "550e8400-e29b-41d4-a716-446655440000"
email: "john@example.com"
name: "John Doe"
status: "active"
role: "user"
createdAt: "2024-01-15T10:30:00Z"
pagination:
page: 1
limit: 20
total: 1
totalPages: 1
hasNext: false
hasPrev: false
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT token from /auth/login
apiKey:
type: apiKey
in: header
name: X-API-Key
description: API key for service-to-service calls
security:
- bearerAuth: []
```
### 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**: Search by name or email
"""
# Implementation
pass
@app.post(
"/users",
response_model=User,
status_code=201,
tags=["Users"],
summary="Create a new user",
responses={
400: {"model": ErrorResponse},
409: {"model": ErrorResponse, "description": "Email already exists"},
},
)
async def create_user(user: UserCreate):
"""Create a new user and send welcome email."""
pass
@app.get(
"/users/{user_id}",
response_model=User,
tags=["Users"],
summary="Get user by ID",
responses={404: {"model": ErrorResponse}},
)
async def get_user(
user_id: UUID = Path(..., description="User ID"),
):
"""Retrieve a specific user by their ID."""
pass
@app.patch(
"/users/{user_id}",
response_model=User,
tags=["Users"],
summary="Update user",
responses={
400: {"model": ErrorResponse},
404: {"model": ErrorResponse},
},
)
async def update_user(
user_id: UUID = Path(..., description="User ID"),
user: UserUpdate = ...,
):
"""Update user attributes."""
pass
@app.delete(
"/users/{user_id}",
status_code=204,
tags=["Users", "Admin"],
summary="Delete user",
responses={404: {"model": ErrorResponse}},
)
async def delete_user(
user_id: UUID = Path(..., description="User ID"),
):
"""Permanently delete a user."""
pass
# Export OpenAPI spec
if __name__ == "__main__":
import json
print(json.dumps(app.openapi(), indent=2))
```
### Template 3: Code-First (TypeScript/Express with tsoa)
```typescript
// tsoa generates OpenAPI from TypeScript decorators
import {
Controller,
Get,
Post,
Patch,
Delete,
Route,
Path,
Query,
Body,
Response,
SuccessResponse,
Tags,
Security,
Example,
} from "tsoa";
// Models
interface User {
/** Unique identifier */
id: string;
/** User email address */
email: string;
/** Display name */
name: string;
status: UserStatus;
role: UserRole;
/** Avatar URL */
avatar?: string;
/** Custom metadata */
metadata?: Record<string, unknown>;
createdAt: Date;
updatedAt?: Date;
}
enum UserStatus {
Active = "active",
Inactive = "inactive",
Suspended = "suspended",
Pending = "pending",
}
enum UserRole {
User = "user",
Moderator = "moderator",
Admin = "admin",
}
interface CreateUserRequest {
email: string;
name: string;
role?: UserRole;
metadata?: Record<string, unknown>;
}
interface UpdateUserRequest {
name?: string;
status?: UserStatus;
role?: UserRole;
metadata?: Record<string, unknown>;
}
interface Pagination {
page: number;
limit: number;
total: number;
totalPages: number;
hasNext: boolean;
hasPrev: boolean;
}
interface UserListResponse {
data: User[];
pagination: Pagination;
}
interface ErrorResponse {
code: string;
message: string;
details?: { field: string; message: string }[];
requestId?: string;
}
@Route("users")
@Tags("Users")
export class UsersController extends Controller {
/**
* List all users with pagination and filtering
* @param page Page number (1-based)
* @param limit Items per page (max 100)
* @param status Filter by user status
* @param search Search by name or email
*/
@Get()
@Security("bearerAuth")
@Response<ErrorResponse>(400, "Invalid request")
@Response<ErrorResponse>(401, "Unauthorized")
@Example<UserListResponse>({
data: [
{
id: "550e8400-e29b-41d4-a716-446655440000",
email: "john@example.com",
name: "John Doe",
status: UserStatus.Active,
role: UserRole.User,
createdAt: new Date("2024-01-15T10:30:00Z"),
},
],
pagination: {
page: 1,
limit: 20,
total: 1,
totalPages: 1,
hasNext: false,
hasPrev: false,
},
})
public async listUsers(
@Query() page: number = 1,
@Query() limit: number = 20,
@Query() status?: UserStatus,
@Query() search?: string,
): Promise<UserListResponse> {
// Implementation
throw new Error("Not implemented");
}
/**
* Create a new user
*/
@Post()
@Security("bearerAuth")
@SuccessResponse(201, "Created")
@Response<ErrorResponse>(400, "Invalid request")
@Response<ErrorResponse>(409, "Email already exists")
public async createUser(@Body() body: CreateUserRequest): Promise<User> {
this.setStatus(201);
throw new Error("Not implemented");
}
/**
* Get user by ID
* @param userId User ID
*/
@Get("{userId}")
@Security("bearerAuth")
@Response<ErrorResponse>(404, "User not found")
public async getUser(@Path() userId: string): Promise<User> {
throw new Error("Not implemented");
}
/**
* Update user attributes
* @param userId User ID
*/
@Patch("{userId}")
@Security("bearerAuth")
@Response<ErrorResponse>(400, "Invalid request")
@Response<ErrorResponse>(404, "User not found")
public async updateUser(
@Path() userId: string,
@Body() body: UpdateUserRequest,
): Promise<User> {
throw new Error("Not implemented");
}
/**
* Delete user
* @param userId User ID
*/
@Delete("{userId}")
@Tags("Users", "Admin")
@Security("bearerAuth")
@SuccessResponse(204, "Deleted")
@Response<ErrorResponse>(404, "User not found")
public async deleteUser(@Path() userId: string): Promise<void> {
this.setStatus(204);
}
}
```
### Template 4: Validation & Linting
```bash
# Install validation tools
npm install -g @stoplight/spectral-cli
npm install -g @redocly/cli
# Spectral ruleset (.spectral.yaml)
cat > .spectral.yaml << 'EOF'
extends: ["spectral:oas", "spectral:asyncapi"]
rules:
# Enforce operation IDs
operation-operationId: error
# Require descriptions
operation-description: warn
info-description: error
# Naming conventions
operation-operationId-valid-in-url: true
# Security
operation-security-defined: error
# Response codes
operation-success-response: error
# Custom rules
path-params-snake-case:
description: Path parameters should be snake_case
severity: warn
given: "$.paths[*].parameters[?(@.in == 'path')].name"
then:
function: pattern
functionOptions:
match: "^[a-z][a-z0-9_]*$"
schema-properties-camelCase:
description: Schema properties should be camelCase
severity: warn
given: "$.components.schemas[*].properties[*]~"
then:
function: casing
functionOptions:
type: camel
EOF
# Run Spectral
spectral lint openapi.yaml
# Redocly config (redocly.yaml)
cat > redocly.yaml << 'EOF'
extends:
- recommended
rules:
no-invalid-media-type-examples: error
no-invalid-schema-examples: error
operation-4xx-response: warn
request-mime-type:
severity: error
allowedValues:
- application/json
response-mime-type:
severity: error
allowedValues:
- application/json
- application/problem+json
theme:
openapi:
generateCodeSamples:
languages:
- lang: curl
- lang: python
- lang: javascript
EOF
# Run Redocly
redocly lint openapi.yaml
redocly bundle openapi.yaml -o bundled.yaml
redocly preview-docs openapi.yaml
```
## SDK Generation
```bash
# OpenAPI Generator
npm install -g @openapitools/openapi-generator-cli
# Generate TypeScript client
openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-fetch \
-o ./generated/typescript-client \
--additional-properties=supportsES6=true,npmName=@myorg/api-client
# Generate Python client
openapi-generator-cli generate \
-i openapi.yaml \
-g python \
-o ./generated/python-client \
--additional-properties=packageName=api_client
# Generate Go client
openapi-generator-cli generate \
-i openapi.yaml \
-g go \
-o ./generated/go-client
```
## Best Practices
### Do's
- **Use $ref** - Reuse schemas, parameters, responses
- **Add examples** - Real-world values help consumers
- **Document errors** - All possible error codes
- **Version your API** - In URL or header
- **Use semantic versioning** - For spec changes
### Don'ts
- **Don't use generic descriptions** - Be specific
- **Don't skip security** - Define all schemes
- **Don't forget nullable** - Be explicit about null
- **Don't mix styles** - Consistent naming throughout
- **Don't hardcode URLs** - Use server variables
## Resources
- [OpenAPI 3.1 Specification](https://spec.openapis.org/oas/v3.1.0)
- [Swagger Editor](https://editor.swagger.io/)
- [Redocly](https://redocly.com/)
- [Spectral](https://stoplight.io/open-source/spectral)Related Skills
Google Maps Lead Generation
Generate high-quality B2B leads from Google Maps with deep contact enrichment.
ai-music-generation
Generate AI music and songs with Diffrythm, Tencent Song Generation via inference.sh CLI. Models: Diffrythm (fast song generation), Tencent Song Generation (full songs with vocals). Capabilities: text-to-music, song generation, instrumental, lyrics to song, soundtrack creation. Use for: background music, social media content, game soundtracks, podcasts, royalty-free music. Triggers: music generation, ai music, generate song, ai composer, text to music, song generator, create music with ai, suno alternative, udio alternative, ai song, ai soundtrack, generate soundtrack, ai jingle, music ai, beat generator
Goal: Build an LLM-based RAG App
Here is the MVP Implementation Plan.
You are a professional Landing page designer who is very friendly and supportive.
Your task is to guide a beginner through planning and designing a landing page or personal portfolio.
You are a professional Chief Marketing Officer. Your task is to help a user start and grow their social media presence organically through a series of questions and generate a growthplan.md blueprint.
Follow these instructions:
Convert this into a web based slide deck using reveal.js.
Use the following brand colour and logo.
technical-article-writer
Write compelling technical articles and blog posts for developer audiences. Use this skill whenever the user asks to write a blog post, technical article, or any long-form technical content. Also trigger when the user says 'write about [technical topic]', 'help me draft an article', 'turn this into a blog post', 'write a post about', 'I want to publish something about', or mentions writing for a developer audience. Covers the full pipeline: idea sharpening, hook/title generation, article structure, body drafting, and editing. Even if the user just says 'I want to write about X' without specifying format, use this skill. Do NOT use for platform-specific optimization, newsletter strategy, or ghostwriting voice matching.
substack-ghostwriting
Write, optimize, and grow Substack content — both newsletter issues (email-first) and web posts (web-first articles/essays). Covers ghostwriting with voice matching, Substack algorithm optimization, Notes strategy, email formatting, SEO, growth tactics, and monetization planning. Use when the user mentions Substack, newsletters, write a newsletter issue, Substack post, Substack article, web post on Substack, evergreen content, SEO for Substack, newsletter growth, Notes strategy, ghostwrite for, match someone's voice, write in the style of, newsletter monetization, paid subscribers, or any task involving Substack as a platform. Also trigger for general article/newsletter writing even if Substack isn't named explicitly, or when the user wants to adapt existing content (blog post, talk, thread) into newsletter or web post format. Do NOT use for generic blog post writing without a newsletter/Substack context (-> See samber/cc-skills@technical-article-writer skill).
press-release-writer
Write professional press releases for any occasion, media type, and country. Use when the user wants to write, draft, or improve a press release, communiqué de presse, media announcement, news release, or PR statement — including product launches, funding rounds, partnerships, crisis communications, earnings, executive hires, events, M&A, open source milestones, and media advisories. Covers all release types, media targets (print, digital/wire, broadcast, social/SMPR, trade press), and region-specific conventions (Western/Eastern Europe, Americas, Middle East, Africa, Asia, Oceania). Also trigger when the user says 'I need to announce something' or 'how do I tell the press about X.'
Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.
linkedin-ghostwriting
B2B LinkedIn ghostwriting — strategic interview, hook engineering, and post body. Use when the user wants to write LinkedIn content, create ghostwritten posts, ghostwrite for a founder or executive, develop a B2B social strategy, or needs hooks, post structures, or copywriting frameworks for LinkedIn. Apply when the user shares a story, result, or insight and wants it turned into a post.
docx
Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a 'report', 'memo', 'letter', 'template', or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.