Blog
Exécuter Claude Code à distance depuis votre téléphone
Comment Tactic Remote transforme votre Mac en serveur de codage IA permanent et votre iPhone en surface de contrôle de premier ordre — avec de vrais détails d'architecture, pas du marketing.
Suivez les mises à jour produit et ingénierie de cette catégorie.
Voir la catégorieClaude Code est un assistant de codage IA basé sur le terminal. Il tourne sur votre Mac, lit votre code, écrit du code, exécute des tests et commite des changements. Le problème : vous devez rester devant votre Mac pendant qu'il travaille.
Tactic Remote existe pour briser cette contrainte. Votre Mac reste le moteur d'exécution. Votre iPhone devient la surface de contrôle. Cet article couvre exactement comment cela fonctionne — l'architecture, le protocole, les compromis et la configuration. Sans approximations.
En bref : Un serveur WebSocket Node.js sur votre Mac gère Claude Code via tmux. Votre iPhone se connecte en LAN ou via Cloudflare Tunnel, envoie des commandes et reçoit la sortie terminal en streaming. Les notifications push vous alertent quand Claude termine ou a besoin d'une saisie.
L'architecture
Quatre composants, trois chemins réseau :
Le serveur Node.js a exactement une seule dépendance runtime : le package npm ws. Tout le reste — serveur HTTP, authentification, limitation de débit, gestion tmux, navigation de fichiers — est construit sur les modules natifs de Node.js. C'est délibéré. Moins de dépendances signifie moins de choses qui cassent, moins de risques liés à la chaîne d'approvisionnement et une surface d'attaque plus réduite.
Comment le serveur contrôle Claude Code
Voici la partie qui surprend la plupart des gens : il n'y a pas d'API entre le serveur et Claude Code. Le serveur contrôle Claude Code de la même manière que vous — en tapant dans un terminal.
Claude Code tourne dans une session tmux. Le serveur envoie des frappes avec tmux send-keys et lit la sortie avec tmux capture-pane. C'est de l'automatisation de terminal, pas une intégration SDK.
Création d'une session
Quand vous créez une nouvelle session depuis votre iPhone :
Le flag -l de send-keys est critique — il dit à tmux d'interpréter le contenu littéralement, empêchant les caractères spéciaux d'être traités comme des noms de touches tmux.
Le buffer de scrollback de 50 000 lignes fait 25x le défaut tmux. Les sessions Claude Code produisent une sortie énorme — logs de compilation, diffs de fichiers, suites de tests. Sans cela, vous perdriez le contexte après quelques minutes de travail intensif.
Envoi d'un message à Claude
Quand vous tapez un prompt sur votre iPhone et appuyez sur envoyer :
Le C-u au début efface la ligne de saisie. Sans lui, si Claude avait laissé du texte partiel dans le prompt (d'une saisie précédente interrompue), votre message s'ajouterait à du bruit.
Arrêt de Claude
L'arrêt est une séquence multi-étapes car Claude Code a deux états nécessitant un traitement différent :
Si Claude est en pleine exécution, Ctrl+C l'interrompt. Si Claude est déjà à son prompt, /exit est la commande de sortie de Claude Code. Envoyer les deux couvre les deux états. Les pauses de 200ms laissent à Claude le temps de traiter chaque signal avant le suivant.
Streaming de la sortie terminal
C'est le problème d'ingénierie le plus difficile de tout le système. Claude Code produit du texte à des centaines de lignes par seconde pendant la compilation ou les exécutions de tests. Cette sortie doit atteindre votre iPhone en temps réel, sans vider la batterie ni surcharger le réseau.
La boucle de polling
Le serveur capture le contenu terminal avec un intervalle de polling d'une seconde :
Cela récupère les 2 000 dernières lignes de scrollback en texte brut avec les codes d'échappement ANSI préservés.
Pourquoi le polling plutôt que l'événementiel ? tmux n'offre pas de notifications de changement. Nous avons évalué les watchers de système de fichiers sur le socket interne de tmux — fragile selon les versions de macOS. Le polling à 1 seconde est un bon équilibre : assez rapide pour que la sortie semble temps réel, assez lent pour minimiser l'utilisation CPU quand la session est inactive.
Détection de stabilité
Le moniteur de sortie ne fait pas que streamer des captures brutes. Il exécute un algorithme de détection de stabilité :
- Capturer le contenu terminal chaque seconde
- Comparer avec la capture précédente
- Si différent : envoyer la mise à jour à l'iPhone, réinitialiser le compteur de stabilité
- Si identique pendant 5 captures consécutives (5 secondes stables) : vérifier si Claude attend une saisie
- Si Claude est à son prompt : envoyer une mise à jour finale avec
final: true, puis arrêter le polling
Cela gère le rendu progressif de Claude — pendant les longues sorties, le terminal change rapidement. Après que Claude termine, l'écran se stabilise. Cinq secondes de stabilité est un signal fiable que Claude a terminé.
Le moniteur a un plafond dur de 120 vérifications (2 minutes). Si la sortie change encore après 2 minutes, le moniteur s'arrête et le client peut demander un rafraîchissement manuel.
Comment nous détectons l'état de Claude
Le serveur fait du screen-scraping de l'interface TUI de Claude Code pour déterminer ce qu'il fait. C'est nécessairement heuristique :
Nous vérifions les dernières lignes de la sortie terminal pour ces patterns. Si nous voyons Goodbye! ou Session ended, Claude s'est arrêté. Si nous voyons un prompt shell ($ en fin de ligne) sans indicateurs spécifiques à Claude, la session est retournée au shell.
Est-ce fragile ? Un peu. Si Claude Code change sa disposition TUI, nos heuristiques cassent. Mais l'alternative — construire un canal IPC personnalisé dans Claude Code — nécessiterait de maintenir un fork et de suivre les changements upstream. Le screen-scraping de l'interface TUI existante est pragmatique : ça fonctionne avec chaque version de Claude Code sans modification.
Préservation des couleurs ANSI
Une décision de design clé : le serveur préserve les codes d'échappement ANSI dans la sortie. Il supprime les séquences terminales problématiques (mouvement du curseur, séquences de titre OSC, changements de mode privé) mais conserve délibérément les codes couleur :
L'app iOS parse ensuite ces codes en style AttributedString natif. Cela vous donne la sortie couleur complète de Claude Code — coloration syntaxique, couleurs de diff, indicateurs d'état — fidèlement rendue sur l'écran de votre téléphone. Le parseur supporte les 16 couleurs standard, le mode 256 couleurs et le vrai couleur 24 bits.
Le protocole WebSocket
Le serveur parle deux protocoles simultanément sur la même connexion WebSocket — un protocole plat legacy et un protocole requête/réponse/événement plus récent.
Nouveau protocole (recommandé)
Trois types de trames :
Le champ id permet un multiplexage asynchrone correct des requêtes. Le client peut avoir plusieurs requêtes en cours et associer correctement les réponses. Le protocole legacy n'a pas d'ID de requête — les réponses sont positionnelles, et si vous envoyez deux requêtes rapidement, vous ne pouvez pas savoir quelle réponse correspond à quelle requête.
Catalogue complet des méthodes
| Méthode | Objectif |
|---|---|
list_sessions | Obtenir toutes les sessions tmux avec noms, chemins, état d'attachement |
create_session | Créer une nouvelle session tmux à un chemin donné |
attach_session | Basculer vers une session existante, obtenir sa sortie actuelle |
delete_session | Tuer une session tmux immédiatement |
kill_session | Arrêter Claude proprement, puis tuer la session |
start_claude | Lancer Claude Code dans la session courante |
stop_claude | Envoyer la séquence Ctrl+C + /exit |
send_to_claude | Taper un message et appuyer sur Entrée |
send_key | Envoyer une seule touche (Enter, Escape, Tab, y, n, Ctrl+C) |
get_output | Obtenir le contenu terminal actuel et l'état de Claude |
get_full_output | Obtenir jusqu'à 5 000 lignes de scrollback |
change_path | Changer le répertoire de travail |
list_directory | Naviguer dans les fichiers à un chemin |
create_folder | Créer un nouveau répertoire |
La méthode send_key possède une liste blanche explicite de 18 touches. Vous ne pouvez pas envoyer de séquences de touches arbitraires — seulement les touches qui ont du sens pour interagir avec l'interface de Claude Code. Les touches y et n sont spécifiquement incluses pour répondre aux invites de permission de Claude depuis votre téléphone.
Réseau : LAN vs. Cloudflare Tunnel
Deux modes de connexion résolvent deux problèmes différents.
Réseau local (LAN)
Votre iPhone se connecte directement à votre Mac via WiFi :
L'app Mac compagnon publie un service Bonjour (_ws._tcp.) pour que votre iPhone puisse le découvrir automatiquement sur le réseau. Aucune configuration nécessaire — ouvrez l'app, tapez sur la bannière, vous êtes connecté.
Latence : Aller-retour sous 10ms. Le streaming terminal semble instantané.
Limitation : Fonctionne uniquement sur le même réseau. Sortez de chez vous et vous perdez la connexion.
Cloudflare Tunnel
Pour l'accès distant, l'app Mac compagnon peut démarrer un Cloudflare Tunnel :
Le tunnel est sortant uniquement depuis votre Mac. Aucun port n'est ouvert sur votre pare-feu. Pas de configuration routeur. Cloudflare gère la terminaison TLS, la protection DDoS et le proxying WebSocket.
La configuration Quick Tunnel génère un sous-domaine aléatoire *.trycloudflare.com et une clé API aléatoire de 32 caractères :
Aucun compte Cloudflare requis. Gratuit. Fonctionne en environ 10 secondes.
Latence : 30–80ms typique, selon votre distance de la périphérie Cloudflare la plus proche.
Compromis : L'URL change à chaque redémarrage du tunnel. Pour une URL persistante, vous avez besoin d'un compte Cloudflare et d'un tunnel nommé (toujours gratuit).
Connexion rapide par QR code
Configurer une connexion manuellement signifie saisir une adresse IP, un port et une clé API sur un clavier de téléphone. C'est source d'erreurs et pénible.
L'app Mac compagnon génère un QR code contenant les détails de connexion en JSON :
Scannez-le depuis l'app iPhone grâce au détecteur de codes-barres du framework Vision. Un scan configure toute la connexion — mode, adresse, authentification. En environ 3 secondes.
Pipeline de notifications
Les notifications push sont la fonctionnalité phare de Tactic Remote pour les workflows « lancer et oublier ». Démarrez une longue tâche, partez, recevez une notification quand Claude termine ou a besoin de votre saisie.
Comment ça fonctionne
Claude Code supporte les hooks — des scripts shell qui s'exécutent sur les événements du cycle de vie. L'app Mac compagnon auto-configure ces hooks pour faire un POST vers le serveur local :
Quand Claude termine une tâche, ce hook se déclenche. Le serveur reçoit le POST, diffuse un événement de notification à tous les clients connectés, et l'app iOS déclenche une notification locale via UNNotificationCenter.
Déduplication des événements
Les événements de hook peuvent se déclencher en succession rapide (par ex., Claude arrête et redémarre plusieurs sous-tâches). L'app iOS déduplique les événements avec une fenêtre de 3 secondes basée sur event|project|session|timestamp. Si le même événement logique arrive deux fois dans les 3 secondes, le doublon est silencieusement ignoré.
Premier plan vs. arrière-plan
Quand l'app est au premier plan, les événements de notification ajoutent un indicateur visuel au buffer terminal :
Quand l'app est en arrière-plan, une notification système se déclenche. Tapez dessus pour revenir directement dans votre session.
Modèle de sécurité
Exécuter du code généré par IA à distance exige un modèle de sécurité sérieux. Voici le nôtre.
Authentification
Le serveur supporte l'authentification par clé API via deux mécanismes :
- En-tête
Authorization: Bearer <key>(standard) - En-tête
Sec-WebSocket-Protocol: <key>(solution de repli pour les bibliothèques WebSocket iOS qui ne peuvent pas définir d'en-têtes personnalisés sur la requête d'upgrade — une contrainte mobile courante)
L'authentification est vérifiée une fois à la connexion. En cas d'échec, le WebSocket est fermé immédiatement avec le code 1008 (Policy Violation).
Prévention de l'injection de commandes
Chaque commande externe que le serveur exécute passe par execSafe(), qui appelle child_process.spawn() avec shell: false. Les arguments sont passés en tableaux, jamais interpolés dans des chaînes. L'injection shell est structurellement impossible.
La validation des entrées ajoute une défense en profondeur :
| Entrée | Validation |
|---|---|
| Noms de session | /^[a-zA-Z0-9_-]{1,64}$/ |
| Commande Claude | /^claude(\s+--?[a-zA-Z0-9-]+)*$/ |
| Noms de touches | Liste blanche explicite de 18 touches |
| Chemins de fichiers | Résolus en absolu, vérifiés avec startsWith() |
Protection contre la traversée de chemin
La navigation de fichiers est restreinte à l'arborescence du répertoire personnel de l'utilisateur. Les répertoires sensibles sont bloqués indépendamment des autres paramètres :
La vérification utilise une correspondance segment par segment (pas une correspondance de sous-chaîne), donc un répertoire nommé my-.ssh-backup ne déclenchera pas de faux positif.
Limitation de débit
Les tentatives d'authentification échouées sont limitées à 30 par minute par IP via une fenêtre glissante en mémoire. Au-delà de la limite, le serveur retourne 429 Too Many Requests avec un indice retryAfter.
Aucune dépendance cloud
Votre code ne quitte jamais votre Mac. Tactic Remote est un plan de contrôle, pas un plan de données. Le WebSocket transporte du texte terminal — les saisies de commandes et les chaînes de sortie. Les fichiers source, l'historique git et les artefacts de build restent sur votre machine.
Avec Cloudflare Tunnel, le tunnel chiffre le trafic de bout en bout. Cloudflare voit des trames WebSocket chiffrées, pas votre code.
L'app iOS : pas un émulateur de terminal
Tôt dans le développement, nous avons pris une décision consciente : l'app iPhone n'est pas un simple émulateur de terminal. Entasser un terminal 80x24 complet sur un écran de téléphone de 10 cm est une expérience terrible.
À la place, l'app fournit :
- Saisie de style conversation : Tapez des messages à Claude dans un champ texte, pas dans un prompt terminal
- Vue de sortie terminal : Texte rendu avec support des couleurs ANSI, défilement auto, zoom par pincement (taille de police par défaut 8pt)
- Boutons d'action rapide : Enter, Escape, Tab, Y, N, Ctrl+C — les touches dont vous avez réellement besoin pour interagir avec Claude Code
- Sélecteur de session : Parcourez et basculez entre les sessions tmux
- Navigateur de chemin : Naviguez dans le système de fichiers de votre Mac pour définir le répertoire de travail
- Commandes slash : Auto-complétion pour
/help,/clear,/compact,/cost,/model,/status
Stratégie de reconnexion
Les apps mobiles vivent dans un environnement réseau hostile. Votre téléphone bascule entre WiFi et cellulaire, entre dans des ascenseurs, se met en veille. La stratégie de reconnexion de l'app gère tout cela :
- Déconnexion détectée : L'événement de fermeture WebSocket se déclenche
- Backoff exponentiel : Nouvelle tentative après
min(attempts * 3, 15)secondes, jusqu'à 5 tentatives - Conscience de l'arrière-plan : Si l'app est en arrière-plan, sauter la reconnexion. Définir un flag pour reconnecter au retour au premier plan
- Restauration de session : À la reconnexion, lister les sessions → trouver la session précédemment active → réattacher → interroger la sortie à 0.2s, 0.7s et 1.5s de délai
Le polling échelonné de la sortie (0.2s, 0.7s, 1.5s) après reconnexion gère le cas où tmux a besoin d'un moment pour produire une capture après le réattachement. Un polling unique immédiat retournerait souvent un contenu vide.
Buffer terminal
Le TerminalBuffer est un buffer circulaire plafonné à 500 000 caractères et 10 000 lignes. En cas de dépassement, le contenu est tronqué depuis le début, en s'alignant sur la limite de retour à la ligne la plus proche pour ne jamais voir une première ligne partielle.
Ce plafond existe car le rendu AttributedString devient coûteux à grande échelle. 500K caractères représentent environ 30 minutes de sortie intensive de Claude Code — suffisant pour toute session raisonnable tout en gardant l'UI réactive.
L'app Mac compagnon
L'app Mac compagnon est une application de barre de menu qui gère le serveur Node.js, le tunnel Cloudflare et les paramètres système.
Bundling du serveur
Le serveur Node.js entier est inclus dans l'app Mac. Au premier lancement, elle copie les fichiers serveur vers ~/Library/Application Support/ClaudeCodeRemote/Server/. Aux lancements suivants, elle compare les fichiers octet par octet et ne recopie que les fichiers modifiés. npm install ne se relance que si package.json a changé.
Cela signifie que les utilisateurs ne touchent jamais le terminal pour installer ou mettre à jour le serveur.
Détection des dépendances
L'app vérifie les outils requis (Node.js, tmux, Homebrew) en scannant d'abord les chemins connus (/opt/homebrew/bin/, /usr/local/bin/), puis en se repliant sur which. Si des dépendances manquent, un écran de configuration guide l'utilisateur à travers l'installation.
Prévention de la mise en veille
Quand le serveur tourne, l'app appelle IOPMAssertionCreateWithName pour empêcher macOS de se mettre en veille. C'est essentiel — un Mac en veille ne peut pas servir de connexions WebSocket.
Auto-configuration des hooks
L'app compagnon écrit des scripts shell dans ~/.claude/hooks/ qui font des POST des événements du cycle de vie vers le serveur local. Cela se fait automatiquement au démarrage du serveur — aucune configuration manuelle nécessaire.
Ce que nous n'avons pas construit
Certaines choses que nous avons délibérément choisi de ne pas faire :
Pas de multiplexage de terminal dans l'app. Nous utilisons tmux côté serveur, mais l'app iPhone affiche une session à la fois. Des panneaux divisés sur un écran de téléphone seraient illisibles.
Pas d'édition de fichiers. L'app peut naviguer dans les fichiers mais pas les éditer. Claude Code gère l'édition de fichiers — vous êtes le relecteur, pas l'éditeur. Ajouter un éditeur de code mobile serait un excès de périmètre qui dégraderait l'expérience principale.
Pas de mode hors ligne. Si votre Mac est injoignable, l'app vous montre le dernier état connu mais ne peut rien faire d'utile. Nous ne prétendons pas le contraire.
Pas de repli sur bureau distant. Le partage d'écran et VNC existent, mais ils sont 10x pires pour ce cas d'usage. Tactic Remote envoie du texte structuré, pas des pixels. Cela signifie moins de bande passante, moins de latence, et une UI conçue pour la tâche plutôt qu'un bureau réduit.
Configuration rapide
Envie de passer les détails ? Voici le minimum pour démarrer.
Sur votre Mac
- Installez l'app Mac compagnon depuis tacticremote.com/download
- Lancez-la — elle installe automatiquement les dépendances et démarre le serveur
- Notez le QR code affiché dans l'app
Sur votre iPhone
- Installez Tactic Remote depuis App Store
- Scannez le QR code depuis l'app Mac
- Créez une session pointant vers votre répertoire de projet
- Démarrez Claude et envoyez votre premier prompt
Pour l'accès distant (en dehors de votre réseau domestique), activez le toggle Cloudflare Tunnel dans les paramètres de l'app Mac. L'app génère automatiquement une URL publique.
Configurer les notifications
Dans l'app Mac, les hooks sont configurés automatiquement au démarrage du serveur. Sur l'iPhone, accordez les permissions de notification quand demandé. C'est tout.
FAQ
Claude continue-t-il de tourner si je ferme l'app iPhone ?
Oui. Claude tourne dans tmux sur votre Mac. L'app iPhone est une fenêtre sur cette session. Fermez l'app, mettez votre téléphone dans votre poche — Claude continue de travailler. Rouvrez l'app et vous verrez tout ce qui s'est passé pendant votre absence.
Que se passe-t-il si mon réseau tombe ?
L'app iPhone se reconnecte automatiquement avec un backoff exponentiel (jusqu'à 5 tentatives sur ~45 secondes). À la reconnexion, elle se réattache à votre session précédente et récupère la sortie accumulée. Aucun travail n'est perdu — tmux bufferise tout côté Mac.
Combien de batterie ça consomme ?
L'app iPhone ne maintient pas de connexion permanente en arrière-plan. En arrière-plan, elle se déconnecte proprement. L'impact batterie est essentiellement nul quand vous ne l'utilisez pas activement.
Puis-je l'utiliser avec d'autres outils de codage IA ?
Tactic Remote est construit autour de l'interface terminal de Claude Code, mais l'architecture sous-jacente (gestion de session tmux, streaming terminal) fonctionne avec tout outil basé sur le terminal. S'il tourne dans un terminal, le serveur peut le gérer. Les heuristiques de détection d'état sont spécifiques à Claude Code, mais la boucle de base send-keys/capture-pane est universelle.
Mon code est-il en sécurité ?
Votre code ne quitte jamais votre Mac. Tactic Remote transmet du texte terminal via des connexions WebSocket chiffrées. Le serveur n'a aucun composant cloud, aucune télémétrie et aucune analytique. Avec Cloudflare Tunnel, le trafic est chiffré de bout en bout — Cloudflare proxie des trames chiffrées, pas votre code source.
Pour approfondir des sous-systèmes spécifiques, consultez Pourquoi nous avons choisi tmux comme backbone de session, Construire le streaming terminal en temps réel, et la documentation du modèle de sécurité.
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.