
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=falseevita el asistente interactivo, que colgaría el/execesperando una respuesta que nadie va a dar.GOOSE_BIN_DIR=/usr/local/binlo deja en el PATH.- Corre como root a propósito: la frontera de seguridad es el hipervisor, no el usuario.

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 5 · Levantar el servidor ACP
En background, con /bg:
Las dos banderas son cicatrices:
--host 0.0.0.0porque el default de goose es127.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-unauthenticatedporque sin ella goose exigeGOOSE_SERVER__SECRET_KEY. Para una demo está bien; para algo que dure, no.
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:
Si responde ok, la caja y el bind están bien y cualquier problema que siga es del editor.

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.
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+P → Preferences: 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
envva 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. 🤓
