Modern Python backend stack: FastAPI, SQLAlchemy 2.0, Pydantic v2, uv, ruff. Use when: building Python APIs, async services, or working with Python backend code. Triggers: "fastapi", "python backend", "sqlalchemy", "pydantic", "uv", "ruff", "python api", "async python".
/plugin marketplace add timequity/vibe-coder/plugin install vibe-coder@vibe-coderThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/testing.mdLive docs: Add
use context7to prompt for up-to-date FastAPI, SQLAlchemy, Pydantic documentation.
| Tool | Purpose | Why |
|---|---|---|
| uv | Package manager | 10-100x faster than pip |
| ruff | Linter + formatter | Replaces black, isort, flake8 |
| FastAPI | Web framework | Async, auto-docs, Pydantic |
| SQLAlchemy 2.0 | ORM | Async support, type hints |
| Pydantic v2 | Validation | 5-50x faster than v1 |
| pytest | Testing | See testing.md |
# Initialize
uv init my-api
cd my-api
uv add fastapi sqlalchemy[asyncio] pydantic pydantic-settings
uv add --dev ruff pytest pytest-asyncio httpx
# pyproject.toml
[tool.ruff]
line-length = 100
select = ["E", "F", "I", "N", "UP", "B", "A", "C4", "SIM"]
[tool.ruff.format]
quote-style = "double"
[tool.pytest.ini_options]
asyncio_mode = "auto"
src/
├── main.py # FastAPI app
├── config.py # Settings (pydantic-settings)
├── db/
│ ├── __init__.py
│ ├── engine.py # Async engine + session
│ └── models.py # SQLAlchemy models
├── api/
│ ├── __init__.py
│ ├── deps.py # Dependencies (get_db, get_user)
│ └── routes/
│ ├── __init__.py
│ ├── auth.py
│ └── users.py
├── schemas/ # Pydantic models
│ ├── __init__.py
│ └── user.py
└── services/ # Business logic
└── user.py
tests/
├── conftest.py
└── test_users.py
from fastapi import FastAPI
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
await init_db()
yield
# Shutdown
await close_db()
app = FastAPI(lifespan=lifespan)
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/{user_id}", response_model=UserOut)
async def get_user(
user_id: int,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
user = await db.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
from pydantic import BaseModel, EmailStr, Field
from datetime import datetime
class UserCreate(BaseModel):
email: EmailStr
name: str = Field(min_length=1, max_length=100)
class UserOut(BaseModel):
id: int
email: str
name: str
created_at: datetime
model_config = {"from_attributes": True} # For ORM mode
from pydantic_settings import BaseSettings
from functools import lru_cache
class Settings(BaseSettings):
database_url: str
secret_key: str
debug: bool = False
model_config = {"env_file": ".env"}
@lru_cache
def get_settings() -> Settings:
return Settings()
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker, DeclarativeBase
engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/db",
echo=False,
pool_size=5,
max_overflow=10,
)
AsyncSessionLocal = sessionmaker(
engine, class_=AsyncSession, expire_on_commit=False
)
class Base(DeclarativeBase):
pass
from sqlalchemy import String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
name: Mapped[str] = mapped_column(String(100))
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
posts: Mapped[list["Post"]] = relationship(back_populates="author")
from typing import AsyncGenerator
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
from sqlalchemy import select
from sqlalchemy.orm import selectinload
# Get one
user = await db.get(User, user_id)
# Query with filter
stmt = select(User).where(User.email == email)
result = await db.execute(stmt)
user = result.scalar_one_or_none()
# Eager load relationships
stmt = select(User).options(selectinload(User.posts)).where(User.id == user_id)
# Pagination
stmt = select(User).offset(skip).limit(limit).order_by(User.created_at.desc())
result = await db.execute(stmt)
users = result.scalars().all()
from fastapi import HTTPException, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return JSONResponse(
status_code=422,
content={"error": {"code": "VALIDATION_ERROR", "details": exc.errors()}},
)
# Custom exceptions
class NotFoundError(Exception):
def __init__(self, resource: str, id: int):
self.resource = resource
self.id = id
@app.exception_handler(NotFoundError)
async def not_found_handler(request, exc):
return JSONResponse(
status_code=404,
content={"error": {"message": f"{exc.resource} {exc.id} not found"}},
)
| Don't | Do Instead |
|---|---|
pip install | uv add |
black + isort + flake8 | ruff |
| SQLAlchemy 1.x style | SQLAlchemy 2.0 with Mapped[] |
| Pydantic v1 | Pydantic v2 (model_config, not Config) |
| Sync database calls | Async with asyncpg/aiosqlite |
| Global DB session | Dependency injection |
| Business logic in routes | Services layer |
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.