Chaser s'installe dans Claude Code et tourne à chaque tour de conversation. Vous avez le droit de savoir exactement ce qu'il exécute, ce qu'il écrit sur votre disque et ce qui quitte votre poste. Cette page donne les listes complètes, pas un résumé rassurant.
L'installateur enregistre exactement ces sept entrées dans votre configuration Claude Code. Aucune autre.
| Événement | Script | Rôle |
|---|---|---|
SessionStart | hook_sessionstart.js | Injecte le HANDOFF et la mémoire au démarrage |
Stop | hook_handoff_auto.js | Met à jour le handoff en fin de tour |
SessionEnd | hook_handoff_auto.js --force | Handoff de fin de session |
PreCompact | hook_handoff_auto.js --force | Handoff avant une compaction |
PreToolUse | hook_chaser.js | Bouclier de sécurité |
PostToolUse | hook_chaser.js | Déduplication de session, carte AST des gros fichiers lus, compression des sorties d'outils volumineuses |
UserPromptSubmit | hook_chaser.js | Conseil de compaction, économies du tour, Tier 0 (opt-in) |
Le PreToolUse ne se déclenche que sur les outils qui touchent
votre système ou le réseau : Bash, Edit, Write,
MultiEdit, NotebookEdit, WebFetch et les outils MCP
de type fetch/navigate.
Ce que le Bouclier ne protège pas, et il vaut mieux le savoir avant d'acheter. Il surveille les points de persistance (LaunchAgents macOS, services systemd utilisateur, fichiers d'init de shell, cron, clés SSH, démarrage Windows) et distingue nos écritures des écritures tierces par une empreinte scellée AVANT l'écriture. Cette distinction ne vaut que pour ce qui arrive APRÈS l'installation : une machine déjà compromise au moment où Chaser s'installe obtient un Bouclier qui validera la persistance en place. Une porte dérobée posée la veille fait partie de l'environnement qu'il découvre, pas des événements qu'il observe. Le Bouclier est un garde-fou sur les actions de l'agent, pas un antivirus : un audit du poste avant installation reste nécessaire, et il n'est pas de notre ressort.
Seconde limite, du même ordre. L'index des empreintes que
Chaser reconnaît comme siennes (.rapport/puits_chaser.json) est un
fichier ordinaire. Entre deux passages de notre porte de qualité, qui parvient à y
écrire obtient le silence du Bouclier. Le contrôle de porte le rattrape ensuite, en
confrontant cet index au journal scellé append-only — c'est une détection
différée, pas un verrou. Nous l'assumons pour une raison de temps : relire
un journal de plusieurs mégaoctets avant chacune de vos actions ferait payer la
vérification sur tout votre travail. Nous préférons l'écrire plutôt que de vous
laisser croire la fenêtre fermée.
La liste est courte, et elle est exhaustive.
moteur/hook_chaser.js — le composant qui s'exécute à chaque tour — ne
contient aucune URL et n'ouvre aucune connexion. Ses décisions
(bouclier, compression, conseil) sont calculées en local, en JavaScript pur.
GET /version.json, une fois par jour, pour savoir
si une mise à jour existe. Une requête de lecture : aucune donnée de votre
part n'est transmise.POST /beta, uniquement si une mise à jour est
téléchargée. Le corps de la requête contient votre clé de licence, et
rien d'autre — c'est ce qui autorise le téléchargement.Vos prompts, vos fichiers, vos noms de projet et le contenu de vos sessions ne sont envoyés nulle part par Chaser.
Dans votre projet :
HANDOFF.md à la racine du projet — votre passation de session, lisible..rapport/ — états locaux (throttle des conseils, compteurs)..handoff_global/ — journaux de mesure et mémoire.Points de PERSISTANCE, hors projet — ce qui survit à la fermeture de votre terminal. C'est la partie qu'un acheteur regarde en premier, et elle manquait à cette page jusqu'au 03/08/2026 :
schtasks :
Chaser-Relais (relais local, toutes les 10 min) et
Chaser-ReleveBornes (relevé de gain, quotidien).~/Library/LaunchAgents/ :
com.chaser.relais.plist et
com.chaser.relevebornes.plist, chargés par
launchctl bootstrap.$XDG_CONFIG_HOME/systemd/user/ (par défaut
~/.config/systemd/user/) : chaser-relais et
chaser-relevebornes, chacune avec son .service et
son .timer. Aucun service système, aucun sudo :
tout est dans votre compte utilisateur.
XDG_RUNTIME_DIR), rien
n'est posé — nous refusons en l'annonçant, et nous ne nous rabattons ni sur
cron ni sur un processus détaché. Si le « lingering » est désactivé
pour votre compte, la pose réussit mais vos minuteries s'arrêteront à la
déconnexion — typiquement en SSH ; l'installateur vous en avertit et
vous donne loginctl enable-linger $USER.mcpServers dans
~/.claude.json, la configuration de Claude Code, avec sauvegarde
du fichier avant écriture.Tout est en texte clair. Vous pouvez les ouvrir, les auditer, les
supprimer — python moteur/autonomie.py --desinstaller retire les
tâches, les LaunchAgents et l'entrée MCP (les hooks se retirent à part). Rien de tout cela n'émet vers l'extérieur : le
relais est un service LOCAL, et c'est le point 2 ci-dessus qui décrit ce qui
sort de votre poste.
Une économie annoncée sans protocole n'est pas une mesure, c'est une promesse. Les nôtres sont calculées sur des journaux réels et publiées avec leur méthode.
Un audit automatique interdit toute affirmation chiffrée sans réserve ni source sur nos pages publiques. Concrètement : le « −70 % » correspond à une médiane mesurée de 71,7 % dans le mode le plus agressif ; l'agrégat le plus flatteur (le tarif cache au dixième appliqué à tout) n'est pas le cas typique — et nous l'écrivons comme tel plutôt que de le laisser circuler seul.
La mémoire sur disque (« Doff ») et les deux endroits où elle
ne tient pas. Le Doff — mémoire sur disque, rappel borné par tour — est
désactivé par défaut (WIRETAP_DOFF=0) : personne n'y
tombe sans l'avoir activé soi-même. Nous publions ici ses deux limites mesurées,
parce qu'elles sont mesurées — les taire reviendrait à vendre un gain qui
n'existe pas partout.
WIRETAP_DOFF=1 y coûte +29,7 % en tokens pondérés et
+24,3 % en dollars réels face au bras témoin. La cause tient en une
phrase : la purge est faite par requête, un tour outillé en produit deux
ou plus, et seule la première est purgeable. Conséquence assumée :
déconseillé sur un workflow outillé tant que la purge en cours de
boucle n'est pas livrée — elle ne l'est pas.Réserve, du même ordre que le reste de cette page : ce second chiffre vient d'une seule session (N=1), trois bras complets, trace payée puis rejouée hors ligne. C'est un tir, pas un banc. La variante qui purgerait en cours de boucle n'existe pas ; simulée sur la même trace, elle plafonne à la parité avec le témoin.
Nous tenons un registre des défauts trouvés dans Chaser. Chaque entrée porte sa cause racine, sa gravité, et le test qui l'empêche de revenir — la règle interne étant qu'un bug corrigé sans test n'est pas corrigé.
| Gravité | Sens | Nombre |
|---|---|---|
| S1 | le système affirme quelque chose de faux | 43 |
| S2 | une panne réelle qu'aucun signal ne remonte | 22 |
| S3 | du code vert mais débranché | 9 |
| S4 | fragile, cassera au prochain ajout | 16 |
90 défauts enregistrés, dont 90 fermés avec leur test de garde. 0 défaut ouvert. Ce compteur ne redescend jamais — un défaut fermé reste au registre. Un défaut ouvert est un défaut dont la cause n'est pas établie : nous préférons l'écrire ainsi plutôt que de poser une garde qui passerait pour de bonnes raisons sans en être une. Le tableau ci-dessous est engendré depuis le registre à chaque livraison — il n'est pas rédigé à la main, donc il ne peut pas rester en retard sur lui.
Aucun défaut ouvert à ce jour.
Chiffres au 01/08/2026, recalés sur le registre : cette page annonçait encore 31 défauts alors que le registre en comptait 58. La page était donc plus flatteuse que la réalité — cet écart est lui-même entré au registre (B59), avec les quatre autres trouvés le même jour : un tableau de banc resté sur un run vieux de deux semaines (B58), une procédure de reproduction que sa cible ne pouvait pas exécuter (B60), et une porte de qualité qui écrasait le fichier de travail qu'elle est censée protéger, sans en garder copie (B61), puis accusait vingt suites innocentes d'un même passage plutôt que d'admettre qu'un écrivain externe tenait le fichier (B62). Chaque livraison passe une porte de qualité de 181 suites de tests, et la SBOM publie les 138 composants du moteur. Le produit compte 143 modules branchés et testés : chacun doit se charger depuis le point d'entrée unique, et une suite de la porte l'exige à chaque livraison — « branché » est vérifié, pas déclaré. Ces cinq chiffres sont désormais recalculés à chaque porte contre le registre, la SBOM, la liste des suites et le moteur lui-même : ils ne peuvent plus dériver en silence. Le paquet livré contient son guide d'installation, LISEZMOI_TESTEUR.md, à la racine de l'archive — c'est la première chose à ouvrir après le téléchargement. La mémoire longue est portée par MemBrick, une brique indépendante intégrée en sens unique : son banc de mutations compte 360 mutations rattrapées sur 360 posées, et ce chiffre est rapproché de la trace de course vendorisée avec la copie — même règle que les autres, la source productrice fait foi. Le moteur et ses preuves rejouables sont publics, sans licence — source consultable, tous droits réservés : github.com/HQU-kenaxvi/membrick (paper, contrat généré, procédure de reproduction) — et sa page produit. Bornes dites : aucune prétention SOTA sur la qualité de rappel, pas un mécanisme d'effacement, et une survie prouvée à un processus tué — pas à une coupure de courant.
Pendant seize jours, qui possédait le dépôt complet et le re-clonait sous
Windows obtenait un corpus de banc ne correspondant à aucun run que nous avons
publié. bench/corpus_2026Q3.jsonl ressortait en
e76f36a2… là où le run du 17/07 publie c35ce8ff… comme
« corpus gelé lié par SHA-256 ». Contenu identique, octets différents : la
vérification échouait, et rien n'expliquait pourquoi.
La cause. Les deux corpus sources étaient en unspecified côté
git, donc soumis à core.autocrlf : à chaque checkout Windows, git les
réécrivait en CRLF. git status ne montrait rien — il renormalise à la
lecture. L'écart n'apparaissait donc jamais chez nous, uniquement chez qui nous
vérifie. bench/corpus_v2_2026Q3.jsonl était exposé de la même façon à
partir du 31/07 (6f0ae3e5… au lieu de 31c19ebe…).
Qui était concerné, exactement. Le dépôt complet n'est détenu que par nos
clients. Les deux voies ouvertes aux tiers passent par des octets figés côté serveur,
et nous les avons rejouées le 02/08 : le pack autonome
chaserbench-verification.zip
rend VERDICT : CONFORME, contrôle du SHA du corpus compris, et le
corpus servi directement vaut bien
31c19ebe…. Cela réduit le nombre de personnes touchées ; cela ne
change rien au fait que la promesse « vérifiez sans nous faire confiance »
était fausse pour celles qui l'étaient.
Ce qui n'était pas atteint. Les preuves de /preuves
sont indépendantes de ce défaut : un bundle est un JSON autoportant, vérifié hors
ligne, qui ne lit aucun fichier du dépôt. Six contrôles repassés le 02/08 : le
bundle publié, vérifié par le vérificateur publié, rend valide: true
(inclusion, cohérence, signature) ; les octets servis en ligne sont identiques à
ceux du dépôt (verifier_preuve.py = 9a5a8776…,
preuve_exemple.json = 44fca427…) ; le journal n'a fait
que grandir, de 13 489 à 15 816 entrées, et sa racine recalculée sur le
préfixe 13 489 vaut 71837021…, exactement la racine publiée ; la
clé de signature est inchangée (6a8877cd…) ; un bundle émis le 02/08
passe le vérificateur publié ; et l'ancien vérificateur, téléchargé entre le 29 et
le 31/07, rend valide: true avec signature: null — un verdict
plus faible, jamais un verdict contraire. Aucun bundle publié n'est devenu
invérifiable.
Le correctif, et pourquoi la garde vaut plus que la ligne. Le dossier
bench/ est désormais protégé en entier
(bench/* -text), et non les deux fichiers fautifs : un corpus ajouté
demain serait exposé sans que personne y pense — c'est exactement ainsi que ce défaut
est né. Surtout, le diagnostic existant ne parlait qu'après un écart
d'empreinte constaté, ce qui arrive trop tard quand l'écart n'apparaît que chez le
tiers. La porte de qualité refuse maintenant en amont qu'un fichier scellé sur ses
octets soit laissé sans protection, et cette garde est prouvée par mutation :
protection retirée, la porte refuse ; protection remise, la refabrication retrouve
l'empreinte publiée.
Au registre sous B74, gravité S2. Nous avions fermé le même défaut un
dossier plus loin, le 01/08, sur site/bench/ — sans le généraliser. Le
correctif d'alors traitait le cas rencontré ; transformé en règle le jour même, il
aurait fermé celui-ci du même geste. C'est la raison pour laquelle la protection porte
cette fois sur un dossier entier et s'accompagne d'un refus automatique, plutôt que sur
les fichiers déjà connus.
Jusqu'au 3 août, trois des fichiers que Chaser écrit sur votre disque n'étaient protégés ni contre l'écriture simultanée de deux processus, ni contre une coupure en cours d'écriture. Nous le formulons ainsi parce que la distinction compte : il ne s'agit pas d'une protection qui aurait cessé de fonctionner, mais d'une protection qui n'avait jamais existé.
Mesuré avant correctif, avec deux processus réellement simultanés :
.handoff/memoire.jsonl) : deux
processus ajoutant 40 faits chacun — 57 faits perdus sur 80. Le
fichier était relu, modifié, puis réécrit en entier ; le second à écrire
écrasait le travail du premier.Après correctif, sur le même protocole : 0 perte et 0 écrasement. Ces deux mesures sont désormais une suite de la porte de qualité, qui lance de vrais processus concurrents à chaque livraison — une simulation séquentielle ne verrait rien, la fenêtre de course n'existe qu'entre processus.
Ce qui a changé, en trois points. Les écritures passent par un fichier temporaire puis un remplacement atomique : une coupure — session fermée, batterie, arrêt brutal — laisse désormais le fichier d'origine intact au lieu d'un contenu à moitié écrit. Chez vous, cette coupure est plus probable que la concurrence. Un verrou inter-processus sérialise ensuite les modifications. Enfin, la numérotation des livrables est réservée en une seule opération indivisible.
Et une correction d'une autre nature sur le journal de preuves. Celui qui adosse les bundles publiés sur /preuves, lui, était bien protégé — mais si son verrou était indisponible, il écrivait quand même, silencieusement. C'est un renforcement, pas un ajout : il refuse maintenant d'écrire plutôt que de continuer sans exclusion. Une chaîne de preuve à moitié écrite est pire qu'une absence d'écriture, et une dégradation muette sur la chaîne de preuve est pire que les deux.
Ce que ces mesures ne prouvent pas : qu'aucune course ne subsiste ailleurs dans le produit. Elles couvrent les quatre fichiers nommés ci-dessus, pas l'ensemble de nos écritures. Nous préférons le périmètre exact à un « désormais sûr ».
Objection légitime : cascade, compression, disjoncteur, journal Merkle, seuils appris — à empiler des mécanismes, on finit par débugger l'orchestrateur au lieu de coder. Nous ne pouvons pas y répondre par une promesse, alors voici la mesure, sur 2 007 orchestrations réelles tracées chez nous.
| Sur 1 066 évènements en échec | Nombre | Part |
|---|---|---|
| fournisseur (crédit épuisé, HTTP 402, API en panne) | 1 001 | 93,9 % |
| protection (le disjoncteur a coupé, comme prévu) | 65 | 6,1 % |
| imputables à l'orchestrateur | 0 | 0,0 % |
Et surtout : ce que le système fait quand ça casse. Les 720 fins de chaîne dégradées se répartissent en trois issues, toutes contrôlées : rien n'est écrit et le fichier reste intact (253), un repli déterministe prend le relais sans appeler un seul modèle (271), ou le cliquet conserve la version existante parce que la nouvelle serait moins bonne (196). Aucune catégorie « sortie non validée écrite quand même » n'apparaît dans les traces.
Trois réserves, dans le même souffle que le chiffre : (1) le
chemin nominal ne renseigne pas ce champ — ces 720 issues sont l'échantillon des
exécutions dégradées, pas de toutes ; (2) absence de signal n'est pas
absence de fait : le code contient un chemin fail-open (si le cliquet
qualité est indisponible, l'écriture passe) qui n'apparaît dans aucune trace — ça
ne prouve pas qu'il ne se déclenchera jamais ; (3) ce sont nos traces, sur nos
machines, pas un échantillon multi-clients. Commande :
python outils_dev/fiabilite_orchestrateur.py, rejouée à chaque porte
de qualité.
Quatre composants restent fermés : le compresseur, le routeur de modèles, le rappel de règles et les seuils appris. Ce sont les seules pièces dont la copie ferait gagner du temps à un concurrent.
Une zone d'ombre au milieu d'une page de transparence ne vaut rien. Nous ne vous demandons donc pas de nous croire : pour chacun de ces quatre composants, nous publions trois choses qui ne servent à rien pour le copier, et à tout pour nous tenir responsables.
L'empreinte SHA-256 de chaque fichier fermé est publiée et scellée dans un journal chaîné. Conséquence directe : nous ne pouvons pas modifier un seuil après coup pour faire coller un chiffre annoncé. L'engagement est horodaté, et toute modification devient visible. Une empreinte n'apprend rien à un concurrent ; elle apprend l'essentiel à un client sceptique.
Ce que le composant ne fait jamais. « Le compresseur ne perd aucun signal d'erreur » dit ce qu'un utilisateur a besoin de savoir, sans dire comment il compresse.
La garantie n'est pas une promesse commerciale : elle tombe si son test tombe, et ce test tourne dans la porte de qualité à chaque livraison.
| Composant fermé | Ce qu'il ne fait jamais |
|---|---|
| Compresseur réduit les grosses sorties d'outils |
Perdre un signal d'erreur : une ligne d'échec est conservée, avec ses voisines immédiates. |
| Routeur de modèles choisit le modèle le moins cher qui suffit |
Descendre sous 97 % de l'utilité d'un routeur parfait — et il bat strictement le hasard, mesuré sur banc. |
| Rappel de règles rappelle vos consignes de travail |
Réécrire votre demande : la sortie ne contient pas votre prompt, et le rappel est plafonné en taille. |
| Seuils et politiques quand compacter, quand tenter moins cher |
Appeler le réseau : ces décisions sont calculées localement, sur vos données, qui ne sortent pas. |
Le manifeste complet, avec les empreintes et le chaînon de scellement, est public : engagements.json. Un contrôle automatique compare le code livré à cet engagement — s'ils divergent, nous devons republier.
Notre journal de mesures est scellé dans un arbre de Merkle (RFC 6962, le mécanisme des logs de Certificate Transparency). Vous pouvez vérifier une entrée sans nous faire confiance ni installer le produit :
python verifier_preuve.py preuve_exemple.json —
le script recalcule les empreintes localement, aucun appel réseau.Honnêteté oblige : le champ signature est
null tant que notre clé Ed25519 de scellement n'est pas en
production — la preuve Merkle (inclusion + cohérence append-only) vaut par
elle-même, et nous ne prétendons pas à une authenticité que nous n'avons pas
encore. Si le vérificateur renvoie "valide": false, publiez-le.
Personne n'a encore vérifié indépendamment ces preuves — soyez le premier. Rejouez le pas-à-pas ci-dessus (10 minutes, Python 3 suffit), publiez votre constat signé de votre nom, où vous voulez, même s'il nous est défavorable : nous le lierons ici. C'est la seule chose qui manque à ces chiffres, et elle ne peut venir que de vous.
Tout le reste — ce que le produit exécute chez vous, ce qu'il envoie, comment nous mesurons, ce que nous cassons — est sur cette page, parce qu'aucune de ces informations ne vous demande de nous croire sur parole.