Workflows Claude Code : Subagents, Revue de Code et Débogage
Vous avez maîtrisé les bases. Votre CLAUDE.md est au point, vos hooks fonctionnent parfaitement, vos serveurs MCP donnent à Claude un accès direct à vos outils. Mais vous travaillez toujours avec un Claude à la fois. Une conversation, une tâche, un seul fil d'exécution.
Et si vous pouviez en lancer cinq ?
Les setups avec des patterns de workflow explicites et des définitions d'agents obtiennent 7.0/10 en moyenne dans notre analyse. L'écart entre les utilisateurs occasionnels et les power users n'est pas la configuration — c'est comment ils orchestrent leur travail. Ce guide couvre les patterns qui produisent les meilleurs résultats.
Subagents : déléguer comme un manager, pas un micro-manager
Un subagent est une session Claude Code séparée qui gère une tâche spécifique. Votre session principale reste concentrée pendant que les subagents travaillent sur des morceaux isolés en parallèle. C'est comme confier des tâches à des collègues — chacun reçoit un brief clair et livre un résultat précis.
Quand les subagents ont du sens (et quand non)
Bonnes tâches pour les subagents :
- Des morceaux indépendants qui n'ont pas besoin de contexte partagé
- Plusieurs fichiers qui nécessitent des modifications mais ne dépendent pas les uns des autres
- Des tâches d'exploration (recherche d'une approche) pendant que vous continuez à construire
- Du travail répétitif sur des fichiers similaires (mettre à jour 10 routes API de la même façon)
Mauvaises tâches pour les subagents :
- Tout ce qui nécessite le contexte complet de votre conversation en cours
- Des changements où le fichier A dépend de ce que vous avez décidé dans le fichier B
- Des éditions rapides qui sont plus rapides à faire inline
Voici l'insight clé : si vous pouviez confier la tâche à un collègue avec juste un brief écrit — sans contexte verbal — c'est un bon candidat pour un subagent.
Comment cadrer une tâche de subagent
Des tâches vagues produisent des résultats vagues. « Améliorer l'API utilisateur » ne donne rien à Claude sur quoi s'accrocher. Voici à quoi ressemble une tâche bien cadrée :
## Tâche : Ajouter la validation d'entrée aux endpoints utilisateur
### Fichiers à modifier
- src/api/users/route.ts
- src/api/users/[id]/route.ts
### Fichiers à lire (pour le contexte)
- src/lib/schemas.ts
- src/types/user.ts
### Exigences
- Ajouter la validation zod à tous les corps de requêtes POST/PUT
- Retourner 400 avec des messages d'erreur structurés
- NE PAS modifier les endpoints GET ou DELETE
- NE PAS changer la couche base de données
### Terminé quand
- Fichiers de routes modifiés avec validation
- Schémas zod nouveaux ou mis à jour dans src/lib/schemas.ts
Notez le scope explicite, les exigences claires, et une définition de « terminé ». Le subagent sait exactement quoi toucher, quoi laisser, et quand s'arrêter.
Le pattern Director : lancer des subagents en parallèle
Pour les fonctionnalités plus importantes, vous pouvez utiliser Claude comme directeur — planifiant le travail puis dispatchant des subagents pour chaque morceau :
Vous : "Je dois ajouter un système de notifications. Planifie le travail et utilise des subagents."
Claude (Directeur) :
1. Phase de planification : schéma de notification, endpoints API, composants UI
2. Subagent 1 : Créer la migration de base de données et le schéma Prisma
3. Subagent 2 : Implémenter les endpoints API (GET /notifications, POST /mark-read)
4. Subagent 3 : Construire le composant cloche de notification et le dropdown
5. Intégration : assembler le tout et tester
Chaque subagent reçoit une tâche bornée. La session directeur gère l'intégration et s'assure que les pièces s'assemblent. Ce pattern fonctionne particulièrement bien parce que les subagents démarrent propres — sans le poids du contexte accumulé d'une longue conversation.
J'utilise ce pattern pour toute fonctionnalité qui touche plus de 3 fichiers. Cinq terminaux en parallèle, chacun avec un subagent qui gère un morceau, pendant que la session principale garde la vue d'ensemble.
Revue de code : le workflow quotidien à plus forte valeur
La revue de code est l'un des cas d'usage les plus forts de Claude Code et l'un des plus sous-utilisés. Au lieu de revoir votre propre code (que votre cerveau rationalise comme correct) ou d'attendre un collègue, Claude attrape les problèmes en quelques secondes.
La méthode Fix-First
La plupart des outils de revue vous donnent une liste de problèmes. Vous devez ensuite corriger chacun manuellement. C'est à l'envers.
La méthode Fix-First : Claude corrige les problèmes mécaniques directement et ne vous pose des questions que sur les points ambigus :
## Comment revoir du code (mettez ça dans un skill ou CLAUDE.md)
1. Lire le diff COMPLET d'abord — comprendre le changement dans son ensemble
2. AUTO-CORRIGER les problèmes mécaniques :
- Gestion d'erreurs manquante → ajouter try/catch
- Erreurs de types évidentes → corriger le type
- Violations de style → les corriger
3. Grouper les décisions ambiguës en UNE question :
- "J'ai trouvé 3 décisions de design à confirmer : [A], [B], [C]"
4. Ne jamais signaler des problèmes déjà traités dans le diff
5. Sortie : CRITIQUE (à corriger) et INFORMATIONNEL (à considérer)
Vous ne voulez pas une liste de 15 pointilleries quand 12 auraient pu être auto-corrigées. La méthode Fix-First respecte votre temps.
Revue pré-commit en pratique
Mettez en place un alias shell pour l'usage quotidien :
alias ccreview='claude -p "Revois les changements stagés (git diff --staged). Corrige les problèmes mécaniques. Signale tout ce qui est critique."'
Ou comme skill pour un comportement plus riche :
<!-- .claude/skills/pre-commit-review.md -->
---
name: pre-commit-review
description: Revoir les changements stagés avant de commiter
---
1. Lancer `git diff --staged`
2. Pour chaque fichier :
- Gestion d'erreurs : opérations async en try/catch ?
- Sécurité : secrets en dur, injection SQL, XSS ?
- Types : des `any` qui devraient être spécifiques ?
- Tests : les fonctions modifiées ont des mises à jour de tests ?
3. AUTO-CORRIGER les problèmes mécaniques
4. Reporter CRITIQUE (bloque le commit) et INFORMATIONNEL (nice to have)
5. Si pas d'issue critique : suggérer un message de commit
Tapez /pre-commit-review avant chaque commit. Claude vérifie votre travail, corrige les petites choses, et signale les vrais problèmes. Ça prend 15 secondes et attrape des choses que vous rateriez à 18h un vendredi.
Test-Driven Development : écrire la spec, laisser Claude implémenter
Le TDD avec Claude Code fonctionne différemment du TDD en solo. Vous décrivez ce qu'une fonction doit faire. Claude écrit le test. Vous vérifiez que le test capture votre intention. Puis Claude écrit le code pour le passer.
Ça fonctionne parce qu'un test est une spécification non-ambiguë. Quand vous décrivez une fonctionnalité en mots, Claude peut l'interpréter différemment. Quand vous l'exprimez en test, le comportement attendu est explicite — entrées, sorties, cas limites.
La boucle
1. Vous décrivez ce que la fonction doit faire
2. Claude écrit le test
3. Vous vérifiez que le test correspond à votre intention
4. Claude écrit l'implémentation pour passer le test
5. Claude lance le test pour confirmer
6. Répéter
Un exemple concret : construire un rate limiter
Vous : "J'ai besoin d'un rate limiter. 100 requêtes par minute par IP. Retourner
429 quand dépassé, inclure un header Retry-After. Écris le test d'abord."
Claude écrit :
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { createRateLimiter } from './rate-limiter';
describe('Rate Limiter', () => {
beforeEach(() => {
vi.useFakeTimers();
});
it('should allow requests under the limit', () => {
const limiter = createRateLimiter({ maxRequests: 100, windowMs: 60000 });
const result = limiter.check('192.168.1.1');
expect(result.allowed).toBe(true);
expect(result.remaining).toBe(99);
});
it('should block requests over the limit', () => {
const limiter = createRateLimiter({ maxRequests: 2, windowMs: 60000 });
limiter.check('192.168.1.1');
limiter.check('192.168.1.1');
const result = limiter.check('192.168.1.1');
expect(result.allowed).toBe(false);
expect(result.retryAfter).toBeGreaterThan(0);
});
it('should reset after the window expires', () => {
const limiter = createRateLimiter({ maxRequests: 1, windowMs: 60000 });
limiter.check('192.168.1.1');
vi.advanceTimersByTime(61000);
const result = limiter.check('192.168.1.1');
expect(result.allowed).toBe(true);
});
it('should track IPs independently', () => {
const limiter = createRateLimiter({ maxRequests: 1, windowMs: 60000 });
limiter.check('192.168.1.1');
const result = limiter.check('192.168.1.2');
expect(result.allowed).toBe(true);
});
});
Vous lisez le test. Quatre cas : sous la limite, au-dessus de la limite, reset de la fenêtre, isolation par IP. Ça a l'air bon. Vous dites à Claude de continuer, et il écrit l'implémentation pour passer les quatre. Le test a servi de contrat sur lequel vous vous êtes mis d'accord avant d'écrire du code de production.
Débogage : l'approche systématique qui marche vraiment
Le débogage avec Claude est puissant, mais ça peut tourner en rond si vous le laissez faire. Claude retient plus de contexte et explore plus d'hypothèses que vous — mais il a besoin de structure pour éviter de patiner.
Le workflow de débogage en 7 étapes
Mettez ça dans votre CLAUDE.md ou un skill de débogage :
En débogage :
1. REPRODUIRE — lancer le cas défaillant, capturer l'erreur exacte
2. HYPOTHÈSES — lister 3 causes possibles, classées par probabilité
3. INVESTIGUER — vérifier la cause la plus probable d'abord
4. LOGGER — ajouter du logging à chaque frontière async si vous ne voyez pas où l'exécution s'arrête
5. IDENTIFIER — localiser la ligne ou fonction exacte
6. CORRIGER — appliquer le fix minimal
7. VÉRIFIER — relancer le cas défaillant pour confirmer que le fix marche
La règle critique : ne jamais sauter l'étape 7. Nos données montrent que 40% des sessions de débogage qui tournent mal le font parce qu'un fix a été annoncé mais jamais vérifié. « Ça devrait marcher maintenant » n'est pas une preuve. Lancez-le.
La règle des trois tentatives
C'est le pattern qui sépare le débogage productif du gaspillage de temps :
Si Claude n'a pas trouvé la cause racine après trois tentatives, stop. Ne le laissez pas continuer à deviner — des hypothèses de plus en plus hasardeuses rendent le problème plus dur à diagnostiquer. Choisissez plutôt :
Option A : Nouvelle hypothèse. Repartir de zéro. Reformuler le problème. Parfois la troisième tentative a échoué parce que la première a empoisonné le raisonnement.
Option B : Revue humaine. Claude vous montre tout ce qu'il a trouvé et vous ajoutez du contexte. Peut-être savez-vous quelque chose sur l'environnement de production ou un déploiement récent que Claude ne connaît pas.
Option C : Instrumenter et attendre. Ajouter du logging complet et reproduire le problème. Laisser les logs vous dire où l'exécution s'arrête au lieu de deviner.
En cas de doute : d'abord ajouter du logging
Les sessions de débogage les plus productives commencent par ajouter de l'observabilité avant d'essayer de corriger :
// Avant : échec silencieux — aucune idée où ça casse
async function processOrder(orderId: string) {
const order = await db.orders.findUnique({ where: { id: orderId } });
const payment = await chargePayment(order.amount);
await db.orders.update({ where: { id: orderId }, data: { status: 'paid' } });
}
// Après : chaque étape est visible
async function processOrder(orderId: string) {
console.log('[processOrder] start', { orderId });
const order = await db.orders.findUnique({ where: { id: orderId } });
console.log('[processOrder] fetched order', { found: !!order, amount: order?.amount });
if (!order) {
console.error('[processOrder] order not found', { orderId });
throw new Error(`Order ${orderId} not found`);
}
const payment = await chargePayment(order.amount);
console.log('[processOrder] payment result', { paymentId: payment.id, status: payment.status });
await db.orders.update({ where: { id: orderId }, data: { status: 'paid' } });
console.log('[processOrder] done', { orderId });
}
Quand quelque chose bloque ou échoue, la dernière ligne de log vous dit exactement où l'exécution s'est arrêtée. Cette technique fait gagner plus de temps de débogage que toute analyse savante.
Patterns de prompting qui donnent de meilleurs résultats
La façon dont vous formulez les instructions compte plus qu'on ne le pense. Voici les patterns qui produisent systématiquement du meilleur code.
Définir ce que « terminé » signifie
Mauvais : « Améliorer l'authentification. »
Bon : « Ajouter du rate limiting au endpoint de login. 5 tentatives par email par 15 minutes. Retourner 429 avec header Retry-After. Écrire des tests pour la limite et le reset. Ne pas toucher au endpoint d'inscription. »
Le second prompt n'a aucune ambiguïté. Claude peut l'exécuter sans poser une seule question clarificatrice.
Énoncer les contraintes explicitement
Claude suit les règles qu'il connaît. Si vous ne mentionnez pas une contrainte, il ne la considérera pas :
- NE PAS modifier de fichiers dans src/legacy/ — ce code est gelé
- Le build doit passer avec Node 18 (pas d'API Node 20+)
- Garder la taille du bundle sous 200KB — vérifier avec `npm run analyze`
Demander un plan sur tout ce qui touche 3+ fichiers
Pour les tâches plus importantes, demandez à Claude de planifier avant d'exécuter :
Planifie comment tu implémenterais une couche de cache pour les réponses API. Montre-moi :
1. Quels fichiers tu créerais ou modifierais
2. La stratégie d'invalidation du cache
3. Comment ça s'intègre avec le middleware existant
N'écris pas de code. Juste le plan.
Revoyez le plan, ajustez-le, puis laissez Claude exécuter. Ça attrape les erreurs structurelles avant qu'elles ne se propagent. Changer un plan ne coûte rien. Défaire une implémentation à moitié terminée coûte des heures.
Comment tout se connecte
Votre setup donne à Claude la connaissance du projet. Votre automatisation applique les standards. Vos intégrations donnent à Claude l'accès à votre infrastructure. Les workflows déterminent comment Claude opère au quotidien.
Commencez par la revue pré-commit — c'est le gain le plus facile et celui que vous utiliserez chaque jour. Puis essayez les subagents la prochaine fois que vous avez une fonctionnalité qui touche 4+ fichiers. Évaluez votre setup pour voir où se situe votre orchestration de workflow.
Questions fréquentes
Combien de subagents peuvent tourner en même temps ?
Ça dépend de votre machine (RAM, CPU) et des limites de taux API. Sur une machine de développement typique, 3-5 subagents concurrents fonctionnent bien. Chacun est une session séparée qui consomme des tokens, donc surveillez votre consommation si vous êtes en tarification API.
Dois-je utiliser des subagents pour tout ?
Non. Ils ajoutent du surcoût — changement de contexte, création de session, et le risque que le subagent manque du contexte que la session principale possède. Un bon test : si vous pouviez confier la tâche à un collègue avec juste un brief écrit (pas de contexte verbal), c'est un candidat pour un subagent. Si vous auriez besoin de 10 minutes de conversation pour expliquer le contexte, gardez-le dans la session principale.
Que faire quand le fix de Claude ne marche pas ?
D'abord, assurez-vous que Claude a vraiment vérifié le fix en lançant le test défaillant. Si le fix ne marche vraiment pas, ne le laissez pas réessayer la même approche. Dites « cette approche n'a pas marché — propose une cause racine différente. » Après trois échecs, escaladez : nouvelle hypothèse, revue humaine, ou instrumenter et collecter des données.
Claude Code peut-il faire du pair programming ?
Oui, et ça marche mieux avec un split spécifique : vous pilotez les décisions d'architecture, Claude gère l'implémentation. Décrivez ce que vous voulez à haut niveau, laissez Claude proposer le code, revoyez, itérez. L'anti-pattern est de laisser Claude prendre des décisions d'architecture sans votre input — elles s'accumulent, et quand vous remarquez un mauvais virage, Claude a construit trois couches dessus.
Comment gérer les gros refactorings ?
Découpez-les en phases, un subagent par phase. Phase 1 : « Renommer toutes les occurrences de OldService en NewService. » Phase 2 : « Mettre à jour tous les appelants vers la nouvelle signature d'API. » Phase 3 : « Supprimer les méthodes dépréciées et mettre à jour les tests. » Chaque phase est bornée et testable. La session principale suit la progression et gère l'intégration entre les phases.