Exemple concret pour un projet FastAPI
API REST pour gestion de tâches (todo app). L’objectif est de fournir un backend JSON pour une application mobile.
| Composant | Technologie |
|---|---|
| Langage | Python 3.11 |
| Framework | FastAPI 0.104 |
| ORM | SQLAlchemy 2.0 |
| Base de données | PostgreSQL 15 |
| Tests | pytest + pytest-asyncio |
| Lint | ruff + black |
| CI | GitHub Actions |
api/
├── src/
│ ├── main.py # Point d'entrée FastAPI
│ ├── config.py # Configuration (env vars)
│ ├── models/ # Modèles SQLAlchemy
│ │ ├── __init__.py
│ │ ├── task.py
│ │ └── user.py
│ ├── schemas/ # Pydantic schemas
│ │ ├── __init__.py
│ │ ├── task.py
│ │ └── user.py
│ ├── routes/ # Endpoints REST
│ │ ├── __init__.py
│ │ ├── tasks.py
│ │ └── auth.py
│ └── services/ # Logique métier
│ ├── __init__.py
│ └── task_service.py
├── tests/
│ ├── conftest.py # Fixtures pytest
│ ├── test_tasks.py
│ └── test_auth.py
├── AGENTS.md # Ce fichier
├── Makefile # Commandes
├── pyproject.toml # Dépendances
└── README.md
# BON
def get_task(task_id: int, db: Session) -> Task | None:
"""Récupère une tâche par son ID.
Args:
task_id: L'identifiant de la tâche
db: Session SQLAlchemy
Returns:
La tâche ou None si non trouvée
"""
return db.query(Task).filter(Task.id == task_id).first()
type(scope): description courte
type = feat | fix | docs | style | refactor | test | chore
main : Productionfeature/* : Nouvelles fonctionnalitésfix/* : Corrections de bugs| Tâche | Modèle | Raison |
|---|---|---|
| Exploration code | Haiku | Rapide, peu coûteux |
| Implémentation standard | Sonnet | Bon ratio qualité/coût |
| Architecture/Décisions | Opus | Capacités avancées |
| Debugging complexe | Opus | Raisonnement approfondi |
# ÉTAPE 1 : Reflection (modèle gratuit/cheap)
YOU: "Plan this feature. Don't implement yet.
Think through edge cases, error handling.
Output a detailed plan."
# ÉTAPE 2 : Implementation (modèle frugal)
YOU: "Now implement according to your plan."
OBLIGATOIRE :
ai-generated sur PRsmake test, make lint)INTERDIT :
Pour optimiser les coûts :
# Vérifier le cache hit rate (objectif > 85%)
opencode stats --cache
# Vérifier les coûts du mois
opencode stats --costs
# Développement
make install # Installer dépendances
make test # Lancer tests avec coverage
make lint # Ruff + Black
make run # uvicorn src.main:app --reload
# IA
opencode # Démarrer session
opencode stats # Stats usage
# TOUJOURS utiliser ce pattern pour la pagination
@router.get("/tasks/")
async def list_tasks(
skip: int = Query(0, ge=0),
limit: int = Query(100, le=100),
db: Session = Depends(get_db)
) -> List[TaskSchema]:
return task_service.get_all(db, skip=skip, limit=limit)
# Utiliser OAuth2PasswordBearer pour l'auth
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@router.get("/tasks/me")
async def get_my_tasks(
token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db)
):
user = auth_service.get_current_user(db, token)
return task_service.get_by_user(db, user.id)
Tip du nom : Si je m’appelle “Hadrien” dans ce fichier, l’agent doit m’appeler par mon nom au début de chaque message. Si l’agent arrête → contexte compressé = répéter les guardrails.