Sandbox
El sandbox es un contenedor por tarea donde el agente instala dependencias, corre builds y tests, y levanta la app para que la vea QA. Vive aparte del contenedor del agente: el agente edita el código y maneja git en el suyo, y manda los comandos pesados al sandbox. Los dos ven el mismo código en /workspace/projects/<repo>/, así que lo que el agente edita ya está en el sandbox sin copiar nada.
Thulu crea el sandbox con el primer comando que el agente le manda y lo apaga después de 30 minutos sin uso. Entre corridas, la etapa siguiente encuentra el sandbox como lo dejó la anterior, con la app levantada, mientras no pasen esos 30 minutos. Las subtareas usan el sandbox de su tarea padre.
Para el uso diario no hay nada que hacer en la página “Sandboxes”: alcanza con que el agente tenga el sandbox habilitado en su etapa. La página sirve para ver qué está corriendo, quién espera lugar y matar un sandbox trabado. Si ningún agente tiene argus-sandbox tildado en ninguna etapa, la página lo avisa con un link a Agentes.
Darle el sandbox a un agente
Sección titulada «Darle el sandbox a un agente»Un agente sólo puede usar el sandbox en las etapas donde tiene tildado el servidor MCP argus-sandbox. Sin eso, la corrida no recibe las herramientas y el agente instala y construye dentro de su propio contenedor, sin caché y sin que nadie más pueda ver la app.
-
Abrí “Agentes” en la barra lateral y elegí el agente.
-
Andá a la pestaña “MCP”. Hay un bloque por cada etapa en la que trabaja el agente.
-
En la etapa que corresponda, tildá
argus-sandbox. El contador “Tools” pasa a 7/7: el sandbox se concede entero, sin elegir herramientas sueltas.
argus-sandbox tildado en la etapa En curso. Hay que repetirlo en cada etapa donde el agente tenga que construir o levantar la app. -
Tocá “Guardar configuración”.
Con argus-sandbox, la corrida recibe también la skill del sistema octopus-sandbox, que le enseña al agente a levantar el proyecto, qué hacer cuando un build se queda sin memoria y cómo dejar la app lista para la etapa siguiente. Ver Agentes y MCPs.
Qué puede hacer el agente con el sandbox:
| Herramienta | Para qué |
|---|---|
exec |
Correr un comando de shell. Devuelve la salida, los errores y el código de salida. Cada comando tiene un tope de 30 minutos. |
preview_url |
Pedir la dirección de un puerto donde escucha la app: una para el navegador de QA y otra para una persona (ver Puertos y previews). |
attach_file |
Adjuntar a la tarea un archivo que generó en el sandbox (un PDF, un reporte de cobertura), hasta 50 MB. |
init_status, init_run, init_script_get, init_script_update |
Consultar, correr y corregir el script de arranque del proyecto (ver Script de arranque). |
Ver qué está corriendo
Sección titulada «Ver qué está corriendo»La página está en el modo Configuración: tocá “Configuración” abajo en la barra lateral y después “Sandboxes”, en el grupo “Operación”.

“Sandboxes activos” lista un sandbox por tarea:
| Columna | Qué muestra |
|---|---|
| “Tarea” | El título de la tarea, con link a su detalle. También aparecen “Precalentado de <proyecto>” (el precalentamiento de la caché de un proyecto) y “Tanda de Evidencia” (la app de una tanda de Evidencia): ocupan un lugar igual que una tarea. |
| “Contenedor” | Los primeros 12 caracteres del contenedor (en Kubernetes, el pod). |
| “Estado” | “Listo” (acepta comandos) o “Arrancando”. Los desalojados y los que fallaron salen de la lista. |
| “Inactivo” | Hace cuánto no recibe un comando. Al llegar al desalojo por inactividad, Thulu lo apaga. |
| “Puertos” | Pares puerto-del-host:puerto-del-sandbox. En Docker, 32800:3000 quiere decir que la app que escucha en el 3000 del sandbox se abre en localhost:32800 del servidor. |
La página se actualiza sola cada 4 segundos. Cada persona ve sólo los sandboxes de su workspace.
“Cola” lista las tareas que pidieron un sandbox cuando ya estaban todos ocupados, con su etapa y la prioridad de esa etapa. Cuando se libera un lugar se lo lleva la de prioridad más alta, y entre iguales la que llegó primero. Thulu relanza la etapa en la que está la tarea para que el agente retome. “Sacar de la cola”, al final de la fila, saca una tarea que ya no tiene que esperar.
Matar un sandbox
Sección titulada «Matar un sandbox»Sirve cuando un sandbox quedó en mal estado (un proceso colgado, un disco lleno) o para liberar un lugar ya.
-
En “Sandboxes activos”, tocá el botón de apagado al final de la fila. También podés hacerlo desde la tarea: la fila “Sandbox” de sus propiedades muestra el estado, cuánto lleva inactivo y “Matar”.
-
Confirmá con “Matar”. Aparece el aviso “Sandbox eliminado”.

El diálogo nombra la tarea dueña del sandbox.
Matar el sandbox no toca la tarea ni su etapa. Si el agente vuelve a mandar un comando, Thulu le crea uno nuevo: se pierden los procesos que corrían, /tmp y lo instalado fuera del repo, y se conservan el código del repo y la caché de dependencias del workspace. Hace falta rol admin.
Cambiar los límites y las prioridades
Sección titulada «Cambiar los límites y las prioridades»El panel “Configuración” tiene tres números y una prioridad por etapa. Valen para toda la instalación, no por workspace: sólo los admins del workspace operador pueden guardarlos. El resto ve el panel en sólo lectura con el aviso “Los límites de sandboxes y las prioridades por etapa se aplican a todos los espacios de trabajo de esta instalación.”
| Campo | Default | Qué hace |
|---|---|---|
| “Máximo de sandboxes simultáneos” | 3 | Cuántos sandboxes pueden estar vivos a la vez. El siguiente que se pida espera en la cola. |
| “Desalojo por inactividad (minutos)” | 30 | Cuánto tiempo sin comandos antes de apagar un sandbox. Uno que está corriendo un comando no se apaga. Si todos los lugares están ocupados y alguien pide uno, Thulu también desaloja en el momento el que lleva más de ese tiempo sin uso. Con 0 no se desaloja nunca. |
| “Espera por un lugar libre (segundos)” | 120 | Cuánto espera el pedido del agente a que se libere un lugar. Pasado ese tiempo, el agente recibe que quedó en cola y Thulu relanza la etapa cuando le toca el turno. Con 0 la tarea pasa a la cola enseguida. |
| “Prioridad por etapa” | Las etapas que no son de inicio ni de fin reciben 10, 20, 30… según su orden en el tablero, también las que creás después; las de inicio y fin, 0. En el tablero de fábrica: Backlog 0, En curso 10, Hecho 0 | Gana el número más alto cuando se libera un lugar. La prioridad va por id de etapa: dos tableros con una etapa del mismo id comparten el número. |
-
Cambiá los valores. Para que QA pase adelante de Desarrollo cuando falta lugar, dale a su etapa un número más alto.
-
Tocá “Guardar configuración”. Al lado aparece “Guardado”. Si un campo está vacío o no es un número válido, queda marcado con el motivo y no se guarda nada: los valores se guardan todos juntos o ninguno. Las tareas que ya estaban en la cola se reordenan con las prioridades nuevas.

QA y Revisión con prioridad sobre En curso.
A este panel también se llega desde el tablero: en el menú de una columna, “Comportamiento” tiene el link “Prioridad del sandbox”. El panel “Capacidad” de Infraestructura muestra cuántos sandboxes corren contra el máximo, con el link “Cambiar el límite de sandboxes”.
Puertos y previews
Sección titulada «Puertos y previews»El sandbox expone cuatro puertos para la app: 3000, 5173, 8000 y 8080. El operador puede cambiar la lista con OCTOPUS_SANDBOX_PORTS (por ejemplo 3000,4200,8080); un sandbox conserva la lista con la que se creó. Si el agente pide la dirección de otro puerto, preview_url le contesta cuáles hay y el agente tiene que mover la app a uno de esos desde el script de arranque.
preview_url devuelve dos direcciones. La primera es para el navegador del agente de QA (argus-browser), que corre en otro contenedor. La segunda es para una persona, y depende del runtime:
La dirección para personas es http://<host>:<puerto-del-host>, con el puerto que muestra la columna “Puertos” y el host de OCTOPUS_PUBLIC_HOST (localhost si no está definido). Por default Thulu publica esos puertos sólo en 127.0.0.1 del servidor donde corre el daemon: si Thulu está en tu máquina, la abrís directo; si está en un servidor, la dirección con el dominio público no responde y necesitás un túnel SSH (ssh -L 32800:localhost:32800 servidor) para abrir http://localhost:32800. El operador puede publicarlos en otra interfaz con OCTOPUS_SANDBOX_PUBLISH_IP (0.0.0.0 los abre en todas).
No hay dirección para personas. Los puertos de la app quedan en un Service interno del cluster al que sólo llegan los pods de la misma tarea (el navegador de QA incluido). Para ver la app, el agente tiene que describir en la tarea cómo levantarla, o adjuntar capturas y videos con la evidencia.
En Docker, la fila “Sandbox” de la tarea muestra un link “Puerto N” por cada puerto publicado. En Kubernetes no hay link: te enterás si el agente describe la app en un comentario o adjunta capturas.
Script de arranque
Sección titulada «Script de arranque»Cada proyecto puede guardar un script que levanta la app en el sandbox: el script en bash, los puertos, un “Comando de listo” (por ejemplo curl -fsS http://localhost:3000/) con su timeout, parámetros, y una fase de “Setup” que instala dependencias. Se edita en la página del proyecto, en el panel “Script de arranque”, con historial de revisiones.
El agente lo corre con init_run en lugar de adivinar cómo se levanta el proyecto. Si no hay script, el agente averigua cómo levantarlo, y cuando le funciona lo guarda como revisión nueva, que queda registrada en el historial y en la auditoría con el agente como autor. Lo mismo si el script se rompe por una incompatibilidad. Cada workspace tiene además una caché persistente en /cache (npm, Go, pip y las versiones que instala mise) que sobrevive a los desalojos.
El detalle está en Proyectos.
Runtimes: Docker y Kubernetes
Sección titulada «Runtimes: Docker y Kubernetes»Quien instala Thulu elige dónde corren agentes y sandboxes. Desde la UI no se ve ni se cambia: es configuración del daemon (variables de entorno en Docker, values del chart de Helm en Kubernetes). Ver Operación self-hosted.
- Un contenedor por sandbox en el mismo host, con las capabilities de Linux quitadas salvo ocho básicas (
CHOWN,SETUID,KILLy similares),no-new-privileges, 6 GB de memoria (swap incluido), 2 CPU y un tope de 4096 procesos (OCTOPUS_SANDBOX_CPUS,OCTOPUS_SANDBOX_PIDS_LIMIT). - Corre como root dentro del contenedor, así que el agente puede instalar paquetes con
apt-get. ConOCTOPUS_ROOTLESS_AGENTS=truecorre como uid 1000, sin capabilities. - Corre en la red propia de la instalación,
octopus-agents, y publica sus puertos en127.0.0.1. - Sin Docker adentro: un
docker-compose upno funciona; los servicios que la app necesita corren como procesos. - Sin filtro de salida a internet: el sandbox y los agentes pueden conectarse a cualquier host que alcance la máquina, incluida tu red interna. El endurecimiento adicional de Docker está postergado.
- El runtime Kubernetes pide una licencia con la función
kubernetes; sin ella el daemon no arranca con ese runtime. - Un pod por sandbox en el namespace del workspace, con Pod Security
restricted, cuota de recursos y límites por contenedor. Corre como uid 1000, sin root niapt: un paquete del sistema hay que reemplazarlo por uno que instale mise, npm o pip. - RuntimeClass obligatoria (
OCTOPUS_RUNTIME_CLASS, Kata Containers por default en el chart; también gVisor): cada sandbox corre en su propia microVM o kernel aislado. El daemon no arranca sin una, y una política de admisión rechaza pods sin RuntimeClass o privilegiados. - Salida a internet controlada por
OCTOPUS_TENANT_EGRESS_MODE:open(default): DNS, el daemon y HTTPS (443) a direcciones públicas. Quedan afuera los rangos privados, la metadata de la nube y las IPs de los nodos.proxy-only: DNS, el daemon y sólo los destinos deOCTOPUS_TENANT_EGRESS_ALLOW_CIDRS(tu proxy, GitHub Enterprise, el registry interno).
- Consecuencia práctica: un registry en otro puerto, una base de la red interna o un servicio por SSH no responden desde el sandbox. Los gestores de paquetes tienen que usar mirrors HTTPS.
- Validado en un cluster k3s de un solo nodo con Kata; nunca corrió en un cluster de varios nodos.
En los dos runtimes Thulu pasa HTTP_PROXY, HTTPS_PROXY y NO_PROXY al sandbox, y OCTOPUS_EXTRA_CA_BUNDLE agrega la autoridad certificante de tu empresa. Para código que no es de confianza, el límite fuerte es Kubernetes con Kata.
Cuándo intervenir
Sección titulada «Cuándo intervenir»En el día a día los sandboxes se crean y se apagan solos. Estos son los casos en que conviene mirar la página:
-
Una tarea no arranca y figura en “Cola”: están todos los lugares ocupados. Esperá a que un sandbox se desaloje, matá uno que ya no haga falta o subí el máximo.
-
Hay un lugar libre y la tarea sigue en “Cola”: Thulu intentó relanzar la etapa en la que está ahora la tarea y no pudo, por ejemplo porque la tarea se movió a una columna donde no tiene agente asignado. Llevá la tarea a una columna con agente para que corra de nuevo, o tocá “Sacar de la cola” si ya no tiene que esperar. Si el plan del workspace limita cuántos agentes corren a la vez, la otra causa es que el workspace llegó a ese tope aunque la instalación tenga lugar.

Después de matar un sandbox queda un lugar libre, pero la tarea en cola sigue ahí porque estaba en una columna sin agente. Sacar de la cola la libera. -
El agente reporta que un comando terminó con código 137: el proceso pasó los 6 GB de memoria del sandbox. La skill
octopus-sandboxle indica bajar el paralelismo del build antes de reportarlo. Si el sandbox entero dejó de responder, matalo. -
El agente dice que el sandbox está caído o que el comando “timed out” al segundo: el contenedor murió. Matalo para que el próximo pedido cree uno nuevo.
-
La app no abre en tu navegador: en Docker, revisá que estés en el servidor o con un túnel al puerto del host; en Kubernetes no hay acceso directo.
-
El agente no tiene las herramientas del sandbox: falta tildar
argus-sandboxen la etapa del agente.