Inicio rápido de Sandboxes
Este inicio rápido crea un sandbox con Lizard SDK, ejecuta Python en él, escribe un archivo, abre un puerto y libera los recursos. Cada paso tiene código en TypeScript y Python. Necesitas una cuenta de Lizard (lizard.build) en Pro o en la prueba, una clave API y un proyecto. Para saber primero qué son los Sandboxes, lee la descripción general.
Instalar y autenticar
Instala Lizard SDK y crea una clave API en Settings → API keys, o con lizard keys create <name>. Guárdala en LIZARD_API_KEY. Cada sandbox pertenece a un proyecto; los ejemplos pasan su ID como projectId (Python: project_id), y project también acepta un slug o un nombre.
npm install @lizard-build/sdk
pip install lizard-sdk
export LIZARD_API_KEY="<your-api-key>"Ejecutar un comando
Sandbox.create arranca un sandbox desde una plantilla, aquí interpreter, que incluye Python y bibliotecas de datos habituales. timeoutMs fija su duración; la del SDK por defecto es de cinco minutos.
import { Sandbox } from '@lizard-build/sdk';
const sandbox = await Sandbox.create('interpreter', {
projectId: 'proj_123', timeoutMs: 300_000,
});
try {
const result = await sandbox.process.exec("python -c 'print(2 ** 10)'");
console.log(result.stdout, result.stderr, result.exitCode);
} finally {
await sandbox.kill();
}from lizard import Sandbox
sandbox = Sandbox.create("interpreter", project_id="proj_123", timeout_ms=300_000)
try:
result = sandbox.process.exec_("python -c 'print(2 ** 10)'")
print(result.stdout, result.stderr, result.exit_code)
finally:
sandbox.kill()Un código de salida distinto de cero es un resultado, no un error: comprueba tú mismo exitCode (Python: exit_code).
Archivos
Escribe texto o bytes con fs.write, lee texto con fs.read y lee bytes con fs.readBytes (Python: read_bytes). Todos los archivos del disco sobreviven a una pausa y entran en un snapshot. Un kill o la expiración borra el disco, así que guarda lo que necesites después en un volumen de Persistent Volumes en /workspace o en un snapshot.
await sandbox.fs.write("/tmp/task.py", "print(42)\n");
const result = await sandbox.process.exec("python /tmp/task.py");
console.log(result.stdout);sandbox.fs.write("/tmp/task.py", "print(42)\n")
result = sandbox.process.exec_("python /tmp/task.py")
print(result.stdout)Puertos públicos
Inicia un servidor que escuche en 0.0.0.0 y llama a exposePort(port) (Python: expose_port). Devuelve url, hostname y accessToken. El puerto es privado: abre url en un navegador (lleva ?lizard_token=) o envía el token en la cabecera X-Lizard-Access-Token. Las solicitudes sin el token reciben 401. El sandbox deja de atender el puerto cuando se detiene. Consulta URLs de vista previa para un servidor de desarrollo que construyó un agente.
await sandbox.process.exec(
"nohup python -m http.server 3000 --bind 0.0.0.0 --directory /tmp >/tmp/http.log 2>&1 </dev/null &",
);
const { url, hostname, accessToken } = await sandbox.exposePort(3000);
console.log(url); // open in a browser
const res = await fetch(`https://${hostname}/`, {
headers: { 'X-Lizard-Access-Token': accessToken },
});sandbox.process.exec_(
"nohup python -m http.server 3000 --bind 0.0.0.0 --directory /tmp >/tmp/http.log 2>&1 </dev/null &"
)
exposed = sandbox.expose_port(3000)
print(exposed.url) # open in a browserConectar a un sandbox en ejecución
Guarda el ID del sandbox (sandbox.sandboxId, Python: sandbox.sandbox_id) y llama a Sandbox.connect(id) desde otro proceso o en una solicitud posterior para obtener un handle del mismo sandbox. connect solo comprueba que el sandbox existe: no reanuda un sandbox pausado y lanza NotFoundError cuando el sandbox ya se detuvo o venció.
const connected = await Sandbox.connect(sandbox.sandboxId);
console.log(await connected.getInfo());connected = Sandbox.connect(sandbox.sandbox_id)
print(connected.get_info())Pausa, reanudación y snapshots
pause() guarda la memoria del sandbox, sus procesos en ejecución y todos los archivos de su disco. Una pausa completada detiene los cargos de cómputo; el almacenamiento en Persistent Volumes se sigue cobrando. resume() restaura el sandbox con el mismo ID y reanuda los cargos de cómputo. Ambas llamadas ponen el trabajo en cola y responden al instante; espera a paused o running para confirmar que han terminado.
await sandbox.pause();
await sandbox.waitForStatus('paused');
await sandbox.resume();
await sandbox.waitForStatus('running');- La pausa cierra las conexiones de red abiertas. Los programas del sandbox deben reconectarse tras reanudar.
- Si no se pueden guardar los procesos, el sandbox sigue en marcha y
waitForStatuslanza un error con el motivo. Si falla la reanudación, el sandbox sigue pausado con su checkpoint; vuelve a llamar aresume(). - El plazo de vida se detiene mientras el sandbox está pausado y continúa al reanudar. Un sandbox pausado no cuenta para el límite de sandboxes en marcha.
Pausa rápida. pause({ fast: true }) (Python: pause(fast=True), CLI: lizard sandbox pause <id> --fast) conserva solo los archivos: todo el disco y /workspace. Tarda alrededor de un segundo con cualquier tamaño de memoria, mientras que una pausa completa tarda más cuanta más memoria esté en uso. Los procesos en ejecución terminan y resume() arranca el sandbox de nuevo con sus archivos, como tras un reinicio; la respuesta de la reanudación incluye memoryRestored: false. Úsalo cuando nada de lo que se está ejecutando deba sobrevivir. La facturación y el plazo de vida funcionan igual que en cualquier pausa.
await sandbox.pause({ fast: true });
await sandbox.waitForStatus('paused');Un snapshot guarda la memoria de un sandbox en marcha, sus procesos en ejecución y todos los archivos de su disco. Solo se restaura en su propio proyecto y su propia región. Pueden restaurarlo el usuario que lo tomó y los miembros de ese proyecto. Sandbox.restore(id, { projectId }) (Python: project_id=) con cualquier otro proyecto falla con HTTP 403 y code igual a SNAPSHOT_SCOPE. Antes de capturar, cierra clientes y terminales y deja de escribir en /workspace.
Si el sandbox tiene un volumen de Persistent Volumes conectado, el snapshot incluye una copia de los archivos del volumen tal como estaban al capturar. Cada restauración recibe esa copia, no el volumen real, y no puede conectar otro volumen. Cualquiera que pueda restaurar el snapshot puede leer esos archivos. Un snapshot de un sandbox sin volumen puede montar uno al restaurar con volumeId (Python: volume_id), del mismo proyecto y la misma región.
const saved = await sandbox.snapshot('my-app');
await Sandbox.waitForSnapshot(saved.id);
const copy = await Sandbox.restore(saved.id);Un snapshot está listo cuando la llamada termina y se restaura desde disco, así que poolSize no se aplica. Cada restauración se ejecuta con el tamaño del origen y se factura al precio por hora de ese tamaño; size no se aplica a una restauración. En la CLI, usa lizard sandbox pause <id>, lizard sandbox resume <id>, lizard sandbox snapshot <id> --name my-app y lizard sandbox restore <snapshot-id>; consulta lizard sandbox para --volume.
Limpieza y siguientes pasos
Llama a kill() cuando termine la tarea, como hacen los ejemplos en finally. En Python, with Sandbox.create(...) as sandbox: detiene el sandbox al salir del bloque. Si olvidas detener un sandbox, se detiene al agotarse su duración, cinco minutos después de crearlo salvo que fijes otra duración; consulta recursos y duración.
- Cada llamada, opción y error: referencia de la API y el SDK de Sandboxes.
- Código de un LLM con estado entre llamadas: intérprete de código.
- Archivos que sobreviven a un sandbox: Persistent Volumes.
- Un agente de programación en un sandbox: Claude Code u OpenCode.
- Los mismos pasos desde una terminal:
lizard sandbox. En el navegador: el panel de Sandboxes. - Tamaños, precios y cuántos sandboxes pueden ejecutarse a la vez: límites. Descripción del producto y comparación: Sandboxes.
Actualizado