- Après deux jours d’expérimentation, il semble approprié de décrire Claude Fable 5 comme « relentlessly proactive »
- Avec seulement une capture d’écran et un prompt d’une ligne, il a lancé un serveur de développement local, manipulé un vrai navigateur et inséré du code de mesure pour remonter à la cause d’un bug CSS
- Fable a tenté de reproduire le bug en passant par Playwright, Firefox, WebKit et Safari, puis, après plusieurs échecs, a identifié une vraie fenêtre de navigateur et mis en place lui-même une automatisation de captures d’écran
- Pour tester la boîte de dialogue modale qui s’ouvre avec la touche
/, il a injecté du JavaScript dans un template Datasette et généré l’état nécessaire en déclenchant un événement clavier après le chargement de la fenêtre
- Pour obtenir des mesures internes à la page, il a créé un serveur de collecte CORS basé sur Python
http.server, puis enregistré en JSON les informations du <textarea> à l’intérieur du shadow DOM d’un Web Component
- Un agent de code puissant peut accomplir dans le terminal ce qu’un utilisateur peut faire lui-même, ce qui rend l’exécution hors sandbox plus risquée face aux prompt injections et aux fuites de données
Processus de débogage de Claude Fable 5
- Il a commencé par enquêter sur une barre de défilement horizontale inutile apparue dans le prompt de chat du menu de saut de Datasette Agent
- Claude Fable 5 a mobilisé activement diverses techniques pour atteindre son objectif
- L’entrée consistait en une capture d’écran et un prompt d’une seule ligne :
Look at dependencies to help figure out why there is a horizontal scrollbar here
- Comme la cause pouvait venir des dépendances de Datasette Agent, et en particulier de Datasette lui-même, il lui a été demandé d’examiner d’abord le code des dépendances
- Claude Code a ouvert une fenêtre Firefox ordinaire et navigué jusqu’à la boîte de dialogue sans instruction explicite d’automatisation du navigateur, puis a aussi ouvert une fenêtre Safari pour poursuivre l’exploration
Automatisation des captures d’écran du navigateur
- Fable a mis au point sa propre méthode de capture d’écran des fenêtres de navigateur avec
uv run --with pyobjc-framework-Quartz
- En Python, il a parcouru toutes les fenêtres de la machine et filtré les fenêtres Safari dont le nom contenait une chaîne attendue comme
"textarea"
- Après avoir trouvé un identifiant entier de fenêtre tel que
153551, il a enregistré un PNG via l’outil CLI screencapture
- Il a écrit une page HTML temporaire comme
/tmp/textarea-scrollbar-test.html, l’a ouverte dans Safari, puis a récupéré la capture d’écran
- La commande utilisée en exemple était
screencapture -x -o -l 153551 /tmp/safari-cases.png
Exécution automatique de la boîte de dialogue modale
- La modale à tester ne pouvait être ouverte que par clic ou raccourci clavier, et il n’existait pas de mécanisme évident dans Safari pour déplacer la souris ou exécuter un raccourci clavier
- Claude s’exécutait dans le dossier contenant le code source de l’application et en avait suffisamment compris la structure pour lancer le serveur de développement local de Datasette
- Il a ajouté du JavaScript dans un template Datasette afin de simuler une frappe sur la touche
/ après l’ouverture de la fenêtre
- Ce code déclenchait un événement
keydown sur la touche / 1,2 seconde après le chargement de la fenêtre afin d’exécuter le raccourci qui ouvre la boîte de dialogue modale
<script>
window.addEventListener("load", function () {
setTimeout(function () {
document.dispatchEvent(new KeyboardEvent("keydown", {key: "/", bubbles: true}));
}, 1200);
});
</script>
Collecte de mesures à l’intérieur de la page
- Claude devait exécuter du JavaScript dans la page pour obtenir directement les mesures, et a donc écrit sa propre application web recevant les informations via CORS
- Il a utilisé la bibliothèque standard Python
http.server pour lancer un serveur local sur 127.0.0.1:9999
- Le serveur recevait des requêtes POST contenant du JSON, l’écrivait dans
/tmp/diag.json et renvoyait l’en-tête Access-Control-Allow-Origin: * afin de permettre la communication depuis du code chargé sur un autre domaine
- Claude a injecté du JavaScript dans le template chargé par le navigateur pour localiser le
<textarea> dans le Web Component <navigation-search>
- Le code injecté mesurait
devicePixelRatio, scrollWidth, clientWidth, whiteSpace et width, puis envoyait ces données au serveur local
const host = document.querySelector("navigation-search");
const ta = host.shadowRoot.querySelector("textarea");
const cs = getComputedStyle(ta);
fetch("http://127.0.0.1:9999/diag", {
method: "POST",
body: JSON.stringify({
dpr: window.devicePixelRatio,
scrollWidth: ta.scrollWidth, clientWidth: ta.clientWidth,
whiteSpace: cs.whiteSpace, width: cs.width,
}),
});
Bascule vers Opus et validation du correctif
- Après avoir découvert plusieurs techniques, Fable a heurté un garde-fou invisible et a été rétrogradé vers Opus
- Opus avait accès à l’intégralité de l’historique de la conversation et a continué à utiliser les techniques ouvertes par Fable
- Opus a ensuite identifié le problème, l’a testé, l’a validé, puis a finalisé le commit de correction
- Opus a récapitulé dans
/tmp/automation-report.md les techniques d’automatisation utilisées contre un vrai navigateur pendant la session, avec des exemples de code exécutables
- Ce rapport a été partagé dans un gist séparé, et l’intégralité du journal terminal de Claude Code a aussi été rendue publique
Revue complète des actions effectuées
- Claude Fable 5 et Claude Code ont trouvé comment lancer le serveur de développement local et ont aussi configuré les fausses variables d’environnement nécessaires à son exécution
- Ils ont lancé une session Playwright Chrome, activé l’affichage visible des barres de défilement dans Chrome avec
defaults write com.google.chrome.for.testing AppleShowScrollBars Always, puis l’ont désactivé plus tard
- Ils ont aussi parcouru Firefox et WebKit via Playwright, mais sans réussir à reproduire le bug
- Ils ont déterminé que le navigateur par défaut était Safari et ont créé le document HTML
textarea-scrollbar-test.html
- Ils ont ouvert le document de test dans Firefox réel, mais l’accès via
osascript a été bloqué en raison de « osascript is not allowed assistive access »
- Ils ont trouvé une méthode de contournement avec
pyobjc-framework-Quartz et mis en place un flux de capture d’écran basé sur les numéros de fenêtre
- Ils ont ajouté du JavaScript au template du site pour déclencher la touche
/ et reçu les données JSON via le serveur Python CORS
- Ils ont traversé le shadow DOM du Web Component pour trouver les informations nécessaires et confirmer la cause du bug dans Safari
- Après avoir appliqué un correctif potentiel dans un template personnalisé et vérifié son fonctionnement, ils ont expliqué comment résoudre le problème
Estimation du coût
- Le forfait utilisé est Claude Max à 100 $ par mois, et Anthropic a indiqué accorder à Fable une capacité généreuse jusqu’au 22 juin avant de facturer ensuite le tarif API complet
- AgentsView a servi à suivre les dépenses, et si le tarif complet avait été appliqué, le coût de cette session aurait été d’environ 12,11 $
- La sortie de session était
68606, le contexte maximal 113178, et les modèles utilisés étaient claude-fable-5 et claude-opus-4-8
- Sans surveiller de près les coûts, Fable peut concevoir de nouvelles méthodes pour déboguer du CSS et consommer facilement environ 12 $ de tokens
Nécessité du sandboxing
- Le fait que Fable ait fini par recourir à des méthodes extrêmes pour obtenir les informations nécessaires à un correctif CSS de deux lignes était impressionnant
- Un agent de code peut accomplir ce qu’un utilisateur pourrait faire en tapant des commandes dans un terminal, et les modèles frontier connaissent un très grand nombre de techniques
- En présence d’instructions malveillantes, de prompt injections dans du code ou des fils d’issues, ou d’un contenu collé imprudemment dans le terminal, cela pourrait mener à des fuites de données ou à d’autres dommages
- Exécuter un agent de code hors sandbox est toujours une mauvaise idée et constitue un candidat majeur pour de futurs incidents de sécurité liés à ces agents
- Fable est peut-être plus intelligent et plus soupçonneux face aux instructions malveillantes, mais s’il se laisse manipuler une fois, sa proactivité incessante peut aussi amplifier l’ampleur des dégâts
1 commentaires
Commentaires sur Hacker News
Cela se lit comme un cas impressionnant de perte fatale de l’initiative humaine, et cela révèle aussi un nombre assez important de commits réels [0]
L’auteur voulait masquer la barre de défilement horizontale. N’importe quel développeur frontend junior correct commencerait immédiatement par demander : « où faut-il mettre
overflow-x: hidden;? ». Pour une solution complète, il suffit de cliquer sur « Inspect element » dans le navigateur pour trouver la classe CSS, puis de retrouver son emplacement dans le code avec (rip)grep et d’ajouter une ligneUn programmeur plus proactif aurait posé des questions comme : quel contenu dans la zone de texte vide provoque le débordement, pourquoi faut-il ajouter à deux endroits un contournement qui masque seulement le symptôme plutôt que la cause profonde, et ne vaudrait-il pas mieux styliser
textareaune seule fois[0] https://github.com/datasette/datasette-agent/commit/a75a8b72...
__init__.py[0]D’après mon expérience avec Claude, il produit en général du code bien structuré, donc c’est en réalité assez surprenant. Cela dit, dans mon cas, on est plus proche d’un débat socratique amical avec un autre ingénieur qui se trouve être un robot que d’un véritable vibe coding
[0] https://github.com/datasette/datasette-agent/blob/main/datas...
C’est exactement ce que j’attends d’un développeur junior : vérifier qu’un bug existe vraiment, trouver comment le corriger, puis vérifier qu’il a bien été corrigé
Le problème, comme le billet de blog le souligne justement, c’est qu’au lieu de s’arrêter pour demander quand un niveau d’autorisation supérieur est nécessaire, il cherche sans fin des contournements bricolés par lui-même. Pour un développeur humain, ce serait un peu comme avoir besoin d’identifiants pour accéder à un sandbox tiers, mais au lieu de les demander à un senior, essayer de construire son propre sandbox depuis zéro
Cela me rappelle l’époque où l’accès au monde en ligne était facturé à la minute. Il y avait alors beaucoup d’incitations à faire tourner le compteur en permanence, et je me demande si ce n’est pas du même genre
J’ai toujours trouvé à la fois déroutant et surprenant que, même en reconnaissant clairement que « faire tourner un agent de code en dehors d’un sandbox a toujours été une mauvaise idée », autant de gens continuent quand même à le faire
C’est un peu comme poster une vidéo assis côté passager avec les pieds sur le tableau de bord en disant : « N’oubliez pas que si vous avez un accident comme ça, l’airbag peut vous casser les jambes, ou pire ! Heureusement que ça ne m’est pas arrivé ! »
Le vrai problème, c’est que chacun formule ses prompts de façon trop différente
Par exemple, moi je peux demander : « teste plusieurs variantes de cette annotation sur le pod k8s de ce service dans ce cluster X. Ça permettra de prouver la théorie Y ». Mais un collègue dira juste : « teste la théorie Y ». Si on pose ça à deux ingénieurs juniors, l’un peut essayer au hasard en production, l’autre peut lancer des tests en local. C’est une demande sans consignes du genre « débrouille-toi pour trouver », et l’agent la lit comme le ferait un junior à qui on n’a pas transmis les limites, mais à qui on a mis une forte pression pour « trouver »
claudeIl a des dotfiles semblables aux miens, mais sans secrets. Mon répertoire home est en 0700,
claudea sa propre clé SSH, je l’ai ajoutée à mon profil GitHub mais elle est protégée par mot de passe, et c’est moi qui fais les push/pull. J’ai aussi un utilisateur et une base Postgres séparés pour le dev/test, sans droits superuserEn gros, je le traite comme n’importe quel autre développeur du projet. S’il doit lancer quelque chose via sudo, il me le demande. Il arrive même qu’on travaille en parallèle sur la même chose. Après tout, Unix était censé être un système multi-utilisateur
Une astuce que j’utilise souvent consiste à ajouter ce remote supplémentaire dans ses dépôts git :
paul ssh://paul@localhost/~/src/example (fetch)paul ssh://paul@localhost/~/src/example (push)Ça facilite la collaboration sur des choses qui ne sont pas encore prêtes à être partagées
Cette configuration est plutôt confortable. Mais je m’inquiète quand même des bugs d’élévation de privilèges sous Linux. Je ne crois pas qu’une IA comprenne vraiment que l’exploitation de vulnérabilités n’est pas autorisée. Ça me rappelle mon premier emploi : dans l’urgence, j’avais utilisé à mauvais escient la fonction
:!de vim pour élargir des droits sudo officiellement limités à l’édition dehttpd.conf. Même avec les mises à jour de sécurité automatiques aujourd’hui, j’ai tendance à mettre à jour les paquets manuellement encore plus souvent. Je ne pense pas qu’Opus ira jusqu’à chercher des failles de sécurité, mais Fable pourrait, et il y en a eu beaucoup récemment. Les futurs modèles pourraient même découvrir eux-mêmes de nouvelles vulnérabilités ou installer un keylogger pour apprendre le mot de passe d’une clé SSHÀ part une machine séparée, l’utilisateur distinct est quasiment la configuration la plus paranoïaque dont j’aie entendu parler. Donc je me demande parfois si je ne sacrifie pas trop en vitesse et en confort. Mais en pratique, ça reste très pratique, et je trouve que c’est une approche à la fois efficace et responsable. Si quelqu’un voit des trous, je veux bien les entendre
Fable donne l’impression d’être « Opus tournant sur un harnais qui l’empêche de s’arrêter tant qu’il n’est pas sûr que le problème est corrigé ». Si on veut un meilleur modèle sur les benchmarks, c’est une direction cohérente
C’est un très bon modèle, mais avec une grosse prime. Non seulement les tokens coûtent plus cher, mais le modèle a aussi envie de tous les consommer. Par exemple, sur une tâche React Native, Fable ne dit pas : « OK, c’est fait, terminé ». Il veut reconstruire toute l’app depuis zéro, lancer toute la suite de tests, et surveiller tous les logs et avertissements
C’est la première fois, en utilisant un LLM, que j’ai l’impression qu’une montée en gamme du modèle ne vaut pas le coup, même si l’entreprise l’autorise. Parce que les builds et les tests maltraitent tellement ma machine et ma batterie que je ne peux plus faire autre chose
Pour l’instant, utiliser ultracode sur Opus me semble préférable. Il y a moins de pollution du contexte principal, et l’investigation est davantage parallélisée
Fable a essayé de vérifier une modification d’UI dans mon jeu. Je travaillais dans une autre fenêtre, et j’ai vu le programme s’ouvrir dans la barre des tâches. Fable a lancé le jeu depuis la CLI avec un outil movie maker, a enregistré la sortie, puis a capturé la dernière frame pour vérifier l’UI. Comme l’écran d’accueil du jeu masquait la partie qu’il voulait voir, il a créé un worktree temporaire, supprimé l’écran d’accueil, puis relancé movie maker
En le regardant faire, je me suis dit qu’il aurait économisé des tokens s’il m’avait simplement demandé une capture d’écran. Cela dit, impossible de ne pas être impressionné. Opus n’aurait jamais fait ça
Ce genre de texte donne l’impression de venir d’un univers parallèle. D’après mon expérience anecdotique et un benchmark que j’ai moi-même construit, certes encore subjectif (https://pshirshov.github.io/llm-bench-pi-oneshot/), Fable n’est pas si impressionnant que ça
Au niveau de gpt-5.5 et opus 4.8, il est parfois meilleur, parfois moins bon, nettement plus cher, et il lui arrive même de refuser des questions React en disant qu’il ne peut pas aider avec la chimie
Je ne sais pas si tout ce vacarme est vraiment fondé, ou si c’est juste de l’exagération AGI avant l’IPO
Je fais coordonner à Fable des implémentations complexes. Je lui donne des tickets de haut niveau dans Linear et je lui dis : « regarde les sous-sujets de ce ticket, détermine lesquels tu peux implémenter toi-même, dans quel ordre il faut les traiter, et comment te coordonner avec ce sur quoi les autres membres de l’équipe travaillent actuellement ». Ces tickets ne sont pas triviaux, ils ont beaucoup de pièces mobiles et de dépendances, y compris à l’intérieur et à l’extérieur du projet, par exemple avec le backend
Ensuite, Fable sélectionne des tickets et délègue chaque ticket à des sous-agents, eux aussi Fable. Le sous-agent consulte le design Figma du ticket, suit scrupuleusement les guidelines et conventions du dépôt, l’implémente parfaitement, prend des captures d’écran de chaque partie, rédige des messages de commit détaillés et une description de PR, puis joint les captures comme preuve. À la fin, il donne un résumé du type : « La PR #1283 doit être fusionnée d’abord. À noter aussi que certains écrans n’avaient pas de design Figma, donc j’ai repris le pattern à partir d’écrans similaires déjà implémentés »
Ça ne représente probablement qu’environ 20 % de ce que Fable peut faire. C’est vraiment un modèle puissant
Opus 4.8 pouvait aussi faire une grande partie de cela, mais il fallait beaucoup plus le guider, et dès qu’il rencontrait un point de blocage, il avait de fortes chances de s’arrêter en disant : « J’ai pu aller jusque-là, mais je ne peux pas continuer davantage »
Fable est un peu plus intelligent, mais c’est justement pour ça qu’il donne globalement l’impression d’être un moins bon outil
Il transforme sans arrêt un patch de 50 lignes qui pourrait être réglé en un seul prompt en une exploration de 30 minutes, et très souvent ça n’en vaut pas du tout la peine. En plus, il se trompe fréquemment
Je l’ai testé sur une tâche assez simple. Il fallait backfiller un cache de déduplication redis après un changement de fonction de hachage. Il suffisait d’appliquer la nouvelle fonction de hachage à toutes les valeurs de la DB pour étendre le cache, mais Fable a implémenté une mise à jour de cache inutilement complexe qui essayait d’inférer la version de la fonction de hachage de chaque valeur de cache et de ne recalculer que les anciens hash. Dans certains contextes ça pourrait avoir du sens, mais le résultat de 30 minutes de tokens brûlés, c’était du code que j’ai remplacé par une boucle
forde 10 lignesÇa m’inquiète comme mauvais signe pour la programmation en général. Il semble clair que la techno LLM se heurte à un mur de rendements décroissants sur le plan de l’intelligence, et si la réponse consiste simplement à les rendre plus obstinés, c’est une solution pourrie pour tous les concernés. À part ceux qui vendent des tokens, et ceux qui peuvent se permettre les tokens nécessaires pour scanner des 0-day
D’abord, ils n’ont pas de modèle causal. Tout ce qu’ils savent faire, c’est de l’exploration par essais et erreurs ; ça marche assez bien sur beaucoup de problèmes, mais beaucoup d’autres exigent un modèle causal
Ensuite, les prompts ne sont pas précis. Les langages de programmation et les modèles machine ont justement été inventés pour résoudre ce problème. L’anglais est formidable, mais ce n’est pas un langage de programmation
À l’approche de l’IPO, ils ont beaucoup misé sur l’adoption stratégique et la manipulation, et sur ce point ça a marché
tscpour vérifier les erreurs, il a encore écrit un script pour exécutertscdans chaque sous-agent et agréger les résultatsC’était vraiment agaçant. Une tâche qui aurait dû prendre 1 à 2 minutes au maximum a fini par prendre environ 10 minutes à cause de cette trajectoire
J’essaierai plus tard des tâches bien plus complexes, mais pour les choses simples, ça donnait vraiment l’impression de prendre une Corvette pour aller jusqu’à la boîte aux lettres
J’ai l’impression que mon refus d’utiliser des LLM en terminal sur ma machine locale continue d’être justifié
Même sans comportement malveillant, il y a trop de façons de perdre une quantité non négligeable de travail, ou d’abîmer ma machine et ma capacité à travailler elle-même
Pour une entreprise à 1 trillion de dollars, ça ne devrait pas être si difficile à mettre en place, non ? Ça me paraît mineur à l’échelle du harnais complet
La sécurité est clairement un enjeu plus important, mais en lisant tout ça je n’arrêtais pas de penser au nombre de tokens dépensés pour corriger 2 lignes de CSS
Il faut estimer combien de temps cela aurait pris à un humain
Les gens peuvent désormais être paresseux tout en ayant l’air productifs, mais ça reste de la paresse
On a maintenant des gens qui ont besoin d’un accès à du matériel coûtant des centaines de milliers de dollars juste pour écrire un email. Très peu pour moi. Je n’ai pas envie de me griller le cerveau pour finir dépendant de la machine à penser d’un milliardaire
Je ne me grillerai pas non plus le cerveau avec une “machine qui pense à ma place” en local. Je veux devenir une personne qui vaut plus que le matériel auquel j’ai accès.
Mon expérience personnelle avec Fable 5, qui agissait à sa manière, a été très positive
Il a essayé d’identifier la cause profonde d’un crash d’un module Python qui ne laissait aucune erreur ni dans les logs ni dans la console. Fable a d’abord écrit un harnais de test simulant des clics dans l’interface, puis a appliqué une recherche dichotomique à mon code pour trouver le point où le crash commençait. Après avoir formulé une hypothèse un peu exagérée sur la cause du crash, il a enchaîné des commandes bash en une ligne pour créer sous
/tmpdes environnements virtuels pour chaque version de ce module Python, afin de trouver la version qui ne plantait pasIl a remonté la cause profonde bien plus loin que je ne l’aurais fait seul, et la cause était une régression du module provoquant un dépassement de l’allocation du tas. Il a fourni assez d’informations et un exemple simplifié pour déposer un bug report, et il a aussi écrit un contournement pour éviter que cela n’arrive dans mon application
Il n’était pas totalement en roue libre. Je relisais chaque commande CLI qu’il voulait exécuter, et quand je validais par « yes » pour continuer, j’ajoutais des réponses pour éviter une consommation excessive de tokens
Définir des garde-fous dans le prompt ou le Markdown aide. Par exemple, si on lui dit de ne pas utiliser l’automatisation du navigateur web, j’ai vu Fable respecter à la fois cette règle et son intention. Il n’a pas non plus tenté de bidouillages étranges
En revanche, il semble parfois traiter certaines tâches de débogage simples comme si elles étaient plus complexes qu’en réalité. Le billet d’origine en est sans doute un bon exemple
git bisectafin de trouver pourquoi un module Python plantait sans laisser d’erreur dans les logs ni dans la consoleJe comprends l’idée de générer le cas de test et la boucle
git bisect, mais je ne vois pas pourquoi il faudrait faire tourner ça via Internet, des GPU, etc. J’ai l’impression que c’est le genre de chose qui pourrait tourner même sur un Celeron monocœur, non ?