model-skill

SKILL.md

Model Skill

Purpose

Design robust Pydantic v2 data models with full validation and type safety.

Instructions

Basic Model Structure

from pydantic import BaseModel, Field, field_validator, model_validator
from datetime import datetime
from typing import Optional, List
from enum import Enum

class Priority(str, Enum):
    """Task priority levels."""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    URGENT = "urgent"

class TodoStatus(str, Enum):
    """Task status values."""
    PENDING = "pending"
    COMPLETED = "completed"
    OVERDUE = "overdue"

class RecurrenceType(str, Enum):
    """Task recurrence options."""
    NONE = "none"
    DAILY = "daily"
    WEEKLY = "weekly"
    MONTHLY = "monthly"

Full Model Example

class TodoTask(BaseModel):
    """A todo task with full validation."""
    
    id: int = Field(default=0, description="Unique task identifier")
    title: str = Field(..., min_length=1, max_length=200, description="Task title")
    description: Optional[str] = Field(None, max_length=1000)
    priority: Priority = Field(default=Priority.MEDIUM)
    tags: List[str] = Field(default_factory=list)
    status: TodoStatus = Field(default=TodoStatus.PENDING)
    due_date: Optional[datetime] = None
    created_at: datetime = Field(default_factory=datetime.now)
    updated_at: datetime = Field(default_factory=datetime.now)
    completed_at: Optional[datetime] = None
    recurrence: RecurrenceType = Field(default=RecurrenceType.NONE)
    
    @field_validator('title')
    @classmethod
    def strip_title(cls, v: str) -> str:
        """Strip whitespace from title."""
        return v.strip()
    
    @field_validator('tags')
    @classmethod
    def normalize_tags(cls, v: List[str]) -> List[str]:
        """Normalize tags to lowercase."""
        return [tag.lower().strip() for tag in v if tag.strip()]
    
    @model_validator(mode='after')
    def check_overdue(self) -> 'TodoTask':
        """Auto-set overdue status if past due date."""
        if (self.due_date and 
            self.due_date < datetime.now() and 
            self.status == TodoStatus.PENDING):
            self.status = TodoStatus.OVERDUE
        return self
    
    model_config = {
        "use_enum_values": True,
        "validate_assignment": True,
        "json_encoders": {datetime: lambda v: v.isoformat()},
        "json_schema_extra": {
            "example": {
                "title": "Buy groceries",
                "priority": "medium",
                "tags": ["shopping"]
            }
        }
    }
    
    def to_dict(self) -> dict:
        """Convert to dictionary for storage."""
        return self.model_dump(mode='json')
    
    @classmethod
    def from_dict(cls, data: dict) -> 'TodoTask':
        """Create from dictionary."""
        return cls.model_validate(data)

Validation Patterns

Custom Field Validators

@field_validator('email')
@classmethod
def validate_email(cls, v: str) -> str:
    if '@' not in v:
        raise ValueError('Invalid email format')
    return v.lower()

Cross-field Validation

@model_validator(mode='after')
def validate_dates(self) -> 'Model':
    if self.end_date and self.start_date > self.end_date:
        raise ValueError('end_date must be after start_date')
    return self

Best Practices

  • Always use type hints
  • Provide descriptions for all fields
  • Use Enums for constrained choices
  • Add validators for data integrity
  • Include examples in schema
  • Use model_dump() for serialization
  • Use model_validate() for deserialization
Weekly Installs
3
First Seen
Feb 21, 2026
Installed on
opencode3
gemini-cli3
github-copilot3
codex3
kimi-cli3
amp3