Agent skill
pydantic-documentation
Pydantic model patterns for gh-pr-linear-issue-linker. Use when creating or modifying Pydantic models, webhook payloads, API responses, or any data structures.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/pydantic-documentation
SKILL.md
Pydantic Model Patterns
Critical Rule: Use Pydantic for ALL data structures - webhook payloads, API requests/responses, configuration models.
Core Pydantic Patterns
1. Webhook Payload Models
Best for: GitHub/Linear webhook payloads, ensuring type safety.
from pydantic import BaseModel, Field
class PullRequestEvent(BaseModel):
"""GitHub pull request webhook payload."""
action: str = Field(description="Event action (opened, synchronize, etc.)")
number: int = Field(description="Pull request number")
pull_request: PullRequest
sender: User
class PullRequest(BaseModel):
"""Pull request data from GitHub API."""
number: int
title: str
user: User
head: BranchRef
base: BranchRef
2. API Response Models
Best for: Structuring responses from GitHub/Linear APIs.
class LinearTicket(BaseModel):
"""Linear issue/ticket data."""
id: str
title: str
identifier: str # e.g., "ENG-123"
state: str
assignee: User | None = None
class GitHubComment(BaseModel):
"""GitHub PR comment payload."""
body: str = Field(description="Markdown comment body")
3. Configuration Models
Best for: Application settings and environment config.
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
"""Application configuration from environment variables."""
github_app_id: str
github_private_key: str
linear_api_key: str
webhook_secret: str
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
Patterns to Follow
Pattern 1: Enums for Webhook Events
from enum import StrEnum
class GitHubEvent(StrEnum):
"""GitHub webhook event types we handle."""
PULL_REQUEST = "pull_request"
PULL_REQUEST_REVIEW = "pull_request_review"
ISSUE_COMMENT = "issue_comment"
class PullRequestAction(StrEnum):
"""Pull request webhook actions."""
OPENED = "opened"
SYNCHRONIZE = "synchronize"
REOPENED = "reopened"
CLOSED = "closed"
Pattern 2: Nested Models for Complex Payloads
class User(BaseModel):
"""GitHub/Linear user data."""
id: int | str
login: str
email: str | None = None
class BranchRef(BaseModel):
"""Git branch reference."""
ref: str # Branch name
sha: str # Commit SHA
class PullRequest(BaseModel):
"""GitHub pull request data."""
number: int
title: str
state: str
user: User # Nested model
head: BranchRef # Nested model
base: BranchRef # Nested model
Pattern 3: Optional Fields with Defaults
class LinearTicket(BaseModel):
"""Linear issue data."""
id: str
title: str
identifier: str
state: str
# Optional fields
assignee: User | None = None
description: str | None = None
priority: int = 0
labels: list[str] = [] # Empty list default
# Use Field for validation
url: str = Field(pattern=r"^https://linear\.app/.*")
Pattern 4: Validation and Serialization
from pydantic import field_validator, field_serializer
class GitHubWebhook(BaseModel):
"""GitHub webhook payload with validation."""
event: str
signature: str
payload: dict
@field_validator("signature")
@classmethod
def validate_signature(cls, v: str) -> str:
"""Ensure signature has correct format."""
if not v.startswith("sha256="):
raise ValueError("Invalid signature format")
return v
@field_serializer("payload")
def serialize_payload(self, value: dict) -> str:
"""Serialize payload to JSON string."""
return json.dumps(value)
Anti-Patterns to Avoid
❌ Anti-Pattern 1: Using @dataclass Instead of Pydantic
# ❌ BAD - No runtime validation
from dataclasses import dataclass
@dataclass
class PullRequest:
number: int
title: str
Why it's bad: No validation, no JSON serialization, no FastAPI integration.
Fix: Use Pydantic BaseModel.
❌ Anti-Pattern 2: Missing Type Hints
# ❌ BAD - No type safety
class PullRequest(BaseModel):
number = 0 # What type is this?
title = "" # String? Optional?
Why it's bad: Loses all benefits of type checking and validation.
Fix: Always use explicit type hints.
❌ Anti-Pattern 3: Overly Permissive Types
# ❌ BAD - Accepts anything
class WebhookPayload(BaseModel):
data: dict # What's in this dict?
metadata: Any # Completely untyped
Why it's bad: Defeats the purpose of using Pydantic - no structure validation.
Fix: Define specific nested models.
# ✅ GOOD - Specific types
class WebhookPayload(BaseModel):
data: PullRequestData
metadata: WebhookMetadata
❌ Anti-Pattern 4: Mutable Defaults
# ❌ BAD - Mutable default argument
class Config(BaseModel):
tags: list[str] = [] # Shared across instances!
Why it's bad: Pydantic handles this correctly, but use Field(default_factory) to be explicit.
Fix: Use default_factory for mutable types.
# ✅ GOOD - Explicit default factory
class Config(BaseModel):
tags: list[str] = Field(default_factory=list)
❌ Anti-Pattern 5: Manual JSON Parsing
# ❌ BAD - Manual dict manipulation
data = json.loads(request.body)
pr_number = data["pull_request"]["number"]
title = data["pull_request"]["title"]
Why it's bad: Error-prone, no validation, tedious.
Fix: Use Pydantic model parsing.
# ✅ GOOD - Pydantic handles it
event = PullRequestEvent.model_validate(data)
pr_number = event.pull_request.number
title = event.pull_request.title
Quality Checklist
When creating or modifying Pydantic models:
✅ Model Structure
- Use BaseModel, never @dataclass
- Every field has explicit type hints
- Class docstring describes the model's purpose
- Optional fields use
| Noneand have defaults - Use specific types, not dict/Any unless truly dynamic
✅ Field Definitions
- Use Field() for validation constraints
- Use Field(description=...) for API documentation
- Mutable defaults use Field(default_factory=...)
- Pattern validation for strings (URLs, emails, etc.)
✅ Nested Models
- Complex objects use nested BaseModel, not raw dicts
- Shared models extracted to common module
- Clear hierarchy (Event -> PullRequest -> User)
✅ Enums
- Use StrEnum for string constants
- Class docstring explains purpose
- Values match external API exactly (GitHub/Linear)
Examples from Project
Webhook Event Model
# src/models/github.py
class PullRequestEvent(BaseModel):
"""GitHub pull_request webhook event."""
action: PullRequestAction
number: int
pull_request: PullRequest
repository: Repository
sender: User
API Response Model
# src/models/linear.py
class LinearTicket(BaseModel):
"""Linear issue from GraphQL API."""
id: str
identifier: str = Field(pattern=r"^[A-Z]+-\d+$") # e.g., "ENG-123"
title: str
state: str
assignee: User | None = None
Testing Models
import pytest
from pydantic import ValidationError
def test_pull_request_validation():
"""Test PullRequest model validates correctly."""
# Valid data
pr = PullRequest(number=123, title="Fix bug", user=user, ...)
assert pr.number == 123
# Invalid data
with pytest.raises(ValidationError):
PullRequest(number="not-a-number", ...)
Summary
| ✅ DO | ❌ DON'T |
|---|---|
| Use Pydantic BaseModel for all data | Use @dataclass or plain dicts |
| Add explicit type hints to all fields | Rely on implicit types |
| Use Field() for validation/defaults | Use mutable defaults directly |
| Parse JSON with model_validate() | Manual dict access |
| Define nested models for complex data | Use dict or Any |
Golden Rule: Every piece of external data (webhooks, API responses, config) should have a corresponding Pydantic model.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?