Why Python Needs Specific AI Rules
Python's flexibility is a feature for developers and a liability for AI assistants. In TypeScript, the compiler enforces types and catches errors. In Go, the conventions are so strong that code practically writes itself. But Python lets you do almost anything — and AI assistants, without rules, will exercise that freedom in inconsistent and error-prone ways.
The most common issues: missing type hints (the AI skips them because Python doesn't require them), bare exception handling (the AI catches Exception instead of specific types), mixing sync and async incorrectly in FastAPI endpoints, using raw dictionaries instead of Pydantic models, and ignoring your project's specific ORM patterns.
These aren't style preferences — they're quality issues that cause production bugs. Missing type hints make code harder to maintain and tools like mypy useless. Bare exceptions swallow errors silently. Sync calls in async endpoints block the event loop. Each issue is preventable with a single, specific rule.
Rule 1: Type Hints on Everything
Type hints are the single highest-impact rule for Python AI output. Without this rule, AI assistants generate Python without any type annotations — functions with untyped parameters, untyped return values, and untyped variables. The code works, but it's a maintenance nightmare and mypy can't verify it.
The rule: 'Add type hints to every function parameter, return type, and class attribute. Use typing module generics where needed (list[str], dict[str, int], Optional[str]). For complex types, create TypeAlias definitions. Never submit code without complete type annotations.'
This one rule transforms AI-generated Python from scripting-quality to production-quality. Teams that add it report the biggest single improvement in AI output of any rule they implement.
Type hints are the single highest-impact rule for Python teams. AI assistants skip them by default — one rule ('Type hints on every function signature') eliminates 30%+ of review feedback.
Rule 2: Specific Exception Handling
AI assistants love bare `except Exception` blocks because they're safe — they catch everything. But catching everything means catching things you shouldn't: KeyboardInterrupt, SystemExit, and application-specific errors that should propagate up the call stack.
The rule: 'Always catch specific exception types (ValueError, KeyError, HTTPException). Never use bare except or except Exception. Log errors with structured logging (loguru or structlog), never print(). Re-raise unexpected errors after logging. Use try/except only for recoverable operations.'
For FastAPI specifically, add: 'Use HTTPException for client errors (400-499). Let unexpected errors propagate to the global exception handler. Never return 200 with an error message in the body.'
Rule 3: Pydantic Models for All Data Shapes
Without rules, AI assistants use raw dictionaries for everything: API request bodies, database results, configuration objects, function parameters. Dictionaries are untyped, unvalidated, and error-prone — a missing key crashes the app at runtime instead of failing at the schema layer.
The rule: 'Use Pydantic BaseModel for all data shapes: API request/response schemas, configuration objects, database row representations, and inter-function data transfer. Never pass raw dicts between functions. Never use TypedDict as a substitute for Pydantic models in API contexts.'
This rule has a cascading quality effect: once the AI generates Pydantic models, it also generates validation logic, serialization, and documentation (FastAPI auto-generates OpenAPI docs from Pydantic models). One rule improves four aspects of code quality.
Once the AI generates Pydantic models instead of raw dicts, it also generates validation, serialization, and auto-documentation. One rule improves four aspects of code quality.
Rule 4: Async/Await Discipline
FastAPI and modern Python frameworks are async by default, but AI assistants frequently mix sync and async incorrectly. The most common mistake: using synchronous libraries (requests, time.sleep) inside async endpoints, which blocks the event loop and defeats the purpose of async.
The rule: 'In async functions, never call synchronous I/O operations directly. Use httpx instead of requests. Use asyncio.sleep instead of time.sleep. Use async database drivers (asyncpg, aiosqlite) instead of synchronous ones. If you must call sync code, wrap it with asyncio.to_thread().'
For Django projects (which are traditionally sync), the rule is different: 'Use async views and middleware only when the entire call chain is async. Don't mix async views with sync ORM queries — either use Django's async ORM methods or keep the view sync.'
Using synchronous requests or time.sleep inside async endpoints blocks the event loop. The AI does this frequently without explicit rules — always specify 'httpx not requests, asyncio.sleep not time.sleep in async context.'
Rule 5: Project Structure and Imports
Python's import system is flexible enough to create dependency tangles that make projects unmaintainable. AI assistants contribute to this by importing from wherever is convenient rather than following your project's module boundaries.
The rule: 'Follow the project's established module structure. API routes go in app/routes/. Business logic goes in app/services/. Database operations go in app/repositories/. Never import from routes into services (unidirectional dependency). Use absolute imports, never relative imports across packages.'
Add rules for your specific project structure. The AI doesn't know your architecture unless you describe it: 'This project uses a layered architecture: routes -> services -> repositories -> models. Each layer only imports from the layer below it.'
Complete Python Rules Template
Here's a consolidated template for Python teams. It combines all five rule areas into a copy-paste-ready CLAUDE.md section. Customize it for your specific framework (FastAPI, Django, Flask) and project structure.
The template is 35 lines — enough to prevent the most common Python AI issues without overwhelming the model's attention. For framework-specific details beyond these rules, use subdirectory CLAUDE.md files or composable rulesets.
- Type hints on every function signature, return type, and class attribute
- Pydantic BaseModel for all data shapes — no raw dicts between functions
- Catch specific exceptions — never bare except or except Exception
- Structured logging with loguru/structlog — never print() in production code
- Async discipline — httpx not requests, asyncio.sleep not time.sleep in async context
- Absolute imports only — follow layered architecture dependency direction
- Tests with pytest — fixtures over setup/teardown, parametrize for variants
- Virtual environment — all dependencies in pyproject.toml or requirements.txt