CTRL NODE
Ingeniería · 1 mar 2026 · 7 min de lectura

Construyendo un puente WebSocket exclusivamente saliente para agentes de IA locales

Construyendo un puente WebSocket exclusivamente saliente para agentes de IA locales

Los agentes de codificación con IA locales son potentes precisamente porque son locales: leen tus archivos reales, se ejecutan en tu shell real y ven tu repositorio real. Eso es también exactamente lo que hace difícil controlarlos de forma remota. No puedes simplemente exponer una API en tu portátil y darlo por resuelto: estarías abriendo un puerto hacia tu sistema de archivos desde internet público.

Bridge es la pieza de CTRL NODE que resuelve esto sin aceptar nunca una conexión entrante. Se ejecuta en tu máquina, marca hacia afuera hacia nuestro plano de control mediante un único WebSocket, y todo (el despacho de tareas, la salida en vivo, las lecturas de archivos) fluye por ese único canal saliente. Este artículo es un recorrido por cómo funciona realmente esa conexión, basado en el código fuente actual de Bridge.


1. Por qué exclusivamente saliente

La forma ingenua de hacer que un proceso local sea controlable de forma remota es exponerlo: abrir un puerto, tal vez poner ngrok delante, y darlo por hecho. Eso funciona hasta que piensas en qué hay al otro lado de ese puerto: un proceso con acceso de lectura/escritura a tu sistema de archivos y la capacidad de generar agentes de IA que pueden ejecutar código.

Bridge, en cambio, establece exactamente una conexión, y siempre se origina desde tu máquina:

Bridge (your machine) ──outbound WSS──▶ wss://api.ctrlnode.ai/ws/bridge

Sin puerto entrante, sin regla de firewall, sin traversal de NAT, sin relé de túnel de terceros situado entre tú y tus archivos. Si tu red puede alcanzar internet en absoluto, incluso detrás de un firewall corporativo restrictivo, Bridge funciona. La conexión se autentica con un token de emparejamiento, no con una puerta abierta.

2. El token de emparejamiento

Antes de que Bridge pueda conectarse a nada, necesita un token que identifique a qué organización pertenece. Ese token se genera una vez, en la app de CTRL NODE bajo Settings → Bridge, y se entrega a Bridge durante la configuración:

ctrlnode --setup

El asistente de configuración pide la raíz de tu workspace y el token de emparejamiento, y luego escribe ambos en <workspace>/.ctrlnode/.env. A partir de ahí, cada handshake de WebSocket envía ese token como credencial bearer:

// websocket.ts
headers: {
  'authorization': `Bearer ${PAIRING_TOKEN}`,
  'x-bridge-version': BRIDGE_VERSION,
  'x-agents': Object.keys(discoveredAgents).join(','),
}

El token nunca sale de tu archivo .env, salvo en esa cabecera. No hay un almacén de credenciales separado, ni un flujo de OAuth: solo un token bearer que delimita la conexión a tu organización.

3. El ciclo de vida de la conexión

Al arrancar, Bridge resuelve su configuración (raíz del workspace, token de emparejamiento, claves de API de proveedores) buscando en ~/.ctrlnode/.env, luego en el .env del directorio actual, y finalmente subiendo por el árbol del home. Una vez que tiene un token, abre el WebSocket y envía un handshake:

{ action: 'handshake', version, agents: discoveredAgents, providers: availableProviders }

Ese handshake le indica al plano de control qué proveedores de IA están realmente disponibles en esta máquina: Bridge solo anuncia lo que realmente puede ejecutar.

Las conexiones no permanecen abiertas para siempre sin mantenimiento. Dos cosas ocurren en segundo plano:

  • Heartbeat: cada 30 segundos (configurable), Bridge envía el estado actual de cada agente. Esto también es lo que mantiene el socket vivo a través de balanceadores de carga y proxies inversos que descartan silenciosamente las conexiones inactivas.
  • Sondeo de configuración: cada 60 segundos, Bridge vuelve a escanear el sistema de archivos en busca de agentes añadidos o eliminados y resincroniza.

4. Reconectar sin perder eventos

Las redes se caen. Los portátiles se duermen. Cuando el WebSocket se cierra, Bridge no se rinde sin más, pero tampoco reintenta a ciegas, porque una conexión cerrada puede significar dos cosas muy distintas.

Si el cierre parece un fallo de autenticación (códigos de cierre 1008/1002, o un mensaje de "Unauthorized"/"401"), Bridge espera 30 segundos antes de volver a intentarlo: martillear un servidor que acaba de rechazar tu token no sirve de nada. Para cualquier otro caso (una conexión Wi-Fi caída, una máquina dormida que despierta), reintenta en un intervalo fijo más corto.

Mientras está desconectado, Bridge no descarta los eventos que habría enviado. Las finalizaciones de tareas, la salida en streaming, los cambios de estado: todo lo generado mientras está sin conexión va a una cola pendiente (con un límite de 100 elementos) y se vacía en el momento en que la conexión se restablece. No pierdes los últimos segundos de una tarea solo porque el Wi-Fi de tu máquina falló a mitad de ejecución.

5. Enrutando tareas hacia proveedores

Un único proceso Bridge puede ejecutar varios proveedores de IA en paralelo: Claude, GitHub Copilot, Google Gemini, OpenAI Codex, Cursor, Hermes y OpenClaw están todos soportados hoy, cada uno con un estilo de invocación distinto por debajo: algunos a través de SDKs oficiales, algunos manejando una CLI mediante el Agent Client Protocol (ACP), y uno (OpenClaw) a través de un gateway HTTP local.

Cuando llega una tarea por el WebSocket, Bridge no la enruta en proceso por tipo de proveedor: resuelve el agente de destino, y cada agente ya sabe qué proveedor lo respalda (MultiProvider agrupa todos los proveedores configurados y despacha según la propiedad del agente). El proveedor entonces genera o invoca el proceso de IA subyacente, y tres callbacks transmiten todo de vuelta por el mismo socket:

  • onStream: tokens y llamadas a herramientas, a medida que ocurren
  • onMessage: salida de texto incremental
  • onComplete: estado final y motivo

Nada de esto espera a que la tarea completa termine antes de que veas algo. La salida se transmite en vivo, de la misma forma en que lo haría si estuvieras viendo una terminal local.

6. Dos formas en que un agente toca tus archivos

Cada tarea se ejecuta en uno de dos modos, y la diferencia importa:

  • Modo Output (el predeterminado): el workspace del agente es una carpeta aislada bajo <workspace>/tasks/<taskId>/. Puede leer y escribir dentro de ese sandbox, pero nunca toca el resto de tu sistema de archivos.
  • Modo Work Directory: el directorio de trabajo del agente es tu repositorio real. Esto es lo que hace posibles las refactorizaciones in situ, las correcciones de errores y el trabajo de funcionalidades que abarca varios archivos: el agente edita el código al que apuntas, no una copia de él.

Incluso en modo Work Directory, el log y los metadatos propios de la tarea siguen viviendo bajo la carpeta propia de CTRL NODE, separados de tu repositorio, de modo que el historial de ejecución de una tarea nunca termina confirmado por accidente junto con tu código.

7. Lo que realmente ve la nube

Esta es la parte que vale la pena dejar explícita: el plano de control (la app web de CTRL NODE, el dashboard, el historial de tareas) nunca recibe el contenido de tus archivos. Recibe actualizaciones de estado, salida de texto en streaming y metadatos de tareas a través del WebSocket. Los archivos en sí permanecen en la máquina donde se ejecuta Bridge. Si estás auditando una base de código o refactorizando algo sensible, el código nunca sale de tu infraestructura.

El propio Bridge es de código abierto y con licencia MIT, distribuido como binarios precompilados para Windows, Linux y macOS a través de GitHub Releases, sin necesidad de ningún paso de build para ejecutarlo. Si quieres verificar cualquiera de las afirmaciones de este artículo, el código está ahí mismo.

Pruébalo

# Windows
iwr https://github.com/ctrlnode-ai/ctrlnode/releases/latest/download/install.ps1 | iex

# Linux / macOS
curl -fsSL https://github.com/ctrlnode-ai/ctrlnode/releases/latest/download/install.sh | bash

# then pair it
ctrlnode --setup

Una única conexión saliente, tus claves y tu código permanecen en tu máquina, y cada proveedor de IA que ya usas (Claude, Copilot, Gemini, Codex, Cursor, Hermes, OpenClaw) se vuelve despachable de forma remota desde el mismo plano de control.