Agent.spboucher.ai — Architecture du système d'exploitation agentique
Version 0.1 — 10 novembre 2026. Document de conception : rien de ce qui suit n'est encore construit.
Les constats cités viennent des quatre rapports de docs/research/ (sources et dates y figurent) ; les choix
d'architecture sont les miens et sont signalés comme tels.
1. Ce que nous construisons, et ce que nous ne construisons pas
Objet. Une plateforme agentique dont nous possédons tout le code : la boucle d'agent, l'orchestration des sous-agents, la mémoire, les outils, l'exécution durable et la console Web. Les modèles d'Anthropic et d'OpenAI (et plus tard des modèles locaux) sont des fournisseurs interchangeables derrière une interface à nous.
Ce n'est pas une surcouche de Claude Code ou de Codex (c'est le rôle de Claude Remote et Codex Remote), ni un assemblage de LangGraph/CrewAI/AutoGen. Nous n'utilisons aucun framework agentique tiers ; nous reprenons leurs meilleurs mécanismes et évitons leurs défauts documentés.
Non-objectifs assumés (tirés de la recherche) :
- pas d'isolation multi-locataire : un seul propriétaire ;
- pas de garantie « exactement une fois » sur les effets externes — personne ne l'offre ; nous visons « au moins une fois, résultat enregistré une seule fois, effets idempotents ou réconciliés » ;
- pas de discussion de groupe libre entre agents, pas d'« équipe » à rôles avec gestionnaire automatique, pas d'essaim de pairs : ce sont les formes qui échouent le plus dans les études (MAST, Cognition) ;
- pas de filtre anti-injection par prompt ni de juge LLM comme barrière de sécurité : la sécurité est structurelle ;
- pas de graphe de connaissances, pas de base vectorielle dédiée, pas de fine-tuning au départ ;
- pas de Temporal/Kubernetes : un processus de contrôle + PostgreSQL suffisent à cette échelle.
2. Ce que la recherche impose
Constat (source dans docs/research/) |
Conséquence de conception |
|---|---|
| Aucun framework ne rend les effets de bord idempotents ; la reprise par « ré-exécution du nœud » (LangGraph, MAF) rejoue les appels modèle et outil | Journal d'événements en ajout seul ; à la reprise on renvoie le résultat enregistré, on ne rappelle jamais le modèle ; chaque outil déclare sa classe d'effet |
| Les échecs multi-agents viennent d'abord de la spécification (42 %), du désalignement entre agents (37 %) et de la vérification (21 %) ; le multi-agent coûte 4 à 15 fois plus de jetons et nuit au raisonnement séquentiel | Délégation par contrat typé ; multi-agent réservé au travail large en lecture et à la vérification ; budgets hiérarchiques imposés par le runtime |
| Les écritures parallèles se marchent dessus (Cognition, Anthropic) | Un seul écrivain par espace de travail ; écrivains parallèles uniquement sur worktrees isolés avec fusion par le parent |
| La qualité baisse avec la longueur du contexte, même à récupération parfaite | Contexte actif petit : déchargement des gros résultats en fichiers, effacement des anciens résultats, compaction lisible, sous-agents comme compression |
| Le cache de prompt dépend d'un préfixe stable ; changer de modèle, d'effort ou de liste d'outils l'invalide ; l'API Anthropic vérifie que l'historique n'est pas réécrit | Transcription en ajout seul ; liste d'outils figée par conversation ; un modèle par fil — on change de modèle en déléguant à un sous-agent, pas en plein fil |
| La mémoire en fichiers + recherche égale ou bat les systèmes spécialisés tant que l'historique pertinent reste modeste ; les réécritures LLM destructives sont le point faible | Mémoire durable en Markdown versionné par git, indexée par Postgres ; on invalide, on n'écrase pas |
| Les défenses anti-injection publiées sont contournées à > 90 % ; l'approbation par classifieur manque environ 17 % des actions à risque | Règle de deux par exécution, bac à sable OS, proxy de sortie, approbations humaines durables ; le classifieur n'est qu'un filtre de confort |
Les évasions de bac à sable réelles passent par un fichier écrit par l'agent puis exécuté hors bac (hooks, .git/config, venv) |
Tout ce que l'agent écrit est une entrée non fiable pour les outils côté hôte ; chemins auto-modifiants protégés |
| Horizon fiable à 80 % : quelques heures de travail humain | Travail long découpé en unités d'une à trois heures-homme, chacune terminée par un point de contrôle vérifiable |
3. Vue d'ensemble
Navigateur (bureau, tablette, téléphone, PWA)
│ HTTPS + WSS (Caddy sur BHS64 → WireGuard)
▼
┌──────────────────────── PLAN DE CONTRÔLE (un nœud toujours allumé) ─────────────────────────┐
│ Passerelle API auth, REST /api/v1, flux d'événements WS, approbations, console │
│ Noyau (kernel) journal · ordonnanceur · baux · budgets · politique · minuteries │
│ Moteur d'agent boucle modèle↔outils, contexte, compaction, sous-agents, vérification │
│ Routeur de modèles adaptateurs Anthropic / OpenAI / local, tarifs, limites, bascule │
│ Mémoire dépôts git Markdown + index Postgres (plein texte + pgvector) │
│ Courtier d'outils registre, MCP, skills, proxy de sortie, coffre à secrets │
│ PostgreSQL 17 journal, files, index mémoire, audit, métriques │
└───────────────┬───────────────────────────────────────────────────────────────────────────────┘
│ SSH restreint (commande forcée) + RPC JSON sur stdio
▼
┌──────────────────────── PLAN D'EXÉCUTION (nœuds MacLustr autorisés) ────────────────────────┐
│ Exécuteur (runner) reçoit une étape, l'exécute dans un bac à sable, renvoie le résultat │
│ Niveau 0 lecture seule, pas de shell Niveau 1 Seatbelt + worktree + proxy │
│ Niveau 2 VM Linux jetable (Apple container) Niveau 3 VM macOS (GUI, AppleScript) │
└───────────────────────────────────────────────────────────────────────────────────────────────┘Principe directeur : le plan de contrôle décide et consigne, le plan d'exécution agit et ne décide de rien. Les exécuteurs ne réclament jamais de travail eux-mêmes ; ils reçoivent une étape signée par un bail et rendent un résultat. Tout l'état vit dans PostgreSQL ; n'importe quel processus peut mourir sans perte.
4. Le noyau : journal, étapes, reprise
4.1 Modèle de données central
- Mission : objectif du propriétaire, projet, budget global, définition du « terminé ».
- Exécution (run) : une instance d'agent — racine ou sous-agent — avec son contrat, son modèle, son espace de travail, son budget, son parent. Les exécutions forment un arbre.
- Étape (step) : l'unité journalisée. Types :
model_call,tool_call,spawn,join,wait_human,timer,compaction,checkpoint,verdict. Chaque étape a un numéro de séquence stable dans son exécution. - Événement : enregistrement en ajout seul (
events), partitionné par mois : tout ce qui s'est passé, avec niveau de confiance de la source (propriétaire > raisonnement d'agent > sortie d'outil > contenu Web). - Artefact : fichier adressé par contenu (sorties volumineuses, rapports, diffs) ; le contexte n'en garde qu'un aperçu et le chemin.
4.2 Sémantique d'exécution
- Avant chaque étape, le moteur écrit une intention (
step_startedavec le hachage de la requête). - L'étape s'exécute ; son résultat est écrit dans la même transaction que la mise à jour d'état (jetons, coût, ledger).
- À la reprise, le moteur relit le journal de l'exécution : toute étape qui a un résultat le renvoie tel quel ; la boucle repart à la première étape sans résultat.
- Une étape avec intention mais sans résultat est traitée selon sa classe d'effet :
| Classe (déclarée par l'outil) | Exemples | Au redémarrage |
|---|---|---|
read |
lire un fichier, grep, recherche Web | rejouée |
idempotent_write |
écrire un fichier à contenu donné, git commit dans un worktree |
rejouée avec la clé d'idempotence hash(run_id, seq) ; l'exécuteur renvoie le résultat déjà produit s'il existe |
non_idempotent |
envoyer un courriel, git push, appel d'API payante, AppleScript |
réconciliation : sonde « est-ce déjà fait ? » si l'outil en fournit une, sinon suspension et question au propriétaire. Jamais de nouvelle tentative aveugle |
model_call |
appel LLM | rejoué (aucun effet externe) ; le coût perdu est comptabilisé |
- Baux et jetons de clôture : une exécution active détient un bail renouvelé toutes les 30 s et un jeton monotone vérifié à chaque écriture d'état. Un processus zombie dont le bail a été repris ne peut plus rien écrire.
- Attentes durables : approbation humaine, minuterie, attente d'un sous-agent = une ligne dans le journal, pas un processus bloqué. Une approbation peut attendre des jours ; le délai expiré vaut refus.
- Annulation : propagée de la racine aux feuilles ; chaque exécuteur tue son groupe de processus.
- Versionnage : chaque exécution enregistre la version du moteur et le hachage de son prompt système et de sa liste d'outils. Une exécution longue reprend avec la version qui l'a lancée (les anciennes versions restent installées tant qu'une exécution les référence) ou est migrée explicitement à un point de contrôle.
Pourquoi notre propre noyau plutôt que DBOS/Restate/Temporal (choix, contre la recommandation n° 1 du
rapport 4) : l'exigence est de contrôler l'orchestration de bout en bout ; à l'échelle d'un seul propriétaire le
débit n'est pas un problème, seule la justesse l'est ; et nos besoins (classes d'effet, réconciliation, budgets
hiérarchiques, bifurcation depuis une étape) dépassent ce que ces moteurs journalisent. Le prix est la justesse,
donc le noyau reste petit (journal, baux, minuteries, files SKIP LOCKED) et il est validé par des tests de
chaos : tuer le processus à chaque frontière d'étape et vérifier qu'aucune étape n'est perdue ni doublée. DBOS
reste la solution de repli si ces tests ne passent pas.
5. Le moteur d'agent
5.1 Boucle
Un tour = une réponse du modèle + l'exécution de ses appels d'outils. Les outils read d'un même tour
s'exécutent en parallèle, les écritures en série. La boucle s'arrête sur : réponse sans appel d'outil, budget
atteint, plafond de tours, annulation, ou refus du crochet d'arrêt (§ 5.5). États terminaux typés :
done, partial, blocked, failed, cancelled, budget_exhausted — un agent tué par une erreur ne
« réussit » jamais.
Pilotage en cours de route : un message du propriétaire est mis en file et lu dès la fin des appels d'outils en cours, dans le même tour ; l'interruption annule l'outil en cours.
5.2 Assemblage du contexte (ordre figé, favorable au cache)
[outils — liste figée, ordre déterministe]
[système — rôle, règles, format ; aucun horodatage ni identifiant volatil]
[index mémoire — instantané pris au lancement, puis gelé]
[messages — en ajout seul]- Tout changement en cours de route (mode, rappel, fichier modifié) est ajouté comme message, jamais édité dans le préfixe.
- Les outils nombreux (MCP, skills) sont différés : seuls leurs noms et descriptions courtes entrent en contexte ; le schéma se charge à la demande et s'ajoute sans invalider le cache.
- Fichiers d'instructions par projet (
AGENTS.md, lu aussi si c'est unCLAUDE.md) : courts, table des matières vers la documentation ; les invariants sont imposés par des tests et des crochets, pas par de la prose.
5.3 Soulager le contexte, par paliers
- Déchargement : tout résultat d'outil au-delà d'environ 3 000 jetons va dans un artefact ; le contexte garde un aperçu et le chemin.
- Effacement des anciens résultats d'outils, par lots assez gros pour amortir la réécriture du cache (primitive native côté Anthropic ; équivalent géré par nous côté OpenAI).
- Compaction vers 50–60 % de la fenêtre, avec notre résumé structuré et lisible : objectif, contraintes, décisions, fichiers touchés, faits vérifiés avec identifiants d'événements, problèmes ouverts, prochaines étapes ; consignes du propriétaire, messages d'erreur, identifiants et chemins conservés mot pour mot. La compaction des fournisseurs sert de transport quand elle existe, mais notre résumé est toujours écrit au journal (celle d'OpenAI est chiffrée et illisible — inacceptable comme seule trace).
- Réhydratation après compaction : instructions, plan, ledger, index mémoire et quelques fichiers récents sont relus depuis le disque, avec plafond par élément et garde anti-emballement.
5.4 Sous-agents et orchestration
Contrat de délégation (objet typé, refusé s'il manque le critère de fin) :
objective ce qu'il faut accomplir, en une ou deux phrases
context_refs artefacts, fichiers, entrées de mémoire à lire (références, pas de copie)
boundaries ce qui est hors périmètre ; fichiers possédés ; interdits
output_schema schéma JSON du résultat attendu
tools liste blanche d'outils et niveau de bac à sable
model, effort choisis par le routeur ou imposés
budget jetons, dollars, tours, durée
done_criteria vérifiable par machine quand c'est possible
context_mode fresh (défaut) | fork (copie du journal parent) | artifact_onlyEnveloppe de résultat : status, charge utile validée par le schéma, références d'artefacts, liste de
preuves (commande exécutée, test passé, source citée), questions ouvertes. Le parent ne reçoit que cette
enveloppe ; les gros livrables restent en artefacts. Le texte de l'enveloppe est marqué comme donnée et analysé
pour repérer des instructions injectées.
Formes d'orchestration autorisées (toutes exprimées en code ordinaire, étapes journalisées — pas de langage de graphe) :
- orchestrateur → travailleurs en lecture : recherche, exploration de code, revue, analyse ; éventail puis rassemblement ; les frères qui ont réussi ne sont pas rejoués si l'un échoue ;
- écrivains isolés : un worktree git par écrivain, fusion unique par le parent, conflits renvoyés à un agent ;
- planificateur → exécutant → évaluateur pour le travail long (§ 5.5) ;
- conseiller : un modèle plus fort consulté ponctuellement par un exécutant moins cher.
Ledger du superviseur (inspiré de Magentic-One et des listes de fonctionnalités d'Anthropic) : éléments de plan avec propriétaire, statut et preuve, plus une liste de faits établis. Un travailleur ne peut modifier que ses propres éléments, et seulement en joignant une preuve.
Limites imposées par le runtime, jamais par le prompt : profondeur 3, concurrence par mission configurable (12 par défaut, plafond global lié aux limites de débit des fournisseurs), budget par sous-arbre — la dépense d'un enfant est débitée au parent.
5.5 Planification et vérification
- Définition du terminé écrite avant le travail : pour le code, une liste de critères en JSON dont seul le
champ
passesest modifiable ; pour la recherche, les questions auxquelles répondre et le niveau de preuve ; pour l'analyse financière, les chiffres à reproduire et leur tolérance. - Oracles déterministes d'abord : tests, vérification de types, lint ; ré-exécution des analyses numériques depuis une copie propre et comparaison ; pour la recherche, re-téléchargement du passage cité.
- Évaluateur à contexte propre : il voit l'artefact et les critères, pas le raisonnement du travailleur ; de préférence un modèle d'un autre fournisseur ; il doit citer ses preuves. Un juge LLM n'est jamais seul arbitre quand un contrôle exécutable existe.
- Crochet d'arrêt : la mission ne peut se déclarer terminée que si les critères passent ; sinon la boucle reprend ou escalade.
- Détection de blocage (déterministe) : mêmes appels d'outils répétés, ledger inchangé depuis N étapes, plafonds atteints → une replanification, puis escalade au propriétaire.
- Travail sur plusieurs jours : routine fixe à chaque reprise — lire le fichier de progression et le journal git, lancer le test de fumée, traiter une unité, vérifier, valider (commit), mettre à jour la progression.
6. Mémoire
Principes : la transcription est la source de vérité, toute mémoire en est une vue dérivée et reconstructible ; fichiers pour ce que les agents lisent et écrivent, Postgres pour ce que le système indexe ; on ajoute et on invalide, on n'écrase pas ; le contenu non fiable n'écrit jamais en mémoire durable sans garde.
| Couche | Durée | Support | Contenu |
|---|---|---|---|
| 0. Journal | permanent | Postgres events (plein texte) + artefacts |
tout ce qui s'est passé |
| 1. Contexte de travail | une exécution | fenêtre du modèle + todo.md, notes.md dans le dossier d'exécution |
§ 5.2–5.3 |
| 2. État de projet | des semaines | fichiers dans le dépôt du projet : PROGRESS.md, features.json, DECISIONS.md, init.sh |
où en est le travail |
| 3. Mémoire durable | permanent | Markdown dans un dépôt git par portée : global/, project/<id>/, agent/<rôle>/, skills/ |
faits, préférences, procédures, leçons |
- Chaque portée a un
MEMORY.mdd'au plus 200 lignes (une ligne par fiche) ; seuls l'index global et celui du projet courant sont injectés. Les fiches se lisent à la demande. - En-tête de fiche : type, événements sources,
verified,valid_from,invalid_at, confiance, auteur. - Lecture : d'abord agentique (lire l'index, ouvrir, grep). Un outil
memory_searchcomplète : plein texte- pgvector, fusion par rangs réciproques, filtre par portée et validité, léger a priori de récence ; il renvoie des extraits avec chemin et provenance. Le code n'est pas vectorisé : les agents font grep dans l'arbre de travail.
- Écriture : libre dans les notes d'exécution et de projet. Les écritures vers
global/, les manuels d'agents et les skills passent par une branche de propositions. - Consolidation (fin d'exécution, compaction, ou la nuit) : un agent relit les nouvelles transcriptions,
vérifie les propositions contre le journal, dédoublonne, marque les fiches contredites
invalid_at, applique des modifications par deltas aux manuels (ajouter, corriger, retirer une puce — jamais réécrire en entier), valide avec un message citant les événements, puis fusionne. Les changements de projet fusionnent seuls ; ceux deglobal/et des skills attendent l'approbation du propriétaire sur un diff. - Apprentissage par l'expérience : une leçon n'est retenue que s'il existe un signal de résultat (test passé, confirmation du propriétaire) ; chaque puce de manuel porte des compteurs « a aidé / a nui » alimentés par les exécutions suivantes.
- Garde-fous : un fait issu uniquement du Web ou d'une sortie d'outil est stocké
verified=false, jamais promu dans la couche injectée ni dans les skills sans corroboration ;git revertest le retour arrière ; un contrôle hebdomadaire vérifie la taille des index, les liens cassés, les fiches non vérifiées anciennes. - Reporté volontairement : graphe de connaissances (on ne garde que les colonnes bi-temporelles), réécriture automatique des anciennes fiches, score d'importance appris, tableau partagé entre agents. À rouvrir seulement si un jeu d'évaluation propre au projet montre que la base « tout charger ou grep » est battue.
7. Modèles et routage
Interface fournisseur unique : stream(conversation, outils, options) → événements normalisés
(texte, raisonnement résumé, appel d'outil, usage, arrêt, refus). Un adaptateur par fournisseur garde la
transcription native intacte (les blocs de raisonnement d'Anthropic et les éléments chiffrés d'OpenAI sont
renvoyés tels quels) ; une conversation n'est donc jamais convertie d'un fournisseur à l'autre en cours de fil.
- Anthropic : API Messages via le SDK officiel TypeScript, streaming, raisonnement adaptatif,
effort, cache de prompt, effacement de résultats, budgets de tâche, repli côté serveur sur refus. - OpenAI : API Responses (recommandée pour tout nouveau projet), sans état côté serveur.
- Local (plus tard) : point d'accès compatible servi par MLX sur un nœud Ultra ; aucun n'existe aujourd'hui.
Catalogue vivant : la liste des modèles, fenêtres de contexte et capacités est lue auprès des API de modèles des fournisseurs ; les tarifs sont dans une table versionnée. Relevé du 10 novembre 2026 :
| Rôle | Anthropic | OpenAI | Prix entrée / sortie par million de jetons |
|---|---|---|---|
| Raisonnement le plus exigeant, longues missions | claude-fable-5-2 |
gpt-6-astra |
8 $ / 40 $ · 10 $ / 50 $ |
| Boucle principale par défaut | claude-opus-5-5 |
gpt-6.1-sol |
4 $ / 20 $ · 2 $ / 10 $ |
| Travailleurs, exploration, revue | claude-sonnet-5-5 |
gpt-6.1-terra |
2 $ / 10 $ · 1 $ / 5 $ |
| Volume : extraction, classement, résumés | claude-haiku-5-5 |
gpt-6-luna |
0,10 $ / 0,50 $ · 0,10 $ / 0,50 $ |
Politique de routage (déclarative, modifiable dans la console) :
- le modèle est fixé par exécution ; changer de modèle = déléguer à un sous-agent ;
- le premier levier de coût est l'effort sur un bon modèle, mesuré avant toute cascade ;
- chaque rôle (planificateur, exécutant, évaluateur, consolidateur de mémoire, classifieur) a un modèle et un effort par défaut, surchargeables par mission ;
- l'évaluateur est de préférence d'un autre fournisseur que l'exécutant ;
- mode par lots (−50 %) pour le travail non urgent : consolidation nocturne, évaluations ;
- bascule automatique vers l'autre fournisseur sur panne ou limite de débit, uniquement à une frontière de sous-agent ;
- le coût est jugé par tâche terminée, jetons en cache comptés à part.
8. Outils et intégrations
Chaque outil est un objet typé : nom, description, schéma d'entrée, classe d'effet, classe de risque (lecture / écriture dans l'espace de travail / réseau / externe ou irréversible), niveau de bac à sable minimal, parallélisable ou non, sonde de réconciliation éventuelle.
| Famille | Outils | Notes |
|---|---|---|
| Fichiers | lire, lister, chercher (ripgrep), éditer (remplacement exact avec contrôle de fraîcheur), écrire | l'édition refuse si le fichier a changé depuis la dernière lecture |
| Shell | exécution dans le bac à sable, sortie plafonnée et déchargée | une seule chaîne opaque : c'est pourquoi les actions à contrôler sont promues en outils dédiés |
| Git | statut, diff, commit, branche, worktree, push (externe → approbation) |
jetons courts et limités |
| Web | recherche (outil serveur du fournisseur ou service tiers), récupération côté serveur, navigateur Playwright isolé au niveau 2 | le contenu Web est toujours une donnée non fiable |
| Délégation | lancer un sous-agent, attendre, envoyer un message, lire le ledger | § 5.4 |
| Mémoire | voir, créer, modifier, rechercher | § 6 |
| Propriétaire | poser une question, demander une approbation, notifier | rendu spécifique dans la console |
| MacLustr | inventaire et télémétrie (agentd, lecture seule), soumettre une étape à un nœud | § 9 |
| macOS | AppleScript, automatisation d'interface | uniquement en VM macOS (niveau 3) |
| MCP | client pour serveurs stdio et HTTP ; versions épinglées, descriptions hachées, alerte si une description change, chaque serveur sous bac à sable | la spécification 2026-07-28 est sans état : bien adaptée |
| Skills | format SKILL.md standard (nom et description injectés, corps à la demande) ; registre skills.spboucher.ai en lecture |
une skill téléchargée n'est jamais exécutée sans revue |
En frontière externe seulement : le protocole A2A (carte d'agent, tâches, états input-required) pour exposer ou
appeler des agents tiers ; en interne, nos enveloppes typées.
9. Exécution et isolation sur MacLustr
Niveaux de bac à sable (le niveau est choisi par la politique d'après la classe de risque de la mission) :
| Niveau | Pour | Mécanisme | Réseau | Secrets |
|---|---|---|---|---|
| 0 | recherche en lecture | aucun shell ; récupération côté plan de contrôle | via le récupérateur | aucun |
| 1 | code et analyse dans un espace de travail | Seatbelt (profil refus par défaut), écriture limitée à un worktree éphémère, utilisateur macOS agent sans droits admin ni autorisations TCC, taskpolicy pour mémoire et priorité |
proxy à liste blanche de domaines | injectés par le proxy, jamais dans l'environnement |
| 2 | code non fiable, installation de paquets, navigation | VM Linux par tâche (Apple container), détruite ensuite |
proxy à liste blanche | aucun par défaut |
| 3 | interface graphique macOS, AppleScript | VM macOS (Tart ou Lume, deux par hôte) | proxy | aucun |
- Seatbelt est marqué obsolète par Apple mais applique toujours les profils sur macOS 27 (vérifié) ; c'est ce qu'utilisent Claude Code et Codex. Il n'existe pas de quota CPU dur hors VM sur macOS.
- Répartition : le plan de contrôle détient une clé SSH par nœud, restreinte par commande forcée (un seul
programme : l'exécuteur),
restrict, et adresse d'origine ; la cible est l'utilisateuragent. Ni le mot de passe sudo du cluster ni la clé de la passerelle ne servent au travail des agents. - Placement : l'ordonnanceur choisit le nœud d'après la télémétrie réelle (agentd) et les besoins déclarés de l'étape ; les calculs lourds vont sur les nœuds Ultra, pas sur le plan de contrôle.
- Proxy de sortie : composant minimal, à jour, sur le plan de contrôle ; liste blanche par mission ; il injecte les identifiants HTTP à la sortie. C'est la cible la plus précieuse du système et il est traité comme tel (l'incident OpenAI/Hugging Face de juillet 2026 est passé par un proxy de ce type).
10. Sécurité et permissions
Modèle de menace : contenu hostile lu par un agent (Web, dépôt, document, sortie d'outil, serveur MCP), erreur ou excès de zèle d'un agent, vol de la session Web du propriétaire. Pas d'attaquant interne.
- Authentification de la console : celle de Claude Remote, déjà éprouvée — mot de passe + second facteur
obligatoire (passkey ou TOTP), cookies
__Host-, CSRF, contrôle d'origine des WebSockets, limitation de débit, CSP stricte. - Règle de deux par exécution : une exécution ne cumule jamais sans humain plus de deux propriétés parmi (a) lire du contenu non fiable, (b) accéder à des secrets ou données sensibles, (c) changer un état externe ou communiquer vers l'extérieur. Un agent qui lit le Web n'a donc ni secrets, ni sortie hors liste blanche.
- Lecteur en quarantaine : le contenu Web est lu par un sous-agent sans outils d'action, qui rend des données structurées ; l'agent qui agit ne voit jamais le texte brut. Plan-puis-exécution pour les missions sensibles.
- Permissions : évaluation refuser → demander → autoriser, dans le harnais, pas dans le modèle. Les
chemins auto-modifiants (
.git, configuration d'agent, crochets, fichiers rc, transcriptions) sont protégés quelles que soient les règles. - Approbations humaines durables pour toute action externe ou irréversible : la console montre l'appel exact, sa justification et son diff ; l'attente peut durer des jours ; l'absence de réponse vaut refus. Pour limiter la fatigue : regroupement, règles « toujours autoriser ceci dans ce projet », et un classifieur facultatif qui n'auto-approuve qu'à l'intérieur d'un bac à sable et qui ne voit ni les sorties d'outils ni la prose de l'agent.
- Ce que l'agent écrit est non fiable pour tout outil hors bac à sable : rien de ce qu'il a produit n'est exécuté ou interprété côté hôte sans diff ou revue.
- Canaux d'exfiltration fermés : la console n'affiche pas automatiquement d'images ou de liens distants ; une URL sortante doit être sur la liste blanche ou déjà présente dans la tâche.
- Secrets : dans le trousseau du plan de contrôle ; jamais dans un prompt, un environnement de bac à sable, un journal ou une fiche de mémoire (un nettoyeur de secrets filtre les écritures).
- Gouverneurs : plafonds par exécution et par mission en dollars, jetons, durée, appels d'outils ; plafond quotidien global ; bouton d'arrêt général qui révoque les baux et les identifiants du proxy.
- Audit : le journal est la piste d'audit ; chaque décision de politique et chaque approbation y figurent.
Référentiel de contrôle : le Top 10 OWASP des applications agentiques 2026 (ASI01–ASI10), couvert point par
point dans
docs/security.mdau moment de la construction.
11. Protocoles
- Console ⇄ passerelle : REST
/api/v1(missions, exécutions, approbations, mémoire, réglages) et un flux WebSocket d'événements typés — cycle de viemission → exécution → étape → élémentavecstarted / delta / completed, et demandes d'approbation initiées par le serveur. Un seul protocole pour toutes les interfaces. Reprise du flux par curseur (dernier numéro d'événement reçu), donc aucune perte après une coupure mobile. - Passerelle ⇄ exécuteur : RPC JSON sur stdio à travers SSH ; chaque requête porte l'identifiant d'étape, la clé d'idempotence, le jeton de bail et le profil de bac à sable ; la réponse est le résultat ou une référence d'artefact. L'exécuteur écrit son résultat sur disque avant de répondre, pour qu'une nouvelle tentative le relise.
- Agents entre eux : uniquement par le noyau — contrat, enveloppe, ledger, messages adressés. Pas de canal direct, donc tout est journalisé et rejouable.
- Extérieur : MCP pour les outils, A2A en frontière.
- Observabilité : chaque étape émet une trace OpenTelemetry (
gen_ai.*, derrière une fine couche de correspondance car les noms sont encore instables) avec identifiants de mission, d'exécution, de parent et d'étape, jetons et coût. La tableeventsreste la référence.
12. La console
Même socle que Claude Remote : Next.js en export statique, thème clair par défaut, PWA, pensée d'abord pour le téléphone. Écrans :
| Écran | Rôle |
|---|---|
| Accueil | ce qui attend le propriétaire (approbations, questions), missions en cours, dépense du jour, santé |
| Mission | objectif, définition du terminé, arbre d'exécutions vivant (qui fait quoi, avec quel modèle, combien dépensé), ledger du plan, artefacts |
| Exécution | fil chronologique : messages, raisonnement opérationnel résumé, appels d'outils avec entrées et sorties, diffs, compactions ; pilotage (message, pause, arrêt, bifurcation depuis une étape) |
| Approbations | file d'attente avec l'action exacte, son contexte, son diff ; approuver, refuser, « toujours autoriser » |
| Projets | dépôts, instructions, critères, historique des missions |
| Mémoire | navigation dans les fiches, propositions en attente avec diff, historique git, invalidations |
| Agents et politiques | rôles, modèles et efforts par défaut, outils autorisés, niveaux de bac à sable, budgets |
| Outils | registre, serveurs MCP et leur état, skills |
| Cluster | nœuds, exécuteurs, bacs à sable actifs (télémétrie réelle) |
| Coûts et traces | dépense par mission, modèle et jour ; coût par tâche terminée ; lecture des traces |
| Réglages | sécurité, clés des fournisseurs (écriture seule), notifications, bouton d'arrêt général |
Règles d'interface inchangées : aucune donnée inventée, horodatage de collecte visible, état inconnu affiché comme tel. Sur téléphone, l'usage central est : voir ce qui attend, approuver ou répondre, relancer.
13. Technologies
| Besoin | Choix | Raison |
|---|---|---|
| Langage | TypeScript strict de bout en bout (Node 26) | un seul langage pour le noyau, les outils et la console ; réemploi direct du code de Claude Remote |
| Structure | monorepo pnpm : kernel, engine, providers, memory, tools, runner, server, web, shared |
modules séparés, un seul déploiement |
| Base | PostgreSQL 17 + pgvector ; plein texte natif d'abord, BM25 (pg_search) si l'évaluation le justifie |
déjà présent sur les nœuds |
| Files et minuteries | tables Postgres, FOR UPDATE SKIP LOCKED, LISTEN/NOTIFY comme simple sonnette + sondage lent |
pas de Redis |
| Fournisseurs | @anthropic-ai/sdk, SDK officiel OpenAI |
pas de couche de compatibilité |
| Validation | zod partout (contrats, enveloppes, entrées d'outils) | |
| Bac à sable | profils Seatbelt générés par nous (en s'inspirant du sandbox-runtime d'Anthropic, Apache-2.0), Apple container, Tart |
|
| Navigateur | Playwright dans une VM de niveau 2 | |
| Console | Next.js 16 (export statique), Tailwind 4, composants de Claude Remote, React Flow pour l'arbre | |
| Traces | OpenTelemetry ; visualisation dans la console, Langfuse auto-hébergé seulement si nécessaire | |
| Tests | vitest, tests de chaos du noyau, Playwright, jeux d'évaluation par domaine | |
| Déploiement | mld + PM2, route MacLustr Tunnel, sauvegarde chiffrée nocturne |
standard du cluster |
Placement proposé : plan de contrôle sur M4M64c (64 Go, PostgreSQL déjà en service, 259 Go libres) ;
exécuteurs de niveau 1 et 2 sur m4mm, m4mn, m5ma, m6ma ; calcul lourd sur M3U96a et M3U96b ; M5M36 reste dédié à
Claude Remote et Codex Remote. Le DNS agent.spboucher.ai pointe déjà sur la passerelle.
14. Plan de développement
Chaque phase se termine par une démonstration vérifiable ; on ne passe pas à la suivante sans elle.
| Phase | Contenu | Critère de sortie |
|---|---|---|
| 0. Fondations | monorepo, schéma, authentification et coque de console reprises de Claude Remote, déploiement vide | agent.spboucher.ai en ligne, authentifié, tests verts |
| 1. Noyau durable | journal, étapes, baux, minuteries, attentes, annulation | tests de chaos : arrêt brutal à chaque frontière d'étape, aucune étape perdue ni doublée |
| 2. Agent unique | boucle, adaptateurs Anthropic et OpenAI, outils fichiers/shell/git, bac à sable niveau 1 local, permissions et approbations, console d'exécution en direct | un agent corrige un bogue réel dans un dépôt, tests à l'appui ; reprise après arrêt du processus en plein travail |
| 3. Contexte et mémoire | déchargement, effacement, compaction, réhydratation ; mémoire en fichiers + index ; consolidation | une mission dépasse trois compactions sans perdre son objectif ; jeu d'évaluation mémoire battant la base « grep » |
| 4. Orchestration | contrats, enveloppes, ledger, éventail en lecture, écrivains en worktrees, budgets hiérarchiques, détection de blocage | mission de recherche à plusieurs sous-agents ; comparaison chiffrée avec l'agent unique à budget de jetons égal |
| 5. Vérification et travail long | définition du terminé, oracles, évaluateur à contexte propre, crochet d'arrêt, routine de reprise | mission de programmation sur plusieurs heures, sans intervention, critères tous verts et vérifiés indépendamment |
| 6. Exécution distribuée | exécuteurs sur nœuds, utilisateur agent, SSH à commande forcée, proxy de sortie, coffre à secrets, niveau 2 |
étapes exécutées sur trois nœuds ; tests d'évasion et d'exfiltration refusés |
| 7. Outils étendus | MCP, skills, navigateur isolé, Web en quarantaine, niveau 3 macOS/AppleScript | mission Web de bout en bout sans secret exposé ; un flux AppleScript en VM |
| 8. Console complète | arbre de mission, approbations sur téléphone, mémoire, coûts, traces, politiques | parcours complet sur vrai iPhone |
| 9. Durcissement | revue OWASP agentique, tests d'injection, sauvegarde et restauration, plafonds, arrêt général | exercice de restauration ; campagne d'injection documentée |
| 10. Domaines | profils d'agents recherche, programmation, analyse financière (FinData), automatisation ; modèles locaux si un point d'accès existe | jeux d'évaluation par domaine, coût par tâche terminée suivi |
Les phases 0 à 2 donnent déjà un agent utilisable ; chacune des suivantes ajoute une capacité mesurable.
15. Risques assumés et points ouverts
- Justesse du noyau maison : c'est le risque principal ; il est contenu par la petite taille du noyau et les tests de chaos, avec DBOS comme repli.
- Coût : une mission multi-agents de plusieurs heures peut coûter des dizaines à des centaines de dollars (les chiffres publiés vont de 9 $ en solo à 200 $ avec harnais complet). Les plafonds sont obligatoires dès la phase 2.
- Injection : aucune défense n'est fiable seule ; la protection repose sur la structure (règle de deux, bac à sable, approbations). Un agent qui lit le Web et agit sans humain reste un risque résiduel.
- Limites de macOS : pas de quota CPU dur hors VM ; deux VM macOS par hôte ; Apple resserre l'accès complet au disque. Le niveau 3 restera rare et supervisé.
- Modèles qui progressent : chaque élément du harnais compense une faiblesse d'un modèle ; il doit pouvoir être retiré. Les jeux d'évaluation servent aussi à décider quoi supprimer.
- Non vérifié dans la recherche : comportement détaillé de certaines fonctions OpenAI (sorties structurées,
mode arrière-plan), performances des modèles d'embeddings sur MLX, disponibilité d'Apple
containersur les nœuds. À confirmer au moment où chaque phase en a besoin.
16. Décisions à prendre par le propriétaire avant la phase 0
- Plafonds de dépense : par mission, par jour, et globalement par mois chez chaque fournisseur.
- Clés API : réutiliser les clés déjà posées pour Claude Remote et Codex Remote, ou en créer de dédiées (recommandé : dédiées, pour suivre et révoquer séparément).
- Compte
agentsur les nœuds d'exécution : sa création demande sudo sur chaque nœud concerné. - Nœud du plan de contrôle : M4M64c proposé.
- Premier domaine à viser après le socle : programmation, recherche ou analyse financière.