Autopilot
Une boucle autonome portable car elle demande au travail ce que « fait » signifie plutôt que de le supposer — et ne s'arrête pas tant que cette réponse n'est pas satisfaite.
Trois affirmations que cette compétence existe pour rendre impossibles :
- « Ça marche » alors que rien ne l'a exécuté.
- « C'est fait » alors que le seul juge était celui qui l'a fait.
- « J'ai travaillé dessus » sans aucun enregistrement de ce qui a été essayé, de ce qui a échoué et pourquoi.
Le sujet importe peu. Un refactor, une migration, un rapport, un jeu de données, une ferme de rendu, un cluster : la boucle ci-dessous est identique et seul le contrôle diffère.
0. Amorçage — une fois par projet
<skill> ci-dessous est le répertoire où se trouve ce fichier — .agents/skills/autopilot
après une installation en CLI, ou là où il a été cloné. Exécutez tout depuis la racine du PROJET.
node <skill>/scripts/discover.mjs # contrôles, foyers mémoire, signaux de danger
node <skill>/scripts/bootstrap.mjs # crée le registre s'il est absent
node <skill>/scripts/skills.mjs # la bibliothèque de compétences — choisissez les niches de ce projet
node <skill>/scripts/tools.mjs # ce que cette machine peut déjà ATTEINDRE : serveurs MCP, plugins
discover affiche la propre commande de contrôle du projet. Cette commande est la
définition de « fait » pour chaque itération ci-dessous.
Si elle affiche checks: [], ne le croyez pas encore. La découverte ne lit que les fichiers
qui déclarent un contrôle ; le véritable contrôle d'un projet est souvent nommé en prose.
Recherchez dans chaque chemin listé dans memoryHomes, ainsi que dans le README et la config CI,
une commande exécutable — un projet avec checks: [] côtoyait un CLAUDE.md nommant
./tests/run_all.sh, qui exécutait 63 tests en quatre secondes, tandis que le contrôle qu'un
agent aurait inventé (node --check) était vert sur une application morte.
Ce n'est que lorsque cette recherche revient vide que le projet n'a véritablement aucun contrôle automatique — courant pour la prose, la recherche et l'ops, et pas une permission de juger votre propre travail. Convenez d'un contrôle d'acceptation avant la première itération et inscrivez-le dans l'objectif (§1). N'importe lequel de ceux-ci est un contrôle ; « Je l'ai révisé et ça a l'air correct » n'en est pas :
| Le travail | Un contrôle qui n'est pas votre propre opinion |
|---|---|
| code | une commande qui se termine par 0, exécutée au premier plan |
| un document | une liste affirmation par affirmation avec une source ou une commande par affirmation |
| données | une requête que quelqu'un d'autre peut relancer et qui renvoie la forme attendue |
| infra / ops | une observation du système lui-même, avant et après |
| recherche | la requête ou l'extraction qui produit le nombre, plus le résultat que vous avez ENREGISTRÉ À L'AVANCE comme le réfutant — les deux ré-exécutables par quelqu'un d'autre |
Lisez ce que la découverte a trouvé avant de toucher à quoi que ce soit :
memoryHomes— où réside déjà la connaissance durable. Utilisez ces fichiers. Ne créez jamais un deuxièmeCHANGELOG.md, un deuxième répertoire d'apprentissages, un deuxièmeAGENTS.md. Un deuxième foyer pour un type de connaissance est la manière la plus courante pour un agent de rendre un dépôt pire.signals.envFilesPresentetsignals.remote— avant la première itération, demandez si l'environnement de travail pointe vers la production. Cela a été le cas, sur des projets où rien dans le dépôt ne le disait et où chaque exécution locale semblait inoffensive. Supposez oui jusqu'à preuve du contraire.signals.vcs—nonesignifie qu'aucune annulation n'existe. Copiez les entrées quelque part en sécurité avant l'itération un, et dites où dansgoal.md; le §8 « valider ce qui est vert » n'a aucun sens ici et c'est exactement à ce moment que le travail est perdu.signals.dirty— le travail non validé est celui de quelqu'un. Créez une branche, ne construisez jamais par-dessus.
Armez-vous avant l'itération un
skills.mjs est la liste restreinte des compétences publiques qui valent la peine, étiquetées par niche.
Les étiquettes sont le vocabulaire — any et review sur chaque projet, puis web,
react, db, docs, perf, a11y, mac, infra, research, design selon
les besoins réels du projet.
node <skill>/scripts/skills.mjs # le catalogue et ses étiquettes
node <skill>/scripts/skills.mjs --install any --dry-run # ce qu'il EXÉCUTERAIT
node <skill>/scripts/skills.mjs --install any # l'ensemble toujours utile
node <skill>/scripts/skills.mjs --install react,perf,db # les niches de ce projet
Choisissez, n'accumulez pas. Chaque description de compétence installée est chargée à chaque tour : cent compétences n'est pas cent capacités, c'est une fenêtre plus petite et un modèle qui survole.
Installer, c'est exécuter du code tiers avec vos permissions, c'est donc un
acte annoncé : --dry-run d'abord, dites ce que vous êtes sur le point d'ajouter et pourquoi, puis
installez. Si le projet ne correspond à aucune niche du catalogue, any seul est la
bonne réponse — et find-skills est le point d'entrée pour une niche sur laquelle le catalogue
est léger (recherche, infra, données sont légères aujourd'hui).
Ensuite, mesurez ce que vous venez de dépenser. skill-cleaner vient avec l'ensemble any
et c'est ainsi que « choisissez, n'accumulez pas » cesse d'être un conseil :
node --experimental-strip-types <skills-root>/skill-cleaner/scripts/skill-cleaner.ts \
--root .agents/skills --root-only --no-logs
Il signale le budget qu'occupent les descriptions installées, les doublons (deux compétences répondant à une seule question — le défaut que cette boucle traque, un niveau au-dessus), et les longues descriptions qui méritent d'être compressées. Agissez en conséquence : désinstallez ce que ce projet n'utilise pas, et fusionnez un doublon plutôt que de garder les deux. Un audit que vous lisez et ignorez coûte le même contexte qu'aucun audit.
Les compétences ne sont que la moitié — l'autre moitié est la portée
skills.mjs dit ce que l'agent SAIT. tools.mjs dit ce qu'il peut TOUCHER : les
serveurs MCP qu'il trouve dans les fichiers de configuration qu'il sait lire, les plugins
qui en apportent plus, et ce qu'aucun fichier sur le disque ne peut vous dire. Un résultat vide signifie
« pas dans ces fichiers », jamais « pas sur cette machine ».
node <skill>/scripts/tools.mjs
Une capacité que vous n'avez pas n'est pas une raison pour réduire l'objectif. C'est une échelle
— déjà accessible → la propre CLI de l'application → un serveur public → un connecteur (garagez-le,
§6) → écrivez-en un avec new-mcp.mjs. Les barreaux, ce que chacun coûte et les pièges
dans chacun d'eux sont dans references/tooling.md ; lisez-le avant de construire quoi que ce soit,
car les deux échecs qu'il prévient sont invisibles d'ici : décider qu'une capacité manque alors qu'elle est
déjà configurée, et construire une deuxième réponse à une question à laquelle quelque chose répond déjà.
Celui qui va mordre : la plupart des harnais lisent leur configuration MCP au DÉMARRAGE, donc
un serveur écrit en cours d'exécution est généralement invisible pour la session qui l'a écrit. C'est pourquoi
l'échafaudage est aussi une CLI — node server.mjs --call <tool> '<json>',
les mêmes gestionnaires. Utilisez cette forme maintenant et laissez la session suivante récupérer le serveur.
« Continuer après un redémarrage » est une boucle bloquée qui tient un fichier.
Ensuite, tout au long : ce que vous apprenez ici devient une compétence en soi (§5), écrite par la boucle et utilisée dans la même session — et une capacité qui manquait devient un outil en soi, utilisé de la même manière.
1. L'objectif — la chose sur laquelle la boucle tourne jusqu'à
Avant l'itération un, écrivez une phrase falsifiable et 2 à 5 critères de complétion. Dans
goal.md, ou partout où la découverte a trouvé que cela résidait déjà.
- Falsifiable : « améliorer X » ne l'est pas. « Chaque chemin qui dépense de l'argent est derrière un robinet explicite, et chacun est détenu par un type ou un test qui échoue » peut l'être.
- Chaque critère doit pouvoir être vérifié par quelqu'un qui n'est pas vous — la même barre que le §0. Un critère que vous seul pouvez confirmer n'est pas un critère ; réécrivez-le.
- Les inconnues sont autorisées, en tant que critères à part entière : « nous savons si N en est la cause » est un critère de complétion légitime pour la recherche.
- Un grand objectif est atteint par de petits, et les critères SONT cette décomposition — chacun une tranche qui peut être livrée, vérifiée et validée de manière autonome. Un critère trop grand pour une itération est divisé en ses propres critères ; la profondeur est acceptable, et chaque niveau conserve la même barre (vérifiable par quelqu'un qui n'est pas vous). Un niveau qui cesse d'être falsifiable est un plan, pas un critère.
- Une capacité que vous n'avez pas est un critère, pas un détour. « La boucle peut piloter X
sans tête, prouvé par un aller-retour » va dans le tableau à côté du travail qu'il
débloque (
references/tooling.md). Écrite, la construction d'un outil est limitée et son absence est visible ; non écrite, elle devient un après-midi qui n'a produit aucun critère et se lit comme un progrès. - Si personne ne vous a donné d'objectif — « continue » et rien d'autre — la première
itération produit UNIQUEMENT un
goal.mdproposé et la question pour l'humain. Un critère que vous avez rédigé puis satisfait est l'affirmation #2 ci-dessus, portant une liste de contrôle. goal.mdporte également l'état FIXE : la commande de contrôle, sa sortie de référence, la réponse à la question de production, la branche (ou l'endroit où se trouve la copie des entrées), et les compétences installées. Une reprise qui doit re-dériver tout cela n'a pas repris.
La boucle tourne ensuite jusqu'à ce que chaque critère soit satisfait ET vérifié. Pas jusqu'à ce que le modèle se sente fini,
pas jusqu'à ce que les critiques se taisent — ils ne le font jamais. Chaque itération se termine en
marquant dans goal.md quel critère a bougé et ce qui le prouve.
N'arrêtez la boucle tôt que pour les raisons des §6 (demander), §7 (piétiner) et §8 (contexte).
2. L'itération
Une itération = un changement livré, contrôlé, vérifié, enregistré. Pas un fichier, pas un tour.
Choisissez. Parmi les critères non satisfaits de l'objectif. Si plusieurs sont ouverts, prenez celui dont l'échec invaliderait le plus de travail — ordonnez par risque×portée, pas par ce qui est facile.
Comprenez avant de raccourcir. Tracez la vraie chose de bout en bout. Ensuite, avant de
construire quoi que ce soit de nouveau, demandez si cela existe déjà — voir
references/premise-check.md, l'habitude au rendement le plus élevé dans cette compétence et
celle qui a mis le plus de temps à être apprise.
Construisez la plus petite chose qui soit réellement correcte. Cause racine, pas le symptôme que la demande nomme : trouvez d'abord tous les autres endroits avec la même forme, et corrigez là où ils passent tous.
Prouvez. Exécutez le contrôle découvert, au premier plan, en lisant le code de sortie dans le shell qui l'a exécuté — ou, mieux, laissez quelque chose qui n'écrit pas le résumé le lire pour vous :
node <skill>/scripts/prove.mjs --record -- npm run verify # le contrôle, son vrai statut, dans goal.md
node <skill>/scripts/prove.mjs --times 3 -- <check> # un contrôle qui n'est pas d'accord avec lui-même est instable
Prouver et Vérifier sont les deux étapes qu'un modèle peut NARRER — les autres laissent un
fichier, un commit ou un diff, tandis que « le contrôle a réussi » et « le relecteur a accepté »
étaient tous deux du texte écrit par le contexte qui voulait qu'ils soient vrais. L'exécuteur de preuve
répond au premier : il engendre sans shell, donc le statut qu'il rapporte est celui de
l'enfant lui-même ; il refuse un contrôle dont le propre script npm contient un pipe
("verify": "tsc | tail" a rapporté le statut de tail, qui est la forme qui a livré six
déploiements rouges lus comme verts) ; il rapporte 250 lorsque la boucle a été
arrêtée, 251 lorsque le même contrôle renvoie deux statuts différents, et avec
--record écrit le nombre que l'exécution a produit — y compris un échec —
dans goal.md.
Ce qu'il ne peut pas voir : un pipe à l'intérieur d'un script shell, une cible Makefile ou un binaire que votre contrôle invoque. Il supprime le mensonge qu'il peut prouver ; il ne certifie pas votre contrôle. §3 est ce qui répond pour Vérifier — enregistrez le verdict et ses preuves dans le registre, ou cette étape est aussi de la narration.
Exécutez-le UNE FOIS AVANT la première itération aussi et collez
cela dans goal.md : un échec qui vous a précédé est une décision à enregistrer, pas votre
itération en faute, et sans la référence, vous adopterez soit le rouge de quelqu'un d'autre
soit vous compterez son vert comme un progrès. Un contrôle qui a jamais été en désaccord avec
lui-même est instable — relancez-le trois fois avant qu'un critère soit marqué comme satisfait. Trois
façons dont un contrôle ment, toutes observées :
| `check | tail` |
check > log; echo "EXIT=$?" | ; fait que le statut est celui de la DERNIÈRE commande — toujours 0 |
| un wrapper en arrière-plan | la notification de complétion rapporte le wrapper |
Lorsqu'il n'y a pas de commande, Prouver n'est pas sauté et n'est pas « Je l'ai relu ».
Relancez le contrôle d'acceptation exactement comme goal.md le formule, collez sa sortie,
et dites à quoi un résultat d'échec aurait ressemblé. Si vous ne pouvez pas énoncer l'échec,
vous n'avez pas de contrôle.
Chaque nouvelle garde a besoin d'une démonstration que vous l'avez vue échouer sans le correctif. Supprimez le correctif, exécutez, voyez le rouge, restaurez. Une garde qui ne peut pas se déclencher est pire qu'aucune : elle se lit comme une preuve que le cas est traité. La même règle en dehors du code — si le contrôle ne peut pas échouer, c'est de la décoration.
Et lorsque le travail a ÉMIS quelque chose — une config, un script, un fichier unit, un
serveur généré — exécutez la chose que vous avez émise. La lire ne prouve rien ;
trois fois en une seule campagne, le défaut était invisible sur la page et évident à la
première exécution. Un serveur MCP généré semblait correct et aurait suspendu son
client, car une notification JSON-RPC ne doit recevoir aucune réponse. Un wrapper de transporteur
se lisait parfaitement et s'est terminé par 0 sans avoir jamais invoqué l'agent, car ses
étapes étaient jointes avec &&. Un plist launchd passait plutil -lint dans un sens comme dans l'autre —
seul launchctl bootstrap + kickstart, puis la lecture de ce qu'il a écrit, a montré qu'il tournait
réellement. Émettre n'est pas faire.
Vérifiez — §3. Ne sautez jamais, ne le faites jamais vous-même.
Livrez de la manière dont ce projet accepte le travail : commit et PR, publiez, appliquez,
remettez. Stagiez par nom — jamais -A/-u/., ils prennent les modifications locales seulement et -u
manque les nouveaux fichiers. Ensuite vérifiez que la chose a réellement été livrée : une exécution
locale verte n'est pas un déploiement, et une PR fusionnée n'est pas un changement en direct.
Enregistrez — §4. Ensuite mettez à jour goal.md et commencez l'itération suivante.
3. Vérifier avec quelqu'un qui n'a pas fait le travail
Ce n'est pas la même chose qu'exécuter le contrôle, et ce n'est pas optionnel.
Vos propres correctifs sont la deuxième plus grande source de défauts — 58 à 68 % de toutes les découvertes dans les tours ultérieurs d'une campagne mesurée, sur un seul dépôt. Vous ne pouvez pas les voir, car escrire les a exclus de la vue.
- Chaque itération : au moins un sous-agent qui n'a pas fait le travail, avec la portée exacte, en lecture seule, dont le travail est de RÉFUTER l'affirmation selon laquelle c'est fait. « Confirmé » de la part d'un relecteur qui n'a pas r...