Aller au contenu

PD-290 — Dashboard mobile d'arbitrage pour sessions Claude Code parallèles

1. Contexte

Le workflow de gouvernance ProbatioVault lance jusqu'à X sessions Claude Code en parallèle (une par story active). Chaque session est une machine à états finis (FSM) à 11 étapes qui peut se bloquer en attente d'une décision humaine : gate PMO (⅗/8), question d'expression de besoin, arbitrage d'ambiguïté architecturale.

Aujourd'hui, il est impossible depuis un téléphone de : - Voir l'état agrégé de toutes les sessions actives - Répondre à une session bloquée sur une question simple (GO/NON_CONFORME) - Avoir une conversation avec une session bloquée sur une question complexe

2. Problème

Absence de visibilité et de contrôle mobile sur un ensemble de sessions Claude Code parallèles.

Cas concrets non couverts : - 3 sessions actives simultanément, impossible de savoir laquelle est bloquée sans ouvrir chaque terminal - Gate 5 bloquée en attente d'un arbitrage architectural — pas de moyen de répondre depuis le téléphone - Nuit/weekend : impossible de débloquer une session urgente à distance

3. Solution — Architecture à deux composants

Composant 1 — Canal iMessage natif (Claude Code Channels)

Chaque session de gouvernance démarre avec le channel iMessage :

claude --channels plugin:imessage@claude-plugins-official

Routage multi-session par préfixe obligatoire : - [PD-285] GO gate 5 → seule la session PD-285 traite le message - [PD-285] Explique pourquoi tu proposes cette architecture → conversation complexe - [ALL] status → broadcast, chaque session répond son état dans iMessage - Messages sans préfixe reconnu → ignorés silencieusement

Les sessions filtrent sur leur propre préfixe [PD-XXX] et sur [ALL]. La réponse arrive directement dans iMessage, sur le thread de self-chat.

Composant 2 — Dashboard read-only local (Flask)

Page web légère, accessible en WiFi local uniquement, qui agrège l'état de toutes les sessions via lecture des WORKFLOW-STATE.md.

Fonctionnalités : - Liste de toutes les stories actives avec leur étape courante (step 0–10) - Indicateur d'état : RUNNING / BLOCKED / DONE / FAILED - Motif de blocage si disponible (ex: "En attente Gate 5") - Horodatage du dernier changement d'état - Refresh automatique (polling côté client, intervalle configurable, défaut 30s)

Ce que le dashboard ne fait pas : aucune action, aucun bouton, aucune saisie. Toute interactivité passe par iMessage.

4. Exigences fonctionnelles

EF-01 — Configuration iMessage par session

Chaque session governance doit être lancée avec --channels plugin:imessage@claude-plugins-official. Les hooks de démarrage du workflow (gov-workflow.sh) intègrent ce flag automatiquement.

EF-02 — Filtre de routage strict

Chaque session filtre les messages entrants sur son préfixe [PD-XXX] exact et sur [ALL]. Un message [PD-285] ... n'est traité que par la session PD-285. Un message sans préfixe reconnu est ignoré (pas de réponse).

EF-03 — Commande broadcast [ALL] status

Toutes les sessions actives répondent dans iMessage avec leur état courant :

[PD-285] Step 5 — BLOCKED (Gate 5, en attente arbitrage)
[PD-286] Step 6 — RUNNING (agent 3/7)
[PD-287] Step 9 — DONE

EF-04 — Dashboard agrégateur

Serveur Flask local lisant les WORKFLOW-STATE.md de toutes les stories actives. Refresh automatique côté client (meta refresh ou fetch polling, intervalle 30s par défaut). Accessible sur http://localhost:5290 en WiFi local.

EF-05 — Hooks governance modifiés

gov-workflow.sh et les scripts de démarrage de step intègrent le flag --channels automatiquement. Pas de modification manuelle requise lors du lancement d'une story.

5. Invariants

ID Invariant
INV-01 Les sessions continuent si le dashboard Flask est down (indépendance totale)
INV-02 Dashboard strictement read-only — aucune action depuis l'interface web
INV-03 Idempotence iMessage — un double envoi du même message n'a pas d'effet secondaire
INV-04 Filtre de routage strict — une session ne traite que les messages avec son préfixe exact
INV-05 Dashboard accessible en WiFi local uniquement — pas d'exposition internet
INV-06 iMessage self-chat uniquement (send to self) — pas d'accès par tiers

6. Hors scope

  • Cloudflare Tunnel ou exposition internet du dashboard
  • Authentification du dashboard (read-only local = risque minimal)
  • Boutons d'action dans le dashboard
  • response.json (remplacé par iMessage)
  • Application native iOS
  • Multi-utilisateur
  • Remote Control (couvert nativement par Anthropic pour le cas mono-session)
  • Notifications push ntfy (déjà en place dans local-agent-ops, hors scope de cette story)

7. Dépendances

Dépendance Source État
WORKFLOW-STATE.md Chaque epic directory Existant
Claude Code Channels — iMessage plugin claude-plugins-official Disponible (research preview, v2.1.80+)
Hooks governance (gov-workflow.sh) ia-governance/scripts À modifier
Flask pip À installer
Bun système Requis par les plugins Channels

8. Critères d'acceptation

  • [PD-XXX] GO envoyé depuis iPhone → session concernée traite, autres ignorent
  • [ALL] status → chaque session active répond dans iMessage avec son état
  • Message sans préfixe → ignoré silencieusement, pas de réponse
  • Dashboard localhost:5290 affiche toutes les sessions actives avec refresh 30s
  • Dashboard reste accessible si une session est down
  • Lancer ./scripts/gov-workflow.sh PD-XXX backend intègre automatiquement --channels

9. Questions ouvertes

  • Bun : vérifier si Bun est installé sur le MacBook Pro. Si non, l'installer est un prérequis bloquant pour le plugin iMessage.
  • Refresh interval : 30s est le défaut — faut-il un contrôle manuel (bouton "refresh maintenant") dans le dashboard ?
  • Persistance iMessage : les réponses restent dans Messages.app — convient comme historique d'arbitrage.
  • Préfixe case-sensitive : [PD-285] vs [pd-285] — normaliser en majuscules.