Les workflows Claude : orchestrer l'IA comme on architecture un système

TL;DR : Un workflow Claude, c’est le moment où l’on cesse de converser avec un agent pour commencer à l’orchestrer. On reprend la main sur le flux de contrôle (boucles, branches, fan-out), on délègue le raisonnement local à des agents spécialisés, et on transforme une suite de prompts fragiles en un pipeline reproductible. Cet article explique pourquoi cela compte, comment en construire un proprement, et les pièges à éviter.

Pourquoi un architecte devrait s’intéresser aux workflows

Quand j’ai commencé à utiliser des assistants IA pour le développement, le modèle mental était celui du chat : je pose une question, j’obtiens une réponse, j’itère. C’est puissant pour explorer, c’est désastreux pour produire. Un chat est non-déterministe par construction : la même demande, deux fois, ne suit pas le même chemin. Or l’ingénierie logicielle repose précisément sur l’inverse : la reproductibilité, la traçabilité, la décomposition.

Un workflow Claude répond à ce besoin. C’est un script (du code, versionnable, relisible) qui décrit qui fait quoi, dans quel ordre, et comment les résultats se recombinent. Le modèle ne décide plus de la structure : il l’exécute. Le raisonnement reste flou et probabiliste à l’intérieur de chaque agent ; la colonne vertébrale, elle, redevient déterministe.

C’est exactement la distinction que nous connaissons entre orchestration et chorégraphie dans les systèmes distribués :

Chat (chorégraphie implicite)Workflow (orchestration explicite)
Flux de contrôleDécidé par le modèle, à chaque tourDécidé par le code, une fois pour toutes
ReproductibilitéAucune garantieForte (même script + mêmes entrées)
ObservabilitéFil de discussionArbre de phases, logs structurés
ParallélismeSéquentiel par natureFan-out natif, borné
CoûtImprévisibleBudgétable

Pour un architecte, le workflow n’est pas un gadget de productivité. C’est le passage du prototype jetable au composant de système.

L’utilité réelle : trois problèmes qu’un workflow résout

Je me méfie des outils qui cherchent leur problème. Voici les trois pour lesquels un workflow gagne vraiment sa place.

1. La couverture exhaustive (« décomposer pour ne rien rater »)

Une seule fenêtre de contexte, aussi grande soit-elle, finit par diluer son attention. Demandez à un agent unique de relire 40 fichiers et il survolera les derniers. Un workflow fait du fan-out : un agent par dimension, par fichier, par sous-système, chacun avec toute son attention sur une part du problème. C’est le pattern map d’un map-reduce, appliqué au raisonnement.

Exemple type : Une revue de code multi-dimensions : un agent traque les bugs de correction, un autre les régressions de performance, un troisième les failles de sécurité. Aucun ne dépend des autres ; tous tournent en parallèle.

2. La confiance (« vérifier avant de conclure »)

Un agent qui trouve un bug est, structurellement, motivé à en trouver. D’où les faux positifs plausibles. Le contre-pattern architectural est l’vérification adversariale : pour chaque trouvaille, on lance N sceptiques indépendants dont le seul but est de la réfuter. On ne garde que ce qui survit au vote. C’est le quorum d’un système de consensus, transposé à l’évaluation de la qualité.

3. L’échelle qu’un seul contexte ne peut pas tenir

Une migration sur 300 fichiers, un audit de toute une base, un balayage de logs sur des semaines : aucune conversation ne tient cela en mémoire. Un workflow itère sur la liste de travail, isole chaque élément (un worktree git par agent quand ils écrivent en parallèle), et recombine. La charge dépasse le contexte ; le pipeline, lui, ne sature jamais.

Si votre tâche n’entre dans aucune de ces trois catégories (couverture, confiance, échelle), vous n’avez probablement pas besoin d’un workflow. Un seul agent suffit, et le sur-engineering a un coût (en jetons comme en lisibilité).

Anatomie d’un workflow : les primitives

Un workflow Claude est un script JavaScript (et non TypeScript, pas d’annotations de types) qui s’appuie sur quelques primitives. Les comprendre, c’est comprendre tout le modèle d’exécution.

agent(prompt, opts) : l’unité de raisonnement

C’est l’appel atomique : on délègue une tâche à un sous-agent. Sans schéma, il renvoie son texte final. Avec un schéma JSON (opts.schema), il est forcé de produire une sortie structurée et validée : le modèle ré-essaie tant que la forme ne colle pas. C’est la différence entre parser du texte à la main (fragile) et recevoir un objet typé (robuste).

const audit = await agent(
  "Analyse ce module et liste les dépendances circulaires.",
  { schema: CYCLES_SCHEMA, label: "deps:scan" }
)

Conseil d’architecte : Traitez chaque agent comme une fonction pure : entrée explicite, sortie schématisée, pas d’effet de bord caché. Un agent qui « se souvient » d’un contexte implicite est un agent qu’on ne peut pas tester isolément.

pipeline(items, ...stages) : le défaut

pipeline fait passer chaque élément à travers toutes les étapes sans barrière entre elles. L’élément A peut être à l’étape 3 pendant que B est encore à l’étape 1. Le temps total est celui de la chaîne la plus lente, pas de la somme des plus lentes par étape.

C’est le choix par défaut pour tout travail multi-étapes. C’est aussi celui qu’on oublie le plus, par réflexe séquentiel.

parallel(thunks) : la barrière, à utiliser avec parcimonie

parallel lance des tâches concurrentes et attend qu’elles finissent toutes avant de rendre la main. C’est une barrière de synchronisation. Elle n’est justifiée que lorsque l’étape suivante a réellement besoin de tous les résultats précédents à la fois :

  • dédoublonner / fusionner sur l’ensemble complet ;
  • sortir tôt si le total est zéro (« 0 bug → on saute la vérification ») ;
  • comparer chaque trouvaille « aux autres ».

Elle n’est pas justifiée par « je dois d’abord aplatir/filtrer » (faites-le dans une étape de pipeline) ni par « c’est plus propre » (la latence de la barrière est bien réelle).

phase(), log(), budget : l’observabilité et la maîtrise du coût

phase() regroupe les agents dans l’affichage de progression. log() émet une ligne lisible par l’humain. budget expose le plafond de jetons : budget.remaining() permet d’écrire des boucles qui s’adaptent à l’enveloppe accordée. Un workflow qui ne logue pas ses décisions de troncature (top-N, échantillonnage) ment par omission : il donne l’illusion d’avoir tout couvert.

Construire un workflow, étape par étape

Voici la démarche que je suis, dans l’ordre.

Étape 0 : Scouter en ligne avant d’orchestrer

L’erreur classique est de vouloir tout structurer d’avance. On ne connaît pas toujours la forme du travail avant de l’avoir tâté. La bonne approche est hybride : explorer d’abord à la main (lister les fichiers, identifier les modules, mesurer le diff), puis lancer le workflow sur la liste de travail découverte. On a besoin de connaître la forme avant l’orchestration, pas avant la tâche.

Étape 1 : Déclarer l’intention (meta)

Tout script commence par un bloc meta, un littéral pur, sans variables ni appels de fonction :

export const meta = {
  name: 'review-changes',
  description: 'Revue multi-dimensions du diff, chaque trouvaille vérifiée',
  phases: [
    { title: 'Review' },
    { title: 'Verify' },
  ],
}

Ce bloc est le contrat lisible du workflow : ce qu’il fait, en combien de phases. C’est la première chose qu’un collègue lira.

Étape 2 : Modéliser le flux de données, pas les étapes

Posez-vous une seule question : l’étape N a-t-elle besoin de TOUS les résultats de l’étape N-1 en même temps ?

  • Nonpipeline. C’est presque toujours la réponse.
  • Oui, vraimentparallel comme barrière, puis reprise du pipeline.

Étape 3 : Le pattern canonique, trouver puis vérifier

const DIMENSIONS = [
  { key: 'bugs', prompt: 'Cherche les bugs de correction…' },
  { key: 'perf', prompt: 'Cherche les régressions de performance…' },
  { key: 'sec',  prompt: 'Cherche les failles de sécurité…' },
]

const results = await pipeline(
  DIMENSIONS,
  d => agent(d.prompt, { label: `review:${d.key}`, phase: 'Review', schema: FINDINGS_SCHEMA }),
  review => parallel(review.findings.map(f => () =>
    agent(`Vérifie de façon adversariale : ${f.title}`, {
      label: `verify:${f.file}`, phase: 'Verify', schema: VERDICT_SCHEMA,
    }).then(v => ({ ...f, verdict: v }))
  ))
)

const confirmed = results.flat().filter(Boolean).filter(f => f.verdict?.isReal)
return { confirmed }

Ici, les trouvailles de la dimension « bugs » se vérifient pendant que la dimension « perf » est encore en cours d’analyse. Aucun temps machine gaspillé.

Étape 4 : Itérer sans tout réécrire

Chaque invocation d’un workflow persiste son script sur disque et renvoie son chemin. Pour itérer, on édite ce fichier et on relance avec le scriptPath : inutile de renvoyer tout le script. Et grâce à la reprise (resumeFromRunId), le préfixe inchangé des appels d’agents revient depuis le cache ; seul ce qui a changé ré-exécute.

Patterns de qualité (la boîte à outils de l’architecte)

Ce sont les figures de style réutilisables. On les compose selon la tâche.

  • Vérification adversariale : N sceptiques par trouvaille, instruits de réfuter. On tue la trouvaille si la majorité réfute. Empêche les conclusions « plausibles mais fausses » de survivre.
  • Vérification multi-perspectives : quand une trouvaille peut échouer de plusieurs manières, donnez à chaque vérificateur un angle distinct (correction, sécurité, perf, reproductibilité) plutôt que N clones. La diversité attrape ce que la redondance laisse passer.
  • Panel de juges : générer N solutions sous des angles différents (MVP d’abord, risque d’abord, utilisateur d’abord), les noter en parallèle, puis synthétiser à partir de la gagnante en greffant les meilleures idées des autres. Bat le « une-seule-tentative-itérée » quand l’espace des solutions est large.
  • Boucle jusqu’à épuisement : pour une découverte de taille inconnue (bugs, cas limites), relancer des chercheurs jusqu’à K tours consécutifs sans rien de nouveau. Les compteurs simples (tant que count < N) ratent la queue de distribution.
  • Balayage multi-modal : des agents qui cherchent chacun différemment (par conteneur, par contenu, par entité, par temps). Chacun est aveugle à ce que les autres trouvent.
  • Critique de complétude : un agent final qui demande « qu’est-ce qui manque ? » : une modalité non exécutée, une affirmation non vérifiée, une source non lue. Ce qu’il trouve devient le tour de travail suivant.

Le piège du dédoublonnage : Dans une boucle jusqu’à épuisement, dédoublonnez contre l’ensemble de tout ce qui a été vu, jamais contre l’ensemble de ce qui a été confirmé. Sinon les trouvailles rejetées par le juge réapparaissent à chaque tour et le workflow ne converge jamais. C’est le genre de bug d’orchestration qui ne se voit qu’à l’échelle.

Les bonnes pratiques (et les anti-patterns à fuir)

Voici ce que j’aurais aimé qu’on me dise dès le départ.

À faire

  1. Adaptez l’effort à la demande. « Trouve les bugs évidents » → quelques chercheurs, un seul vote. « Audite ça à fond » → grand pool, vote adversarial 3–5 voix, étape de synthèse. Le sur-engineering coûte des jetons et de la lisibilité.
  2. Schématisez toutes les sorties inter-agents. Le texte libre entre étapes est une dette technique. Un schema JSON transforme une dépendance fragile en contrat validé.
  3. Loguez les troncatures. Tout plafond (top-N, échantillonnage, non-retry) doit être annoncé via log(). Le silence se lit comme « tout est couvert ».
  4. Restez dans la boucle entre les phases. Pour un travail en plusieurs temps (comprendre → concevoir → implémenter → relire), enchaînez plusieurs workflows en séquence, en lisant chaque résultat avant de décider du suivant. Un seul méga-workflow opaque est ingérable.
  5. Isolez les écritures concurrentes. Si plusieurs agents modifient des fichiers en même temps, donnez-leur chacun un worktree (isolation: 'worktree'). Sinon, ils se marchent dessus.

À fuir

  • La barrière par réflexe. Si vous écrivez parallel → transformation sans dépendance croisée → parallel, cette transformation du milieu n’a pas besoin de la barrière. Réécrivez en pipeline.
  • L’override de modèle « au cas où ». Par défaut, un agent hérite du modèle de la boucle principale : c’est presque toujours le bon choix. Ne forcez un autre palier que si vous êtes certain qu’il convient.
  • Le workflow pour une tâche triviale. Si un seul agent (ou vous-même) règle la chose en un tour, n’orchestrez pas. L’orchestration est une réponse à la couverture, la confiance ou l’échelle. Pas à l’envie de paraître sophistiqué.
  • Le budget non gardé. Une boucle tant que budget.remaining() > X sans vérifier que budget.total est défini partira jusqu’au plafond de sécurité (1000 agents). Gardez toujours budget.total &&.
  • Le non-déterminisme caché. Date.now(), Math.random() et consorts cassent la reprise : ils sont d’ailleurs interdits dans les scripts. Faites entrer les valeurs variables par les entrées, estampillez les résultats après coup.

Une grille de décision

Avant de lancer quoi que ce soit, je me pose ces questions dans l’ordre :

  1. La tâche est-elle triviale ou déjà vérifiée ? → Faites-la en solo. Pas de workflow.
  2. Ai-je besoin de couvrir beaucoup en parallèle ? → Fan-out via pipeline.
  3. Mes conclusions doivent-elles être incontestables ? → Ajoutez une passe de vérification adversariale.
  4. La charge dépasse-t-elle un seul contexte ? → Itérez avec isolation par worktree.
  5. Le travail a-t-il plusieurs phases distinctes ? → Plusieurs workflows en séquence, en restant dans la boucle.

Conclusion : du prompt à l’architecture

Le saut conceptuel à opérer est le suivant : cessez de penser en termes de conversations, pensez en termes de systèmes. Un workflow n’est pas un « super prompt ». C’est une topologie d’exécution : des unités de raisonnement (les agents), un flux de contrôle déterministe (le script), des contrats de données (les schémas), et des invariants de qualité (la vérification adversariale).

Tout ce qu’un architecte sait déjà sur la décomposition, l’idempotence, l’observabilité et le coût s’applique presque tel quel. La seule nouveauté, c’est que les composants ne sont plus des services au comportement spécifié, mais des agents au raisonnement probabiliste. D’où la règle d’or qui résume tout le reste :

Délimitez strictement ce qui est flou (le raisonnement, à l’intérieur des agents) et gardez rigoureusement déterministe ce qui structure (le flux, les contrats, la vérification).

C’est précisément la frontière entre un jouet impressionnant et un outil sur lequel on peut bâtir.


Les primitives décrites (agent, pipeline, parallel, phase, log, budget) correspondent au modèle d’orchestration de workflows de Claude Code.