SPB Git

Repository Public

ARCHITECTURE.md 38.7 KB

# 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

text
 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

  1. Avant chaque étape, le moteur écrit une intention (step_started avec le hachage de la requête).
  2. 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).
  3. À 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.
  4. 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é
  1. 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.
  2. 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.
  3. Annulation : propagée de la racine aux feuilles ; chaque exécuteur tue son groupe de processus.
  4. 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)

text
[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 un CLAUDE.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

  1. 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.
  2. 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).
  3. 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).
  4. 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) :

text
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_only

Enveloppe 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 passes est 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.md d'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_search complè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 de global/ 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 revert est 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) :

  1. le modèle est fixé par exécution ; changer de modèle = déléguer à un sous-agent ;
  2. le premier levier de coût est l'effort sur un bon modèle, mesuré avant toute cascade ;
  3. 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 ;
  4. l'évaluateur est de préférence d'un autre fournisseur que l'exécutant ;
  5. mode par lots (−50 %) pour le travail non urgent : consolidation nocturne, évaluations ;
  6. bascule automatique vers l'autre fournisseur sur panne ou limite de débit, uniquement à une frontière de sous-agent ;
  7. 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'utilisateur agent. 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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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).
  9. 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.
  10. 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.md au 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 vie mission → exécution → étape → élément avec started / 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 table events reste 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 container sur les nœuds. À confirmer au moment où chaque phase en a besoin.

# 16. Décisions à prendre par le propriétaire avant la phase 0

  1. Plafonds de dépense : par mission, par jour, et globalement par mois chez chaque fournisseur.
  2. 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).
  3. Compte agent sur les nœuds d'exécution : sa création demande sudo sur chaque nœud concerné.
  4. Nœud du plan de contrôle : M4M64c proposé.
  5. Premier domaine à viser après le socle : programmation, recherche ou analyse financière.
Files main
Menu

Theme