SPB Git

Repository Public

ARCHITECTURE.md 38.7 KB 465 lines markdown

1# Agent.spboucher.ai — Architecture du système d'exploitation agentique23Version 0.1 — 10 novembre 2026. Document de conception : rien de ce qui suit n'est encore construit.4Les constats cités viennent des quatre rapports de `docs/research/` (sources et dates y figurent) ; les choix5d'architecture sont les miens et sont signalés comme tels.67## 1. Ce que nous construisons, et ce que nous ne construisons pas89**Objet.** Une plateforme agentique dont nous possédons tout le code : la boucle d'agent, l'orchestration des10sous-agents, la mémoire, les outils, l'exécution durable et la console Web. Les modèles d'Anthropic et d'OpenAI11(et plus tard des modèles locaux) sont des fournisseurs interchangeables derrière une interface à nous.1213**Ce n'est pas** une surcouche de Claude Code ou de Codex (c'est le rôle de Claude Remote et Codex Remote), ni14un assemblage de LangGraph/CrewAI/AutoGen. Nous n'utilisons aucun framework agentique tiers ; nous reprenons15leurs meilleurs mécanismes et évitons leurs défauts documentés.1617**Non-objectifs assumés** (tirés de la recherche) :1819- pas d'isolation multi-locataire : un seul propriétaire ;20- pas de garantie « exactement une fois » sur les effets externes — personne ne l'offre ; nous visons « au moins21  une fois, résultat enregistré une seule fois, effets idempotents ou réconciliés » ;22- pas de discussion de groupe libre entre agents, pas d'« équipe » à rôles avec gestionnaire automatique, pas23  d'essaim de pairs : ce sont les formes qui échouent le plus dans les études (MAST, Cognition) ;24- pas de filtre anti-injection par prompt ni de juge LLM comme barrière de sécurité : la sécurité est structurelle ;25- pas de graphe de connaissances, pas de base vectorielle dédiée, pas de fine-tuning au départ ;26- pas de Temporal/Kubernetes : un processus de contrôle + PostgreSQL suffisent à cette échelle.2728## 2. Ce que la recherche impose2930| Constat (source dans `docs/research/`) | Conséquence de conception |31|---|---|32| 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 |33| 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 |34| 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 |35| 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 |36| 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 |37| 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 |38| 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 |39| 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 |40| 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 |4142## 3. Vue d'ensemble4344```45 Navigateur (bureau, tablette, téléphone, PWA)46        │ HTTPS + WSS  (Caddy sur BHS64 → WireGuard)47        ▼48┌──────────────────────── PLAN DE CONTRÔLE (un nœud toujours allumé) ─────────────────────────┐49│  Passerelle API        auth, REST /api/v1, flux d'événements WS, approbations, console       │50│  Noyau (kernel)        journal · ordonnanceur · baux · budgets · politique · minuteries       │51│  Moteur d'agent        boucle modèle↔outils, contexte, compaction, sous-agents, vérification  │52│  Routeur de modèles    adaptateurs Anthropic / OpenAI / local, tarifs, limites, bascule       │53│  Mémoire               dépôts git Markdown + index Postgres (plein texte + pgvector)          │54│  Courtier d'outils     registre, MCP, skills, proxy de sortie, coffre à secrets              │55│  PostgreSQL 17         journal, files, index mémoire, audit, métriques                        │56└───────────────┬───────────────────────────────────────────────────────────────────────────────┘57                │ SSH restreint (commande forcée) + RPC JSON sur stdio58                ▼59┌──────────────────────── PLAN D'EXÉCUTION (nœuds MacLustr autorisés) ────────────────────────┐60│  Exécuteur (runner)    reçoit une étape, l'exécute dans un bac à sable, renvoie le résultat   │61│  Niveau 0  lecture seule, pas de shell     Niveau 1  Seatbelt + worktree + proxy              │62│  Niveau 2  VM Linux jetable (Apple container)   Niveau 3  VM macOS (GUI, AppleScript)         │63└───────────────────────────────────────────────────────────────────────────────────────────────┘64```6566Principe directeur : **le plan de contrôle décide et consigne, le plan d'exécution agit et ne décide de rien**.67Les exécuteurs ne réclament jamais de travail eux-mêmes ; ils reçoivent une étape signée par un bail et rendent un68résultat. Tout l'état vit dans PostgreSQL ; n'importe quel processus peut mourir sans perte.6970## 4. Le noyau : journal, étapes, reprise7172### 4.1 Modèle de données central7374- **Mission** : objectif du propriétaire, projet, budget global, définition du « terminé ».75- **Exécution (run)** : une instance d'agent — racine ou sous-agent — avec son contrat, son modèle, son espace76  de travail, son budget, son parent. Les exécutions forment un arbre.77- **Étape (step)** : l'unité journalisée. Types : `model_call`, `tool_call`, `spawn`, `join`, `wait_human`,78  `timer`, `compaction`, `checkpoint`, `verdict`. Chaque étape a un numéro de séquence stable dans son exécution.79- **Événement** : enregistrement en ajout seul (`events`), partitionné par mois : tout ce qui s'est passé, avec80  niveau de confiance de la source (propriétaire > raisonnement d'agent > sortie d'outil > contenu Web).81- **Artefact** : fichier adressé par contenu (sorties volumineuses, rapports, diffs) ; le contexte n'en garde82  qu'un aperçu et le chemin.8384### 4.2 Sémantique d'exécution85861. Avant chaque étape, le moteur écrit une **intention** (`step_started` avec le hachage de la requête).872. L'étape s'exécute ; son **résultat** est écrit dans la même transaction que la mise à jour d'état88   (jetons, coût, ledger).893. À la reprise, le moteur relit le journal de l'exécution : toute étape qui a un résultat le **renvoie tel90   quel** ; la boucle repart à la première étape sans résultat.914. Une étape avec intention mais sans résultat est traitée selon sa **classe d'effet** :9293| Classe (déclarée par l'outil) | Exemples | Au redémarrage |94|---|---|---|95| `read` | lire un fichier, grep, recherche Web | rejouée |96| `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 |97| `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 |98| `model_call` | appel LLM | rejoué (aucun effet externe) ; le coût perdu est comptabilisé |991005. **Baux et jetons de clôture** : une exécution active détient un bail renouvelé toutes les 30 s et un jeton101   monotone vérifié à chaque écriture d'état. Un processus zombie dont le bail a été repris ne peut plus rien écrire.1026. **Attentes durables** : approbation humaine, minuterie, attente d'un sous-agent = une ligne dans le journal,103   pas un processus bloqué. Une approbation peut attendre des jours ; le délai expiré vaut refus.1047. **Annulation** : propagée de la racine aux feuilles ; chaque exécuteur tue son groupe de processus.1058. **Versionnage** : chaque exécution enregistre la version du moteur et le hachage de son prompt système et de106   sa liste d'outils. Une exécution longue reprend avec la version qui l'a lancée (les anciennes versions restent107   installées tant qu'une exécution les référence) ou est migrée explicitement à un point de contrôle.108109**Pourquoi notre propre noyau plutôt que DBOS/Restate/Temporal** (choix, contre la recommandation n° 1 du110rapport 4) : l'exigence est de contrôler l'orchestration de bout en bout ; à l'échelle d'un seul propriétaire le111débit n'est pas un problème, seule la justesse l'est ; et nos besoins (classes d'effet, réconciliation, budgets112hiérarchiques, bifurcation depuis une étape) dépassent ce que ces moteurs journalisent. Le prix est la justesse,113donc le noyau reste petit (journal, baux, minuteries, files `SKIP LOCKED`) et il est validé par des **tests de114chaos** : tuer le processus à chaque frontière d'étape et vérifier qu'aucune étape n'est perdue ni doublée. DBOS115reste la solution de repli si ces tests ne passent pas.116117## 5. Le moteur d'agent118119### 5.1 Boucle120121Un tour = une réponse du modèle + l'exécution de ses appels d'outils. Les outils `read` d'un même tour122s'exécutent en parallèle, les écritures en série. La boucle s'arrête sur : réponse sans appel d'outil, budget123atteint, plafond de tours, annulation, ou refus du crochet d'arrêt (§ 5.5). États terminaux typés :124`done`, `partial`, `blocked`, `failed`, `cancelled`, `budget_exhausted` — un agent tué par une erreur ne125« réussit » jamais.126127Pilotage en cours de route : un message du propriétaire est mis en file et lu dès la fin des appels d'outils en128cours, dans le même tour ; l'interruption annule l'outil en cours.129130### 5.2 Assemblage du contexte (ordre figé, favorable au cache)131132```133[outils — liste figée, ordre déterministe]134[système — rôle, règles, format ; aucun horodatage ni identifiant volatil]135[index mémoire — instantané pris au lancement, puis gelé]136[messages — en ajout seul]137```138139- Tout changement en cours de route (mode, rappel, fichier modifié) est **ajouté** comme message, jamais édité140  dans le préfixe.141- Les outils nombreux (MCP, skills) sont différés : seuls leurs noms et descriptions courtes entrent en contexte ;142  le schéma se charge à la demande et s'ajoute sans invalider le cache.143- Fichiers d'instructions par projet (`AGENTS.md`, lu aussi si c'est un `CLAUDE.md`) : courts, table des matières144  vers la documentation ; les invariants sont imposés par des tests et des crochets, pas par de la prose.145146### 5.3 Soulager le contexte, par paliers1471481. **Déchargement** : tout résultat d'outil au-delà d'environ 3 000 jetons va dans un artefact ; le contexte149   garde un aperçu et le chemin.1502. **Effacement** des anciens résultats d'outils, par lots assez gros pour amortir la réécriture du cache151   (primitive native côté Anthropic ; équivalent géré par nous côté OpenAI).1523. **Compaction** vers 50–60 % de la fenêtre, avec **notre** résumé structuré et lisible : objectif, contraintes,153   décisions, fichiers touchés, faits vérifiés avec identifiants d'événements, problèmes ouverts, prochaines154   étapes ; consignes du propriétaire, messages d'erreur, identifiants et chemins conservés mot pour mot. La155   compaction des fournisseurs sert de transport quand elle existe, mais notre résumé est toujours écrit au journal156   (celle d'OpenAI est chiffrée et illisible — inacceptable comme seule trace).1574. **Réhydratation** après compaction : instructions, plan, ledger, index mémoire et quelques fichiers récents158   sont relus depuis le disque, avec plafond par élément et garde anti-emballement.159160### 5.4 Sous-agents et orchestration161162**Contrat de délégation** (objet typé, refusé s'il manque le critère de fin) :163164```165objective        ce qu'il faut accomplir, en une ou deux phrases166context_refs     artefacts, fichiers, entrées de mémoire à lire (références, pas de copie)167boundaries       ce qui est hors périmètre ; fichiers possédés ; interdits168output_schema    schéma JSON du résultat attendu169tools            liste blanche d'outils et niveau de bac à sable170model, effort    choisis par le routeur ou imposés171budget           jetons, dollars, tours, durée172done_criteria    vérifiable par machine quand c'est possible173context_mode     fresh (défaut) | fork (copie du journal parent) | artifact_only174```175176**Enveloppe de résultat** : `status`, charge utile validée par le schéma, références d'artefacts, liste de177preuves (commande exécutée, test passé, source citée), questions ouvertes. Le parent ne reçoit que cette178enveloppe ; les gros livrables restent en artefacts. Le texte de l'enveloppe est marqué comme donnée et analysé179pour repérer des instructions injectées.180181**Formes d'orchestration autorisées** (toutes exprimées en code ordinaire, étapes journalisées — pas de langage182de graphe) :183184- *orchestrateur → travailleurs en lecture* : recherche, exploration de code, revue, analyse ; éventail puis185  rassemblement ; les frères qui ont réussi ne sont pas rejoués si l'un échoue ;186- *écrivains isolés* : un worktree git par écrivain, fusion unique par le parent, conflits renvoyés à un agent ;187- *planificateur → exécutant → évaluateur* pour le travail long (§ 5.5) ;188- *conseiller* : un modèle plus fort consulté ponctuellement par un exécutant moins cher.189190**Ledger du superviseur** (inspiré de Magentic-One et des listes de fonctionnalités d'Anthropic) : éléments de191plan avec propriétaire, statut et preuve, plus une liste de faits établis. Un travailleur ne peut modifier que ses192propres éléments, et seulement en joignant une preuve.193194**Limites imposées par le runtime**, jamais par le prompt : profondeur 3, concurrence par mission configurable195(12 par défaut, plafond global lié aux limites de débit des fournisseurs), budget par sous-arbre — la dépense196d'un enfant est débitée au parent.197198### 5.5 Planification et vérification199200- **Définition du terminé écrite avant le travail** : pour le code, une liste de critères en JSON dont seul le201  champ `passes` est modifiable ; pour la recherche, les questions auxquelles répondre et le niveau de preuve ;202  pour l'analyse financière, les chiffres à reproduire et leur tolérance.203- **Oracles déterministes d'abord** : tests, vérification de types, lint ; ré-exécution des analyses numériques204  depuis une copie propre et comparaison ; pour la recherche, re-téléchargement du passage cité.205- **Évaluateur à contexte propre** : il voit l'artefact et les critères, pas le raisonnement du travailleur ; de206  préférence un modèle d'un autre fournisseur ; il doit citer ses preuves. Un juge LLM n'est jamais seul arbitre207  quand un contrôle exécutable existe.208- **Crochet d'arrêt** : la mission ne peut se déclarer terminée que si les critères passent ; sinon la boucle209  reprend ou escalade.210- **Détection de blocage** (déterministe) : mêmes appels d'outils répétés, ledger inchangé depuis N étapes,211  plafonds atteints → une replanification, puis escalade au propriétaire.212- **Travail sur plusieurs jours** : routine fixe à chaque reprise — lire le fichier de progression et le journal213  git, lancer le test de fumée, traiter une unité, vérifier, valider (commit), mettre à jour la progression.214215## 6. Mémoire216217Principes : la transcription est la source de vérité, toute mémoire en est une vue dérivée et reconstructible ;218fichiers pour ce que les agents lisent et écrivent, Postgres pour ce que le système indexe ; on ajoute et on219invalide, on n'écrase pas ; le contenu non fiable n'écrit jamais en mémoire durable sans garde.220221| Couche | Durée | Support | Contenu |222|---|---|---|---|223| 0. Journal | permanent | Postgres `events` (plein texte) + artefacts | tout ce qui s'est passé |224| 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 |225| 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 |226| 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 |227228- Chaque portée a un `MEMORY.md` d'au plus 200 lignes (une ligne par fiche) ; seuls l'index global et celui du229  projet courant sont injectés. Les fiches se lisent à la demande.230- En-tête de fiche : type, événements sources, `verified`, `valid_from`, `invalid_at`, confiance, auteur.231- **Lecture** : d'abord agentique (lire l'index, ouvrir, grep). Un outil `memory_search` complète : plein texte232  + pgvector, fusion par rangs réciproques, filtre par portée et validité, léger a priori de récence ; il renvoie233  des extraits avec chemin et provenance. Le code n'est pas vectorisé : les agents font grep dans l'arbre de travail.234- **Écriture** : libre dans les notes d'exécution et de projet. Les écritures vers `global/`, les manuels d'agents235  et les skills passent par une branche de propositions.236- **Consolidation** (fin d'exécution, compaction, ou la nuit) : un agent relit les nouvelles transcriptions,237  vérifie les propositions contre le journal, dédoublonne, marque les fiches contredites `invalid_at`, applique des238  modifications par deltas aux manuels (ajouter, corriger, retirer une puce — jamais réécrire en entier), valide239  avec un message citant les événements, puis fusionne. Les changements de projet fusionnent seuls ; ceux de240  `global/` et des skills attendent l'approbation du propriétaire sur un diff.241- **Apprentissage par l'expérience** : une leçon n'est retenue que s'il existe un signal de résultat (test passé,242  confirmation du propriétaire) ; chaque puce de manuel porte des compteurs « a aidé / a nui » alimentés par les243  exécutions suivantes.244- **Garde-fous** : un fait issu uniquement du Web ou d'une sortie d'outil est stocké `verified=false`, jamais245  promu dans la couche injectée ni dans les skills sans corroboration ; `git revert` est le retour arrière ; un246  contrôle hebdomadaire vérifie la taille des index, les liens cassés, les fiches non vérifiées anciennes.247- **Reporté volontairement** : graphe de connaissances (on ne garde que les colonnes bi-temporelles), réécriture248  automatique des anciennes fiches, score d'importance appris, tableau partagé entre agents. À rouvrir seulement249  si un jeu d'évaluation propre au projet montre que la base « tout charger ou grep » est battue.250251## 7. Modèles et routage252253**Interface fournisseur unique** : `stream(conversation, outils, options) → événements normalisés`254(texte, raisonnement résumé, appel d'outil, usage, arrêt, refus). Un adaptateur par fournisseur garde la255transcription native intacte (les blocs de raisonnement d'Anthropic et les éléments chiffrés d'OpenAI sont256renvoyés tels quels) ; une conversation n'est donc jamais convertie d'un fournisseur à l'autre en cours de fil.257258- **Anthropic** : API Messages via le SDK officiel TypeScript, streaming, raisonnement adaptatif, `effort`,259  cache de prompt, effacement de résultats, budgets de tâche, repli côté serveur sur refus.260- **OpenAI** : API Responses (recommandée pour tout nouveau projet), sans état côté serveur.261- **Local (plus tard)** : point d'accès compatible servi par MLX sur un nœud Ultra ; aucun n'existe aujourd'hui.262263**Catalogue vivant** : la liste des modèles, fenêtres de contexte et capacités est lue auprès des API de modèles264des fournisseurs ; les tarifs sont dans une table versionnée. Relevé du 10 novembre 2026 :265266| Rôle | Anthropic | OpenAI | Prix entrée / sortie par million de jetons |267|---|---|---|---|268| Raisonnement le plus exigeant, longues missions | `claude-fable-5-2` | `gpt-6-astra` | 8 $ / 40 $ · 10 $ / 50 $ |269| Boucle principale par défaut | `claude-opus-5-5` | `gpt-6.1-sol` | 4 $ / 20 $ · 2 $ / 10 $ |270| Travailleurs, exploration, revue | `claude-sonnet-5-5` | `gpt-6.1-terra` | 2 $ / 10 $ · 1 $ / 5 $ |271| Volume : extraction, classement, résumés | `claude-haiku-5-5` | `gpt-6-luna` | 0,10 $ / 0,50 $ · 0,10 $ / 0,50 $ |272273**Politique de routage** (déclarative, modifiable dans la console) :2742751. le modèle est fixé **par exécution** ; changer de modèle = déléguer à un sous-agent ;2762. le premier levier de coût est l'**effort** sur un bon modèle, mesuré avant toute cascade ;2773. chaque rôle (planificateur, exécutant, évaluateur, consolidateur de mémoire, classifieur) a un modèle et un278   effort par défaut, surchargeables par mission ;2794. l'évaluateur est de préférence d'un autre fournisseur que l'exécutant ;2805. mode par lots (−50 %) pour le travail non urgent : consolidation nocturne, évaluations ;2816. bascule automatique vers l'autre fournisseur sur panne ou limite de débit, **uniquement à une frontière de282   sous-agent** ;2837. le coût est jugé **par tâche terminée**, jetons en cache comptés à part.284285## 8. Outils et intégrations286287Chaque outil est un objet typé : nom, description, schéma d'entrée, **classe d'effet**, **classe de risque**288(lecture / écriture dans l'espace de travail / réseau / externe ou irréversible), niveau de bac à sable minimal,289parallélisable ou non, sonde de réconciliation éventuelle.290291| Famille | Outils | Notes |292|---|---|---|293| 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 |294| 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 |295| Git | statut, diff, commit, branche, worktree, `push` (externe → approbation) | jetons courts et limités |296| 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 |297| Délégation | lancer un sous-agent, attendre, envoyer un message, lire le ledger | § 5.4 |298| Mémoire | voir, créer, modifier, rechercher | § 6 |299| Propriétaire | poser une question, demander une approbation, notifier | rendu spécifique dans la console |300| MacLustr | inventaire et télémétrie (agentd, lecture seule), soumettre une étape à un nœud | § 9 |301| macOS | AppleScript, automatisation d'interface | uniquement en VM macOS (niveau 3) |302| 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 |303| 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 |304305En frontière externe seulement : le protocole A2A (carte d'agent, tâches, états `input-required`) pour exposer ou306appeler des agents tiers ; en interne, nos enveloppes typées.307308## 9. Exécution et isolation sur MacLustr309310**Niveaux de bac à sable** (le niveau est choisi par la politique d'après la classe de risque de la mission) :311312| Niveau | Pour | Mécanisme | Réseau | Secrets |313|---|---|---|---|---|314| 0 | recherche en lecture | aucun shell ; récupération côté plan de contrôle | via le récupérateur | aucun |315| 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 |316| 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 |317| 3 | interface graphique macOS, AppleScript | VM macOS (Tart ou Lume, deux par hôte) | proxy | aucun |318319- Seatbelt est marqué obsolète par Apple mais applique toujours les profils sur macOS 27 (vérifié) ; c'est ce320  qu'utilisent Claude Code et Codex. Il n'existe pas de quota CPU dur hors VM sur macOS.321- **Répartition** : le plan de contrôle détient une clé SSH par nœud, restreinte par commande forcée (un seul322  programme : l'exécuteur), `restrict`, et adresse d'origine ; la cible est l'utilisateur `agent`. Ni le mot de323  passe sudo du cluster ni la clé de la passerelle ne servent au travail des agents.324- **Placement** : l'ordonnanceur choisit le nœud d'après la télémétrie réelle (agentd) et les besoins déclarés de325  l'étape ; les calculs lourds vont sur les nœuds Ultra, pas sur le plan de contrôle.326- **Proxy de sortie** : composant minimal, à jour, sur le plan de contrôle ; liste blanche par mission ; il injecte327  les identifiants HTTP à la sortie. C'est la cible la plus précieuse du système et il est traité comme tel328  (l'incident OpenAI/Hugging Face de juillet 2026 est passé par un proxy de ce type).329330## 10. Sécurité et permissions331332**Modèle de menace** : contenu hostile lu par un agent (Web, dépôt, document, sortie d'outil, serveur MCP),333erreur ou excès de zèle d'un agent, vol de la session Web du propriétaire. Pas d'attaquant interne.3343351. **Authentification de la console** : celle de Claude Remote, déjà éprouvée — mot de passe + second facteur336   obligatoire (passkey ou TOTP), cookies `__Host-`, CSRF, contrôle d'origine des WebSockets, limitation de débit,337   CSP stricte.3382. **Règle de deux par exécution** : une exécution ne cumule jamais sans humain plus de deux propriétés parmi339   (a) lire du contenu non fiable, (b) accéder à des secrets ou données sensibles, (c) changer un état externe ou340   communiquer vers l'extérieur. Un agent qui lit le Web n'a donc ni secrets, ni sortie hors liste blanche.3413. **Lecteur en quarantaine** : le contenu Web est lu par un sous-agent sans outils d'action, qui rend des données342   structurées ; l'agent qui agit ne voit jamais le texte brut. Plan-puis-exécution pour les missions sensibles.3434. **Permissions** : évaluation refuser → demander → autoriser, dans le harnais, pas dans le modèle. Les344   chemins auto-modifiants (`.git`, configuration d'agent, crochets, fichiers rc, transcriptions) sont protégés345   quelles que soient les règles.3465. **Approbations humaines durables** pour toute action externe ou irréversible : la console montre l'appel exact,347   sa justification et son diff ; l'attente peut durer des jours ; l'absence de réponse vaut refus. Pour limiter la348   fatigue : regroupement, règles « toujours autoriser ceci dans ce projet », et un classifieur facultatif qui349   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.3506. **Ce que l'agent écrit est non fiable** pour tout outil hors bac à sable : rien de ce qu'il a produit n'est351   exécuté ou interprété côté hôte sans diff ou revue.3527. **Canaux d'exfiltration fermés** : la console n'affiche pas automatiquement d'images ou de liens distants ; une353   URL sortante doit être sur la liste blanche ou déjà présente dans la tâche.3548. **Secrets** : dans le trousseau du plan de contrôle ; jamais dans un prompt, un environnement de bac à sable, un355   journal ou une fiche de mémoire (un nettoyeur de secrets filtre les écritures).3569. **Gouverneurs** : plafonds par exécution et par mission en dollars, jetons, durée, appels d'outils ; plafond357   quotidien global ; **bouton d'arrêt général** qui révoque les baux et les identifiants du proxy.35810. **Audit** : le journal est la piste d'audit ; chaque décision de politique et chaque approbation y figurent.359    Référentiel de contrôle : le Top 10 OWASP des applications agentiques 2026 (ASI01–ASI10), couvert point par360    point dans `docs/security.md` au moment de la construction.361362## 11. Protocoles363364- **Console ⇄ passerelle** : REST `/api/v1` (missions, exécutions, approbations, mémoire, réglages) et un flux365  WebSocket d'événements typés — cycle de vie `mission → exécution → étape → élément` avec `started / delta /366  completed`, et demandes d'approbation initiées par le serveur. Un seul protocole pour toutes les interfaces.367  Reprise du flux par curseur (dernier numéro d'événement reçu), donc aucune perte après une coupure mobile.368- **Passerelle ⇄ exécuteur** : RPC JSON sur stdio à travers SSH ; chaque requête porte l'identifiant d'étape, la369  clé d'idempotence, le jeton de bail et le profil de bac à sable ; la réponse est le résultat ou une référence370  d'artefact. L'exécuteur écrit son résultat sur disque avant de répondre, pour qu'une nouvelle tentative le relise.371- **Agents entre eux** : uniquement par le noyau — contrat, enveloppe, ledger, messages adressés. Pas de canal372  direct, donc tout est journalisé et rejouable.373- **Extérieur** : MCP pour les outils, A2A en frontière.374- **Observabilité** : chaque étape émet une trace OpenTelemetry (`gen_ai.*`, derrière une fine couche de375  correspondance car les noms sont encore instables) avec identifiants de mission, d'exécution, de parent et376  d'étape, jetons et coût. La table `events` reste la référence.377378## 12. La console379380Même socle que Claude Remote : Next.js en export statique, thème clair par défaut, PWA, pensée d'abord pour le381téléphone. Écrans :382383| Écran | Rôle |384|---|---|385| **Accueil** | ce qui attend le propriétaire (approbations, questions), missions en cours, dépense du jour, santé |386| **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 |387| **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) |388| **Approbations** | file d'attente avec l'action exacte, son contexte, son diff ; approuver, refuser, « toujours autoriser » |389| **Projets** | dépôts, instructions, critères, historique des missions |390| **Mémoire** | navigation dans les fiches, propositions en attente avec diff, historique git, invalidations |391| **Agents et politiques** | rôles, modèles et efforts par défaut, outils autorisés, niveaux de bac à sable, budgets |392| **Outils** | registre, serveurs MCP et leur état, skills |393| **Cluster** | nœuds, exécuteurs, bacs à sable actifs (télémétrie réelle) |394| **Coûts et traces** | dépense par mission, modèle et jour ; coût par tâche terminée ; lecture des traces |395| **Réglages** | sécurité, clés des fournisseurs (écriture seule), notifications, bouton d'arrêt général |396397Règles d'interface inchangées : aucune donnée inventée, horodatage de collecte visible, état inconnu affiché398comme tel. Sur téléphone, l'usage central est : voir ce qui attend, approuver ou répondre, relancer.399400## 13. Technologies401402| Besoin | Choix | Raison |403|---|---|---|404| 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 |405| Structure | monorepo pnpm : `kernel`, `engine`, `providers`, `memory`, `tools`, `runner`, `server`, `web`, `shared` | modules séparés, un seul déploiement |406| 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 |407| Files et minuteries | tables Postgres, `FOR UPDATE SKIP LOCKED`, `LISTEN/NOTIFY` comme simple sonnette + sondage lent | pas de Redis |408| Fournisseurs | `@anthropic-ai/sdk`, SDK officiel OpenAI | pas de couche de compatibilité |409| Validation | zod partout (contrats, enveloppes, entrées d'outils) | |410| Bac à sable | profils Seatbelt générés par nous (en s'inspirant du `sandbox-runtime` d'Anthropic, Apache-2.0), Apple `container`, Tart | |411| Navigateur | Playwright dans une VM de niveau 2 | |412| Console | Next.js 16 (export statique), Tailwind 4, composants de Claude Remote, React Flow pour l'arbre | |413| Traces | OpenTelemetry ; visualisation dans la console, Langfuse auto-hébergé seulement si nécessaire | |414| Tests | vitest, tests de chaos du noyau, Playwright, jeux d'évaluation par domaine | |415| Déploiement | `mld` + PM2, route MacLustr Tunnel, sauvegarde chiffrée nocturne | standard du cluster |416417**Placement proposé** : plan de contrôle sur **M4M64c** (64 Go, PostgreSQL déjà en service, 259 Go libres) ;418exécuteurs de niveau 1 et 2 sur m4mm, m4mn, m5ma, m6ma ; calcul lourd sur M3U96a et M3U96b ; M5M36 reste dédié à419Claude Remote et Codex Remote. Le DNS `agent.spboucher.ai` pointe déjà sur la passerelle.420421## 14. Plan de développement422423Chaque phase se termine par une démonstration vérifiable ; on ne passe pas à la suivante sans elle.424425| Phase | Contenu | Critère de sortie |426|---|---|---|427| **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 |428| **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 |429| **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 |430| **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 » |431| **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 |432| **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 |433| **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 |434| **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 |435| **8. Console complète** | arbre de mission, approbations sur téléphone, mémoire, coûts, traces, politiques | parcours complet sur vrai iPhone |436| **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 |437| **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 |438439Les phases 0 à 2 donnent déjà un agent utilisable ; chacune des suivantes ajoute une capacité mesurable.440441## 15. Risques assumés et points ouverts442443- **Justesse du noyau maison** : c'est le risque principal ; il est contenu par la petite taille du noyau et les444  tests de chaos, avec DBOS comme repli.445- **Coût** : une mission multi-agents de plusieurs heures peut coûter des dizaines à des centaines de dollars (les446  chiffres publiés vont de 9 $ en solo à 200 $ avec harnais complet). Les plafonds sont obligatoires dès la phase 2.447- **Injection** : aucune défense n'est fiable seule ; la protection repose sur la structure (règle de deux, bac à448  sable, approbations). Un agent qui lit le Web et agit sans humain reste un risque résiduel.449- **Limites de macOS** : pas de quota CPU dur hors VM ; deux VM macOS par hôte ; Apple resserre l'accès complet450  au disque. Le niveau 3 restera rare et supervisé.451- **Modèles qui progressent** : chaque élément du harnais compense une faiblesse d'un modèle ; il doit pouvoir452  être retiré. Les jeux d'évaluation servent aussi à décider quoi supprimer.453- **Non vérifié dans la recherche** : comportement détaillé de certaines fonctions OpenAI (sorties structurées,454  mode arrière-plan), performances des modèles d'embeddings sur MLX, disponibilité d'Apple `container` sur les455  nœuds. À confirmer au moment où chaque phase en a besoin.456457## 16. Décisions à prendre par le propriétaire avant la phase 04584591. **Plafonds de dépense** : par mission, par jour, et globalement par mois chez chaque fournisseur.4602. **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ées461   (recommandé : dédiées, pour suivre et révoquer séparément).4623. **Compte `agent` sur les nœuds d'exécution** : sa création demande sudo sur chaque nœud concerné.4634. **Nœud du plan de contrôle** : M4M64c proposé.4645. **Premier domaine à viser** après le socle : programmation, recherche ou analyse financière.465
Files main
Menu

Theme