architect-python-uv-fastapi-sqlalchemy

Use when scaffolding production-ready FastAPI services with uv, SQLAlchemy, Alembic, Postgres, Docker, and CI gates.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "architect-python-uv-fastapi-sqlalchemy" with this command: npx skills add ajrlewis/ai-skills/ajrlewis-ai-skills-architect-python-uv-fastapi-sqlalchemy

Architect: Python + uv + FastAPI + SQLAlchemy

Use this skill when the user wants a production API scaffold in Python with modern packaging (uv), database migrations, containerization, and CI. Docker is required by default for this runnable base architect skill. Only allow NO_DOCKER=yes when the user explicitly asks for a local-only exception.

Inputs

Collect these values first:

  • PROJECT_NAME: kebab-case repository/folder name.
  • MODULE_NAME: import-safe module name (usually snake_case).
  • PYTHON_VERSION: default 3.12.
  • DATABASE_URL: runtime DB URL.
  • NO_DOCKER: default no. Set yes only when user explicitly opts out of containerization.

Use these version defaults unless user requests otherwise:

  • uv latest stable via astral-sh/setup-uv
  • Python 3.12
  • postgres:16-alpine

Preflight Checks

Run before scaffolding:

command -v uv >/dev/null && uv --version || echo "uv-missing"
python3 --version
command -v docker >/dev/null && docker --version || echo "docker-missing"

Execution modes:

  • production-default: create and validate container artifacts (NO_DOCKER=no).
  • local-no-docker: skip container files only when user explicitly sets NO_DOCKER=yes.
  • offline-smoke: tools/network constrained; scaffold structure and report verification limits.

Production-default contract:

  • Must create Dockerfile, .dockerignore, and docker-compose.yml.
  • Must include CI image build check.
  • Must run containerized smoke validation.

Scaffold Workflow

  1. Initialize project:
uv init --package {{PROJECT_NAME}}
cd {{PROJECT_NAME}}
  1. Install runtime and dev dependencies:
uv add fastapi "uvicorn[standard]" sqlalchemy asyncpg alembic pydantic-settings
uv add -d pytest pytest-asyncio httpx ruff mypy
  1. Create source layout:
src/{{MODULE_NAME}}/
  api/routes/health.py
  core/config.py
  db/base.py
  db/session.py
  main.py
tests/
  1. Initialize Alembic and wire metadata:
uv run alembic init alembic
  • Set alembic.ini sqlalchemy.url to ${DATABASE_URL}.
  • In alembic/env.py, import Base.metadata from src/{{MODULE_NAME}}/db/base.py.
  1. Add infrastructure and CI files (NO_DOCKER=no):
  • Dockerfile
  • .dockerignore
  • docker-compose.yml
  • .github/workflows/ci.yml If NO_DOCKER=yes, document this exception in project notes and keep non-container validation.

Required File Templates

src/{{MODULE_NAME}}/core/config.py

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
    app_name: str = "api"
    environment: str = "development"
    database_url: str = "postgresql+asyncpg://app:app@localhost:5432/app"


settings = Settings()

src/{{MODULE_NAME}}/db/base.py

from sqlalchemy.orm import DeclarativeBase


class Base(DeclarativeBase):
    pass

src/{{MODULE_NAME}}/db/session.py

from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine

from {{MODULE_NAME}}.core.config import settings

engine = create_async_engine(settings.database_url, pool_pre_ping=True)
SessionLocal = async_sessionmaker(bind=engine, expire_on_commit=False)

src/{{MODULE_NAME}}/api/routes/health.py

from fastapi import APIRouter

router = APIRouter()


@router.get("/healthz", tags=["health"])
async def healthcheck() -> dict[str, str]:
    return {"status": "ok"}

src/{{MODULE_NAME}}/main.py

from fastapi import FastAPI

from {{MODULE_NAME}}.api.routes.health import router as health_router

app = FastAPI(title="{{PROJECT_NAME}}")
app.include_router(health_router)

Dockerfile

FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS build
WORKDIR /app
COPY pyproject.toml uv.lock ./
COPY src ./src
RUN uv sync --frozen --no-dev

FROM python:3.12-slim AS run
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN useradd --create-home --shell /bin/bash app
COPY --from=build /app/.venv /app/.venv
COPY src ./src
COPY alembic ./alembic
COPY alembic.ini ./
ENV PATH="/app/.venv/bin:$PATH"
USER app
EXPOSE 8000
CMD ["uvicorn", "{{MODULE_NAME}}.main:app", "--host", "0.0.0.0", "--port", "8000"]

.dockerignore

.git
.venv
__pycache__
.pytest_cache
.mypy_cache
.ruff_cache
*.pyc
dist
build

docker-compose.yml

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 5s
      retries: 20
    volumes:
      - pg_data:/var/lib/postgresql/data

  api:
    build: .
    environment:
      DATABASE_URL: postgresql+asyncpg://app:app@db:5432/app
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8000:8000"

volumes:
  pg_data:

Keep ports: - "8000:8000" on the api service so the host can reach the app. If documenting direct docker run usage for the API image, include -p 8000:8000 and the required DATABASE_URL; docker compose remains the default local path because it provides the database too.

.github/workflows/ci.yml

name: ci
on:
  push:
  pull_request:

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - uses: astral-sh/setup-uv@v5
      - name: Install deps
        run: uv sync --frozen --dev
      - name: Ruff
        run: uv run ruff check .
      - name: Ruff Docstrings
        run: uv run ruff check . --select D
      - name: Mypy
        run: uv run mypy src
      - name: Pytest
        run: uv run pytest -q
      - uses: docker/setup-buildx-action@v3
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: false
          tags: {{PROJECT_NAME}}:ci
          cache-from: type=gha
          cache-to: type=gha,mode=max

Guardrails

  • Documentation contract for generated code:

    • Python: write module docstrings and docstrings for public classes, methods, and functions.
    • Next.js/TypeScript: write JSDoc for exported components, hooks, utilities, and route handlers.
    • Add concise rationale comments only for non-obvious logic, invariants, or safety constraints.
    • Apply this contract even when using template snippets below; expand templates as needed.
  • Keep async DB stack consistent (sqlalchemy.ext.asyncio + asyncpg).

  • Never hardcode secrets; use environment variables and .env.

  • Ensure Alembic migrations are generated and committed.

  • Ensure container runs as non-root user.

  • Prefer docker compose in docs and scripts.

  • Treat NO_DOCKER=yes as an explicit exception, not default behavior.

  • Ensure uv.lock is committed before Docker build; the Dockerfile copies it explicitly for deterministic uv sync --frozen installs.

Validation Checklist

  • Confirm generated code includes required docstrings/JSDoc and rationale comments for non-obvious logic.

Run and fix failures before finishing:

uv run ruff check .
uv run ruff check . --select D
uv run mypy src
uv run pytest -q
uv run alembic upgrade head
test -f uv.lock
docker build -t {{PROJECT_NAME}}:local .
docker compose up -d --build
docker compose ps
curl http://localhost:8000/healthz

local-no-docker (NO_DOCKER=yes):

uv run ruff check .
uv run ruff check . --select D
uv run mypy src
uv run pytest -q
uv run alembic upgrade head

Fallback (offline-smoke):

python3 -m compileall src
test -f Dockerfile || echo "docker-artifacts-missing-in-offline-smoke"

Decision Justification Rule

  • Every non-trivial decision must include a concrete justification.
  • Capture the alternatives considered and why they were rejected.
  • State tradeoffs and residual risks for the chosen option.
  • If justification is missing, treat the task as incomplete and surface it as a blocker.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

addon-docling-legal-chunk-embed

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

architect-python-uv-batch

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

addon-google-agent-dev-kit

No summary provided by upstream source.

Repository SourceNeeds Review