Phase 20 : Architecture de bots fédérés
Arc OS — de "un bureau" à "centre de commande pour tous les projets" Auteur : Rick (Lead Architect) | Date : 2026-04-02 Statut : 20.1–20.5 COMPLET Approuvé par : CEO
Le problème
Le CEO gère plusieurs projets (Arc OS, Msolution, RTS_001) depuis un téléphone. Architecture actuelle : un bot Telegram → une session Claude → une fenêtre de contexte. Ça casse à 3+ projets :
- Pollution de la fenêtre de contexte (200K tokens partagés entre projets sans rapport)
- Pas d'isolation de projet (le code msolution fuite dans les prompts citadel)
- Pas de capacité multi-utilisateur (impossible d'inviter un designer dans le chat d'un projet)
- Contexte de réponse cassé (répondre à un message du mauvais projet = chaos)
La solution : la fédération
CEO ↔ @citadel_master_bot (Master) ← commandes globales uniquement
│
├── /status → interroge tous les enfants
├── /emergency-stop → signal kill à tous
├── /deploy all → déploiement en cascade
│
├── @citadel_v2_bot (Enfant 1) ← chat séparé, contexte séparé
│ └── Session Claude #1, cwd=/opt/repos/citadel-v2
│
├── @msolution_bot (Enfant 2) ← peut ajouter un designer au chat
│ └── Session Claude #2, cwd=/opt/repos/msol
│
└── @rts_bot (Enfant 3) ← peut ajouter l'agent Morty
└── Session Claude #3, cwd=/opt/repos/rts-001
Analyse de décision : Bot unique vs Fédération
Option A : Bot unique + sélecteur de projet
| Critère | Évaluation | Détails |
|---|---|---|
| Complexité du code | Faible (1 bot) | Ajouter variable activeProject, /switch change le cwd |
| Isolation du contexte | FAIBLE | Une session Claude = une fenêtre de contexte pour tous les projets. Changer pollue le contexte. |
| Commodité CEO | Moyenne | Doit se souvenir de /switch. Risque : envoyer tâche au mauvais projet. Pas de séparation visuelle. |
| Multi-utilisateur | IMPOSSIBLE | Un chat = un CEO. Impossible d'inviter des gens dans un chat scopé au projet. |
| Contexte de réponse | CASSÉ | Répondre à un message d'un autre projet = Claude confus. |
Verdict : Fonctionne pour CEO solo avec 1-2 projets. Casse à 3+.
Option B : Bots fédérés (Master + Enfants) — RETENU
| Critère | Évaluation | Détails |
|---|---|---|
| Complexité du code | Moyenne (N+1 bots) | Chaque bot = tmux séparé + session Claude. Master = coordinateur léger. |
| Isolation du contexte | PARFAITE | Chaque session Claude = fenêtre de contexte propre, CLAUDE.md propre, cwd propre. Zéro pollution. |
| Commodité CEO | ÉLEVÉE | Chats Telegram séparés = "salles" séparées. Glisser entre projets. UX mobile native. |
| Multi-utilisateur | NATIF | Ajouter @designer au chat @msolution_bot. Il voit seulement son projet. |
| Contexte de réponse | PARFAIT | Répondre dans le chat @citadel_v2_bot = 100% contexte citadel. Telegram préserve nativement le fil. |
Verdict : Solution correcte. Plus de complexité infra, mais résout TOUS les problèmes.
Pourquoi la fédération gagne
- Isolation du contexte — facteur décisif. Une session Claude pour 3+ projets = débordement du contexte en 30 minutes de travail actif. La fédération donne à chaque projet 200K tokens propres.
- Préparation multi-utilisateur — pas une "future fonctionnalité", c'est une fondation. Sans ça Arc OS ne peut pas devenir un produit.
- Réponse = RAG natif — Telegram a déjà résolu le problème de contexte. On mappe juste réponse → prompt GSD.
Architecture Emergency Stop
CEO tape /emergency-stop dans le chat Master
│
▼
Master Bot (Node.js/Bun, léger, PAS une session Claude)
│
├── 1. Lire config/bot_registry.json
│ { "children": [
│ { "name": "citadel-v2", "tmux": "citadel", ... },
│ { "name": "msolution", "tmux": "msolution", ... }
│ ]}
│
├── 2. Pour chaque enfant (en parallèle) :
│ a) tmux send-keys -t $SESSION "C-c" Enter ← gracieux : Ctrl+C
│ b) sleep 2
│ c) tmux send-keys -t $SESSION "/exit" Enter ← sortie explicite
│ d) sleep 2
│ e) tmux kill-session -t $SESSION ← kill forcé si encore en vie
│
├── 3. Mettre à jour office-state.json : tous les agents → idle
│
└── 4. Répondre au chat Master :
"EMERGENCY STOP exécuté.
citadel-v2 : ARRÊTÉ (était : travaillant sur les hooks)
msolution : ARRÊTÉ (était : idle)
Tous les agents réinitialisés en idle."
Protocole de kill (3 niveaux)
| Niveau | Action | Timeout | Quand |
|---|---|---|---|
| 1. Gracieux | Ctrl+C via tmux |
2s | Toujours en premier |
| 2. Explicite | commande /exit |
2s | Si gracieux n'a pas fonctionné |
| 3. Forcé | tmux kill-session |
immédiat | Dernier recours |
Failsafe
Tâche cron toutes les 5 minutes vérifie /tmp/emergency-stop.flag. Si le fichier existe et est récent (<10 min), exécute la séquence de kill. Couvre le cas où le Master Bot lui-même a crashé.
Smart Context Recall
Problème
Le CEO répond à un message vieux de 3 jours et dit "fais pareil mais pour un autre module". Claude n'a aucune idée du message référencé.
Solution : Transformation Réponse → Prompt GSD
L'API Telegram Bot fournit l'objet reply_to_message avec le texte original complet.
CEO répond à : "J'ai déployé les hooks sur VPS, tout fonctionne"
CEO écrit : "fais pareil pour msolution"
│
▼
Child Bot reçoit :
{
"message": {
"text": "fais pareil pour msolution",
"reply_to_message": {
"text": "J'ai déployé les hooks sur VPS, tout fonctionne",
"date": 1743580800,
"message_id": 847
}
}
}
│
▼
Le bot construit le prompt GSD pour Claude :
┌─────────────────────────────────────────────┐
│ CONTEXT (depuis la réponse) : │
│ > [2026-04-02] "J'ai déployé les hooks │
│ > sur VPS, tout fonctionne" │
│ │
│ TÂCHE (nouveau message) : │
│ "fais pareil pour msolution" │
│ │
│ PROJET : msolution (depuis le scope bot) │
└─────────────────────────────────────────────┘
Deep Recall (messages plus anciens)
Couche 1 : Historique du fil (rapide)
Le bot stocke les 50 derniers messages dans state/thread_history.json par chat.
Réponse → le bot trouve l'original → injecte dans le bloc CONTEXT.
Couche 2 : Recall de bibliothèque (fallback)
Si le message n'est pas dans l'historique du fil (>50 msgs auparavant) →
le bot lance /citadel-recall avec le texte de la réponse →
tire le contexte depuis library-export/ → injecte dans le prompt.
Flux : reply_to_message → thread_history → library-export/ → prompt GSD
Principe clé
Claude ne sait JAMAIS rien sur les réponses Telegram directement. Le middleware du bot TRANSFORME TOUJOURS la réponse en bloc propre CONTEXT + TÂCHE avant d'envoyer à la session Claude.
Spécification du Master Bot
Ce qu'est le Master Bot
- Service léger Bun/Node.js (~300 lignes)
- API Telegram Bot (long-polling)
- Lit
config/bot_registry.jsonpour le registry des enfants - Endpoint HTTP santé :
/api/master/health - Conteneur Docker dans compose partagé
Ce que le Master Bot N'EST PAS
- PAS une session Claude (pas d'IA, pas d'appels LLM)
- PAS un proxy de messages (ne transfère pas les messages aux enfants)
- PAS un store d'état (lit l'état depuis les fichiers des enfants)
Protocole Child Bot
Chaque child bot doit :
- S'enregistrer dans
config/bot_registry.jsonau démarrage - Envoyer un heartbeat (toutes les 60s) au Master via fichier :
state/heartbeat_<name>.json - Gérer
reply_to_message→ injection CONTEXT GSD - Stocker les 50 derniers messages dans
state/thread_history.json - Répondre au signal emergency-stop (gracieux Ctrl+C → /exit → kill)
- Utiliser le logger structuré (
shared/logger.ts) — logs vers/var/log/citadel/<name>/ - Accepter la variable env
BOT_NAMEpour le nommage dynamique - Exposer
/api/child/healthpour les vérifications santé watchdog
Estimation des ressources
| Ressource | Actuel | Phase 20 |
|---|---|---|
| RAM VPS | ~4 Go utilisé / 11 Go total | ~5,5 Go (+ ~500 Mo par session enfant) |
| Conteneurs Docker | 2 (bridge + frontend) | 4-5 (+ master + 2 enfants) |
| Tokens bot Telegram | 1 | 3-4 (@BotFather, gratuit) |
| Sessions tmux | 1 (citadel) | 3-4 (master + enfants) |
| Ports | 18889, 19200 | + 19201-19203 (APIs enfants) |
Sous-phases de la Phase 20
20.1 — Fondation Master Bot
- Bot Telegram Bun + TypeScript (long-polling)
config/bot_registry.json— registry enfants- Commandes :
/status,/emergency-stop,/list,/health - Conteneur Docker dans
docker/docker-compose.yml - Endpoint santé :
/api/master/health - Pas d'IA, pas de session Claude — orchestrateur pur
20.2 — Protocole Child Bot (Premier enfant)
- Définir le protocole d'enregistrement child bot
- Middleware message :
reply_to_message→ injection CONTEXT GSD - Historique fil : 50 derniers messages dans
state/thread_history.json - Protocole d'arrêt gracieux (réagir à emergency-stop)
- Pilote : migrer
@citadel_v2_botdepuis Claude Channel vers bot personnalisé - Heartbeat au Master (toutes les 60s via fichier)
20.3 — Moteur d'onboarding (FAIT)
/new_project <name>— interview interactive en 4 étapes- Matching de skills (registry + bibliothèque), détection de blueprint
- Auto-provisioning : répertoires, CLAUDE.md, MANIFEST.md, .env, registry, tmux
20.4 — Bibliothèque de skills & suppression de projet (FAIT)
/remove_project <name>— triple confirmation + noms protégés- Skills de bibliothèque auto-matchés et copiés pendant l'onboarding
- Hook de rechargement du registry pour les mises à jour en mémoire
20.5 — Infrastructure Phantom-Ready (FAIT)
shared/logger.ts— logging structuré JSONL, découpage quotidien par fichiershared/vault.ts— secrets chiffrés AES-256-GCM (tokens dans vault, pas .env)master-bot/watchdog.ts— moniteur auto-réparant avec backoff exponentiel- Commande
/watchdogpour statut en temps réel des enfants - Config logrotate + script setup VPS
- Tous les console.log → logger structuré
Commandes Master Bot (final)
| Commande | Action | Réponse |
|---|---|---|
/status |
Lire état + santé + heartbeat de tous les enfants | Tableau de bord agrégé |
/emergency_stop |
Séquence de kill à 3 niveaux sur tous les enfants | Confirmation avec statut par enfant |
/list |
Afficher les enfants enregistrés | Nom, statut, session tmux |
/deploy <name|all> |
Déclencher le déploiement pour un/des enfant(s) | Log de déploiement par enfant |
/health |
Vérifier les endpoints santé de tous les enfants | Matrice de santé |
/new_project <name> |
Démarrer l'interview d'onboarding | Conversation en 4 étapes |
/remove_project <name> |
Supprimer le projet avec confirmation | Triple confirmation + nettoyage |
/watchdog |
Afficher le statut watchdog | Échecs, redémarrages, backoff par enfant |
/cancel |
Annuler l'opération active | Abandonner onboarding/suppression |
Hors périmètre (Phase 21+)
- Multi-tenancy SaaS (JWT, facturation Stripe)
- Tableau de bord web alternatif à Telegram
- Commandes vocales via Telegram
- Éditeur de sprites d'agents et personnalisation du bureau
- Mécanisme de rotation de clé vault
- Monitoring santé peer multi-VPS
Architecture Phase 20 par Rick (Lead Architect). Phases 20.1–20.5 complètes. Approuvé par CEO 2026-04-02.