Cristian Carreño

Sala de control para agentes de IA

Agents Control Center

Una sola bandeja y un plano de control para muchas sesiones de Claude Code, en varias cuentas y en las máquinas que quieras, también desde un teléfono.

Rol
Único autor
Período
oct. 2026
Estado
En uso diario
Código
Privado, hecho en Enara Health
commits en 11 días
149
versiones, de 0.1 a 0.76
108
pruebas
565
dependencias de ejecución
10
  • TypeScript
  • Bun
  • React
  • SQLite
  • tmux
  • Noise
  • WebAuthn
  • Web Push
  • MCP
  • whisper.cpp

01 Contexto

Por qué existe

Uso varias suscripciones de Claude en paralelo, en más de una máquina. Cada sesión pide permisos y espera respuestas en su propia pestaña de terminal, así que las solicitudes se acumulan donde nadie está mirando. Los límites del plan solo se ven en la línea de estado de cada sesión, y una sesión que llega a uno simplemente se queda detenida.

Hay dos costos más que es fácil pasar por alto. Una conversación que se retoma después de que vence su caché de prompts cuesta cerca del doble de su tamaño en reescribirse. Y el control remoto integrado muestra una conversación a la vez, no las preguntas que esperan en todas ellas. Quería un solo lugar para ver cada sesión, responder lo que pregunta y mantener el trabajo andando cuando se agota una cuenta o una máquina, sin escribir cada respuesta a mano.

02 En uso

Qué hace

Todo lo de aquí funciona entre sesiones, cuentas y máquinas, algo que una sola sesión de Claude Code no puede ver. Claude Code es el agente que maneja hoy; el servidor llega a los agentes a través de adaptadores, así que se pueden sumar otros sin tocar la interfaz.

La lista de sesiones: once sesiones de Claude Code en cuatro máquinas y tres cuentas, con estado, actividad en vivo, memoria y CPU, un aviso por una sesión que usa demasiada CPU y una sesión abierta que pide hacer force push, marcada como riesgo alto. La lista de sesiones: once sesiones de Claude Code en cuatro máquinas y tres cuentas, con estado, actividad en vivo, memoria y CPU, un aviso por una sesión que usa demasiada CPU y una sesión abierta que pide hacer force push, marcada como riesgo alto.
Datos simulados Todas las sesiones de cuatro máquinas y tres cuentas, con su actividad y su carga en vivo. Un force push espera aprobación, marcado como riesgo alto.
La bandeja de decisiones: cuatro solicitudes de permiso y preguntas de sesiones y dos decisiones de un tablero de planificación; una está abierta y explica por qué su comando es de riesgo alto, junto a las decisiones anteriores de esa sesión. La bandeja de decisiones: cuatro solicitudes de permiso y preguntas de sesiones y dos decisiones de un tablero de planificación; una está abierta y explica por qué su comando es de riesgo alto, junto a las decisiones anteriores de esa sesión.
Datos simulados Una sola bandeja para todo lo que esperan los agentes: solicitudes de permiso, preguntas y decisiones de planificación, con el riesgo de cada comando explicado.
La vista de red: cuatro máquinas conectadas a la principal con su latencia, las sesiones orbitando cada máquina y mensajes entre agentes viajando por los enlaces. La vista de red: cuatro máquinas conectadas a la principal con su latencia, las sesiones orbitando cada máquina y mensajes entre agentes viajando por los enlaces.
Datos simulados Cuatro máquinas, cada una conectada a la principal, con sus sesiones en órbita y mensajes que viajan entre agentes. Sumar una máquina es pegar un comando.
El diálogo para mover una sesión a otra máquina en la misma cuenta, con un aviso de que la carpeta allá tiene dos commits que la sesión no tiene, y la opción de una copia aparte o una rama de respaldo. El diálogo para mover una sesión a otra máquina en la misma cuenta, con un aviso de que la carpeta allá tiene dos commits que la sesión no tiene, y la opción de una copia aparte o una rama de respaldo.
Datos simulados Mover una conversación a otra máquina. Primero se revisa la carpeta de destino; si tiene commits que la sesión no tiene, el trabajo va a una copia aparte.
Una tarjeta sobre la lista de sesiones: un agente en una máquina pide dos archivos privados de otra máquina, listados por nombre y tamaño, con Enviarlos y Rechazar. Una tarjeta sobre la lista de sesiones: un agente en una máquina pide dos archivos privados de otra máquina, listados por nombre y tamaño, con Enviarlos y Rechazar.
Datos simulados Un agente pide archivos privados a otra máquina. La persona ve nombres y tamaños, y lo aprobado viaja por el enlace cifrado, nunca por una conversación.
El diálogo de pegado seguro: un nombre, dos credenciales con los valores ocultos, la sesión a la que se avisa, el archivo env ignorado por git donde se escriben y un vencimiento. El diálogo de pegado seguro: un nombre, dos credenciales con los valores ocultos, la sesión a la que se avisa, el archivo env ignorado por git donde se escriben y un vencimiento.
Datos simulados Pegado seguro: las credenciales se guardan cifradas y se escriben en un archivo env que git ignora. La sesión solo conoce los nombres de las claves.
Una sesión leída en voz alta en un teléfono: la frase que se está leyendo aparece destacada, con pausa, anterior, siguiente y saltar, el micrófono de comandos hablados, la voz y la velocidad. Una sesión leída en voz alta en un teléfono: la frase que se está leyendo aparece destacada, con pausa, anterior, siguiente y saltar, el micrófono de comandos hablados, la voz y la velocidad.
Datos simulados En el teléfono, una sesión leída en voz alta mientras trabaja: la frase que suena se destaca, y los comandos hablados pausan, repiten, saltan o dictan una respuesta.
  • Una bandeja para todas las sesiones

    Las solicitudes de permiso y las preguntas de cada sesión, cuenta y máquina llegan a una sola lista, con el comando completo y una evaluación de riesgo. Responde con una tecla numérica, con una respuesta rápida o desde el teléfono. Los force push, los merges y las migraciones piden una segunda confirmación.

  • Las máquinas que quieras

    Una máquina principal y tantos nodos como vincules. Cada uno se suma pegando un comando, se reconecta solo después de una suspensión o un corte de red, y muestra su CPU y su memoria. Las sesiones nuevas van a la máquina que tiene capacidad.

  • Sesiones que se mueven, con su trabajo

    Una sesión sigue en otra cuenta cuando se le acaba el plan, o en otra máquina cuando falta memoria. Su trabajo sin commit viaja con ella, en privado, y para moverla no se hace ningún commit ni push.

  • Recuperación y detenciones automáticas

    Un guardián de memoria opcional pausa la sesión inactiva más pesada cuando queda poca memoria. Las sesiones que llevan mucho rato inactivas se cierran después de escribir una nota de traspaso y se reanudan desde ella por unos pocos miles de tokens. Las sesiones cerradas se reabren con la misma conversación, y las desactualizadas se reinician en la versión más nueva de Claude Code sin perderla.

  • Secretos que nunca entran a una conversación

    El pegado seguro guarda las credenciales cifradas y solo las escribe en archivos env que git ignora; la sesión se entera de los nombres de las claves, nunca de los valores. Un agente que necesita un archivo como .env de otra máquina lo pide, y la persona aprueba una lista de nombres y tamaños.

  • Ida y vuelta por voz

    Dicta con whisper.cpp en tu propia máquina, alternando entre español e inglés sobre la marcha. Kokoro lee en voz alta las respuestas del agente a medida que llegan, y los comandos de voz pausan, repiten o saltan; decir «responde» graba una respuesta, la envía cuando dejas de hablar y lee la respuesta siguiente.

  • Agentes que trabajan juntos

    Un servidor MCP en cada sesión permite que los agentes se encuentren, se manden mensajes, le pidan a la persona que inicie una sesión, pidan archivos y soliciten una ejecución de QA en un navegador real. Las sesiones que inició otra aparecen debajo de ella, aunque estén en otra máquina.

  • El plan y la caché de prompts, a la vista

    El uso del plan de cada cuenta y, para cada sesión inactiva, su tamaño y cuánto tiempo sigue caliente su caché de prompts, porque volver después de que vence cuesta cerca del doble de la conversación.

  • Un mapa en vivo de lo que corre

    La vista Activity dibuja el árbol de procesos de una sesión, con los servidores que dejó escuchando y un botón para detener comandos desbocados. La vista de red muestra todas las máquinas, con cada mensaje entre agentes volando por los enlaces.

  • Cuentas y terminales desde cualquier dispositivo

    Agrega una cuenta de Claude y autentícala desde el teléfono, y abre en el navegador la terminal en vivo de una sesión cuando espera una tecla que la app no puede enviar.

03 Arquitectura

Cómo funciona

Un servidor Bun local encuentra cada sesión interactiva de Claude Code en la máquina, lee lo que está haciendo y la maneja a través de su propia terminal. Una app React, instalable en un teléfono, las muestra todas con una sola bandeja para las preguntas. Cualquier número de nodos corre el mismo programa sin interfaz y se conecta a la máquina principal por un enlace cifrado; la máquina principal da las órdenes y retransmite todo entre ellos.

Arquitectura de Agents Control Center El servidor lee la pantalla y la transcripción de cada sesión y escribe en su terminal; los agentes llegan a él a través del servidor MCP que hay dentro de cada sesión; los nodos, tantos como haya vinculados, se conectan por un canal Noise y solo aceptan llamadas de una lista. Pantallas Máquina principal Nodos, los que quieras Navegador de PC PWA React, una bandeja Teléfono passkey, push, voz Datos locales SQLite + JSON Servidor ACC Bun, consulta cada 2 s MCP agents dentro de cada sesión Sesiones de Claude tmux, varias cuentas Nodo ACC 1 por máquina, sin UI Sesiones de Claude las cuentas del nodo WebSocket HTTPS + push bandeja, mover loopback pantalla + teclas stdio Noise IK controla
El servidor lee la pantalla y la transcripción de cada sesión y escribe en su terminal; los agentes llegan a él a través del servidor MCP que hay dentro de cada sesión; los nodos, tantos como haya vinculados, se conectan por un canal Noise y solo aceptan llamadas de una lista.
  1. Adaptadores para agentes y terminales

    El servidor nunca llama directamente a Claude Code. Un adaptador de agente solo lee el estado propio del agente: sus cuentas, sesiones, transcripciones, subagentes, decisiones pasadas, flags de arranque y cómo retomar una conversación. Pausar, cerrar y entregar mensajes no dependen del agente, y un transporte de terminal envía teclas, lee la pantalla y abre pestañas. Claude Code, tmux y cmux están implementados; Codex CLI, Gemini CLI, opencode o Aider serían, cada uno, un adaptador más.

  2. Encontrar y vigilar sesiones sin ser su dueño

    Cada dos segundos el servidor lee el archivo que Claude Code escribe por cada proceso en ejecución y el final de cada transcripción, y mide CPU y memoria sobre todo el árbol de procesos de cada agente. Las sesiones viven en tmux, no como procesos hijos del servidor, así que lo sobreviven.

  3. Una bandeja, respondida con seguridad

    Las solicitudes de permiso y las preguntas se leen de la pantalla de la terminal y se revisan contra quince reglas de riesgo. Para responder, el servidor vuelve a leer la pantalla y solo escribe si la solicitud sigue coincidiendo con la que viste. Las aprobaciones de alto riesgo, como los force push, los merges y las migraciones, piden una segunda confirmación.

  4. Las máquinas que quieras, sobre Noise

    Cada nodo se conecta a la máquina principal con el handshake Noise IK, después de una primera vinculación con un token de un solo uso, así que no hay un número fijo de máquinas: cada una es otro par vinculado. La máquina principal solo puede invocar en él una lista cerrada de llamadas, sin ninguna llamada genérica de shell, archivos o exec. Los eventos van numerados y con acuse de recibo, y una llamada repetida nunca se ejecuta dos veces.

  5. Un servidor MCP en cada sesión

    La app instala un servidor MCP agents en cada cuenta de cada máquina. Los agentes lo usan para ver dónde corren y cuánto plan les queda, encontrarse, mandarse mensajes, iniciar o mover sesiones, pedir archivos y solicitar una ejecución de QA. Los mensajes llegan marcados como que no vienen del usuario.

  6. Sesiones que se mueven

    Cuando una sesión llega al límite de su plan, la app la mueve por sí sola, prefiriendo el mismo grupo de cuentas, luego la misma máquina y después el margen de plan y la memoria libre. Entre máquinas, el trabajo sin commit viaja como un git bundle, parches binarios y un paquete de archivos, y el destino comprueba que git status coincida.

  7. Secretos fuera de las conversaciones

    El pegado seguro mantiene las credenciales cifradas en reposo y solo las escribe en archivos env que git ignora, así que un secreto nunca llega a un commit. Los agentes usan los valores desde la shell sin imprimirlos, y cada guardado, escritura, lectura y borrado queda auditado sin el valor.

  8. Un teléfono que es un control remoto de verdad

    Los teléfonos se vinculan con un código QR y llegan a la app por Tailscale. La app se bloquea con una passkey y las notificaciones push van cifradas de extremo a extremo. La voz se queda en tus propias máquinas: whisper.cpp transcribe, Kokoro lee en voz alta y Vosk escucha los comandos de voz.

04 Decisiones

Las decisiones que le dieron forma

  1. Decisión 01

    Adaptadores, para que Claude Code sea el primer agente y no el único

    Elegí
    Un adaptador de agente que solo lee el estado propio del agente, y un transporte de terminal que envía teclas, lee la pantalla y abre pestañas.
    En vez de
    Llamar a Claude Code y a tmux directamente desde el servidor.
    Porque
    Otro agente u otra terminal es un módulo nuevo detrás de la misma bandeja, el mismo teléfono y el mismo enlace entre máquinas.
    Costo
    Con un solo agente implementado, la interfaz está moldeada por Claude Code, y los traslados y el cierre por inactividad todavía leen directamente los archivos de Claude Code.
  2. Decisión 02

    Manejar la terminal real en vez de envolver al agente

    Elegí
    Leer los archivos de sesión y las transcripciones del propio Claude Code, interpretar la pantalla de su terminal y escribir en tmux.
    En vez de
    Iniciar las sesiones con un SDK, lo que las escondería de la terminal y perdería las funciones interactivas.
    Porque
    También aparecen las sesiones abiertas a mano, las funciones interactivas se mantienen y las sesiones sobreviven a los reinicios de la app.
    Costo
    Nada de eso es una interfaz pública, así que una actualización de Claude Code puede romper una lectura. Varias versiones arreglaron justamente eso, y los parsers se prueban contra pantallas y transcripciones reales.
  3. Decisión 03

    Escribir un canal Noise, con el nodo iniciando la conexión

    Elegí
    Un enlace Noise IK implementado en el repositorio sobre primitivas auditadas, probado contra los vectores de prueba publicados.
    En vez de
    SSH, que necesita un servidor y redirección de puertos dentro de WSL, y una VPN como enlace con los nodos, que autentica máquinas y no esta app.
    Porque
    Autenticación mutua en un solo intercambio, funciona detrás de NAT y sumar una máquina es pegar un comando.
    Costo
    Un protocolo a mi cargo, que hay que mantener seguro, y una red en estrella: todo lo que va entre nodos pasa por la máquina principal.
  4. Decisión 04

    Mover el trabajo sin commit ni push

    Elegí
    Empaquetar el trabajo sin commit como un bundle, parches y un paquete de archivos, enviarlo por el enlace y verificarlo al llegar.
    En vez de
    La primera versión, en la que los agentes hacían commit y push a una rama de trabajo en curso antes de moverse.
    Porque
    El trabajo nunca debe llegar a un remoto solo porque una sesión se movió; puede contener archivos que nunca deberían salir de la máquina.
    Costo
    Una larga cola de casos borde: archivos de metadatos de la plataforma, un traslado de 1,2 GB que hizo caer el servidor y el rollback cuando un traslado falla a medio camino.
  5. Decisión 05

    Acotar lo que los agentes pueden hacer solos

    Elegí
    Un agente puede moverse sin preguntar solo cuando se le agotó el plan o a su máquina le falta memoria, y solo dentro de su grupo de cuentas. Iniciar sesiones, moverse entre grupos y pedir archivos quedan esperando al usuario.
    En vez de
    La autonomía total o preguntar por todo.
    Porque
    Las emergencias comunes se resuelven de inmediato, y todo lo que gaste el plan de otra persona o se meta en otra máquina sigue siendo una decisión humana.
    Costo
    Más tarjetas de aprobación en la bandeja.
  6. Decisión 06

    Mantener los secretos fuera de la conversación

    Elegí
    Un almacén local cifrado para las credenciales, un traspaso de archivos entre máquinas que la persona aprueba, y un hook que detiene, una vez, la llamada a una herramienta que está por leer un secreto y le indica la vía segura.
    En vez de
    Pegar claves en el chat, o dejar que los agentes lean archivos .env cada vez que necesitan un valor.
    Porque
    Todo lo que entra a una conversación queda en su transcripción y se vuelve a enviar con cada solicitud posterior.
    Costo
    Un paso más cada vez que un agente necesita una clave, y por ahora los secretos guardados se quedan en la máquina principal.
  7. Decisión 07

    Llegar al teléfono por una red privada

    Elegí
    Tailscale con su certificado, bloqueo con passkey y Web Push implementado en el repositorio.
    En vez de
    Un túnel público con una capa de acceso adelante, o un servidor de retransmisión que mantener en marcha.
    Porque
    Nada es accesible desde internet y no hay un servidor extra que mantener.
    Costo
    Tailscale en ambos dispositivos, y los teléfonos vinculados en la red local tienen que vincularse de nuevo.

05 Lo interesante

Vale la pena mirarlo de cerca

  • Las aprobaciones son compare-and-swap

    Una tecla solo se envía si la solicitud, leída otra vez desde la pantalla, todavía tiene la huella que la persona aprobó. Los mensajes solo se escriben en un cuadro de texto vacío, nunca encima de un borrador.

  • Estado e historial van por separado en un enlace inestable

    Los snapshots son estado y se envían completos, así que una reconexión solo reenvía el último. Lo que tiene que pasar una sola vez son eventos numerados que se retienen hasta el acuse de recibo, y las llamadas son idempotentes por id. Las reconexiones usan backoff con jitter.

  • Pensado en torno a la caché de prompts

    Muestra la vida útil de la caché de cada sesión, mantiene las cachés calientes con pings mínimos que se detienen al 80% del plan, cierra las sesiones inactivas después de escribir una nota de traspaso y agrega sus propias indicaciones a los resultados de las herramientas en vez del system prompt, para que la caché siga siendo válida.

  • Traslados que sobreviven a una mala red

    Los archivos viajan en trozos que retransmite la máquina principal, cuatro a la vez, cada uno verificado con SHA-256 y reenviado si llega dañado. Sobre 1 GB, el origen primero arma un solo paquete, comprimido con zstd cuando ambas máquinas lo tienen.

  • Comandos de voz sin un micrófono abierto

    Mientras lee en voz alta, escucha unas pocas palabras de comando. Solo salen del dispositivo ráfagas cortas de voz, hacia la máquina que corre la voz, y se ignora un comando que la propia voz acaba de decir.

  • Pocas dependencias

    Diez dependencias de ejecución. Noise, Web Push, la verificación de WebAuthn y el servidor MCP están escritos en el repositorio, cada uno lo bastante pequeño para leerlo.

06 Hecho con agentes

Cómo encajan los agentes

Se construyó en once días, 149 commits de la versión 0.1 a la 0.76, y cada uno de sus 132 commits que no son merge tiene a Claude como coautor. El archivo de reglas fija tres hábitos: todo en inglés, una entrada en el CHANGELOG y subir la versión con cada pull request, y la verificación completa (tipos, pruebas, build web, validación del plugin) antes de cada push. Los merges pasan por un script que corre las mismas verificaciones sobre el resultado en un worktree desechable.

Lo que más cambió es quién lleva los mensajes. Los agentes se preguntan entre ellos directamente en vez de pasar por mí, piden los archivos que necesitan sin que se peguen secretos en una conversación, le piden a QA Console que revise su trabajo de interfaz en un navegador real y se mueven solos fuera de una cuenta cuyo plan se agotó.

Hizo trabajo real mientras se construía, y el historial lo muestra bajo carga: un traslado de sesión de 1,2 GB que hizo caer el servidor, servidores de voz acumulándose en memoria, transcripciones de 90 MB. Cada uno se convirtió en un arreglo y una prueba.

Contacto

¿Quieres profundizar en Agents Control Center?

Escríbeme por LinkedIn