Files
plugin-claude-miam/docs/hooks-delegation.md
T
angeandClaude Opus 5.5 2ce4af8963 v0.9.0 : attente unique des délégations et contrôles de MIAM
- reprise lancée une fois en arrière-plan ; suivre et sleep refusés pendant l'attente
- réveil lu par le plugin : résultat et conduite selon fin, gain compté à ce moment
- lecture entière d'une sortie au verdict valide refusée, sauf chemins sensibles (réglage chemins_sensibles)
- compteurs d'attentes, d'essais et d'échecs de contrôle dans /miam-economies
- skill deleguer : controle, attendus, reprise et tableau des fin ; README et cahier à jour

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 09:37:11 +01:00

27 KiB

Forcer la délégation par les hooks

État au 2026-11-02, base de travail du plugin. But : que Claude pilote et que MIAM, l'API ou Haiku écrivent. Claude découpe, confie, contrôle par des machines, et n'écrit lui-même que ce qui ne peut pas être confié.

1. Constat

MIAM (v2.5.2-dev, phase 2) sait déjà router : modèle local (27B, 15,5 Go, un seul à la fois), API OpenRouter (plafond 2 /jour, ~0,0135 dépensés le 2026-11-02), OpenCode, et Haiku côté Claude. moteur="auto" choisit entre local et API. Les moyens existent ; c'est Claude qui ne les utilise pas spontanément.

Journal : 185 délégations (165 ok, 10 refusées, 3 erreurs, 3 annulées, 4 rejetées), dont 9 API et 5 OpenCode. Par jour : 103 (30/10), 52, 19, 12 (02/11, journée en cours). La baisse n'est pas rapportée au volume de travail : elle alerte, elle ne prouve rien.

Session du 2026-11-02, tâche PH2-D1 : seule la lecture imposée par le hook de démarrage a été déléguée. 8 tests répétitifs écrits à la main alors que leur modèle était dans le fichier. Les délégations suivantes ont toutes suivi un rappel de l'utilisateur.

Pourquoi les hooks actuels n'ont pas suffi

Mécanisme actuel Ce qui a échappé
Refus de Read si fichier ≥ 20 000 caractères sans limit ≤ 400 Contourné légalement : plusieurs plages de 75 à 240 lignes sur instances.py, allow_large sur des lignes géantes de tasks-P2.md
Retenue des sorties shell ≥ 20 000 caractères Ne voit que la taille d'un appel, pas le cumul
Rappel texte (1 toutes les 10 min), consigne prompt.compose, mémoire Coût nul pour Claude au moment de décider : ignorés
Edit, Write, NotebookEdit Aucun contrôle : seule la comptabilité des corrections
Suivi « ce tour a délégué » Non présent pour l'agent principal
Hooks de fin de tour et de soumission Non présents

Conclusion : une consigne perd face à la facilité. Il faut qu'écrire soi-même soit plus lent que déléguer, à l'instant où l'écriture est tentée.

Frictions côté délégation

  • deleguer sans moteur échoue si aucun modèle n'est chargé ; il faut penser à moteur="auto".
  • Le bench occupe le GPU ; auto local peut le préempter (corrigé pour les refus, 093f110, pas pour le reste).
  • plugin-claude-miam n'est pas autorisé pour l'API, et la config affiche projets: null pour OpenRouter (à éclaircir).
  • Un fichier hors projet (scratchpad) fait échouer le routage API.
  • Rien n'oriente vers Haiku quand local et API sont indisponibles.
  • Pas de contrôle automatique du résultat : Claude relit tout, ce qui annule une partie du gain.

2. Principes

  1. Refuser, pas rappeler. Un deny au moment de l'écriture, avec l'appel prêt à copier dans le message.
  2. Budget cumulé, pas seuil par appel. Compter lignes écrites et caractères lus par tour et par fichier.
  3. Découper avant d'écrire. Pas de code sans liste de bouts.
  4. La machine juge, Claude arbitre. Tests, ruff et contrat décident ; Claude ne lit qu'en cas d'échec.
  5. Une sortie de secours chère et visible. Exception motivée, journalisée, affichée.
  6. Ne jamais bloquer le travail. Si aucun exécutant ne répond, la règle s'ouvre et le signale.

3. Pistes de hooks

Seuils proposés, à régler sur les mesures.

# Hook Déclencheur Action Priorité
1 Portillon tests Write/Edit de l'agent principal sur tests/**, *.test.* ajoutant > 10 lignes deny + appel deleguer prêt P0
2 Budget d'écriture Cumul > 30 lignes de code ajoutées par l'agent principal depuis la dernière délégation réussie deny jusqu'à une délégation ou une exception P0
3 Portillon commit git commit sans message issu de deleguer dans le tour deny P0
4 Écritures par shell Bash/PowerShell avec Set-Content, Out-File, >, sed -i, Python écrivant un fichier Comptés comme le hook 2 ; sinon le contournement est immédiat P0
5 Budget de lecture Cumul par tour > 40 000 caractères, ou > 400 lignes par fichier, allow_large et Grep compris deny + « confie la question » P1
6 Portillon découpage Premier Edit/Write de code d'un tour sans plan deny : écrire .claude/miam-plan.json (section 4) P1
7 Sélecteur d'exécutant Tout deny ci-dessus Message calculé : local si prêt et sans bench ; API si projet autorisé ; sinon subagent Haiku P1
8 Bilan de fin de tour Fin de tour de l'agent principal Injecte lignes écrites par Claude et par délégation ; bloque la fin si un bout du plan reste « délégable » non traité P2
9 Compteur visible Ligne d'état délégué 82 % · exceptions 1 pour le tour et la session P2
10 Docs et docstrings *.md hors plan/, docstrings ajoutées en lot Comme le hook 1 P2
11 Attente unique deleguer en file (ok: null avec reprise) ; commande /attendre lancée sans run_in_background Injecte « lance reprise en arrière-plan » ; deny sur l'appel au premier plan P0
12 Pas de suivi pendant l'attente suivre sur une demande attendue, sleep ou boucle d'attente en Bash deny : « tu seras réveillé à la fin » ; permis si fin vaut besoin_claude P0
13 Confiance au verdict Read complet du fichier sortie après fin: "valide" deny hors chemins sensibles : aperçu ou offset/limit P1

Hors comptage : fichiers écrits par MIAM (déjà mesurés en corrections), plan/** et journal de suivi, modifications ≤ 3 lignes, subagents (agentId défini), config locale.

Exception : outil exception(raison, fichiers, lignes) avec motifs fermés (concurrence, securite, debogage-multi-fichiers, secret). Elle ouvre un budget limité aux fichiers cités, est journalisée et apparaît dans le bilan. Pour la concurrence, liste de chemins sensibles à définir plutôt qu'un jugement de Claude.

Repli : si aucun des trois exécutants ne répond, règle ouverte pour le tour et toast. Réutiliser joignable.

Options : garder imposer et incitation, ajouter budget_ecriture, budget_lecture, chemins_sensibles.

À vérifier avant de coder

  • Existence d'un événement de fin de tour de l'agent principal capable de relancer Claude (turn.complete n'est utilisé que pour les subagents).
  • Capacité de tool.call à lire le contenu de Write/Edit avant exécution pour compter les lignes.
  • Possibilité de déclarer exception : outil MCP côté MIAM, ou fichier lu par le hook.

4. Découper en bouts atomiques

Plan attendu par le hook 6 :

{ "tache": "PH2-D1", "bouts": [
  { "id": 1, "quoi": "tests start_all", "fichier": "tests/x.py", "moteur": "auto", "modele": "tests/x.py:613-637",
    "contrat": "4 instances, ordre d, b, c, erreurs par nom", "controle": "pytest -k start_all" },
  { "id": 2, "quoi": "ordre des réservations dans start_instance", "moteur": "claude", "motif": "concurrence" }
] }

Un bout délégable : une fonction ou un groupe de tests, un fichier de sortie, ≤ 80 lignes, signature donnée, exemple à imiter en plage de lignes, contrôle exécutable. Consigne en anglais, langue de sortie précisée. Modules joints, car le 27B invente champs et valeurs.

Relecture de D1 avec ce découpage :

Bout Exécutant possible
Choix du port réservé, messages d'erreur, start_all, stop_all à partir de leur contrat Délégable, contrôlé par tests
8 tests, tests du view model Délégable, modèles présents
Boutons du dashboard, branchement du tray Délégable, patron existant
Lignes de suivi, message de commit Délégable
Absence d'await entre contrôle et réservation dans start_instance Claude (concurrence)
Inventaire des fichiers à modifier Délégable ; Claude lit le résultat

Claude n'aurait gardé que le découpage, le point de concurrence et l'intégration.

5. Faire confiance aux retours

Contrôle par niveaux, du moins cher au plus cher :

  1. Automatique : format="code", sortie=, retour="apercu" ; pytest, ruff, ruff format --check.
  2. Test rouge d'abord : le test échoue sans le code, passe avec.
  3. Taille du diff : conforme au bout annoncé.
  4. Lecture par Claude : seulement si un contrôle échoue, ou en zone sensible.

En cas d'échec, renvoyer la sortie du test à l'exécutant (2 essais) avant toute reprise par Claude.

Pièges connus du 27B à garder en contrôle : docstrings omises, valeurs inventées ; ajouter docstrings et champs aux contrôles plutôt qu'à la relecture.

Risque accepté : des erreurs passeront les tests. La parade est de meilleurs contrats, avec la revue par Claude réservée aux zones sensibles et au diff final.

5 bis. Contrôle automatique des réponses par MIAM

Livré dans MIAM (PH2-H11), sauf commande et perimetre ; contrat exact en section 11. But : Claude reçoit un verdict plutôt que le code ; MIAM juge, retente, escalade.

Contrat de la demande : nouveau paramètre optionnel controle sur deleguer.

contrôle s'applique à ce qu'il vérifie
format tous JSON valide, schéma si fourni ; Python via ast.parse, TypeScript via transpile uniquement
complet tous non vide, non tronqué, symboles demandés présents (fonctions, nombre de tests)
symboles code chaque identifiant importé ou appelé existe dans les modules joints, pour attraper les champs inventés (faiblesse connue du 27B)
docstrings code fonctions publiques documentées (faiblesse connue du 27B)
lint code ruff check et ruff format --check, ou l'équivalent du projet
commande code commande de test lancée dans un clone à l'intérieur du bac à sable AppContainer existant, sans réseau, commandes limitées à celles déclarées par projet
perimetre code seuls les fichiers déclarés changent
citations extraction, résumé toute valeur, nombre ou identifiant cité doit se retrouver dans les fichiers source
traduction traduction placeholders, code et nombres conservés, ratio de longueur plausible

Défauts par type : format + complet toujours ; code ajoute symboles, docstrings, lint ; extraction ajoute citations ; commande seulement si fourni.

Boucle : en cas d'échec, MIAM renvoie l'échec exact au modèle, 2 tentatives maximum, puis escalade local → API → rend la main à Claude avec statut echec_controle, sans accepter silencieusement.

Réponse à Claude : champs verdict (valide, echec_controle, non_controle), controles (nom, résultat, message court), essais, moteur_final, sortie (chemin de fichier), stats de diff ; pas de corps de code quand valide et retour="apercu".

Application : rien n'est écrit dans l'arbre de travail avant que tous les contrôles passent ; le résultat reste dans le clone ou un fichier temporaire ; puis écrit comme sortie déclarée.

Sécurité : la sortie du modèle est non fiable ; elle n'est jamais exécutée hors du bac à sable ; seules les commandes déclarées ; aucun secret dans le clone.

Mesure : le journal reçoit controles, essais, verdict ; echec_controle ne compte aucun gain ; le taux de réussite au premier essai par modèle alimente le choix de modèle (type/seuil) et le taux de réparation ; le temps passé dans les contrôles est suivi.

Limites : des tests écrits par le même modèle peuvent valider un comportement faux : exiger d'abord un test rouge (le test doit échouer sans le code) ou un test écrit séparément ; citations prouve la présence, pas le sens correct ; commande coûte du temps ; passer les contrôles ne remplace pas la revue de Claude sur les zones sensibles (concurrence, sécurité).

Découpage en bouts :

  1. Contrôles purs (format, complet, symboles, docstrings, citations, traduction) avec leurs tests.
  2. Contrôles outillés (lint, perimetre) avec leurs tests.
  3. Boucle de retentative et escalade local → API → echec_controle.
  4. Contrôle commande dans le bac à sable, sur clone, sans réseau.
  5. Champs de réponse (verdict, controles, essais, moteur_final, sortie, stats de diff) et écriture différée.
  6. Journal (controles, essais, verdict, temps) et plugin (le hook lit verdict et saute la lecture quand valide).

Reprise de la main sans suivi répété

Livré dans MIAM (PH2-H11), sauf le chien de garde. miam-attendre est devenu la commande curl donnée dans reprise : aucun exécutable à installer. Contrat exact en section 11.

Problème : suivre plafonne chaque attente à call_wait_s (45 s), donc une tâche longue fait revenir Claude toutes les 45 s, et chaque retour coûte des tokens.

Principe : le temps n'est pas une limite, le seul coût est les tours de Claude. MIAM exécute contrôles, corrections et escalade seul. Claude est réveillé une fois, à un état terminal.

Attente unique : Claude lance une fois, en arrière-plan via Bash avec run_in_background, une petite commande miam-attendre <demande_id>. Elle bloque sur une route HTTP locale authentifiée de MIAM (long polling), imprime une ligne JSON, sort. Claude Code réveille Claude quand une commande d'arrière-plan se termine : aucun token pendant l'attente. Claude termine son tour ou continue autre chose.

États terminaux :

état sens ce que fait Claude
valide tous les contrôles passés, fichier écrit intègre, sans lecture
echec_controle tentatives et escalade épuisées ; le rapport donne le dernier échec reprend la main ou re-découpe
besoin_claude décision réservée à Claude : permission, plafond de dépense API atteint, instruction ambiguë répond puis attend à nouveau
annule demande annulée rien
perdue MIAM redémarré ou injoignable renvoie ou fait lui-même

Pas de limite de durée, mais pas d'attente sans fin : pas de timeout total. Un chien de garde détecte l'absence de progrès : aucun token généré, aucun contrôle terminé et aucun changement de tentative pendant mcp.sans_progres_s (proposé 600 s) donne besoin_claude avec l'étape bloquée. Les tentatives sont bornées (2 par moteur, puis escalade), donc la boucle se termine toujours. miam-attendre sort en perdue après plusieurs échecs de contact avec MIAM.

Hook du plugin : tant que miam-attendre tourne pour une demande, suivre sur cette demande est refusé avec le message « tu seras réveillé à la fin » ; idem pour les boucles de sleep en Bash. Le hook part du demande_id renvoyé en « en_file ».

Réponse de deleguer : si non terminé dans call_wait_s, la réponse donne demande_id, etat et reprise : la commande exacte à lancer.

Autres clients : un client sans commandes d'arrière-plan (OpenCode) garde suivre, avec un attente_s long unique, plus plafonné à 45 s, dans la limite du timeout du client MCP, à vérifier.

Coût attendu : un lancement et un réveil par délégation, indépendamment de la durée.

Bouts :

  1. États terminaux et chien de garde en logique pure, avec tests.
  2. Route de long polling authentifiée.
  3. Commande miam-attendre, avec tests.
  4. Champ reprise dans deleguer.
  5. Hook du plugin refusant suivre.

6. Évolutions côté MIAM

Évolution Effet
moteur="auto" par défaut, repli explicite si tout est indisponible Supprime l'erreur « aucun modèle chargé »
routage qui peut répondre « subagent Haiku » Échelle complète local → API → Haiku
Délégation courte pendant un bench : API plutôt que préemption Ne coupe plus les tests
Projet du plugin autorisé pour l'API ; clarifier projets: null Lève le refus rencontré
deleguer(..., controle="pytest -k x", essais=2) : exécute et renvoie l'échec au modèle Niveau 1 sans Claude, détail en 5 bis
lot=[...] : plusieurs bouts en un appel Moins de tours de pilotage
Écriture directe dans le dépôt avec diff court en retour Claude ne reçoit pas le code

7. Limites

  • Un hook contrôle des appels, pas le raisonnement : Claude peut toujours rédiger puis découper artificiellement.
  • Chaque délégation coûte une consigne et un suivi : sous ~10 lignes, écrire peut être moins cher, d'où les seuils.
  • Des seuils trop stricts multiplieront les exceptions : les suivre dès le début.
  • Le hook 6 ajoute un tour au départ de chaque tâche ; il doit rester sans objet pour une correction minime.

8. Ordre de travail

Chaque lot est découpé en bouts confiés à MIAM : le plugin sert de premier terrain d'essai.

  1. Lot 1 (P0) : compteurs par tour, hooks 1, 2, 3, 4, exception, repli. Vérifier d'abord les points de la section 3.
  2. Lot 2 (MIAM) : auto par défaut, API pendant le bench, projet du plugin.
  3. Lot 3 (P1) : budget de lecture, plan, sélecteur d'exécutant.
  4. Lot 4 : controle=, lot=, écriture directe.
  5. Lot 5 (P2) : bilan, compteur, documentation.

Mesures par session : part des lignes écrites par délégation, net de tokens, taux de reprise, nombre d'exceptions par motif, refus jugés à tort. Objectif proposé après le lot 1 : ≥ 70 % des lignes hors zones sensibles.

9. Décisions attendues

  • Seuils de départ : 10 lignes pour les tests, 30 pour le code, ou plus strict.
  • Mode : refus immédiat, ou une semaine en mesure seule pour régler les seuils (recommandé : refus immédiat sur les tests et le commit, mesure sur le reste).
  • Liste des chemins sensibles exemptés.
  • Part acceptable de Haiku dans l'échelle, à comparer au coût de l'API.

10. Version cible : plugin v0.9.0

But : une version dont les gains de tokens sont réels et mesurés, parce que Claude délègue par défaut.

Valeurs retenues par défaut (issues de la section 9, modifiables) : 10 lignes pour les tests, 30 lignes pour le code, refus immédiat sur tous les hooks P0, budget de lecture de 40 000 caractères par tour et 400 lignes par fichier ; chemins sensibles : src/miam/services/mcp.py, src/miam/services/instances.py, src/miam/core/aio.py plus tout ce qui correspond à *sandbox*, liste à confirmer.

Périmètre plugin (checklist) : compteurs de tour (lignes écrites par l'agent principal, caractères lus, dernière délégation réussie) ; hooks 1, 2, 3, 4 (section 3) ; hook 5 budget de lecture ; hook 6 plan de découpage ; hook 7 sélecteur d'exécutant ; exception avec raisons fermées ; repli quand aucun exécutant ne répond ; refus de suivre pendant miam-attendre ; rapport de fin de tour et compteur visible (hooks 8, 9) ; skill deleguer mis à jour pour enseigner le découpage, moteur="auto" et reprise.

Prérequis MIAM (PH2-H11, même livraison) : moteur="auto" par défaut ; API au lieu de la préemption pendant un benchmark ; projet plugin autorisé pour l'API ; controle avec contrôles purs et lint ; boucle de correction et escalade ; états terminaux, miam-attendre, reprise, chien de garde mcp.sans_progres_s ; verdict. lot=, écritures directes et commande en sandbox peuvent suivre plus tard sans bloquer la v0.9.0.

Vérifications préalables (bloquantes) : les trois points de « À vérifier avant de coder » en section 3 ; durée maximale de blocage tolérée par un client MCP. Fait le 03/11/2026 : une commande en arrière-plan de 11 min réveille bien Claude à sa sortie, sans token pendant l'attente.

Critères d'acceptation (checklist, chacun testable) : une édition de test de l'agent principal de plus de 10 lignes est refusée avec un appel prêt ; une écriture via le shell est comptée ; un git commit sans message délégué est refusé ; une tâche découpée en plusieurs morceaux lisant le même fichier dépasse le budget de lecture et est refusée ; tous les exécutants étant indisponibles, le travail continue et un toast le signale ; une délégation longue coûte un lancement et un réveil, sans appel à suivre ; un echec_controle rend la main avec le dernier échec ; les résultats valide sont intégrés sans que Claude lise le corps du code ; les exceptions apparaissent dans le rapport ; les sous-agents ne sont pas soumis aux budgets ; tous les tests du plugin passent.

Mesure du gain : gain réel = tokens Claude effectivement consommés, lus depuis session.usage, pas les evites estimés. Protocole : rejouer des tâches comparables (une fonction pure avec tests, une tâche UI multi-fichiers, une extraction de document) sur v0.8.0 et v0.9.0, mêmes prompts ; enregistrer tokens Claude totaux, coût cloud, durée, corrections, exceptions, actions refusées à tort, bugs trouvés ensuite. Comparer aussi net (evites - pilotage - corrections) à la différence mesurée pour calibrer l'estimation. Version valide seulement si les tokens Claude mesurés baissent sans hausse des bugs post-merge ; la cible est fixée après la première comparaison, aucun chiffre décidé maintenant.

Ordre des bouts :

  1. vérifications ;
  2. compteurs avec tests ;
  3. hooks P0 et exception ;
  4. prérequis MIAM ;
  5. budget de lecture, plan, sélecteur ;
  6. rapport de fin de tour et compteur ;
  7. skill et docs ;
  8. mesure puis release v0.9.0.

Chaque bout suit la section 4 et est délégué.

11. Contrat livré par MIAM (PH2-H11) et travail restant côté plugin

État au 03/11/2026, code de MIAM non commité, tests verts. Le MIAM installé doit être reconstruit pour l'exposer.

Ce que MIAM accepte

deleguer(..., controle=[...], attendus=[...]) :

  • controle : liste parmi syntaxe, complet, symboles, docstrings, citations, traduction, lint. [] désactive les contrôles.
  • Par défaut : format="code" avec une sortie en .py donne syntaxe, complet, symboles, docstrings, lint ; tout le reste donne complet.
  • attendus : noms qui doivent figurer dans la réponse (fonctions, classes), vérifiés par complet.
  • lint : ruff check --select F,E9 seulement (vraies erreurs, pas le style) ; ignoré si ruff est introuvable (cas de l'exe).
  • symboles et citations comparent la réponse aux fichiers joints : joindre les modules utilisés.
  • Tentatives : mcp.controle_essais (2) par moteur ; une demande locale passe ensuite à l'API.

Écarts avec la section 5 bis : format s'appelle syntaxe (Python seulement) ; commande et perimetre ne sont pas faits ; il n'y a ni moteur_final ni statistiques de diff.

Ce que MIAM renvoie

cas réponse fin (route /attendre)
terminé, contrôles passés ok: true, verdict: "valide", controles: [{nom, ok, message?}], essais, sortie si demandée valide
terminé sans contrôle ok: true, verdict: "non_controle" termine
contrôles échoués partout ok: false, erreur: "echec_controle : nom : message ; …" echec_controle
annulé ok: false, etat: "annulee" annule
demande inconnue (MIAM redémarré) ok: false, sans etat perdue
permission OpenCode, autre cas en attente ok: null besoin_claude
pas fini dans call_wait_s (45 s) ok: null, demande_id, etat, reprise, message (sans objet)

sortie n'est écrite qu'après le verdict valide. Les tentatives rejetées sont journalisées dans delegations.jsonl avec statut: "rejete", sans gain.

Attente unique

reprise vaut exactement :

curl -s -H @"<logs>/mcp/attente.hdr" "http://127.0.0.1:<port>/attendre?demande_id=<id>"
  • attente.hdr contient l'en-tête Authorization, écrit par MIAM au démarrage du serveur MCP : aucun jeton dans la commande ni dans la conversation.
  • GET /attendre répond une seule fois, à l'état final : la même réponse que suivre, plus fin. Chaque attente interne dure au plus ATTENTE_ROUTE_S (3600 s) et reprend en boucle tant que la demande n'est pas finie.
  • À lancer avec Bash et run_in_background: true (Git Bash sous Windows : la commande est en syntaxe POSIX). Vérifié le 03/11/2026 sur le vrai serveur HTTP.

Encore manquant côté MIAM

  • Chien de garde mcp.sans_progres_s : pas encore fait, car le modèle répond sans flux et rien ne mesure l'avancement. La seule limite reste timeout_execution_s, multiplié par le nombre de tentatives. Une très longue tâche peut donc finir en expiration (ok: false, fin: "besoin_claude" ou perdue).
  • Contrôles commande (tests en bac à sable) et perimetre.
  • moteur="auto" par défaut ; API au lieu de la préemption pendant un benchmark.

À coder dans le plugin (v0.9.0), par bouts

Fait le 03/11/2026 (bouts 1 à 7, hooks/attente.ts et register.tsx, tests sur réponses figées), avec deux écarts : le réveil est lu par un hook prompt.submit, qui reconnaît la notification à l'id de la commande d'arrière-plan relevé au lancement et lit lui-même la sortie (une ligne JSON) ; PowerShell est refusé pour reprise, en syntaxe POSIX. Pas encore essayé sur le vrai serveur.

  1. Hook PostToolUse sur deleguer : si ok est null et qu'il y a une reprise, ajouter au contexte « lance reprise une fois avec run_in_background, puis termine ton tour ou fais autre chose », et noter demande_id comme en attente dans l'état du tour.
  2. Hook PreToolUse sur Bash : reconnaître une commande qui contient /attendre?demande_id= ; sans run_in_background, la refuser (« lance-la en arrière-plan ») ; avec, passer la demande à « attendue ».
  3. Hook PreToolUse sur suivre : refuser si la demande est « attendue », avec « tu seras réveillé à la fin ». Refuser aussi les sleep et les boucles d'attente en Bash pendant une attente. Laisser passer suivre si fin vaut besoin_claude (permission à donner).
  4. Hook sur la sortie de la commande d'arrière-plan (ou PostToolUse sur la notification) : lire fin et injecter la conduite :
    • valide : intégrer sans relire le corps, ne pas Read la sortie en entier ;
    • termine : relire ;
    • echec_controle : reprendre la main ou redécouper, avec le dernier motif ;
    • besoin_claude : répondre (autoriser), puis relancer reprise ;
    • annule : rien ;
    • perdue : renvoyer la demande ou faire soi-même.
  5. Hook PreToolUse sur Read : après valide, refuser une lecture complète du fichier sortie (aperçu ou offset/limit seulement), sauf chemin sensible.
  6. Skill deleguer : enseigner controle et attendus, joindre les modules pour symboles, lancer reprise en arrière-plan, et le tableau fin ci-dessus.
  7. Compteurs : essais, nombre de echec_controle et attentes uniques par session, pour la mesure de la section 10.

Tests de chaque hook sur des réponses figées tirées du tableau ci-dessus ; les autres hooks (sections 3 et 10) suivent l'ordre de la section 10.