Blog
30 secondes pour se connecter : comment nous avons construit le parcours de distribution `npx tacticremote`
L'histoire technique derrière `npx tacticremote`, depuis les binaires compilés avec Bun et un lanceur npm minimal jusqu'à l'enregistrement automatique par QR et un premier démarrage plus rapide.
Suivez les mises à jour produit et ingénierie de cette catégorie.
Voir la catégorieL'objectif était simple à formuler et étonnamment difficile à exécuter: un nouvel utilisateur doit pouvoir lancer une commande, scanner un QR code et voir un terminal actif sur son téléphone en 30 secondes.
Cet article explique comment nous y sommes parvenus.
Le problème
Avant l'existence de npx tacticremote, le démarrage du serveur était un processus en plusieurs étapes, qui variait selon la plateforme:
- macOS: télécharger un DMG, le monter, déplacer l'app dans Applications, la lancer et composer avec Gatekeeper.
- Linux / CI: cloner le dépôt, exécuter
npm install, puis comprendre comment lancer et maintenir le serveur dans cet environnement.
Pour les développeurs sur des VM Linux distantes ou dans des conteneurs Docker, c'était franchement pénible. Le chemin par clonage du dépôt exigeait git, Node.js et un environnement npm fonctionnel avec accès au registry. Il n'existait pas de commande unique à donner à quelqu'un en disant simplement "lance ça".
Nous voulions: npx tacticremote → scan → terminé.
Pourquoi ne pas simplement faire npm install ?
Le package serveur a un petit ensemble de dépendances runtime, mais npm install introduit quand même de la friction. Aujourd'hui, ce runtime inclut ws, bonjour-service et qrcode-terminal.
La résolution npm prend du temps avant même que le serveur ne fasse quoi que ce soit d'utile. Dans des environnements contraints, comme des réseaux d'entreprise ou du CI conteneurisé, elle peut aussi échouer à cause des proxys, des miroirs de registry ou des permissions.
Plus important encore, le parcours CLI doit rester léger. Si le package publié embarquait tout l'arbre de dépendances runtime, la première expérience resterait: télécharger du JavaScript, puis démarrer le serveur. Ce n'est pas le niveau d'onboarding que nous voulions.
La couche npm publiée devait donc rester aussi fine que possible.
L'approche de compilation avec Bun
Nous compilons le serveur avec Bun en un binaire unique et autonome. Le résultat est un exécutable d'environ 20 Mo avant compression gzip, qui contient:
- la runtime Bun
- toutes les dépendances runtime
- l'intégralité du code source du serveur
Pas de node_modules. Pas d'installation séparée de Bun. Pas de résolution de dépendances au démarrage. On récupère un binaire, on l'exécute.
GitHub Actions (.github/workflows/build-cli.yml) construit quatre cibles à chaque release:
bun-darwin-arm64- Mac Apple Siliconbun-darwin-x64- Mac Intelbun-linux-x64- Linux x86_64bun-linux-arm64- Linux ARM (Raspberry Pi, AWS Graviton, etc.)
Chaque binaire est envoyé dans un GitHub Release sous forme d'asset gzip.
Le wrapper léger
Le package publié sur npmjs.com n'est pas le serveur lui-même. C'est un script lanceur de 124 lignes situé dans bin/tacticremote.js. Il fait essentiellement ceci:
- Détecte le système d'exploitation et l'architecture CPU avec
process.platformetprocess.arch - Résout le nom du binaire correspondant à cette plateforme
- Vérifie la présence d'un binaire en cache dans
~/.tacticremote/binpour la version courante - S'il n'est pas en cache: télécharge un binaire gzip depuis GitHub Releases, le décompresse et l'écrit sur disque avec les droits d'exécution
- Lance le binaire, hérite de
stdioet relaie les signaux commeSIGINTetSIGTERM
Le premier lancement télécharge l'asset de release et le met en cache localement. Les exécutions suivantes réutilisent le binaire correspondant à la version du package npm.
Ce schéma n'est pas nouveau. esbuild l'a popularisé, turbo l'utilise, prisma fait quelque chose de similaire. L'idée est simple: npm est un canal de distribution, pas un environnement de compilation. On y livre un téléchargeur, pas un arbre de dépendances.
La séparation des package.json
Nous maintenons deux manifestes de package côte à côte:
package.json- la variante de développement. Elle contient toutes les devDependencies (Jest, ESLint, Prettier), les scripts de test et de lint, ainsi que la liste complète des dépendances utilisées en local.package.npm.json- le manifeste de publication allégé. Il pointe le champbinverstacticremote.jset omet l'arbre des dépendances runtime.
Cette séparation garde propres le flux de développement et le package publié. Elle introduit aussi une charge de maintenance claire: les métadonnées partagées doivent rester synchronisées.
Le dépôt ne contient pas encore de vérification de publication qui garantisse cet alignement. L'automatisation CI est donc l'étape suivante la plus évidente.
Le flux d'onboarding en 30 secondes
Une fois le problème de distribution résolu, nous avons passé en revue chaque étape du parcours de connexion pour supprimer les frictions.
Secondes 0-5. L'utilisateur lance npx tacticremote dans son terminal. Au premier lancement, le lanceur détecte qu'aucun binaire n'est en cache et le télécharge. Ensuite, la vérification du cache ne prend que quelques millisecondes.
Secondes 5-10. Le binaire serveur démarre. Il détecte l'adresse IP locale de la machine, génère une clé API aléatoire et imprime un QR code directement dans le terminal à l'aide de caractères blocs Unicode. Pas de navigateur, pas d'interface web à ouvrir.
Secondes 10-15. L'utilisateur ouvre Tactic Remote sur son téléphone. L'écran d'accueil affiche une carte "Connecter votre ordinateur" avec la commande npx tacticremote et un bouton "Scanner le QR". Un appui ouvre la caméra.
Secondes 15-25. L'utilisateur scanne le QR code affiché dans le terminal. Le QR code encode un payload JSON contenant l'adresse IP, le port et la clé API du serveur. L'app décode ce payload et enregistre automatiquement la configuration du serveur - pas d'écran "Ajouter un serveur", pas de saisie manuelle d'IP, pas de copier-coller de clé API.
Secondes 25-30. Le handshake WebSocket se termine. La sortie du terminal commence à s'afficher sur le téléphone. L'indicateur de connexion passe au vert.
L'enregistrement automatique via QR a supprimé l'essentiel de la friction. Le flux précédent demandait: toucher "Ajouter un serveur", saisir l'IP, saisir le port, saisir la clé API, toucher Sauvegarder, toucher Connecter. Cinq tapotements et trois saisies manuelles, chacun pouvant échouer. Le scan QR réduit tout cela à un seul geste.
Ce que nous ferions différemment
Quelques points restent sous-optimaux et ne sont pas encore corrigés:
Pas encore de vérification de signature des artefacts. Le lanceur télécharge via HTTPS, mais ne vérifie pas encore le binaire à l'aide d'une signature ou d'un checksum publié. C'est la principale lacune d'intégrité restante.
Le passage d'un manifeste à l'autre doit être automatisé. Nous séparons un manifeste de développement et un manifeste de publication, mais il nous faut encore une protection plus stricte au moment du publish pour garantir leur cohérence.
Pas de miroir de secours. Si GitHub Releases n'est pas disponible, le lanceur n'a pas de deuxième source. Un miroir supplémentaire rendrait ce chemin de distribution plus robuste.
Vue d'ensemble
Ce parcours de distribution repose sur un principe: les utilisateurs ne devraient pas avoir à penser à l'infrastructure. Ils n'ont pas besoin de savoir ce qu'est Bun, quelle architecture CPU utilise leur machine Linux ou comment copier manuellement une clé API. La commande démarre le flux, le lanceur récupère le bon binaire et le QR code transporte les informations de connexion.
L'architecture du serveur elle-même - son design à dépendance unique et son modèle de sécurité - est décrite dans l'article compagnon Une seule dépendance : construire un serveur de production avec juste le package ws. Cet article explique comment amener rapidement ce serveur entre les mains des utilisateurs.
Si vous n'avez pas encore testé le flux en 30 secondes, rendez-vous sur /download.
Pour l'architecture du serveur, voir Une seule dépendance : construire un serveur de production avec juste le package ws. Pour la configuration, voir le Démarrage rapide.
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.