DEV Community

Cover image for AGENTS.md best practices for Python (FastAPI & Django)
Piekwerk
Piekwerk

Posted on Edited on

AGENTS.md best practices for Python (FastAPI & Django)

Python backends fail agents in characteristic ways: blocking calls
inside async routes, os.environ reads scattered across modules,
migrations edited after they shipped. A good agent config names these
directly. Here is what works, per framework and shared.

Shared: the environment is part of the contract

Python projects die by environment ambiguity, pip vs uv vs poetry,
system Python vs venv. Your config should state the toolchain as fact:

This project uses uv. Commands run through uv run. Never introduce
pip, requirements.txt edits, or a second lockfile.

Then the command table:

| Action | Command |
|---|---|
| Sync environment | `uv sync` |
| All tests | `uv run pytest` |
| Single test | `uv run pytest tests/test_x.py -x` |
| Lint | `uv run ruff check . && uv run ruff format --check .` |
| Type check | `uv run mypy app` |
Enter fullscreen mode Exit fullscreen mode

FastAPI-specific rules that earn their lines

The async trap. The single most valuable FastAPI rule:

Async routes call async I/O only. A blocking call (requests,
time.sleep, sync DB drivers) inside async def stalls the event
loop for every request. Use async drivers, or make the route def
so it runs in the threadpool.

Agents produce this bug constantly, and it passes every test on a dev
machine while degrading production latency.

Pydantic boundaries.

One pydantic model per request/response shape. response_model is
explicit on every route. Raw dicts stop at the boundary.

Without the second sentence, agents skip response_model and internal
fields leak into API responses, a bug class that reaches production
regularly.

Settings, not environ.

Configuration comes from one pydantic-settings object. os.environ
reads outside it are a bug.

Django-specific rules

Migrations are forward-only.

Never edit an applied migration. Fixes happen in new migrations.
Model changes ship with their migration in the same commit.

Agents confidently edit migration files when tests complain about
schema drift, the exact wrong move. This rule prevents the most
destructive Django mistake an agent can make. The same discipline
applies to config files: one baseline, projections derived from it,
never four drifting copies.

The N+1 review habit.

Any queryset traversing a relation in a loop context gets
select_related (FK) or prefetch_related (M2M) reviewed. ORM lazy
loading is the default failure mode.

Settings discipline.

Settings are split per environment; secrets come from the
environment into settings modules, never into code. Raw SQL is a
last resort with a justification comment and parameterization.

Testing rules both frameworks share

  • Fixtures own setup/teardown; tests never mutate module state.
  • Factory-based test data over hardcoded rows.
  • Deterministic only: no sleeps, no real network, frozen time where clocks matter.
  • Every bug fix lands with the regression test that fails without it.

The last one is the highest-value testing rule in any Python agent
config: it converts every agent-fixed bug into a permanent test.

What to leave out

Skip style rules your linter already enforces (ruff does not need an
agent config paragraph describing it), and skip framework tutorials, the agent knows Django; what it needs is your repo's conventions and
the named traps above.

The baseline approach

Our FastAPI and Django kits encode exactly these rules, command
tables, boundary rules, migration safety, the async trap, alongside
the four-format output (AGENTS.md, CLAUDE.md, scoped Cursor rules,
Copilot digest) so all three major agents get the same warnings. They
are two of the twelve kits in the pack; the Next.js kit is free (MIT)
if you want to see the structure first.

Related reading


If you'd rather not assemble this by hand: AgentConfig Studio on Gumroad ships this as version-pinned, validator-tested kits for 12 stacks. The complete Next.js/TypeScript kit is free (MIT) if you want to inspect the structure first.

Top comments (0)