opencode-team-lead : un agent qui planifie, délègue, et ne touche jamais au code
Une session bien partie. Les trois premières tâches tombent proprement, le code est correct, les tests passent. Puis, quelque part autour du message 30, quelque chose change. L’agent repose une question qu’on avait tranchée vingt messages plus tôt. Il génère du code qui contredit ce qu’il a écrit lui-même une heure avant. Et quand tu lui demandes de relire ce code, il te répond que c’est parfait.
Ce n’est pas un problème de modèle. C’est un problème de design.
J’ai construit opencode-team-lead pour résoudre exactement ça — d’abord pour mes propres sessions de développement, avant de le publier. Le plugin évolue en continu au fil des retours d’expérience réels. Cet article correspond à la v0.8.0.
Ce qui se dégrade dans les sessions longues
Deux mécanismes entrent en jeu, indépendamment l’un de l’autre.
Le premier : la saturation de contexte. Plus une session avance, plus la fenêtre se remplit — lectures de fichiers, outputs d’outils, allers-retours de debug, réponses d’agents. Dans OpenCode comme dans tout environnement agentique sérieux, des compactions se déclenchent automatiquement quand le contexte approche sa limite. Un résumé remplace l’historique complet. L’agent repart. Mais les décisions prises au début de la session — choix d’architecture, contraintes identifiées, interfaces négociées — sont absentes du résumé. Elles ne sont pas perdues si quelqu’un les a écrites quelque part. Personne ne les a écrites.
Le deuxième est plus insidieux : un agent qui review son propre code ne fait pas de la revue de code. Il se valide. Le même LLM qui a généré le code va l’évaluer avec les mêmes hypothèses implicites, les mêmes angles morts, les mêmes biais de confirmation. Il ne voit pas les erreurs de conception parce qu’il a conçu de la même façon. Il ne questionne pas les choix d’implémentation parce qu’il les a faits. La revue retourne invariablement LGTM — parce que c’est un auto-portrait qui demande son avis sur sa propre apparence.
Les deux problèmes ont la même conséquence : une session longue avec un agent qui fait tout lui-même diverge. Pas parfois. Systématiquement.
Le pattern team-lead : séparer la pensée de l’action
La réponse n’est pas de mieux prompter. C’est de changer qui fait quoi.
Le pattern s’inspire d’une réalité organisationnelle qu’on connaît bien : dans une équipe humaine qui fonctionne, la personne qui planifie et délègue n’est pas la même que celle qui exécute. Le lead ne code pas — il comprend le problème, décompose le travail, dispatche les tâches, contrôle la qualité. L’exécution appartient à d’autres. Cette séparation n’existe pas par convention — elle existe parce que le coût d’un lead qui rentre dans les détails est trop élevé : il perd la vision globale, il s’investit dans l’implémentation, et il ne peut plus l’évaluer objectivement.
Appliqué aux agents, ça donne un orchestrateur qui suit une règle cardinale : ne jamais lire ni modifier le code directement.
Et ce n’est pas une directive dans un prompt. C’est une contrainte enforced par les permissions. L’orchestrateur ne peut littéralement pas appeler read, edit, write, grep ou glob sur la codebase. Ces outils ne sont pas dans ses permissions autorisées. Il n’a accès qu’à task pour déléguer, todowrite/todoread pour tracker, et quelques commandes git en lecture pour vérifier l’état du repo.
La différence entre “ne pas faire” et “ne pas pouvoir faire” n’est pas anecdotique. Un prompt qui dit “ne pas lire directement” peut être oublié, contourné, ignoré au mauvais moment. Une permission refusée est déterministe.
Cette approche est directement liée au pattern documenté par Anthropic dans leur travail sur le harness engineering : la séparation stricte generator/evaluator. La différence ici, c’est que la séparation est enforced au niveau des permissions plutôt que de reposer sur le comportement attendu du modèle.
Architecture : un orchestrateur et ses délégués
Le plugin s’appelle opencode-team-lead. Il enregistre dans OpenCode un agent team-lead et une pipeline de review complète.
graph TD
User["Utilisateur"] --> TL["Agent team-lead\n(Orchestrateur)"]
TL -->|"task(explore)"| EX["explore\n(Lecture de code)"]
TL -->|"task(general)"| GEN["general\n(Exécution)"]
TL -->|"task(review-manager)"| RM["review-manager\n(Sub-agent invisible)"]
RM -->|Parallèle| RR["requirements-reviewer"]
RM -->|Parallèle| CR["code-reviewer"]
RM -->|Parallèle| SR["security-reviewer"]
TL -.->|"read/edit seulement"| SP[".opencode/scratchpad.md"]L’orchestrateur suit un cycle en cinq phases : Understand → Plan → Delegate → Review → Synthesize. La phase Understand commence toujours par la lecture du scratchpad — pour reprendre l’état existant s’il y en a un. La phase Plan utilise sequential-thinking pour décomposer le travail et todowrite pour le rendre visible. La phase Delegate dispatche chaque tâche à l’agent le plus adapté via task, avec un brief complet : chemins de fichiers concernés, contraintes, format de retour attendu. La phase Review délègue systématiquement au review-manager. La phase Synthesize collecte les résultats et présente un résumé à l’utilisateur.
Le modèle de permissions est deny-by-default. Tout ce qui n’est pas explicitement autorisé est bloqué. L’orchestrateur peut utiliser les outils DCP (distill, prune, compress fournis par opencode-dynamic-context-pruning) pour gérer son propre contexte au fil de la session — c’est la seule opération interne qu’il effectue. Tout le reste passe par des délégués.
Le scratchpad : la mémoire qui survit aux compactions
Le problème des compactions mérite qu’on s’y attarde. Dans une session longue sur un projet complexe, la compaction est inévitable. Et quand elle se déclenche, le résumé automatique est peu fiable sur ce qui doit être préservé exactement : les task_id des délégations en cours, les décisions architecturales prises en cours de session, les interfaces négociées avec les agents exécutants.
La solution est basse technologie — et c’est intentionnel.
.opencode/scratchpad.md est un fichier Markdown dans le repo. L’orchestrateur y écrit son état courant après chaque étape significative : mission en cours, plan structuré avec statuts (pending / in_progress / done / blocked), liste des délégations actives avec leurs task_id, et un résumé technique suffisant pour reprendre sans ambiguïté. C’est le seul fichier que l’orchestrateur est autorisé à lire et écrire.
Le plugin implémente le hook experimental.session.compacting d’OpenCode. Quand une compaction se déclenche, le plugin lit le scratchpad et l’injecte verbatim dans le nouveau contexte, avec un header explicite. L’agent repart avec son état intact.
sequenceDiagram
participant OC as OpenCode
participant Plugin as opencode-team-lead
participant SP as .opencode/scratchpad.md
participant Agent as Agent team-lead
Agent->>SP: Met à jour l'état\n(plan, tâches, task_ids)
OC->>Plugin: Déclenchement compaction
Plugin->>SP: Lit le contenu
Plugin->>OC: Injecte le scratchpad\ndans le nouveau contexte
OC->>Agent: Nouveau contexte\navec état préservéCe n’est pas le mécanisme le plus sophistiqué qui soit. Mais il est déterministe là où un résumé automatique est probabiliste. Ce qui compte pour reprendre une session, c’est d’avoir les bons task_id et les bonnes contraintes — pas un résumé bien formulé.
Si OpenCode n’a pas encore déclenché de compaction et que tu veux forcer l’agent à écrire dans le scratchpad, tu peux lui demander explicitement de “mettre à jour son scratchpad” avant une pause longue. Ce fichier est aussi utile comme point de reprise si tu reprends une mission le lendemain.
Une pipeline de review indépendante
L’autre moitié du problème. L’orchestrateur ne review jamais directement — il délègue cette responsabilité au review-manager, un sub-agent qui opère en mode invisible dans l’UI d’OpenCode (mode subagent : il n’apparaît pas dans la liste des agents, il n’existe que pour être invoqué).
Le review-manager lance trois reviewers spécialisés en parallèle, chacun avec un contexte propre et un périmètre distinct :
- requirements-reviewer : l’implémentation correspond-elle à ce qui était demandé ? Pas de jugement sur le code — uniquement la conformité fonctionnelle.
- code-reviewer : qualité du code, patterns, maintenabilité, cohérence avec la codebase existante.
- security-reviewer : vulnérabilités, configurations exposées, surface d’attaque introduite par le changement.
Chaque reviewer produit un verdict indépendant avec sa justification. Le review-manager confronte les trois verdicts et synthétise en un verdict unique : APPROVED, CHANGES_REQUESTED, ou BLOCKED. Le protocole est strict : APPROVED → l’orchestrateur continue ; CHANGES_REQUESTED → les corrections sont redéléguées au producteur avec le détail des demandes ; BLOCKED → escalade immédiate à l’humain. Maximum deux rounds — au-delà, l’humain reprend la main.
Ce qui change fondamentalement par rapport à l’agent all-in-one : les reviewers n’ont pas écrit le code. Ils arrivent sans contexte de production, sans investissement dans les choix faits, sans biais de confirmation. Le requirements-reviewer peut constater que la feature ne couvre pas le cas d’usage principal sans se sentir obligé de minimiser l’écart. Le security-reviewer peut pointer une surface d’attaque sans avoir à défendre l’implémentation.
C’est exactement ce qu’une self-review ne peut structurellement pas faire.
Installation
Trois lignes dans opencode.json :
{
"plugin": [
"opencode-team-lead@latest",
"@tarquinen/opencode-dcp@latest"
],
"default_agent": "team-lead"
}La dépendance DCP est obligatoire. L’orchestrateur l’utilise activement pour maintenir son propre contexte propre entre les délégations. Sans ça, le contexte de l’orchestrateur lui-même grossit indéfiniment avec les outputs verbeux des agents délégués — les mêmes outputs qui ont déclenché le problème en premier lieu.
"default_agent": "team-lead" est fortement recommandé. Sans ça, chaque nouvelle session démarre avec l’agent général d’OpenCode, et l’orchestrateur n’est invoqué que si tu le sélectionnes manuellement — ce qu’on finit par oublier systématiquement après trois jours.
Les permissions sont extensibles sans casser les defaults. Si tu veux que l’orchestrateur puisse lancer une recherche web ou exécuter des tests :
{
"agent": {
"team-lead": {
"permission": {
"webfetch": "allow",
"bash": {
"npm test": "allow"
}
}
}
}
}La fonction mergePermissions combine tes overrides avec les permissions par défaut du plugin. L’orchestrateur garde ses droits git existants et accède en plus à ce que tu ajoutes. Les overrides ne remplacent pas les defaults — ils s’y ajoutent.
Le repo est sur GitHub (azrod/opencode-team-lead), la documentation complète sur azrod.github.io/opencode-team-lead.
Le plugin est principalement testé et développé avec Claude Sonnet 4.6 thinking. Le mode thinking améliore la qualité des phases Plan et Delegate, qui impliquent une décomposition de problème non triviale. D’autres modèles fonctionneront, mais les résultats peuvent varier — notamment sur la rigueur du respect de la règle cardinale.
Le pattern team-lead n’est pas la solution à tous les problèmes d’agents. Sur une tâche courte et bien définie, l’overhead de délégation ne vaut pas grand-chose — un agent général qui fait directement le travail est plus rapide. Là où le pattern prend tout son sens, c’est sur les missions longues qui impliquent plusieurs phases distinctes, plusieurs fichiers, plusieurs décisions architecturales. C’est là que les compactions font des dégâts, que l’auto-review devient dangereuse, et qu’un orchestrateur qui ne touche jamais au code — mais qui sait exactement qui envoyer et pourquoi — fait une vraie différence.