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 :

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

  1. 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.
  2. Préparation multi-utilisateur — pas une "future fonctionnalité", c'est une fondation. Sans ça Arc OS ne peut pas devenir un produit.
  3. 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

Ce que le Master Bot N'EST PAS

Protocole Child Bot

Chaque child bot doit :

  1. S'enregistrer dans config/bot_registry.json au démarrage
  2. Envoyer un heartbeat (toutes les 60s) au Master via fichier : state/heartbeat_<name>.json
  3. Gérer reply_to_message → injection CONTEXT GSD
  4. Stocker les 50 derniers messages dans state/thread_history.json
  5. Répondre au signal emergency-stop (gracieux Ctrl+C → /exit → kill)
  6. Utiliser le logger structuré (shared/logger.ts) — logs vers /var/log/citadel/<name>/
  7. Accepter la variable env BOT_NAME pour le nommage dynamique
  8. Exposer /api/child/health pour 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

20.2 — Protocole Child Bot (Premier enfant)

20.3 — Moteur d'onboarding (FAIT)

20.4 — Bibliothèque de skills & suppression de projet (FAIT)

20.5 — Infrastructure Phantom-Ready (FAIT)

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+)


Architecture Phase 20 par Rick (Lead Architect). Phases 20.1–20.5 complètes. Approuvé par CEO 2026-04-02.