Secure Code Execution
Run untrusted, AI-generated code inside a lightweight VM that lives in a Rivet Actor.
Agents write code, and that code should not run in your process. An Actor can boot a lightweight VM with its own filesystem, shell, and JavaScript and Python runtimes, and run the code there. The VM boots in milliseconds inside the Actor’s process, so there is no separate sandbox service to deploy. The VM is powered by agentOS.
There are two ways to use it:
- A VM per Actor. The VM lives as long as the Actor, so an agent session keeps its files and processes between runs.
- A temporary VM. Boot a VM for one evaluation and release it when the call ends.
Quickstart
Install
npm install @rivet-dev/agentos-core
Create a VM per Actor
Boot the VM in createVars and dispose it when the Actor sleeps.
import { actor, setup } from "rivetkit";
import { AgentOs } from "@rivet-dev/agentos-core";
export const sandbox = actor({
// One VM per Actor. It boots with the Actor and is released
// when the Actor sleeps.
createVars: async () => ({ vm: await AgentOs.create() }),
onSleep: async (c) => {
await c.vars.vm.dispose();
},
onDestroy: async (c) => {
await c.vars.vm.dispose();
},
actions: {
// `code` came from a model. It runs in the VM,
// not in your process.
run: async (c, code: string) => {
const result = await c.vars.vm.javascript.evaluate(code);
if (result.outcome !== "succeeded") {
throw new Error(result.error.message);
}
return result.value;
},
},
});
export const registry = setup({
use: { sandbox },
});
Run code from a client
import { createClient } from "rivetkit/client";
import type { registry } from "./actor";
const client = createClient<typeof registry>("http://localhost:8080");
// One Actor per agent session, so each session has its own VM.
const sandbox = client.sandbox.getOrCreate(["session-123"]);
const value = await sandbox.run("[1, 2, 3].map((n) => n * 2)");
console.log(value); // [2, 4, 6]
Evaluate code in a temporary VM
When the code has no state to keep, boot a VM for the one call and dispose it in finally.
import { actor } from "rivetkit";
import { AgentOs } from "@rivet-dev/agentos-core";
export const evaluator = actor({
actions: {
// Boot a fresh VM for this call and release it at the end.
evaluate: async (c, code: string) => {
const vm = await AgentOs.create();
try {
const result = await vm.javascript.evaluate(code);
if (result.outcome !== "succeeded") {
throw new Error(result.error.message);
}
return result.value;
} finally {
await vm.dispose();
}
},
},
});
What the VM can do
The actions below belong to the same Actor as the quickstart and use its c.vars.vm.
Shell
Run a command in the VM and read its output. See Bash and Processes for background processes and interactive shells.
exec: async (c, command: string) => {
const result = await c.vars.vm.process.exec(command);
return result.stdout;
},
Files
The VM has a POSIX filesystem. Files the agent writes stay in that Actor’s VM. See Filesystem for directories, batch writes, and mounts.
writeFile: async (c, path: string, contents: string) => {
await c.vars.vm.filesystem.writeFile(path, contents);
},
readFile: async (c, path: string) => {
const bytes = await c.vars.vm.filesystem.readFile(path);
return new TextDecoder().decode(bytes);
},
JavaScript and Python
evaluate() returns the value of an expression, as in the quickstart. execute() runs a program and captures its output. Both are available for JavaScript and Python.
python: async (c, code: string) => {
const result = await c.vars.vm.python.execute(code);
return result.stdout;
},
More
- Networking: run servers inside the VM and reach them from the Actor.
- Software: install packages and tools into the VM.
- Schedules: run commands in the VM on a cron schedule.
- Permissions and resource limits: control network access and cap CPU, memory, processes, and filesystem size.
Persistence
The VM’s filesystem is in memory and is released with the VM. Keep anything that must outlive a wake cycle in the Actor’s state or SQLite, or store the VM’s filesystem durably with agentOS persistence.
Next steps
- agentOS documentation: the full VM API.
- Give an agent a sandbox: drive an E2B, Daytona, Freestyle, or Docker sandbox from an Actor when the code needs a full container.
- Lifecycle: when
createVars,onSleep, andonDestroyrun.