Use when scaffolding or production-hardening a FastAPI service shell after backend architecture is approved or deferred. Produces the settings/logging/health/error-handling/lifespan/DI/container baseline the other FastAPI skills extend. Not for auth, observability, tasks, or performance.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
The command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
File Explorer
2 files
Showing SKILL.md
SKILL.md
Source instructions · Read-only preview
name
fastapi-service-scaffold
description
Use when scaffolding or production-hardening a FastAPI service shell after backend architecture is approved or deferred. Produces the settings/logging/health/error-handling/lifespan/DI/container baseline the other FastAPI skills extend. Not for auth, observability, tasks, or performance.
FastAPI Service Scaffold
When to use
Invoke when starting a new FastAPI service, standardizing an existing service baseline, modernizing a service that lacks validated settings, structured logging, health probes, or layered error handling, or preparing a FastAPI service for container deployment.
Do not use for: auth, session, or OWASP review work (use fastapi-auth-and-security-review), observability vendor wiring — OpenTelemetry, prometheus-client, SLO/alerts (use fastapi-observability-readiness), Celery/RQ/arq or Kafka task and event integration (use fastapi-async-and-task-integration), or performance and resilience gating — pool sizing, circuit breakers, load-test gates (use fastapi-performance-and-resilience).
Inputs
Required:
Service name and the business capability it serves.
Approved backend-architecture.md, or explicit confirmation that backend architecture is intentionally deferred.
Optional:
Approved architecture/security decisions on auth provider, session model, and secret handling.
Data layer named by architecture (SQLAlchemy 2.x + Alembic default) — registered as a seam only, not implemented here.
ASGI server choice if silent (Uvicorn standalone for dev; Gunicorn + uvicorn.workers.UvicornWorker for prod).
Target Python version (3.11+ default), dependency manager (uv default), and monorepo vs single-service repo placement.
Operating rules
Never generate tutorial-grade scaffolding. Assume multiple environments, structured logging, container deployment, ASGI-lifespan shutdown, and operational ownership.
Consume backend-architecture.md; do not invent decisions. Domain boundaries, data layer, and contracts belong to backend-architecture.md; auth provider and secret handling belong to architecture/security. If either is silent on a decision this scaffold needs, pause and raise an ADR candidate rather than guessing.
Owns the DI and principal-provider baseline only — the shell, not the flow. Token verification, session, and protected-route logic belong to fastapi-auth-and-security-review. Scaffold the seam (a typed Depends); do not implement the flow.
Secure by default: settings are validated at boot and fail fast; no secrets in source, committed config, the image, or .env; the container runs as a non-root user from a digest-pinned base image.
Settings are validated, not read ad hoc: a single typed Pydantic Settings (BaseSettings) instance built at startup. Missing or malformed required variables abort boot with a clear message — never a runtime None.
Error handling is layered in a specific order: sys.excepthook and the asyncio loop exception handler (log fatal, flush, exit non-zero for unhandled) → FastAPI/Starlette exception handlers (structured body, no traceback or internals in non-dev) → ASGI-lifespan graceful shutdown (stop accepting, drain in-flight, close registered resources within a bounded timeout) wired to uvicorn signal handling. All four are required.
Observability is a seam, not an implementation: a structlog structured logger bound to a contextvars request context (request id correlated) is mandatory in the baseline; OpenTelemetry, metrics, and alerting are explicitly deferred to fastapi-observability-readiness behind a no-op tracer/metrics interface.
Health probes are mandatory: a liveness endpoint (process is up) and a readiness endpoint (registered dependency checks pass) are separate and wired before any feature route.
A scaffold that does not run is not done. Run typecheck, lint, the test run, and a boot smoke check before declaring completion; fix and re-run on failure.
Confirm the target directory before writing files. Recommend services/<service-name>/ in a monorepo or repo root for a single-service repo. Refuse to write into a plugin or skill repository without explicit user override.
Output contract
The generated service shell MUST conform to:
deployment-standards — env-agnostic image; runtime config injected, not baked; one artifact per environment; non-root container.
observability-standards — structured logging with request-id correlation and an environment tag; tracer/metrics seam present.
security-standards — no secrets in source, committed config, or image; settings fail fast on missing required secrets.
Upstream contract: backend-architecture.md is the source of truth for domain boundaries, data layer, and contracts; architecture/security is the source of truth for auth provider, session model, and secret handling. If either is silent on a decision this scaffold needs, pause and raise an ADR candidate rather than guessing.
Progressive references
Read references/fastapi-scaffold-playbook.md when implementing any owned area or checking the anti-pattern list.
Read references/fastapi-scaffold-quality-rubric.md before declaring the scaffold complete.
Use assets/fastapi-service-scaffold.template.md as the directory-layout, settings, and lifespan reference.
Process
Gather context: service name, business capability, target directory, target Python version, dependency manager, and the auth provider decision from architecture/security. Load backend-architecture.md and extract domain boundaries, data layer, and contracts. If a needed decision is missing, raise an ADR candidate before proceeding. Confirm the target directory is not a plugin or skill repository.
Generate the project layout: pyproject.toml (deps pinned exactly with a hashed lockfile — no unbounded specifiers, requires-python set), mypy/ruff config, .gitignore, and the package structure (domain layout per backend-architecture.md). Reference assets/fastapi-service-scaffold.template.md for the canonical layout.
Generate validated settings: a Pydantic Settings(BaseSettings) in app/config.py parsing the environment at import, instantiated once; abort with a clear message on any missing or malformed required variable. Create .env.example documenting every variable with placeholder values only.
Generate the structured logging and request-context seam: a structlog logger in app/observability/logging.py; a contextvars request context in app/observability/context.py; ASGI middleware that assigns or propagates a request id and binds a bound logger. Add a no-op tracer/metrics interface in app/observability/telemetry.py with explicit TODO comments naming fastapi-observability-readiness as the owner.
Generate the layered error handling: sys.excepthook and loop.set_exception_handler (log fatal, flush, exit non-zero) in app/server/process_handlers.py; FastAPI/Starlette exception handlers returning a structured body with no traceback or internals in non-dev; an ASGI-lifespan (lifespan context manager) that on shutdown stops accepting, drains in-flight, and closes registered resource hooks within a bounded timeout.
Generate health probes: a liveness endpoint (/healthz) returning 200 when the process is up, and a readiness endpoint (/readyz) iterating registered dependency-check callables and returning 503 until all pass. Wire both before any feature router.
Generate the DI and principal-provider baseline: FastAPI Depends providers in app/container.py. Register the principal/auth-context provider as a typed dependency shell. Add explicit TODO comments naming as the owner of token verification, session, and protected-route logic, and the data-layer client (SQLAlchemy session) as a seam owned by the data implementation.
Outputs
Required:
Python/FastAPI service package with pyproject.toml (pinned deps + hashed lockfile, requires-python) and mypy/ruff config.
Validated Pydantic Settings with fail-fast boot and .env.example.
Separate liveness (/healthz) and readiness (/readyz) probes.
Depends DI providers with a typed principal-provider shell (auth flow explicitly deferred).
Multi-stage non-root Dockerfile from a digest-pinned base, .dockerignore, documented HEALTHCHECK.
Service README listing all seams downstream archetypes fill.
Output rules:
Generated files are functional and the app boots, not placeholder-heavy.
No secrets in source, committed config, .env.example, or the image.
The principal provider is a seam, not a flow — token verification, session, and route guards are explicitly deferred to fastapi-auth-and-security-review.
The same image runs in every environment; configuration arrives at runtime via environment variables.
Quality checks
mypy and ruff check report zero errors.
The test command runs and the boot smoke check (GET /healthz → 200, clean lifespan shutdown) passes, or a skip is documented with reason.
pyproject.toml pins every dependency with a hashed lockfile and sets requires-python.
Settings are validated at boot and abort on a missing required variable — verified by removing one required var and observing a clear non-zero exit.
No secrets appear in source, committed config, .env.example, or the built image.
All four error layers are wired: sys.excepthook, asyncio loop handler, FastAPI/Starlette exception handlers, ASGI-lifespan graceful shutdown.
Exception handlers return no traceback or internal details in non-dev environments.
/healthz and /readyz are separate; /readyz returns 503 until registered dependency checks pass.
The structlog logger binds a request id from the contextvars context; the tracer/metrics seam is a no-op with a TODO naming fastapi-observability-readiness.
The Depends principal provider is a typed shell tied to an architecture/security decision; token/session logic is explicitly deferred with TODO comments.
The Dockerfile is multi-stage, runs as non-root, uses a digest-pinned base, and bakes no secrets.
The service README lists all seams downstream archetypes are expected to fill.
Generate container packaging: a multi-stage Dockerfile (build stage, slim runtime stage) running as a non-root user from a digest-pinned base image, a .dockerignore, and a documented HEALTHCHECK hitting /healthz. No secrets baked; runtime config arrives via environment.
Generate local-run documentation in the service README: how to run each environment, every required environment variable (mirrored from .env.example), the runtime-config contract, and the explicit table of seams downstream archetypes fill (auth, observability vendor, task/event, performance gates, data layer).
Build verification (mandatory): run mypy, ruff check, the test command (pytest), and a boot smoke check (start the app, assert httpxGET /healthz returns 200, shut down cleanly via lifespan). Fix and re-run on failure. Then validate against the standards in the Output contract; revise until all pass or explicitly document any unresolved gap in the README.