MagicCode/GUIDE_AUTONOMOUS.md
2026-10-27 00:45:53 +01:00

24 KiB
Raw Permalink Blame History

Guide des agents autonomes (workflows) de MAIA

Un workflow fait travailler des agents sans interface : un agent parent (l'orchestrateur) reçoit une tâche, la découpe, confie des morceaux à des sous-agents, puis rend un résultat. On le lance en ligne de commande, à la main, depuis un script, une tâche planifiée ou un service, et on interroge MAIA pour savoir où il en est.

maia run …/Main/AGENT.md --task "…"
        │
        ▼
  ┌───────────────┐   outil Agent    ┌──────────────┐
  │  agent parent │ ───────────────▶ │  sous-agent  │  (un processus par lancement,
  │    (Main)     │ ◀─── résumé ──── │  (reviewer)  │   en parallèle si besoin)
  └───────────────┘                  └──────────────┘
        │  états, journal, demandes, résultat
        ▼
  ~/.maia/workflows/<id>/   ◀── maia workflows · workflow · logs · approve · reply · stop · result

Sommaire : 1. Préparer les agents · 2. L'agent parent · 3. Les sous-agents · 4. Lancer · 5. Autorisations · 6. Superviser · 7. Intervenir · 8. Scripts et services · 9. Registre · 10. Limites · 11. Dépannage · 12. Aide-mémoire


1. Préparer les agents

Les agents sont des fichiers AGENT.md, un dossier par agent :

X:/projX/
├── MAIA.md                         ← contexte du projet (lu par les agents, sauf omitMd: true)
└── .maia/
    ├── settings.json               ← permissions du projet (allow / ask / deny)
    └── agents/
        ├── Main/AGENT.md           ← agent PARENT (orchestrateur)
        ├── reviewer/AGENT.md       ← sous-agent du projet
        └── test_runner/AGENT.md    ← sous-agent du projet

~/.maia/
├── settings.json                   ← LiteLLM, DefaultModel, permissions globales
└── agents/
    └── doc_checker/AGENT.md        ← sous-agent GLOBAL (disponible pour tous les projets)
  • Créer un agent : dans MAIA interactif, /createAgent (niveau projet ou global) copie un modèle commenté ; il suffit de remplir la description et les sections. Exemples prêts à copier : examples/agents/release_check (parent) et examples/agents/code_reviewer (sous-agent).
  • Le nom de l'agent (name:) doit être celui de son dossier.
  • Un agent parent est un agent comme les autres : même format, mêmes champs. Ce qui en fait un parent, c'est qu'on le lance avec maia run. Le même fichier peut servir de sous-agent dans un autre workflow.

2. L'agent parent

---
name: Main
description: Vérifie qu'une branche est prête à être livrée.
model: sonnet                 # facultatif (voir § 4, « Modèle »)
effort: high                  # étapes maximales : low 10 · medium 25 · high 50
timeout: 60m                  # facultatif : durée maximale du workflow (90s, 30m, 2h, 1d)
permissionMode: wait          # facultatif : wait (défaut) | deny | allow (voir § 5)
permissions:                  # facultatif : règles ajoutées à celles des settings.json
  allow: [Agent, Read, Grep, "Bash(git diff *)"]
---
# Instructions system
Tu es un orchestrateur de vérification avant livraison. Tu ne relis pas le code toi-même :
tu délègues à tes sous-agents et tu consolides leurs résultats.

# Missions
1. Lance reviewer et doc_checker en parallèle sur les fichiers modifiés (git diff --name-only main...HEAD).
2. Si reviewer ne signale aucun problème CRITICAL, lance test_runner.
3. Consolide les trois rapports.

# Constraints (optionnelle)
- ne modifie aucun fichier, ne fais ni commit ni push
- si un problème CRITICAL est trouvé : ne conclus pas seul, demande l'intervention de l'équipe sécurité

# Output
- Verdict : GO ou NO-GO
- Problèmes par gravité, avec fichier et ligne
- Décision de l'équipe sécurité, s'il y en a eu une

Champs de l'en-tête

Champ Rôle pour le parent
name, description obligatoires (comme tout agent)
model modèle du parent ; c'est aussi celui que ses sous-agents héritent
effort nombre maximal d'étapes (un appel au modèle + ses outils) : 10 / 25 / 50. Au-delà, le parent rédige son résultat avec ce qu'il a.
timeout durée maximale du workflow, sous-agents compris ; dépassée : arrêt, état « en erreur ». Sans ce champ : pas de limite.
permissionMode traitement des demandes d'autorisation sans interface (§ 5) ; --permission-mode l'emporte
permissions règles allow / ask / deny ajoutées à celles des settings.json (un deny ou ask des settings n'est jamais levé)
tools restreint les outils du parent ; l'outil Agent et l'outil RequestIntervention restent toujours disponibles
skills, omitMd comme pour un sous-agent (skills autorisés ; omitMd: true = sans MAIA.md / CLAUDE.md)

Sections : # Instructions system, # Missions, # Output sont obligatoires ; # Constraints est facultative. Le résultat final du workflow est la dernière réponse du parent, au format de la section Output.

Bien écrire un parent

  • Nommez les sous-agents dans les missions et les contraintes (« lance reviewer… ») : c'est ainsi que le parent sait qui appeler, et les agents cités apparaissent dès le départ en « non exécuté » dans le suivi.
  • Parallèle ou séquence : écrivez-le. « Lance A et B en parallèle » → les deux sous-agents tournent en même temps ; « Si A …, lance C » → C attend le résultat de A.
  • Contraintes qui demandent un humain : écrivez « demande l'intervention de … ». Le parent utilise alors l'outil RequestIntervention et le workflow passe en attente jusqu'à votre réponse (§ 7).
  • Un sous-agent ne voit rien de la conversation du parent : le parent doit tout mettre dans la tâche qu'il confie (fichiers, objectif, contraintes). Rappelez-le dans les instructions si les sous-agents manquent de contexte.

3. Les sous-agents

Quels sous-agents le parent peut lancer

  • tous ceux du dossier .maia/agents qui contient le parent (pour X:/projX/.maia/agents/Main/AGENT.md : tout X:/projX/.maia/agents/) ;
  • tous les agents globaux (~/.maia/agents/) ;
  • à nom égal, celui du dossier du parent l'emporte ; le parent ne se lance jamais lui-même ;
  • les agents d'un autre projet ne sont pas visibles.

Comment ils s'exécutent

  • chaque lancement = un processus séparé, avec une conversation vide : le sous-agent ne connaît que la tâche reçue et son propre AGENT.md (plus MAIA.md sauf omitMd) ;
  • seul son résumé final (section Output) revient au parent ;
  • modèle : celui du parent, sauf s'il a son propre champ model (nom exact ou morceau : haiku → premier modèle LiteLLM dont le nom contient « haiku ») ;
  • outils : ceux de l'agent principal (intégrés, personnalisés de ./.maia/tools et ~/.maia/tools, Skill), limités par tools: ; jamais l'outil Agent ;
  • permissions : celles des settings.json + celles de son en-tête (elles s'ajoutent, un deny hérité n'est jamais levé). Ses demandes d'autorisation remontent au workflow et sont traitées selon permissionMode (§ 5), attribuées au sous-agent dans le suivi ;
  • étapes : selon son effort (10 / 25 / 50) ; s'il les épuise, on lui demande son résumé ;
  • durée : pas de délai propre dans un workflow (c'est le timeout du workflow qui borne tout) ;
  • conversation : toujours enregistrée dans le registre (traces/<agent>.json, <agent>-2.json au 2e lancement…), que trace soit à true ou non ;
  • un sous-agent ne peut pas poser de question : devant un cas prévu par ses Constraints, il s'arrête sur ce point et le signale dans son résumé ; c'est au parent de demander l'intervention.

Un bon sous-agent a une description claire (le parent choisit d'après elle), une mission étroite, une section Output structurée que le parent pourra consolider, et des tools / permissions limités au nécessaire (ex. tools: Read, Grep, Glob pour un relecteur).

4. Lancer un workflow

maia run X:/projX/.maia/agents/Main/AGENT.md --task "Vérifie la branche feature/x"
maia run ./.maia/agents/Main/AGENT.md "Vérifie la branche feature/x"     # la tâche peut suivre le fichier
maia run ./.maia/agents/Main/AGENT.md --detach --name livraison-nuit     # en arrière-plan
Option Effet
--task "…" la tâche du parent ; sans tâche : « exécute ta mission telle qu'elle est décrite »
--model <spec> modèle du parent (et donc des sous-agents sans model)
--name <nom> nom du workflow, utilisable à la place de l'identifiant
--detach / -d lance en arrière-plan : affiche l'identifiant et rend la main tout de suite
--json résultat en JSON sur la sortie standard
--permission-mode wait|deny|allow remplace permissionMode de l'en-tête
--timeout 30m remplace timeout de l'en-tête
--quiet / -q sans la progression

Avec pnpm (depuis le dépôt MAIA, sans rien installer ni compiler : le script maia exécute les sources avec tsx) :

cd /chemin/vers/maia
pnpm maia run X:/projX/.maia/agents/Main/AGENT.md --task "Vérifie la branche feature/x"
pnpm maia workflows
pnpm maia workflow last --watch
pnpm maia approve last r1

# depuis le dossier du projet, sans s'y déplacer dans le dépôt MAIA :
cd X:/projX
pnpm --dir /chemin/vers/maia maia run ./.maia/agents/Main/AGENT.md --detach
pnpm --dir /chemin/vers/maia maia logs last -f
  • pnpm dev run … fonctionne aussi (même script) ; un -- après le nom du script (pnpm maia -- run …) est accepté et ignoré.

  • Les chemins relatifs (./.maia/agents/Main/AGENT.md) sont résolus depuis le dossier où vous avez tapé la commande (pnpm le transmet dans INIT_CWD), pas depuis le dépôt MAIA. MAIA_CWD=/autre/dossier force un autre dossier.

  • Après pnpm build, la commande compilée est node /chemin/vers/maia/packages/cli/dist/index.js run …, ou maia run … si elle est installée dans le PATH (voir le README, « Lancer MAIA depuis un autre dossier »). Pour une tâche planifiée ou un service, préférez la version compilée : elle démarre plus vite et ne dépend pas de tsx.

  • --detach fonctionne aussi avec pnpm : le processus détaché est relancé avec le même interpréteur (tsx compris).

  • Dossier de travail : le projet qui contient .maia/agents (X:/projX), quel que soit le dossier d'où vous lancez. Si le AGENT.md n'est pas dans un dossier .maia/agents, c'est le dossier de lancement, et les sous-agents disponibles sont ceux du dossier qui contient le dossier de l'agent, plus les globaux.

  • Modèle : --model, sinon model du parent, sinon DefaultModel de ~/.maia/settings.json, sinon le premier modèle de LiteLLM (avec un avertissement). Conseil : fixez DefaultModel pour les workflows planifiés.

  • Au premier plan, la progression s'affiche sur la sortie d'erreur et le résultat sur la sortie standard :

Workflow wf_20261027_000558_3f50 — suivi : maia workflow wf_20261027_000558_3f50
[00:05:58] workflow › Workflow wf_… démarré : agent Main, modèle litellm:sonnet, autorisations « wait », dossier X:/projX
[00:05:58] Main › Sous-agents disponibles : doc_checker, reviewer, test_runner
[00:05:59] reviewer › en exécution
[00:06:00] reviewer › terminé
…
VERDICT GO — …
  • Codes de sortie : 0 terminé · 1 en erreur (dont délai dépassé) · 2 mauvaise utilisation · 130 arrêté par maia stop.
  • --json : { "id", "state", "label", "exitCode", "result", "error" }. Avec --detach --json : { "id", "pid" }.

5. Autorisations sans interface

Les règles des settings.json (et de l'en-tête de l'agent) s'appliquent comme en mode interactif : allow passe sans demander, deny refuse. Ce qui change, c'est une demande ask (ou un outil sans règle, qui demande par défaut) : personne n'est là pour répondre « o/n ». permissionMode décide :

Mode Une demande ask est…
wait (défaut) enregistrée ; l'agent passe en attente jusqu'à maia approve <id> <demande> (ou --deny). Le travail déjà fait est conservé.
deny refusée aussitôt ; le modèle en est informé et continue autrement
allow acceptée aussitôt — à réserver à un environnement isolé (conteneur, machine jetable)

Important : l'outil Agent demande une autorisation par défaut. Sans règle, chaque lancement de sous-agent attend donc un maia approve. Pour un workflow qui doit tourner seul, autorisez au moins le lancement des sous-agents :

# en-tête de l'agent parent
permissions:
  allow: [Agent]                       # tous ses sous-agents
# ou, plus précis :  allow: ["Agent(reviewer)", "Agent(doc_checker)"]

ou dans X:/projX/.maia/settings.json : "permissions": { "allow": ["Agent", "Read", "Grep", "Glob"] }.

Recette pour un workflow de nuit : des règles allow précises pour ce que le workflow doit faire (lecture, Bash(git diff *), Bash(npm test)…), des deny pour ce qui ne doit jamais arriver (Bash(git push *), Bash(rm *)), et wait pour le reste : seules les actions imprévues attendront une réponse. Syntaxe des règles : GUIDE_PERMISSIONS.md.

6. Superviser

maia workflows                 # workflows en cours
maia workflows --all           # tous, y compris terminés et en erreur
maia workflow last             # le plus récent
maia workflow livraison-nuit   # par nom (--name)
maia workflow 3f50 --watch     # par morceau d'identifiant, rafraîchi toutes les 2 s jusqu'à la fin
maia logs 3f50 -f              # journal en continu
maia logs 3f50 reviewer        # journal d'un seul agent
maia result 3f50               # résultat final

<id> accepte : l'identifiant complet, un morceau unique de celui-ci (3f50), le nom donné par --name (le plus récent s'il y en a plusieurs), ou last.

États

État Pour un agent Pour le workflow
non exécuté cité par le parent mais pas encore lancé créé, pas encore démarré
en exécution il travaille au moins un agent travaille
en attente il attend une réponse (autorisation ou intervention) au moins un agent attend
terminé il a rendu son résultat le parent a rendu le résultat
en erreur échec, délai, arrêt, ou workflow interrompu pendant qu'il tournait échec du parent, délai, maia stop, ou processus disparu

Un sous-agent en erreur ne fait pas échouer le workflow : le parent en est informé et décide (le workflow peut être « terminé » avec un agent « en erreur »).

Exemple de maia workflow

Workflow wf_20261027_000558_3f50 : en attente
  Agent parent : Main (X:/projX/.maia/agents/Main/AGENT.md)
  Modèle : litellm:sonnet · autorisations : wait · durée : 2 min 10 s
  Dossier : X:/projX
  Tâche : Vérifie la branche feature/x

Agents :
  Main         en attente   parent · 2 min 10 s · litellm:sonnet
  doc_checker  terminé      41 s · litellm:haiku
  reviewer     en exécution 1 min 02 s · litellm:sonnet
  test_runner  non exécuté

Demandes en attente :
  r3  Main (intervention : équipe sécurité) : Faille CRITICAL dans auth.ts:42, livre-t-on quand même ?
      → maia reply wf_20261027_000558_3f50 r3 "réponse"

Dans MAIA interactif : /workflows (en cours), /workflows all, /workflow <id>.

7. Intervenir : répondre, arrêter

maia approve <id> r1            # autoriser une demande d'autorisation
maia approve <id> r1 --deny     # la refuser
maia reply <id> r3 "Non, on bloque la livraison."   # répondre à une demande d'intervention
maia stop <id>                  # arrêter le workflow et ses sous-agents
  • maia workflow <id> affiche chaque demande en attente avec la commande exacte pour y répondre.
  • Chaque demande reçoit une seule réponse ; une autorisation se règle avec approve, une intervention avec reply.
  • Le workflow lit les réponses et les demandes d'arrêt toutes les secondes.
  • Stop : le tour en cours s'interrompt, les sous-agents en cours reçoivent l'ordre de s'arrêter, le workflow passe « en erreur (arrêté) », code 130. Ce qui a déjà été fait (fichiers, journal, traces) est conservé, mais le workflow ne reprend pas : relancez-en un nouveau.

8. Scripts, tâches planifiées et services

Script : lancer et attendre

#!/usr/bin/env bash
cd /srv/projX
maia run .maia/agents/Main/AGENT.md --task "Vérifie la branche $BRANCH" --json --permission-mode deny > resultat.json
case $? in
  0)   echo "OK : $(jq -r .result resultat.json)" ;;
  130) echo "Arrêté" ;;
  *)   echo "Échec : $(jq -r .error resultat.json)"; exit 1 ;;
esac

Script : lancer en arrière-plan puis surveiller

id=$(maia run .maia/agents/Main/AGENT.md --detach --json | jq -r .id)
while :; do
  state=$(maia workflow "$id" --json | jq -r .state)      # pending | running | waiting | done | error
  [ "$state" = done ] || [ "$state" = error ] && break
  [ "$state" = waiting ] && maia workflow "$id" | sed -n '/Demandes en attente/,$p' | mail -s "MAIA attend" moi@exemple.fr
  sleep 60
done
maia result "$id"

Le JSON utilise des codes stables (pending, running, waiting, done, error) et le libellé français dans label : testez les codes, affichez les libellés.

Tâche planifiée (cron, chaque nuit à 2 h 13) :

13 2 * * *  cd /srv/projX && /usr/local/bin/maia run .maia/agents/Main/AGENT.md --name nuit --quiet >> /var/log/maia-nuit.log 2>&1

Sous Windows, le Planificateur de tâches lance la même commande (maia run X:\projX\.maia\agents\Main\AGENT.md --name nuit --quiet).

Service (systemd, en tant qu'utilisateur maia) : le service lance maia run … au premier plan (pas --detach : systemd suit lui-même le processus) ; pensez à WorkingDirectory= et aux variables d'environnement utiles (LITELLM_API_KEY, variables ${…} de mcp.json).

À savoir pour l'automatisation

  • MAIA lit ~/.maia/settings.json, ~/.maia/agents, ~/.maia/mcp.json de l'utilisateur qui lance la commande : un service lancé sous un autre compte a son propre ~/.maia, et ses workflows n'apparaissent que dans son maia workflows.
  • Aucun terminal n'est nécessaire : maia run et les commandes de supervision fonctionnent sans TTY.
  • NO_COLOR=1 supprime les couleurs de l'affichage texte (elles sont déjà absentes hors terminal).

9. Le registre

Chaque workflow a un dossier dans ~/.maia/workflows/<id>/ (registre global, pour tous les projets) :

Fichier Contenu
workflow.json agent parent, tâche, modèle, dossier, mode d'autorisation, pid, dates, état, erreur
agents.json état de chaque agent (modèle, nombre de lancements, durée, erreur)
events.jsonl journal horodaté, une ligne JSON par évènement (ce qu'affiche maia logs)
requests/ r1.json… : demandes ; r1.answer.json : réponse déposée par approve / reply
traces/ conversation complète de chaque agent (Main.json, reviewer.json, reviewer-2.json…)
result.md résultat final du parent
run.log sortie du processus en mode --detach
stop présent si maia stop a été demandé
  • Pas de serveur : les commandes lisent ces fichiers. Seul le processus du workflow écrit workflow.json, agents.json et events.jsonl (écritures atomiques) ; les réponses et l'arrêt sont déposés dans des fichiers à part.
  • Nettoyage : rien n'est supprimé automatiquement. Supprimez les dossiers des anciens workflows à la main (ils sont nommés par date : wf_AAAAMMJJ_HHMMSS_xxxx).
  • Les traces contiennent tout ce que les agents ont lu (code, sorties de commandes) : traitez ce dossier comme sensible.

10. Limites

  • Un seul niveau d'agents : le parent lance des sous-agents, un sous-agent ne lance jamais d'agent (il n'a pas l'outil Agent). Pour une chaîne plus longue, c'est le parent qui enchaîne les étapes.
  • Le parent ne voit que les résumés de ses sous-agents, pas leur conversation (elle est dans traces/).
  • Une demande d'autorisation à la fois : même avec des sous-agents en parallèle, les demandes ask sont posées l'une après l'autre (la suivante apparaît quand la précédente a reçu sa réponse). D'où l'intérêt des règles allow (§ 5).
  • Seul le parent peut demander une intervention (RequestIntervention) ; un sous-agent signale le besoin dans son résumé.
  • Pas de reprise : un workflow arrêté, en erreur, ou dont le processus a disparu (redémarrage de la machine, fermeture de session) ne reprend pas ; il apparaît « en erreur » et il faut en relancer un.
  • Pas de compactage du contexte pour le parent ni pour les sous-agents : une très longue conversation peut dépasser la fenêtre du modèle. Gardez des missions courtes et des sous-agents qui résument.
  • Les sous-agents n'ont pas les outils MCP (le parent les a, si les serveurs sont activés pour le projet).
  • Pas d'API HTTP : la supervision passe par la ligne de commande et les fichiers du registre, sur la même machine et pour le même utilisateur.
  • Pas de nettoyage automatique du registre.
  • Le délai par sous-agent n'existe pas dans un workflow : seul timeout (du workflow) borne la durée totale.
  • Les sous-agents d'autres projets ne sont pas accessibles ; partagez un agent en le plaçant dans ~/.maia/agents.

11. Dépannage

Symptôme Cause probable / solution
Le workflow reste « en attente » dès le début le lancement d'un sous-agent demande une autorisation : maia workflow <id> puis maia approve, ou ajoutez allow: [Agent] (§ 5)
« Agent parent invalide » section obligatoire manquante, name différent du dossier, description absente : le message dit laquelle
« Aucun sous-agent disponible » le AGENT.md n'est pas dans un dossier .maia/agents, ou ce dossier ne contient que le parent ; vérifiez aussi ~/.maia/agents
Le parent ne lance pas un sous-agent attendu son nom n'apparaît pas dans les missions, ou sa description ne correspond pas à la tâche ; nommez-le explicitement
« en erreur — processus disparu » le processus a été tué (machine éteinte, session fermée, kill) ; relancez. Pour un lancement durable, utilisez un service ou une tâche planifiée
« Aucun modèle indiqué… » ni --model, ni model, ni DefaultModel, et LiteLLM injoignable : vérifiez ~/.maia/settings.json
Rien ne s'affiche avec --detach normal : la sortie va dans ~/.maia/workflows/<id>/run.log ; suivez avec maia logs <id> -f
workflow « x » introuvable / « ambigu » utilisez l'identifiant complet, last, ou un morceau plus long

12. Aide-mémoire

# Lancer (ou : pnpm maia run …  depuis le dépôt MAIA, pnpm --dir <maia> maia run …  d'ailleurs)
maia run <AGENT.md> [--task "…"] [--model m] [--name n] [--detach] [--json]
                    [--permission-mode wait|deny|allow] [--timeout 30m] [--quiet]
# Superviser
maia workflows [--all] [--json]
maia workflow <id> [--json] [--watch]
maia logs <id> [agent] [-f]
maia result <id>
# Intervenir
maia approve <id> <rN> [--deny]
maia reply <id> <rN> "texte"
maia stop <id>
Sous-agents disponibles dossier .maia/agents du parent + ~/.maia/agents
Modèle --model > model du parent > DefaultModel > 1er modèle LiteLLM ; sous-agents : celui du parent sauf model
Autorisations wait (défaut) · deny · allow ; pensez à allow: [Agent]
États non exécuté · en exécution · en attente · terminé · en erreur
Codes de sortie 0 terminé · 1 erreur · 2 utilisation · 130 arrêté
Registre ~/.maia/workflows/<id>/
Niveaux 1 seul : parent → sous-agents