FastAPI governance

Architectural governance for AI-generated FastAPI code

FastAPI projects move fast — new routers, new dependencies, and new endpoints land in a single agent session. Mneme governs the architectural decisions in those repos before generation, so an AI coding agent can't quietly collapse your router / service / repository boundaries or re-litigate settled conventions. There is no bespoke FastAPI parser; the decisions are repo-native rules enforced at the file-write seam and in CI.

Python ecosystem · Repo-native rules

Why governance matters in FastAPI

FastAPI is built around standard Python type hints, dependency injection, automatic validation, and generated OpenAPI documentation. That structure is exactly what makes a project legible — and exactly what an AI coding agent drifts away from when it optimizes for "make the endpoint work" over "respect the architecture." The framework gives you a clean place to put routers, services, repositories, and Pydantic schemas; nothing forces an agent to keep them there.

The faster agents generate API surface, the more often the same architectural decisions get re-decided per file: where business logic lives, how the database is reached, which dependencies guard a router, what shape a response takes. Mneme injects the project's settled decisions into the agent's context and checks the diff, so speed doesn't come at the cost of a coherent codebase.

What Mneme can govern

Mneme governs the architectural decisions a FastAPI team has already made — expressed as repo-native rules in a decision corpus, not as a built-in FastAPI rule pack. Common surfaces:

Five concrete examples of what the governance layer catches in FastAPI repos under AI-assisted development:

Business logic in a route handler

Architecture

Rule. Route handlers must stay thin. Pricing, tax, and inventory logic belong in service modules.

# AI-generated in routers/checkout.py
@router.post("/checkout")
async def checkout(payload: CheckoutIn):
    subtotal = sum(i.price * i.qty for i in payload.items)
    tax = subtotal * 0.0875
    # inventory mutation, payment call, email send inline...
    return {"total": subtotal + tax}
logic in presentation layermissing service abstraction

Database access inside the router

Layer boundary

Rule. Persistence goes through repository modules. No raw queries or sessions in route handlers.

# AI-generated in routers/users.py
@router.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
    return db.execute(
        text(f"SELECT * FROM users WHERE id = {user_id}")
    ).fetchone()
persistence in route layerrepository bypass

Ad hoc construction instead of dependency injection

Dependency injection

Rule. Clients and sessions arrive through Depends. No module-level singletons constructed in handlers.

# AI-generated in routers/reports.py
@router.get("/reports")
async def reports():
    client = StorageClient(API_KEY)   # built inline, not injected
    engine = create_engine(DATABASE_URL)
    ...
bypassed DI containeruntestable handler

Protected router missing its auth dependency

Security

Rule. Routers under /admin must declare the auth dependency. No unauthenticated admin surface.

# AI-generated in routers/admin.py
router = APIRouter(prefix="/admin")  # dependencies=[Depends(require_admin)] dropped

@router.delete("/users/{user_id}")
async def delete_user(user_id: int):
    ...
missing auth dependencyaccess-control regression

Inconsistent response serialization

Schema discipline

Rule. Endpoints declare a response_model. No returning ORM objects or untyped dicts.

# AI-generated in routers/orders.py
@router.get("/orders/{order_id}")  # response_model omitted
async def get_order(order_id: int):
    return order_repo.get(order_id)  # leaks the ORM model + internal fields
unbounded response shapeschema contract drift

Example governance decisions

These are illustrative rules a FastAPI team would author in its own decision corpus. Mneme does not ship them as defaults — it enforces the decisions you record.

decision · api-001Architecture

Route handlers must remain thin. Business logic belongs in service modules.

An agent that inlines pricing, tax, or orchestration logic into a handler is flagged before the change lands.

decision · api-002Layer boundary

Database access must go through repository modules rather than route handlers.

Sessions and queries that appear directly in a router are surfaced as a boundary violation.

decision · api-003Security

Authentication dependencies must be applied consistently to protected routers.

Dropping the auth dependency on an admin or account router is treated as an access-control regression.

How governance fits the workflow

Mneme sits between your architectural decisions and the AI coding tools writing FastAPI code. The loop is the same one Mneme runs for any repository:

  1. Decisions and ADRs are recorded

    Your architectural decisions live as records in .mneme/project_memory.json — each with a scope, constraints, and anti-patterns. ADRs can be imported into the same corpus.

  2. Mneme retrieves the relevant intent

    On a prompt or a file write, Mneme retrieves the decisions in scope for the change and injects them into the agent's context — governance before generation, not review after the fact.

  3. The AI coding agent changes the code

    Claude Code, Cursor, Copilot, or a custom agent edits routers, services, repositories, and schemas with that context in hand.

  4. Mneme checks the proposed change

    mneme check evaluates the diff against the corpus: a matched constraint surfaces as WARN, an anti-pattern hit as FAIL. Aligned changes pass cleanly.

  5. CI gates the merge

    In --mode strict a WARN exits 1 and a FAIL exits 2, so the regression blocks the PR; --mode warn annotates without blocking. One corpus serves the editor, the terminal agent, and the CI runner.

Where it fits in a Python codebase

FastAPI governance is Python governance applied to an API-shaped repository. The decision corpus lives at .mneme/project_memory.json; hooks fire on file writes; mneme check --mode strict gates PR diffs in CI. Because Mneme is itself implemented in Python, the broader Python governance surface — native CLI, benchmark coverage, Claude Code hooks — applies directly to FastAPI projects.

See the Claude Code integration and the Cursor integration for editor and terminal setup, the GitHub Actions integration for CI gating, and architectural drift for the problem this prevents.