Blog
Pourquoi nous avons construit Tactic Remote sur tmux : persistance des sessions et architecture du terminal
Tactic Remote utilise tmux pour gérer les sessions Claude Code, assurant la persistance malgré les déconnexions réseau, les cycles de veille du Mac et les redémarrages de l'app, tout en permettant le streaming en temps réel de la sortie terminal vers votre iPhone.
Suivez les mises à jour produit et ingénierie de cette catégorie.
Voir la catégorieLorsque nous avons commencé à construire Tactic Remote, la première décision architecturale était fondamentale : comment maintenir une session Claude Code en vie et observable quand le dispositif de contrôle (votre iPhone) a une connexion instable ? La réponse a été tmux, et cette décision a façonné presque tout le reste du produit.
Le problème
Claude Code s'exécute comme un processus interactif de longue durée. Une session typique dure de 10 à 60 minutes. Pendant ce temps, Claude lit des fichiers, propose des modifications, exécute des commandes, attend des approbations et itère sur les retours. Si le processus meurt en cours de session, tout le contexte est perdu. Claude doit recommencer, relire les fichiers et reconstruire sa compréhension de la tâche.
Sur un terminal local, ce n'est pas un problème — votre Mac reste allumé et le processus s'exécute jusqu'au bout. Mais Tactic Remote introduit un client mobile. Les iPhones basculent entre Wi-Fi et cellulaire. Ils verrouillent l'écran et suspendent les apps en arrière-plan. Les utilisateurs traversent des zones sans signal. Toute architecture qui lie le cycle de vie du processus Claude Code à la connexion réseau de l'iPhone est fondamentalement cassée.
Nous avions besoin que Claude Code s'exécute indépendamment de toute connexion client, et que les clients puissent se connecter et se déconnecter sans affecter la session en cours.
Pourquoi tmux
tmux est un multiplexeur de terminal utilisé en production depuis 2007. Il sépare le concept de session terminal de l'émulateur de terminal qui l'affiche. Une session tmux s'exécute comme un processus serveur sur la machine hôte. Les clients s'y connectent pour voir et interagir avec la session, et se déconnectent sans affecter les processus en cours.
Nous avons évalué plusieurs alternatives avant de nous engager avec tmux :
screen — Le multiplexeur de terminal originel. Fonctionnel mais moins activement maintenu, avec une API de scripting plus limitée. L'interface de commandes structurée de tmux a rendu le contrôle programmatique nettement plus facile.
Gestion PTY personnalisée — Nous avons prototypé une solution utilisant des pseudo-terminaux bruts avec node-pty. Cela fonctionnait pour les cas simples mais nécessitait de réimplémenter la persistance de session, la gestion des fenêtres et le buffering de sortie. Nous construisions un tmux inférieur en partant de zéro.
Isolation par conteneur — Exécuter Claude Code dans un conteneur Docker avec un PTY attaché. Cela ajoute de la surcharge, complique l'accès au système de fichiers (Claude Code doit lire et écrire vos fichiers de projet réels) et introduit une couche d'abstraction qui crée plus de problèmes qu'elle n'en résout.
nohup / disown — Gestion simple de processus en arrière-plan. Pas de capture de sortie, pas de réattachement, pas de contrôle programmatique. Inadéquat pour des sessions interactives.
tmux nous a fourni tout ce dont nous avions besoin : persistance de session, contrôle programmatique des panneaux, capture de sortie et une API stable et bien documentée. Le compromis est que tmux doit être installé sur le Mac du développeur, mais brew install tmux est un coût d'installation unique que nous considérons acceptable.
Architecture
L'intégration tmux de Tactic Remote fonctionne sur trois couches :
Couche 1 : Gestion des sessions
Quand vous démarrez une session Claude Code via Tactic Remote, le compagnon Mac crée une nouvelle session tmux avec un identifiant unique. Claude Code se lance dans le panneau principal de cette session.
Le flag -d est essentiel — il crée la session en mode détaché. Aucun émulateur de terminal n'a besoin d'être connecté pour que la session existe et s'exécute. Claude Code démarre immédiatement, et le compagnon Mac le surveille en arrière-plan.
Chaque session obtient une session tmux dédiée plutôt qu'un panneau dans une session partagée. Cela offre un isolement propre : variables d'environnement spécifiques à la session, buffers de défilement indépendants et aucun risque d'interférence inter-sessions.
Couche 2 : Capture et streaming de sortie
Le compagnon Mac capture en continu la sortie terminal du panneau tmux et la transmet aux clients iPhone connectés via WebSocket. C'est le mécanisme qui vous permet de voir la sortie de Claude Code en temps réel sur votre téléphone.
La capture de sortie utilise tmux capture-pane avec des coordonnées couvrant le contenu visible du panneau plus le buffer de défilement. Le compagnon exécute une boucle de capture qui :
- Capture le contenu actuel du panneau à un intervalle configurable (défaut : 200ms).
- Compare le contenu capturé à la dernière valeur connue.
- N'envoie que le delta aux clients connectés.
- Maintient un buffer circulaire de sortie récente pour les clients qui se reconnectent et doivent rattraper.
L'intervalle de capture de 200ms est un équilibre entre réactivité et utilisation CPU. À ce rythme, les mises à jour du terminal semblent quasi temps réel sur l'iPhone tout en consommant moins de 2% de CPU sur un Mac moderne. Les utilisateurs préférant des mises à jour plus rapides peuvent réduire l'intervalle à 100ms ; ceux sur batterie peuvent l'augmenter à 500ms.
Couche 3 : Routage des entrées
Quand vous envoyez une entrée depuis l'iPhone — qu'il s'agisse d'une réponse d'approbation, d'un message tapé ou d'une commande de contrôle de session — le compagnon Mac la route vers le panneau tmux approprié via tmux send-keys. Cela maintient l'illusion d'une connexion terminal directe tandis que l'entrée réelle voyage par WebSocket, à travers le réseau, jusque dans la session tmux.
Les réponses d'approbation sont un cas particulier. Au lieu d'être envoyées comme des frappes brutes, elles sont traitées par le système de hooks et injectées comme des réponses structurées attendues par le système de permissions de Claude Code. Cela garantit que les approbations sont atomiques et ne peuvent pas être corrompues par une livraison réseau partielle.
Persistance en pratique
L'architecture tmux fournit de la persistance à plusieurs niveaux :
L'app iPhone se ferme. La session tmux continue de s'exécuter. Claude Code poursuit son travail, et les approbations se mettent en file d'attente sur le compagnon Mac. Quand vous rouvrez l'app, elle se reconnecte au WebSocket, reçoit la sortie mise en buffer, et vous êtes de retour là où vous étiez.
L'iPhone perd le réseau. Identique à la fermeture de l'app du point de vue de la session. Le WebSocket tombe, la sortie est mise en buffer sur le Mac, et la reconnexion restaure l'état.
Le Mac se met en veille. Les sessions tmux survivent aux cycles veille/réveil. Quand le Mac se réveille, le processus serveur tmux reprend, et tout processus Claude Code en cours continue. Le compagnon Mac rétablit le listener WebSocket et se reconnecte à l'iPhone.
Le compagnon Mac plante. La session tmux survit indépendamment. Redémarrer le compagnon Mac détecte les sessions tmux existantes avec le préfixe claude-remote-, s'y rattache et reprend le streaming. Aucun contexte Claude Code n'est perdu.
Le Mac redémarre. C'est le seul scénario où les sessions tmux ne survivent pas, car elles n'existent qu'en mémoire. Claude Code doit être redémarré. Nous le documentons clairement et explorons l'intégration de tmux-resurrect pour les versions futures, bien que la complexité de la restauration de sessions IA interactives (pas seulement l'état du shell) rende cela non trivial.
Cycle de vie des sessions
Une session Tactic Remote passe par ces états :
| État | Statut tmux | Statut iPhone |
|---|---|---|
| Démarrage | Session créée, Claude Code en lancement | Indicateur de chargement |
| Active | Processus en cours, sortie en flux | Vue terminal en direct |
| En attente d'approbation | Processus bloqué sur hook | Notification d'approbation |
| En pause (client déconnecté) | En cours, sortie en buffer | Non connecté |
| Terminée | Processus terminé, session conservée | Résumé de session |
| Expirée | Session détruite après période de rétention | Archivée |
Les sessions terminées sont conservées dans tmux pendant une période configurable (défaut : 30 minutes) pour que vous puissiez consulter la sortie finale même après la fin de Claude Code. Après la période de rétention, la session tmux est détruite et le journal de sortie est archivé.
Observabilité
tmux nous offre des capacités d'introspection difficiles à atteindre avec une solution PTY personnalisée :
- Liste des sessions —
tmux list-sessionsfournit un inventaire instantané de toutes les sessions Tactic Remote actives. - Dimensions des panneaux — Nous pouvons interroger et définir les dimensions des panneaux pour correspondre aux caractéristiques d'affichage de l'iPhone, assurant un retour à la ligne correct.
- Surveillance des processus — La commande
tmux list-panesavec les flags de format nous permet de surveiller le processus Claude Code sans maintenir un système séparé de suivi des PID. - Accès au buffer de défilement — Le buffer de défilement complet est disponible pour la recherche et la consultation, alimentant la vue historique de session sur l'iPhone.
Caractéristiques de performance
L'exécution via tmux ajoute une surcharge minimale par rapport à un terminal direct :
| Métrique | Terminal direct | Session tmux |
|---|---|---|
| Démarrage du processus | ~800ms | ~850ms |
| Latence de frappe | <1ms | ~2ms |
| Surcharge mémoire par session | — | ~3MB |
| Surcharge CPU (session inactive) | — | <0.1% |
La surcharge est non mesurable en pratique. tmux a été optimisé au fil de presque deux décennies d'utilisation en production, et l'indirection supplémentaire qu'il introduit est invisible pour les utilisateurs.
Leçons apprises
Construire sur tmux était le bon choix, mais non sans défis :
Cas limites d'encodage terminal. La sortie de Claude Code inclut occasionnellement des séquences d'échappement ANSI qui interagissent de façon inattendue avec l'émulation de terminal de tmux. Nous maintenons une couche de normalisation qui nettoie la sortie avant le streaming vers l'iPhone.
Installation de tmux sur macOS. tmux n'est pas préinstallé sur macOS. Nous avons envisagé de l'inclure mais avons décidé contre — les développeurs préfèrent généralement gérer leur propre installation de tmux, et l'inclusion créerait des conflits de version pour ceux qui l'ont déjà installé.
Performance de capture-pane à grande échelle. Avec de nombreuses sessions simultanées, l'utilisation CPU de la boucle de capture augmente linéairement. Nous avons implémenté des taux de capture adaptatifs qui réduisent la fréquence pour les sessions sans changements récents de sortie.
tmux est une infrastructure qui disparaît quand elle fonctionne bien. La plupart des utilisateurs de Tactic Remote ne savent pas et ne se soucient pas que tmux soit impliqué — ils voient une session fiable qui survit à tout ce que leur téléphone ou leur réseau peut faire. C'est le résultat que nous visions.
Essayez Tactic Remote
Pilotez vos agents de programmation depuis votre téléphone
Connectez-vous à Claude Code, Codex et aux autres agents sur votre Mac, PC Windows ou Linux. Consultez leur progression et envoyez la prochaine instruction depuis votre iPhone ou iPad.