Run an AI agent's code¶
The reason Sistemo exists: an LLM writes code, and you need to run it without trusting it. A shared-kernel container is a scary boundary for code a model just generated — a real microVM with its own kernel is the right one.
The pattern is always: create → run → read output → destroy.
import shlex
from sistemo import Sandbox
def run_untrusted(code: str) -> str:
with Sandbox(stack="python") as sb: # isolated microVM
result = sb.run(f"python3 -c {shlex.quote(code)}")
return result.stdout if result.ok else f"Error:\n{result.stderr}"
# VM destroyed on block exit — nothing leaks, billing stops
print(run_untrusted("print(sum(range(100)))")) # "4950"
import { Sandbox } from "@sistemo/sdk";
async function runUntrusted(code: string): Promise<string> {
const sb = await Sandbox.create({ stack: "node" });
try {
const r = await sb.run(`node -e ${JSON.stringify(code)}`);
return r.exitCode === 0 ? r.stdout : `Error:\n${r.stderr}`;
} finally {
await sb.close(); // always destroy
}
}
Why this is safe¶
- Own kernel. A guest→host escape has to break out of a VM, not just a container namespace.
- Throwaway. Each run gets a fresh VM; destroy it and the blast radius is gone.
- No host access. The code runs inside the VM's network namespace; it can't see your other sandboxes, the host, or cloud metadata.
Handle failures and timeouts¶
Untrusted code crashes, loops, or floods output. Plan for it:
The server clamps timeout to 120s. For long jobs, run them in the background inside the VM and poll.
Reuse one sandbox for a multi-step agent¶
If your agent runs several steps, keep one sandbox alive so state (files, installed packages) persists between calls:
with Sandbox(stack="python") as sb:
sb.run("pip install pandas")
sb.run("cat > /tmp/data.py <<'EOF'\nimport pandas as pd\nprint(pd.__version__)\nEOF")
print(sb.run("python3 /tmp/data.py").stdout)
Next: Connect an LLM so the agent generates the code itself.