cover

Cómo correr tu agente de código en una microVM y conectarlo a VS Code

author photo

Héctorbliss

@hectorbliss

Vas a levantar un agente de código dentro de una microVM y conectarlo a VS Code por ACP (Agent Client Protocol), sin SSH y sin entrar a la caja: todo con curl desde tu terminal.

Necesitas VS Code, Node y una llave de EasyBits de Dashboard → Developer.

Paso 0 · Variables

Todos los pasos usan estas dos:

Paso 1 · Crear la caja

Un POST. Responde status: "starting" y en unos segundos pasa a running. Guarda el id:

Son 2 vCPU, 2 GB y disco propio, aislada por el hipervisor.

Paso 2 · Darle vida

La caja nace con 30 minutos. Extiéndela antes de invertirle trabajo:

Paso 3 · Instalar el agente

Aquí entra /exec: corre comandos dentro de la caja por REST. No hay llave ed25519, no hay túnel, no hay nada que configurar.

  • CONFIGURE=false evita el asistente interactivo, que colgaría el /exec esperando una respuesta que nadie va a dar.
  • GOOSE_BIN_DIR=/usr/local/bin lo deja en el PATH.
  • Corre como root a propósito: la frontera de seguridad es el hipervisor, no el usuario.
  • El id lleva el prefijo sb_ y así va en la URL. Si lo pasas sin prefijo, la API no responde 404 sino un Unexpected Server Error que no dice nada.
Una llave luminosa entrando a la cerradura de una caja servidor

Paso 4 · Apuntar el LLM

La configuración va en /root/.config/goose/.env con permisos 600. Escríbela con el mismo /exec:

La llave se queda dentro de la caja; tu editor nunca la ve. Si adaptas ese printf, cuidado: con printf '%s' 'KEY=valor\n' el \n queda literal pegado a la llave y el 401 que sigue parece problema de permisos. Verifica que el agente arranca:

Paso 4½ · La carpeta que el cliente va a nombrar

Cada cliente manda un cwd en session/new, y ninguno pregunta si existe del otro lado del cable. VS Code manda la carpeta que tengas abierta en tu Mac; Ghosty Teams manda /data/work. La caja nace sólo con /root, así que goose contesta

y el editor lo resume en un "Failed to connect: Invalid params" sin más pistas. Crea la carpeta antes de conectar nada:

Con VS Code, además, abre una carpeta cuya ruta exista en la caja o conéctate sin carpeta abierta: la ruta de tu disco no significa nada allá.

Paso 5 · Levantar el servidor ACP

En background, con /bg:

Las dos banderas son cicatrices:

  • --host 0.0.0.0 porque el default de goose es 127.0.0.1, y el proxy público dialea la IP del guest, no su loopback. Con el default todo se ve bien por dentro y afuera recibes un 502 sin explicación.
  • --dangerously-unauthenticated porque sin ella goose exige GOOSE_SERVER__SECRET_KEY. Para una demo está bien; para algo que dure, no. La versión seria es exportar esa variable antes del exec y mandar la misma cadena en el header X-Secret-Key desde el cliente; sin header, el wss:// responde 401.
  • El puerto es libre. Aquí va 3000; el default de goose es 3284 y la URL de expose lleva el que elijas.

Paso 6 · Exponer el puerto

Devuelve una URL del tipo https://sb-<uuid>-3000.sandboxes.easybits.cloud, y esa misma URL sirve wss:// sin nada extra. Comprueba antes de ir al editor, pero no con /health: esa ruta la contesta el router público y da ok aunque la microVM esté dormida o goose no escuche. Pégale a la ruta del protocolo:

Un 401 (pide la key) o un 426/400 (pide el upgrade a WebSocket) significan que goose ya escucha. Un 502 significa que nadie contesta en ese puerto desde la IP del guest: revisa el --host 0.0.0.0. Si la caja se durmió por inactividad no hace falta despertarla a mano: el propio upgrade a WebSocket la levanta.

Un servidor conectado a un globo terráqueo y a una barra de dirección con candado

Paso 7 · Instalar el cliente ACP en VS Code

VS Code no habla ACP de fábrica. El cliente es la extensión ACP Client (formulahendry.acp-client): pone el panel de chat, presta el disco y la terminal, y administra los permisos.

O con Cmd+Shift+X buscando ACP Client. El panel se abre con Cmd+Shift+A.

Dos islas flotantes unidas por un puente de luz: laptop de un lado, servidor del otro

Paso 8 · Declarar los dos agentes

VS Code lanza procesos y les habla por stdio, pero no abre WebSockets. Entre ambos va un puente que lee JSON-RPC de stdin y lo empuja al socket: ghosty-acp, que se invoca con npx sin instalar nada.

Abre settings.json con Cmd+Shift+PPreferences: Open User Settings (JSON):

Tres detalles que cuestan diez minutos cada uno:

  • En el local, la ruta va absoluta: goose queda en ~/.local/bin, que no siempre está en el PATH que hereda VS Code al abrirlo desde el Dock, y "command": "goose" truena con un ENOENT mudo.
  • En el remoto, el env va vacío: la llave del modelo ya vive dentro de la caja.
  • El local es opcional, sólo sirve para comparar. Si no tienes goose en tu máquina, deja el segundo.

Guarda, abre el panel y elige el agente en el selector. Si editas la configuración con el agente conectado, ACP: Restart Agent para que la relea.

Ver el protocolo por dentro

El comando ACP: Show Protocol Traffic abre un panel con el JSON-RPC crudo conforme pasa. El primer mensaje ya trae la idea completa:

Eso lo manda el editor: te presto mi disco y mi terminal. Declara los tres en false y el mismo agente pierde el acceso a archivos. El agente no decide qué puede tocar; lo decide quien lo invoca.

Con el remoto conectado, el intercambio es idéntico al del local:

Cambió dónde corre el agente. No cambió cómo se le habla.

Ejercicio de dos minutos. session/new trae cuatro modos: auto aprueba las herramientas solo, approve pregunta por cada una, smart_approve sólo por las sensibles y chat las desactiva. Pon approve, pide que escriba un archivo y mira llegar session/request_permission: el agente se detiene y espera. Cambia a auto y el permiso desapareció. Misma petición, mismo modelo — la política vive del lado del cliente.

Lo que falta

Al cerrar VS Code se pierde todo: las sesiones viven en un Map en memoria del proceso, aunque el agente declara loadSession: true desde el primer mensaje. El botón de detener tampoco interrumpe de verdad, porque falta session/cancel.

Y algo que aparece sin buscarlo: antes de escribir nada, el agente manda available_commands_update con sus comandos, y ahí vienen las skills, marcadas con commandType: "Skill". Salen del cwd que viajó en session/new — goose lee el .agents/skills/ del proyecto donde estás parado, así que cambias de carpeta y cambia la lista. El agente aprende del lugar donde trabaja, pero eso ya es otra sesión.


Esto es la primera de seis sesiones del taller Diseño de sistemas agénticos, donde construimos un agente propio de punta a punta: el harness, la interfaz, la memoria, los permisos y las habilidades.

Abrazo. Blissmo. 🤓

meta cover

Los secretos detrás del poderoso TailwindCSS

Checa este otro Post

meta cover

Te explico qué es Closure en JavaScript

Checa este otro Post

¡Nuevo curso!

Animaciones web con React + Motion 🧙🏻