# Design — Option 1 « Terminal + MCP » (orchestration inter-agents) > Décision produit arbitrée (2026-06-11). Remplace la vue chat structurée par le > terminal natif + délégation inter-agents par outils MCP. Source : agent Architecte. > Statut : **design validé, dev NON commencé** (limite de session atteinte le 2026-06-11, > reset 3:40am Europe/Paris). Reprendre par les lots backend B-0→B-5 et frontend F-1. ## Objectif - **Vue humaine = terminal brut natif** (PTY interactif). Réflexion live + Échap = natifs CLI, zéro parsing par modèle. On abandonne `AgentChatView`/stream-json comme vue. - **Délégation cross-model via MCP** : `idea_ask_agent(target, task)` bloquant → la cible traite quand libre (FIFO) → rend son résultat via NOUVEL outil `idea_reply(result)` → IdeA débloque l'appelant. Fin-de-tour = signal MCP explicite. - Principes : 1 agent = 1 employé (1 process/session, input FIFO) ; hexagonal + SOLID stricts ; plus aucun `parse_event` requis pour vue ni orchestration. ## Découvertes clés de l'architecte (état réel du code) 1. La **file FIFO existe déjà** : `OrchestratorService` (`crates/application/src/orchestrator/service.rs`) a `ask_locks: Mutex>>>` + `ask_lock_for()` + `ASK_QUEUE_WAIT_CAP` (600s) + `ASK_AGENT_TIMEOUT` (300s). On la formalise en port `AgentMailbox` (pour porter un `oneshot` de réponse). 2. `idea_ask_agent` → `agent.message` → `OrchestratorCommand::AskAgent{target_agent, task}` **déjà câblé** (mcp/tools.rs, domain/orchestrator.rs, service.rs). On réimplémente le **corps** de `ask_agent()`. 3. Aujourd'hui `ask_agent` **exige une session structurée** et renvoie `AppError::Invalid` si la cible est en PTY brut (service.rs ~400-410). **Inverser cette branche** : PTY vivant = canal normal. 4. Routage structuré dans `crates/application/src/agent/lifecycle.rs` (`LaunchAgent` ~1100). Levier de bascule : **ne plus injecter la fabrique structurée au composition root** (`crates/app-tauri/src/state.rs`, `with_structured`). 5. `apply_mcp_config` (lifecycle.rs ~1391) écrit déjà `.mcp.json` + `--mcp-config` AVANT le spawn, **chemin PTY inclus** → la CLI PTY a déjà le serveur MCP IdeA (à vérifier par test B-0). Vigilance : `ensure_mcp_server` doit piloter `McpServer::serve` sur le loopback. 6. `idea_reply` n'existe nulle part : seul vrai ajout de surface. ## Lots BACKEND (Rust — agent dev backend) ; NE PAS faire B-6 (nettoyage) avant coordination - **B-0** Prérequis transport MCP : garantir CLI PTY reçoit `--mcp-config ` (endpoint/project/requester) + `serve` piloté loopback. Test : CLI factice PTY appelle `idea_list_agents`, reçoit réponse. - **B-1** Port `AgentMailbox` + `InMemoryMailbox`. Domaine pur (`crates/domain/src/mailbox.rs` ou ports.rs) : trait + `Ticket{id,requester,task}`, `TicketId`, `MailboxError`. Infra (`crates/infrastructure/src/mailbox/`) : `HashMap)>>` + mutex ; `enqueue` rend `PendingReply` (sur `oneshot::Receiver`). Tests : FIFO ; `resolve` réveille le bon pending ; 2 ask même cible sérialisés ; cibles ≠ non bloquants ; timeout retire ticket de tête. - **B-2** Bascule routage : tous en PTY. `state.rs` : retirer `with_structured` de `LaunchAgent`/`OrchestratorService`/`ChangeAgentProfile`. Tests : profil Claude → PTY ; DTO renvoie `CellKind::Pty`. Ne pas supprimer `launch_structured` (mort-code, nettoyage ultérieur). - **B-3** Réimplémenter `ask_agent` : résoudre id → `mailbox.enqueue` → ticket en tête → garantir cible vivante PTY (sinon LaunchAgent PTY bg) → `PtyPort::write` préfixe `[IdeA · tâche de {A} · ticket {id}] {task}\n` → `await PendingReply` borné `ASK_AGENT_TIMEOUT`. PTY vivant = normal. Timeout : garder agent vivant, retirer ticket de tête. Publier `AgentReplied`. Injecter `Arc` + `Arc`. Tests : injection bon handle ; agent mort relancé ; timeout libère file ; AgentReplied. - **B-4** Outil/action `idea_reply` : `ToolDef idea_reply` (schéma `{result:string}` seul, pas de ticket_id exposé), action wire `agent.reply`, `OrchestratorCommand::Reply{from:AgentId, result}`, `validate`, `map_tool_call` (passe `requester` du handshake comme `from`), bras dispatch → `mailbox.resolve(from, result)`. Corrélation implicite : `idea_reply` résout le ticket en tête de la file de l'émetteur (identité via handshake, pas via id géré par le modèle). `tool_returns_reply` : idea_reply = ACK sans inline. Tests : mapping ; validate exige result ; resolve corrèle tête ; reply sans ask = erreur typée (pas de panic). - **B-5** Protocole délégation dans le contexte : injecter dans convention file (`apply_injection`) + description outil : « reçois `[IdeA · tâche …]` → traite → appelle IMPÉRATIVEMENT `idea_reply(result=…)` ; ne réponds jamais qu'en texte. » Test : convention file contient l'instruction. ## Lots FRONTEND (TS/React — agent dev frontend) ; NE PAS faire F-2 (suppression) avant coordination - **F-1** Router toute cellule agent vers `TerminalView` (jamais `AgentChatView`) ; ré-attache PTY + scrollback OK. Backend renverra `cellKind:"pty"`. Lire `frontend/src/features/layout/LayoutGrid.tsx`, `features/chat/AgentChatView.tsx`, `TerminalView`, `adapters/agent.ts`, `ports/index.ts`, `domain/index.ts`. Laisser `AgentChatView` inerte (non monté), pas supprimé. Tests Vitest : agent rend `TerminalView`, jamais `AgentChatView` ; re-mount repeint pty. ## Ordre / dépendances ``` B-0 ─┬─ B-2 ─┬─ B-3 ─ B-4 ─ B-5 B-1 ─┘ └─ F-1 Nettoyage (B-6, F-2) en dernier, coordonné. ``` Chemin critique : B-0 → B-2 → B-3 → B-4 → B-5. B-1 ∥ B-0. F-1 dès B-2. ## Cohérence Domaine sans I/O (port + entités pures) ; oneshot/PTY/MCP = infra ; application via ports. Open/Closed (idea_reply = ajout, dispatch intact) ; Liskov (Claude/Codex identiques derrière PTY+MCP) ; 1 process/agent préservé. ## Fichiers à toucher - Domaine : `mailbox.rs` (nouveau) / `ports.rs` ; `orchestrator.rs` (variante `Reply` + action `agent.reply`). - Application : `orchestrator/service.rs` (ask_agent + reply + injection ports) ; `agent/structured.rs` (supprimé au nettoyage) ; `agent/lifecycle.rs` (routage). - Infra : `mailbox/` (nouveau) ; `orchestrator/mcp/tools.rs` (idea_reply) ; `orchestrator/mcp/server.rs` (passer requester). - app-tauri : `state.rs` (retrait with_structured + injection mailbox + ensure_mcp_server) ; `commands.rs`/`dto.rs` (nettoyage ultérieur). - Frontend : `features/layout/LayoutGrid.tsx` (routage TerminalView) ; `features/chat/*` (nettoyage ultérieur).