Blog
Ejecutar Claude Code de forma remota desde tu teléfono
Cómo Tactic Remote convierte tu Mac en un servidor de codificación IA siempre activo y tu iPhone en una superficie de control de primera clase — con detalles reales de arquitectura, no marketing.
Sigue las novedades de producto e ingeniería de esta categoría.
Ver categoríaClaude Code es un asistente de codificación IA basado en terminal. Se ejecuta en tu Mac, lee tu código, escribe código, ejecuta tests y hace commits. El problema: tienes que estar sentado frente a tu Mac mientras trabaja.
Tactic Remote existe para romper esa restricción. Tu Mac sigue siendo el motor de ejecución. Tu iPhone se convierte en la superficie de control. Este artículo cubre exactamente cómo funciona — la arquitectura, el protocolo, los trade-offs y la configuración. Sin vaguedades.
TL;DR: Un servidor WebSocket Node.js en tu Mac gestiona Claude Code a través de tmux. Tu iPhone se conecta por LAN o Cloudflare Tunnel, envía comandos y recibe la salida del terminal en streaming. Las notificaciones push te alertan cuando Claude termina o necesita entrada.
La arquitectura
Cuatro componentes, tres rutas de red:
El servidor Node.js tiene exactamente una dependencia runtime: el paquete npm ws. Todo lo demás — servidor HTTP, autenticación, limitación de tasa, gestión de tmux, navegación de archivos — está construido sobre módulos nativos de Node.js. Esto es deliberado. Menos dependencias significa menos cosas que se rompen, menos riesgos en la cadena de suministro y una superficie de ataque menor.
Cómo el servidor controla Claude Code
Esta es la parte que sorprende a la mayoría: no hay API entre el servidor y Claude Code. El servidor controla Claude Code de la misma forma que tú — escribiendo en un terminal.
Claude Code se ejecuta dentro de una sesión tmux. El servidor envía pulsaciones con tmux send-keys y lee la salida con tmux capture-pane. Es automatización de terminal, no integración con SDK.
Creación de una sesión
Cuando creas una nueva sesión desde tu iPhone:
El flag -l en send-keys es crítico — le dice a tmux que interprete el contenido literalmente, evitando que caracteres especiales se traten como nombres de teclas tmux.
El buffer de scroll de 50.000 líneas es 25x el defecto de tmux. Las sesiones de Claude Code producen salida enorme — logs de compilación, diffs de archivos, suites de tests. Sin esto, perderías contexto después de unos minutos de trabajo intenso.
Enviar un mensaje a Claude
Cuando escribes un prompt en tu iPhone y pulsas enviar:
El C-u al inicio limpia la línea de entrada. Sin esto, si Claude había dejado texto parcial en el prompt (de una entrada interrumpida anterior), tu mensaje se añadiría a basura.
Detener Claude
Detener es una secuencia de múltiples pasos porque Claude Code tiene dos estados que necesitan manejo diferente:
Si Claude está en medio de la ejecución, Ctrl+C lo interrumpe. Si Claude ya está en su prompt, /exit es el comando de salida de Claude Code. Enviar ambos cubre ambos estados. Los sleeps de 200ms dan tiempo a Claude para procesar cada señal antes de la siguiente.
Streaming de salida del terminal
Este es el problema de ingeniería más difícil de todo el sistema. Claude Code produce texto a cientos de líneas por segundo durante compilación o ejecución de tests. Esa salida necesita llegar a tu iPhone en tiempo real, sin agotar la batería ni saturar la red.
El bucle de polling
El servidor captura el contenido del terminal con un intervalo de polling de 1 segundo:
Esto toma las últimas 2.000 líneas del scrollback como texto plano con códigos de escape ANSI preservados.
¿Por qué polling en vez de orientado a eventos? tmux no ofrece notificaciones de cambio. Evaluamos watchers del filesystem sobre el socket interno de tmux — frágil entre versiones de macOS. Polling a 1 segundo es un buen equilibrio: suficientemente rápido para que la salida se sienta en tiempo real, suficientemente lento para minimizar uso de CPU cuando la sesión está inactiva.
Detección de estabilidad
El monitor de salida no simplemente transmite capturas crudas. Ejecuta un algoritmo de detección de estabilidad:
- Capturar contenido del terminal cada segundo
- Comparar con la captura anterior
- Si diferente: enviar la actualización al iPhone, reiniciar el contador de estabilidad
- Si idéntico durante 5 capturas consecutivas (5 segundos estable): comprobar si Claude está esperando entrada
- Si Claude está en su prompt: enviar una actualización final con
final: true, luego dejar de polling
Esto maneja el renderizado progresivo de Claude — durante salidas largas, el terminal cambia rápidamente. Después de que Claude termina, la pantalla se estabiliza. Cinco segundos de estabilidad son una señal fiable de que Claude terminó.
El monitor tiene un tope duro de 120 comprobaciones (2 minutos). Si la salida sigue cambiando después de 2 minutos, el monitor se detiene y el cliente puede solicitar un refresco manual.
Cómo detectamos el estado de Claude
El servidor hace screen-scraping de la TUI de Claude Code para determinar qué está haciendo. Esto es necesariamente heurístico:
Comprobamos las últimas líneas de la salida del terminal para estos patrones. Si vemos Goodbye! o Session ended, Claude ha salido. Si vemos un prompt de shell ($ al final de línea) sin indicadores específicos de Claude, la sesión ha vuelto al shell.
¿Es frágil? Algo. Si Claude Code cambia el layout de su TUI, nuestras heurísticas se rompen. Pero la alternativa — construir un canal IPC personalizado en Claude Code — requeriría mantener un fork y seguir los cambios upstream. Hacer screen-scraping de la TUI existente es pragmático: funciona con cada versión de Claude Code sin modificación.
Preservación de colores ANSI
Una decisión de diseño clave: el servidor preserva los códigos de escape ANSI en la salida. Elimina secuencias de terminal problemáticas (movimiento de cursor, secuencias de título OSC, cambios de modo privado) pero deliberadamente mantiene los códigos de color intactos:
La app iOS luego analiza estos códigos en estilos nativos AttributedString. Esto te da la salida de color completa de Claude Code — resaltado de sintaxis, coloreado de diffs, indicadores de estado — fielmente renderizada en la pantalla de tu teléfono. El parser soporta los 16 colores estándar, modo 256 colores y color verdadero de 24 bits.
El protocolo WebSocket
El servidor habla dos protocolos simultáneamente en la misma conexión WebSocket — un protocolo plano legacy y un protocolo más nuevo de request/response/event.
Protocolo nuevo (recomendado)
Tres tipos de frames:
El campo id permite multiplexación asíncrona de requests correcta. El cliente puede tener múltiples requests en vuelo y emparejar respuestas correctamente. El protocolo legacy no tiene IDs de request — las respuestas son posicionales, y si envías dos requests rápidamente, no puedes saber qué respuesta pertenece a qué request.
Catálogo completo de métodos
| Método | Propósito |
|---|---|
list_sessions | Obtener todas las sesiones tmux con nombres, rutas, estado de adjunción |
create_session | Crear una nueva sesión tmux en una ruta dada |
attach_session | Cambiar a una sesión existente, obtener su salida actual |
delete_session | Eliminar una sesión tmux inmediatamente |
kill_session | Detener Claude gracefully, luego eliminar la sesión |
start_claude | Lanzar Claude Code en la sesión actual |
stop_claude | Enviar secuencia Ctrl+C + /exit |
send_to_claude | Escribir un mensaje y pulsar Enter |
send_key | Enviar una sola tecla (Enter, Escape, Tab, y, n, Ctrl+C) |
get_output | Obtener contenido actual del terminal y estado de Claude |
get_full_output | Obtener hasta 5.000 líneas de scrollback |
change_path | Cambiar el directorio de trabajo |
list_directory | Navegar archivos en una ruta |
create_folder | Crear un nuevo directorio |
El método send_key tiene una lista blanca explícita de 18 teclas. No puedes enviar secuencias de teclas arbitrarias — solo teclas que tengan sentido para interactuar con la interfaz de Claude Code. Las teclas y y n están específicamente incluidas para responder a los prompts de permisos de Claude desde tu teléfono.
Red: LAN vs. Cloudflare Tunnel
Dos modos de conexión resuelven dos problemas diferentes.
Red local (LAN)
Tu iPhone se conecta directamente a tu Mac por WiFi:
La app Mac companion publica un servicio Bonjour (_ws._tcp.) para que tu iPhone pueda auto-descubrirla en la red. Sin configuración necesaria — abre la app, toca el banner, estás conectado.
Latencia: Sub-10ms de round trip. El streaming del terminal se siente instantáneo.
Limitación: Solo funciona en la misma red. Sales de tu casa y pierdes la conexión.
Cloudflare Tunnel
Para acceso remoto, la app Mac companion puede iniciar un Cloudflare Tunnel:
El túnel es solo saliente desde tu Mac. No se abren puertos en tu firewall. Sin configuración de router. Cloudflare gestiona la terminación TLS, protección DDoS y proxy WebSocket.
La configuración de túnel rápido genera un subdominio aleatorio *.trycloudflare.com y una clave API aleatoria de 32 caracteres:
Sin necesidad de cuenta Cloudflare. Gratis. Funciona en unos 10 segundos.
Latencia: 30–80ms típico, dependiendo de tu distancia al edge de Cloudflare más cercano.
Trade-off: La URL cambia cada vez que reinicias el túnel. Para una URL persistente, necesitas una cuenta Cloudflare y un túnel nombrado (también gratis).
Conexión rápida por código QR
Configurar una conexión manualmente significa introducir una dirección IP, puerto y clave API en un teclado de teléfono. Esto es propenso a errores y molesto.
La app Mac companion genera un código QR con los detalles de conexión como JSON:
Escanéalo desde la app iPhone usando el detector de códigos de barras del framework Vision. Un escaneo configura toda la conexión — modo, dirección, autenticación. Toma unos 3 segundos.
Pipeline de notificaciones
Las notificaciones push son la funcionalidad estrella de Tactic Remote para flujos "configura y olvida". Lanza una tarea larga, vete, recibe notificación cuando Claude termine o necesite tu entrada.
Cómo funciona
Claude Code soporta hooks — shell scripts que se ejecutan en eventos del ciclo de vida. La app Mac companion auto-configura estos hooks para hacer POST al servidor local:
Cuando Claude termina una tarea, este hook se activa. El servidor recibe el POST, transmite un evento de notificación a todos los clientes conectados, y la app iOS dispara una notificación local vía UNNotificationCenter.
Deduplicación de eventos
Los eventos hook pueden dispararse en rápida sucesión (p.ej., Claude para y reinicia múltiples subtareas). La app iOS deduplica eventos usando una ventana de 3 segundos con clave event|project|session|timestamp. Si el mismo evento lógico llega dos veces en 3 segundos, el duplicado se descarta silenciosamente.
Primer plano vs. segundo plano
Cuando la app está en primer plano, los eventos de notificación añaden un indicador visual al buffer del terminal:
Cuando la app está en segundo plano, se dispara una notificación del sistema. Toca para volver directamente a tu sesión.
Modelo de seguridad
Ejecutar código generado por IA de forma remota exige un modelo de seguridad serio. Aquí está el nuestro.
Autenticación
El servidor soporta autenticación por clave API a través de dos mecanismos:
- Cabecera
Authorization: Bearer <key>(estándar) - Cabecera
Sec-WebSocket-Protocol: <key>(respaldo para bibliotecas WebSocket de iOS que no pueden establecer cabeceras personalizadas en la solicitud de upgrade — una restricción común en móvil)
La autenticación se comprueba una vez al conectar. Si falla, el WebSocket se cierra inmediatamente con código 1008 (Policy Violation).
Prevención de inyección de comandos
Cada comando externo que el servidor ejecuta pasa por execSafe(), que llama a child_process.spawn() con shell: false. Los argumentos se pasan como arrays, nunca interpolados en strings. La inyección de shell es estructuralmente imposible.
La validación de entrada añade defensa en profundidad:
| Entrada | Validación |
|---|---|
| Nombres de sesión | /^[a-zA-Z0-9_-]{1,64}$/ |
| Comando Claude | /^claude(\s+--?[a-zA-Z0-9-]+)*$/ |
| Nombres de teclas | Lista blanca explícita de 18 teclas |
| Rutas de archivos | Resueltas a absolutas, comprobadas con startsWith() |
Protección contra traversal de rutas
La navegación de archivos está restringida al árbol del directorio home del usuario. Los directorios sensibles se bloquean independientemente de otras configuraciones:
La comprobación usa coincidencia segmento por segmento (no coincidencia de subcadena), así que un directorio llamado my-.ssh-backup no disparará un falso positivo.
Limitación de tasa
Los intentos fallidos de autenticación se limitan a 30 por minuto por IP usando una ventana deslizante en memoria. Tras exceder el límite, el servidor devuelve 429 Too Many Requests con una sugerencia de retryAfter.
Sin dependencia de la nube
Tu código nunca sale de tu Mac. Tactic Remote es un plano de control, no un plano de datos. El WebSocket transporta texto del terminal — entradas de comandos y cadenas de salida. Los archivos fuente, historial git y artefactos de build permanecen en tu máquina.
Cuando usas Cloudflare Tunnel, el túnel cifra el tráfico de extremo a extremo. Cloudflare ve frames WebSocket cifrados, no tu código.
La app iOS: no es un emulador de terminal
Al principio del desarrollo, tomamos una decisión consciente: la app iPhone no es un emulador de terminal tonto. Meter un terminal completo de 80x24 en una pantalla de 4 pulgadas es una experiencia terrible.
En su lugar, la app proporciona:
- Entrada estilo conversación: Escribe mensajes a Claude en un campo de texto, no un prompt de terminal
- Vista de salida del terminal: Texto renderizado con soporte de color ANSI, auto-scroll, zoom de tamaño de fuente con pellizco (defecto 8pt)
- Botones de acción rápida: Enter, Escape, Tab, Y, N, Ctrl+C — las teclas que realmente necesitas al interactuar con Claude Code
- Selector de sesiones: Navega y cambia entre sesiones tmux
- Navegador de rutas: Navega el sistema de archivos de tu Mac para establecer el directorio de trabajo
- Comandos slash: Autocompletado para
/help,/clear,/compact,/cost,/model,/status
Estrategia de reconexión
Las apps móviles viven en un entorno de red hostil. Tu teléfono cambia entre WiFi y datos, entra en ascensores, va a reposo. La estrategia de reconexión de la app maneja todo esto:
- Caída de conexión detectada: El evento close del WebSocket se dispara
- Backoff exponencial: Reintentar después de
min(attempts * 3, 15)segundos, hasta 5 intentos - Conciencia de segundo plano: Si la app está en segundo plano, saltar reconexión. Establecer flag para reconectar al volver a primer plano
- Restauración de sesión: Al reconectar, listar sesiones → encontrar la sesión previamente activa → re-adjuntar → polling de salida a 0.2s, 0.7s y 1.5s de retraso
El polling de salida escalonado (0.2s, 0.7s, 1.5s) tras la reconexión maneja el caso donde tmux necesita un momento para producir una captura después de re-adjuntar. Un polling inmediato único frecuentemente devolvería contenido vacío.
Buffer del terminal
El TerminalBuffer es un buffer circular limitado a 500.000 caracteres y 10.000 líneas. Cuando se desborda, el contenido se trunca desde el inicio, ajustándose al salto de línea más cercano para que nunca veas una primera línea parcial.
Este límite existe porque el renderizado de AttributedString se vuelve costoso a escala. 500K caracteres son aproximadamente 30 minutos de salida intensa de Claude Code — suficiente para cualquier sesión razonable mientras mantiene la UI responsiva.
La app Mac companion
La app Mac companion es una aplicación de barra de menú que gestiona el servidor Node.js, el túnel Cloudflare y los ajustes del sistema.
Empaquetado del servidor
El servidor Node.js completo está empaquetado dentro de la app Mac. Al primer inicio, copia los archivos del servidor a ~/Library/Application Support/ClaudeCodeRemote/Server/. En inicios posteriores, compara archivos byte por byte y solo re-copia los archivos cambiados. npm install solo se re-ejecuta si package.json ha cambiado.
Esto significa que los usuarios nunca tocan el terminal para instalar o actualizar el servidor.
Detección de dependencias
La app comprueba las herramientas requeridas (Node.js, tmux, Homebrew) escaneando rutas conocidas primero (/opt/homebrew/bin/, /usr/local/bin/), luego recurre a which. Si faltan dependencias, una pantalla de configuración guía al usuario a través de la instalación.
Prevención de reposo
Cuando el servidor está activo, la app llama a IOPMAssertionCreateWithName para prevenir que macOS entre en reposo. Esto es esencial — un Mac dormido no puede servir conexiones WebSocket.
Auto-configuración de hooks
La app companion escribe shell scripts en ~/.claude/hooks/ que hacen POST de eventos del ciclo de vida al servidor local. Esto ocurre automáticamente al iniciar el servidor — sin configuración manual necesaria.
Lo que no construimos
Algunas cosas que deliberadamente elegimos no hacer:
Sin multiplexación de terminal en la app. Usamos tmux en el lado del servidor, pero la app iPhone muestra una sesión a la vez. Paneles divididos en una pantalla de teléfono serían ilegibles.
Sin edición de archivos. La app puede navegar archivos pero no editarlos. Claude Code se encarga de la edición de archivos — tú eres el revisor, no el editor. Añadir un editor de código móvil sería scope creep que degrada la experiencia principal.
Sin modo offline. Si tu Mac es inalcanzable, la app te muestra el último estado conocido pero no puede hacer nada útil. No pretendemos lo contrario.
Sin respaldo de escritorio remoto. Screen sharing y VNC existen, pero son 10x peores para este caso de uso. Tactic Remote envía texto estructurado, no píxeles. Esto significa menor ancho de banda, menor latencia, y una UI diseñada para la tarea en vez de un escritorio encogido.
Configuración rápida
¿Quieres saltarte los detalles? Aquí tienes el mínimo para empezar.
En tu Mac
- Instala la app Mac companion desde tacticremote.com/download
- Lánzala — auto-instala dependencias e inicia el servidor
- Anota el código QR mostrado en la app
En tu iPhone
- Instala Tactic Remote desde App Store
- Escanea el código QR desde la app Mac
- Crea una sesión apuntando al directorio de tu proyecto
- Inicia Claude y envía tu primer prompt
Para acceso remoto (fuera de tu red doméstica), activa el toggle de Cloudflare Tunnel en los ajustes de la app Mac. La app genera una URL pública automáticamente.
Configurar notificaciones
En la app Mac, los hooks se configuran automáticamente cuando el servidor arranca. En el iPhone, concede permisos de notificación cuando se solicite. Eso es todo.
FAQ
¿Claude sigue ejecutándose si cierro la app del iPhone?
Sí. Claude se ejecuta en tmux en tu Mac. La app del iPhone es una ventana a esa sesión. Cierra la app, guarda tu teléfono en el bolsillo — Claude sigue trabajando. Abre la app de nuevo y verás todo lo que pasó mientras estabas fuera.
¿Qué pasa si mi red se cae?
La app del iPhone se reconecta automáticamente con backoff exponencial (hasta 5 intentos en ~45 segundos). Al reconectar, se re-adjunta a tu sesión anterior y obtiene la salida acumulada. No se pierde trabajo — tmux almacena todo en buffer en el lado del Mac.
¿Cuánta batería consume?
La app del iPhone no mantiene una conexión persistente en segundo plano. Cuando está en segundo plano, se desconecta limpiamente. El impacto en batería es esencialmente cero cuando no la estás usando activamente.
¿Puedo usar esto con otras herramientas de codificación IA?
Tactic Remote está construido alrededor de la interfaz de terminal de Claude Code, pero la arquitectura subyacente (gestión de sesiones tmux, streaming de terminal) funciona con cualquier herramienta basada en terminal. Si se ejecuta en un terminal, el servidor puede gestionarla. Las heurísticas de detección de estado son específicas de Claude Code, pero el bucle básico send-keys/capture-pane es universal.
¿Mi código está seguro?
Tu código nunca sale de tu Mac. Tactic Remote transmite texto del terminal por conexiones WebSocket cifradas. El servidor no tiene componente cloud, ni telemetría, ni analytics. Cuando usas Cloudflare Tunnel, el tráfico está cifrado de extremo a extremo — Cloudflare proxea frames cifrados, no tu código fuente.
Si quieres profundizar en subsistemas específicos, consulta Por qué elegimos tmux como backbone de sesiones, Construyendo streaming de terminal en tiempo real, y la documentación del modelo de seguridad.
Prueba Tactic Remote
Controla tus agentes de programación desde el móvil
Conéctate a Claude Code, Codex y otros agentes en tu Mac, Windows o Linux. Consulta el progreso y envía la siguiente instrucción desde el iPhone o iPad.