Aval

GuidesAgents IA et validation humaine

Faire tourner un agent en boucle sur un graphe de tâches

Un fichier d'état avec des dépendances, une routine qui réveille l'agent, une PR par tâche, et vos décisions posées sur votre téléphone avec Aval.

· par Antoine

On donne une liste de tâches à un agent, on lui dit de la dérouler pendant la nuit, et on découvre le matin qu'il a refait trois fois la même chose, ou qu'il attend une réponse depuis 23 h. Pour qu'un agent avance seul pendant des jours, il lui faut trois choses : un endroit où écrire où il en est, quelque chose qui le réveille, et un moyen de vous demander quand il ne doit pas décider seul.

C'est comme ça que taraxe.com avance depuis octobre 2026 : une feuille de route dans un fichier, un agent réveillé toutes les heures, et mes décisions qui arrivent sur mon téléphone. Ce guide décrit le dispositif, sans rien qui soit propre à mon projet.

Si les mots agent, harness, boucle et graphe se mélangent un peu, commencez par les quatre étages d'un agent autonome : ce guide-ci entre dans le détail des deux derniers.

Boucle ou graphe : les deux

On oppose souvent les deux, alors qu'ils se complètent.

  • Une boucle seule relance l'agent avec la même consigne, encore et encore. Mais elle vit dans une session qui finit par s'arrêter, et à chaque tour l'agent doit deviner où il en était.
  • Un graphe seul, c'est un plan bien rangé : des tâches et leurs dépendances. Il ne fait rien tout seul.

Ensemble, ça marche : le graphe garde l'état, la boucle avance dedans. À chaque réveil, l'agent relit le fichier, prend la prochaine tâche débloquée, la fait, et met le fichier à jour. S'il est interrompu, le tour suivant reprend au bon endroit.

Le fichier d'état

Un simple fichier YAML ou JSON suffit, dans le dépôt ou dans un dossier partagé. Chaque tâche, chaque nœud du graphe, a un identifiant, ses dépendances, un état et ce qu'il faut pour la considérer comme finie.

noeuds:
  - id: ci
    titre: Lancer les tests sur chaque PR
    depend_de: []
    etat: merge
    pr: 12

  - id: factures
    titre: Envoyer les factures en PDF
    depend_de: [ci]
    etat: bloque
    question_aval: q_7f3k2m
    raison: Quel fournisseur de mail utiliser ?

  - id: page-prix
    titre: Page des prix
    depend_de: [factures]
    etat: a_faire
    criteres:
      - Les trois offres, en français et en anglais
      - Un lien vers le paiement

Les dépendances dessinent le graphe. Ici, la page des prix attend les factures, qui attendent les tests. Le guide de l'API ne dépend que des tests et peut avancer en parallèle :

ci ──► factures ──► page-prix
 │
 └───► guide-api

Quelques états suffisent : a_faire, en_cours, pr_ouverte, merge, bloque et abandonne. Le champ criteres compte plus qu'il n'en a l'air : c'est lui qui dit à l'agent quand s'arrêter, et à vous quoi vérifier dans la PR.

Gardez un seul fichier, et un seul agent qui l'écrit. Deux boucles qui modifient le même fichier finissent par s'écraser l'une l'autre.

Une tâche, une branche, une PR

Chaque nœud se fait sur sa propre branche et finit en pull request. C'est ce qui rend le dispositif tranquille à suivre : vous ne relisez pas un flot de changements, vous relisez une PR à la fois, avec son titre et ses critères.

Deux règles évitent la plupart des ennuis :

  • Pas plus de deux tâches en cours à la fois, et sur des fichiers différents. Au-delà, les branches se marchent dessus en attendant que vous ayez le temps de les relire.
  • L'agent ne merge jamais lui-même. Le merge, c'est votre validation du résultat. Une protection de branche sur main le garantit mieux qu'une consigne.

Ce qui réveille l'agent

Il y a plusieurs façons de relancer l'agent, selon l'endroit où il tourne.

  • Dans Claude Code, la commande /loop relance une consigne à intervalle régulier, ou laisse l'agent choisir son rythme. C'est le plus simple pour commencer, mais la boucle s'arrête avec la session.
  • Une tâche planifiée survit à la fin des sessions. Les sessions de Claude Code dans le cloud peuvent être lancées par une routine planifiée. Sur votre propre machine, un cron qui lance Claude Code en mode non interactif fait la même chose :
# Toutes les heures, à la minute 4
4 * * * * cd ~/mon-projet && claude -p "$(cat consigne-boucle.md)"

En mode non interactif, personne n'est là pour accepter une permission dans le terminal : réglez à l'avance ce que l'agent a le droit de faire, dans les réglages du projet.

  • Les événements sont le meilleur réveil : le merge d'une PR débloque souvent la tâche suivante. Un agent qui suit ses PRs peut repartir tout de suite au lieu d'attendre l'heure suivante.
  • Dans n8n, un nœud Schedule Trigger joue le rôle du cron. On y revient plus bas.

Un réveil toutes les heures, c'est vingt-quatre tours par jour. La plupart ne trouvent rien à faire. Il faut que ces tours-là ne fassent vraiment rien : pas de message, pas de commentaire, pas de « rien de neuf ». Sinon vous arrêtez de lire au bout de deux jours.

Garder l'humain dans la boucle

Vous intervenez à deux moments différents, et il vaut mieux ne pas les mélanger.

  • Valider un résultat : c'est la PR. Vous la relisez quand vous avez le temps, et vous la mergez ou non.
  • Prendre une décision : un nom de produit, un fournisseur, un prix, une question de périmètre. Là, l'agent ne peut pas avancer sans vous, et une PR n'est pas le bon endroit pour la poser.

Pour les décisions, l'agent a besoin d'un outil pour vous joindre là où vous êtes. Avec Aval, branché en MCP, il appelle ask_human avec la question, les options et un peu de contexte. La question arrive sur Telegram, avec un bouton par option, ou par mail si Telegram n'est pas relié. Vous touchez un bouton dans le métro, c'est fait.

{
  "question": "Pour les factures, j'utilise quel service de mail ?",
  "options": ["Resend", "Postmark", "On en parle d'abord"],
  "context": "Tâche « factures », la seule débloquée. Resend est déjà utilisé ailleurs dans le projet.",
  "agent_name": "Boucle · feuille de route",
  "expires_in_minutes": 2880
}

Ici l'agent laisse deux jours pour répondre (expires_in_minutes, jusqu'à sept jours). L'option « On en parle d'abord » vous laisse une sortie quand aucune des réponses ne convient.

Ne pas attendre la réponse dans la boucle

C'est le point le plus important. Dans une conversation, l'agent pose la question et attend la réponse avec wait_for_answer. Dans une boucle, il ne faut pas : un tour bloqué deux jours sur une question empêche tout le reste d'avancer.

La bonne façon, c'est de laisser la question vivre dans le fichier :

  • l'agent pose la question, écrit son question_id dans la tâche, la passe en bloque, et termine son tour ;
  • aux tours suivants, il relit la question une fois, avec wait_for_answer ou un GET sur l'API, sans attendre ;
  • si la réponse est là, il la note dans la tâche et la repasse en a_faire ;
  • si la question a expiré, c'est un non : la tâche reste bloquée, et l'agent passe à une tâche qui n'en dépend pas.

Relire une question ne coûte rien, même vingt-quatre fois par jour.

La consigne à donner à l'agent

Voici la consigne de départ, à mettre dans le fichier que la boucle lui fait lire, ou dans CLAUDE.md :

Tu avances dans la feuille de route, feuille-de-route.yaml.
À chaque réveil :
1. Relis le fichier. Pour chaque tâche « bloque » qui a une
   question_aval, appelle wait_for_answer une fois. Répondue :
   note la réponse et repasse la tâche en « a_faire ».
   Expirée : c'est un non, laisse-la bloquée.
2. Prends la première tâche « a_faire » dont toutes les
   dépendances sont « merge ». Jamais plus de deux tâches en
   cours en même temps.
3. Fais-la sur sa propre branche, ouvre une PR, passe la tâche
   en « pr_ouverte » avec le numéro de la PR.
4. S'il te faut une décision, pose-la avec ask_human, écris
   le question_id dans la tâche, passe-la en « bloque » et
   arrête-toi. N'attends pas la réponse dans ce tour.
5. Si rien n'a bougé, ne fais rien et n'écris à personne.
Tu ne merges jamais une PR toi-même.

Ajoutez-y ce qui ne doit jamais se faire sans vous dans votre projet : payer, contacter quelqu'un, créer un compte, toucher à la production. Pour des pistes, voir ce qu'un agent IA ne devrait pas faire seul.

Pour Claude Code, le branchement d'Aval tient en une commande : claude mcp add --transport http aval https://www.taraxe.com/aval/mcp, puis /mcp pour vous connecter avec votre mail. Le détail est dans le guide Claude Code.

La même chose avec n8n

Si votre agent vit dans n8n plutôt que dans un terminal, le dispositif est le même :

  • un Schedule Trigger toutes les heures ;
  • la lecture de l'état, dans une table, une feuille de calcul ou un fichier ;
  • pour une décision, un HTTP Request en POST sur https://www.taraxe.com/api/aval/questions avec votre clé d'API, puis l'écriture du question_id dans l'état ;
  • aux tours suivants, un GET sur https://www.taraxe.com/api/aval/questions/ suivi de l'identifiant, sans paramètre wait : il répond tout de suite, avec un status qui vaut pending, answered, expired ou cancelled.

Le guide n8n détaille la clé d'API et le format des réponses.

Les pièges

  • Une question qui expire prise pour un oui. Sans réponse, on ne fait rien. Écrivez-le dans la consigne.
  • Trop de questions. Si l'agent vous demande tout, vous répondrez sans lire. Une question par décision qui compte, avec le contexte pour répondre en dix secondes.
  • Des tâches trop grosses. Une PR que vous n'avez pas le courage de relire reste ouverte, et toute la suite du graphe attend. Découpez.
  • Une tâche bloquée qui bloque tout. Fixez un délai, deux jours par exemple, au-delà duquel l'agent passe à une branche indépendante du graphe.

Questions fréquentes

Combien coûte une boucle comme ça ?

Côté Aval, seules les questions posées se paient : 1 crédit dans Telegram, 2 par mail, et les 40 premiers crédits sont offerts. Relire une réponse est gratuit, et un tour qui ne pose pas de question ne coûte rien. Les packs vont de 10 € les 200 crédits à 50 € les 1 500, sans abonnement. Le coût principal reste celui du modèle à chaque réveil, d'où l'intérêt de tours vides très courts.

Pourquoi ne pas laisser l'agent merger quand les tests passent ?

On peut, une fois qu'une vraie suite de tests tourne sur chaque PR et qu'on a confiance dans le dispositif. Pour commencer, garder le merge vous donne un moment de relecture par tâche, et le droit de dire non à un résultat techniquement correct mais pas celui que vous vouliez.

Que se passe-t-il si je ne réponds pas ?

À l'échéance, la question expire et la relecture rend expired. L'agent la traite comme un refus : la tâche reste bloquée, et il avance ailleurs dans le graphe. Rien ne se fait à votre place.

Faut-il utiliser Claude Code ?

Non. Le dispositif marche avec n'importe quel agent qui sait lire un fichier et appeler un outil MCP ou une API HTTP : Cursor, un script maison, n8n. Aval se branche dans Claude, ChatGPT, Cursor, VS Code et les autres clients MCP, et a une API pour le reste.