Skip to main content
Rivet agentOS

agentOS (Embedded)

Give an agent a computer inside your own process: boot an agentOS VM with @rivet-dev/agentos-core in Node.js or a Rivet Actor, then run processes, read and write files, execute code, and reach its network as direct method calls.

Embedded agentOS is the same computer for one agent, with a filesystem, processes, terminals, networking, and a software registry, run as a library: @rivet-dev/agentos-core boots the VM inside your own Node.js process or Rivet Actor, your application owns its identity and lifecycle, and the same action groups are methods on the VM handle. This page is an overview of that API; the full agentOS docs cover every method, option, and limit.

Quickstart

Install the library

The package includes the native sidecar for your platform, so nothing else needs to be deployed.

npm install @rivet-dev/agentos-core

Boot a VM

AgentOs.create() boots a VM inside this process and returns a handle to it. The VM runs until you call dispose() or the process exits.

import { AgentOs } from "@rivet-dev/agentos-core";

const vm = await AgentOs.create();

Run a command

process.exec runs a shell command line to completion and returns its exit status and captured output.

try {
	const result = await vm.process.exec("echo hello", {
		output: { capture: "all" },
	});
	console.log(result.stdout); // "hello\n"
} finally {
	await vm.dispose();
}

The sections below reuse vm from the quickstart. Library methods take positional arguments, so vm.filesystem.writeFile(path, content) is the same action a hosted VM exposes as v1.filesystem.writeFile({ path, content }).

Processes and shells

process.exec runs a shell command line and process.execFile runs a command with an argument array; process.spawn starts a long-running process and returns its pid for stdin, signals, waiting, and output callbacks. terminal.open allocates a PTY and starts an interactive shell.

const result = await vm.process.exec("ls -la /home/agentos");
console.log(result.stdout);

const { pid } = await vm.process.spawn("node", ["/tmp/server.mjs"]);
vm.onProcessOutput(pid, (event) =>
	console.log(event.stream, new TextDecoder().decode(event.data)),
);
await vm.process.signal(pid, "SIGTERM");

Full docs: Processes & Shells and Bash.

Filesystem

The filesystem methods read and write the VM’s filesystem without starting a process, and every shell and language in the VM sees the same files. Batch, directory, and mount methods follow the same shape, and the library can also mount and unmount filesystems on a running VM.

await vm.filesystem.writeFile("/home/agentos/hello.txt", "Hello, world!");
const content = await vm.filesystem.readFile("/home/agentos/hello.txt");
console.log(new TextDecoder().decode(content));

Full docs: Filesystem.

Code execution

The javascript, typescript, and python methods run code on the VM’s native V8 and CPython 3.13: evaluate returns a JSON-serializable value, execute runs source and captures its output, and spawn starts a long-lived script.

const sum = await vm.javascript.evaluate<number>("1 + 2");
console.log(sum.outcome === "succeeded" ? sum.value : sum.error); // 3

const answer = await vm.python.evaluate<number>("21 * 2");
console.log(answer.outcome === "succeeded" ? answer.value : answer.error); // 42

await vm.javascript.execute("console.log(1 + 2)");

Full docs: Node.js and Python.

Network

Servers inside the VM listen on VM-local ports and are not exposed on the host network; network.httpRequest sends a bounded HTTP request to one and returns the buffered response. The library creates no public preview URLs, so route browser traffic through your application and forward it with httpRequest or vm.fetch.

await vm.filesystem.writeFile(
	"/tmp/app.mjs",
	'import http from "http"; http.createServer((req, res) => res.end("hello")).listen(3000);',
);
await vm.process.spawn("node", ["/tmp/app.mjs"]);

const response = await vm.network.httpRequest({ port: 3000, path: "/" });
console.log(new TextDecoder().decode(response.body));

Full docs: Networking & Previews.

Software

Software ships as immutable .aospkg packages. Because the embedding process is trusted, software.install accepts a registry package by name, an HTTPS URL with a digest, or a local path, while the VM is running or in the software option to AgentOs.create().

const installed = await vm.software.install({ type: "registry", name: "ripgrep" });
console.log(installed.packageName, installed.version, installed.commands);

const result = await vm.process.execFile("rg", ["--version"], {
	output: { capture: "all" },
});
console.log(result.stdout);

Full docs: Software.

Schedules

cron.schedule runs a command or a host callback on a cron expression, or once at an ISO 8601 timestamp. Library jobs run while the embedding process and the VM are alive, so durable scheduling across restarts belongs to the application that owns the VM.

const job = vm.cron.schedule({
	id: "cleanup",
	schedule: "0 * * * *",
	action: { type: "exec", command: "rm", args: ["-rf", "/tmp/cache"] },
});
console.log("Scheduled:", job.id);

console.log(vm.cron.list());

Full docs: Crons & Schedules.

Lifecycle and persistence

A library VM runs until dispose() is called or the process exits, and its root filesystem is in memory by default, so files are discarded when the VM is disposed. To keep them, give the VM a SQLite database and store the root filesystem there with the chunked_sqlite plugin; a new VM created with the same options sees the same files, while running processes, terminals, and language contexts do not survive recreation.

import { resolve } from "node:path";
import { AgentOs } from "@rivet-dev/agentos-core";

const vm = await AgentOs.create({
	database: { type: "sqlite_file", path: resolve("agentos.sqlite") },
	rootFilesystem: { type: "native", plugin: { id: "chunked_sqlite", config: {} } },
});

await vm.filesystem.writeFile("/home/agentos/result.txt", "persistent");
await vm.dispose();

Full docs: Persistence & Sleep and Embedded VMs.

Actions

The library exposes the same groups as namespaces on the VM handle (vm.filesystem, vm.process, vm.cron, …). Where a library method name differs from the hosted action, the capability page lists both: for example process.exec and process.execFile in place of run, and process.writeStdin in place of stdin.write.

GroupActions
configget, set, patch
vmstatus, restart
filesystemreadFile, writeFile, readFiles, writeFiles, stat, exists, mkdir, readdir, readdirEntries, readdirRecursive, move, remove, listMounts, export
processrun, spawn, get, list, tree, wait, signal, stdin.write, stdin.close, pty.resize, output.read
terminalopen, list, stdin.write, pty.resize, output.read, wait, close
networkfetch, fetchStream.start, fetchStream.read, fetchStream.cancel, preview.create, preview.expire
softwareinstall, uninstall, list
cronschedule, list, cancel
contextscreate, get, list, reset, delete
javascriptexecute, evaluate, executeFile, spawn, spawnFile, npm.install, npm.runScript, npm.runPackage
typescriptexecute, evaluate, executeFile, spawn, spawnFile, check, checkProject
pythonexecute, evaluate, executeFile, executeModule, spawn, spawnFile, spawnModule, install

Every action, its input and output, configuration fields, events, and error codes are in the hosted API reference; the library adds host functions, host-directory mounts, and local packages on top.

Next steps

  • Secure Code Execution: run agentOS inside a Rivet Actor so the Actor supplies identity and persistence.
  • Embedded VMs: trusted host capabilities, mount plugins, and sidecar placement.
  • Custom Host Functions: expose your own functions to guest code without leaking credentials into the VM.