Skip to content

Example CLAUDE.md — Python Project

This example shows a complete CLAUDE.md for a Python backend service using FastAPI, pytest for testing, and standard Python tooling. It demonstrates conventions for type hints, virtual environments, and project structure.

The CLAUDE.md File

# Project: Inventory API

FastAPI backend service for inventory management. Python 3.12+.

## Setup

- Virtual environment: `source .venv/bin/activate` (always activate before running commands)
- Install deps: `pip install -e ".[dev]"`
- Environment variables: copy `.env.example` to `.env` for local development

## Commands

- `pytest` — run all tests
- `pytest tests/test_items.py::test_create_item -v` — run a single test
- `pytest --cov=src --cov-report=term-missing` — run tests with coverage
- `ruff check .` — lint
- `ruff format .` — format code
- `mypy src/` — type checking
- `uvicorn src.main:app --reload` — start dev server

Run `ruff check . && mypy src/` before committing.

## Project Structure

- `src/` — application source code
  - `src/main.py` — FastAPI app entrypoint and router mounting
  - `src/models/` — SQLAlchemy ORM models
  - `src/schemas/` — Pydantic request/response schemas
  - `src/routers/` — API route handlers, one file per resource
  - `src/services/` — business logic layer (routers call services, services call repositories)
  - `src/repositories/` — database access layer
  - `src/dependencies.py` — FastAPI dependency injection (db sessions, auth)
- `tests/` — mirrors src/ structure: `tests/test_routers/`, `tests/test_services/`, etc.
- `alembic/` — database migrations

## Coding Conventions

- Type hints on all function signatures — parameters and return types
- Use `from __future__ import annotations` at the top of every module
- Pydantic models for all API input/output — never pass raw dicts across boundaries
- Use `pathlib.Path` instead of `os.path`
- f-strings for string formatting (no .format() or % formatting)
- Docstrings on public functions using Google style

```python
def get_item(item_id: int, db: Session) -> Item:
    """Fetch a single item by ID.

    Args:
        item_id: The item's primary key.
        db: Database session.

    Returns:
        The matching Item.

    Raises:
        NotFoundError: If no item matches the ID.
    """
```

## Testing

- Use pytest with fixtures defined in `conftest.py`
- Test database: use an in-memory SQLite or test-specific PostgreSQL database — never touch the dev database
- Use `httpx.AsyncClient` with `app` for API integration tests
- Factory fixtures for creating test data (see `tests/factories.py`)
- Aim for >80% coverage on business logic in `src/services/`

## Database

- SQLAlchemy 2.0 style (use `select()` not `session.query()`)
- All schema changes go through Alembic migrations — never modify tables manually
- New migration: `alembic revision --autogenerate -m "description"`
- Apply migrations: `alembic upgrade head`

## Error Handling

- Use custom exception classes in `src/exceptions.py`
- Routers should not catch generic exceptions — let the global exception handler deal with unexpected errors
- Service layer raises domain exceptions (NotFoundError, ValidationError, etc.)
- Never return error details from unhandled exceptions in production responses

## Git

- Conventional commits: feat:, fix:, chore:
- Run the full check before committing: `ruff check . && ruff format --check . && mypy src/ && pytest`

## Do NOT

- Do not use `import *`
- Do not use `objects.raw()` or raw SQL — use the repository layer
- Do not use `print()` — use the configured `logging` module
- Do not use `*` imports

Key Sections Explained

Setup — The virtual environment reminder is critical. Claude needs to know to activate the venv before running any Python commands.

Project Structure — The layered architecture (routers -> services -> repositories) tells Claude where new code should go and prevents it from putting business logic in route handlers.

Coding Conventions — Type hints and Pydantic model requirements ensure Claude generates code that passes mypy and follows team standards.

Database — Specifying SQLAlchemy 2.0 style prevents Claude from using the older query API. The Alembic instructions ensure schema changes are done properly.

Do NOT — Prevents common Python anti-patterns. The import * and mutable default argument rules catch issues Claude might otherwise introduce.

See Also