Core Package
agentOS vs agentOS Core
Section titled “agentOS vs agentOS Core”The agentOs() actor (from rivetkit/agent-os) wraps the core package and adds:
Core (@rivet-dev/agent-os-core) | Actor (rivetkit/agent-os) | |
|---|---|---|
| Persistence | In-memory by default (pluggable via mounts) | Persistent filesystem and sessions |
| Distributed state | Manage yourself | Built-in distributed statefulness |
| Stateful VMs | Complex to run yourself | Built into Rivet |
| Sleep/wake | Manual dispose() / create() | Automatic |
| Events | Direct callbacks | Broadcasted to all connected clients |
| Preview URLs | None | Built-in signed URL server |
| Multiplayer | N/A | Multiple clients on same actor |
| Orchestration | N/A | Workflows, queues, cron |
| Agent-to-agent communication | Custom | Built into Rivet Actors |
| Authentication | Set up yourself | Documentation |
We recommend using Rivet Actors because they provide a portable way to run agentOS on any infrastructure with built-in persistence, networking, and orchestration. Use the core package if you need the most bare-bones implementation possible.
Install
Section titled “Install”npm install @rivet-dev/agent-os-coreBoot a VM
Section titled “Boot a VM”import { AgentOs } from "@rivet-dev/agent-os-core";import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common],});
// Run a commandconst result = await vm.exec("echo hello");console.log(result.stdout); // "hello\n"
await vm.dispose();Filesystem
Section titled “Filesystem”import { AgentOs } from "@rivet-dev/agent-os-core";import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common] });
await vm.writeFile("/home/user/hello.txt", "Hello, world!");const content = await vm.readFile("/home/user/hello.txt");console.log(new TextDecoder().decode(content));
await vm.mkdir("/home/user/src");await vm.writeFiles([ { path: "/home/user/src/index.ts", content: "console.log('hi');" }, { path: "/home/user/src/utils.ts", content: "export const add = (a: number, b: number) => a + b;" },]);
const entries = await vm.readdirRecursive("/home/user");for (const entry of entries) { console.log(entry.type, entry.path);}
await vm.dispose();Processes
Section titled “Processes”import { AgentOs } from "@rivet-dev/agent-os-core";import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common] });
// One-shot executionconst result = await vm.exec("ls -la /home/user");console.log(result.stdout);
// Long-running process with streaming outputawait vm.writeFile("/tmp/server.mjs", 'import http from "http"; http.createServer((req, res) => res.end("ok")).listen(3000); console.log("listening");');const proc = vm.spawn("node", ["/tmp/server.mjs"]);vm.onProcessStdout(proc.pid, (data) => { console.log("stdout:", new TextDecoder().decode(data));});vm.onProcessExit(proc.pid, (code) => { console.log("exited:", code);});
// Write to stdinvm.writeProcessStdin(proc.pid, "some input\n");
// Stop or killvm.stopProcess(proc.pid);
await vm.dispose();Agent sessions
Section titled “Agent sessions”The core package returns a sessionId string. All session operations are called on the vm instance with the session ID.
import { AgentOs } from "@rivet-dev/agent-os-core";import common from "@agent-os-pkgs/common";import pi from "@rivet-dev/agent-os-pi";
const vm = await AgentOs.create({ software: [common, pi] });
const { sessionId } = await vm.createSession("pi", { env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },});
// Stream events (each event is a JSON-RPC notification)vm.onSessionEvent(sessionId, (event) => { console.log(event.method, event.params);});
// Handle permissionsvm.onPermissionRequest(sessionId, (request) => { console.log("Permission:", request.description); // Reply with "once", "always", or "reject" vm.respondPermission(sessionId, request.permissionId, "once");});
// Send a prompt. prompt() resolves to { response, text }, where `text` is the// accumulated agent message text and `response` is the raw JSON-RPC response.const { text } = await vm.prompt(sessionId, "Write a hello world script");console.log(text);
// Configure the sessionawait vm.setSessionModel(sessionId, "claude-sonnet-4-6");await vm.setSessionMode(sessionId, "plan");
vm.closeSession(sessionId);await vm.dispose();Session events are live-only: subscribe with onSessionEvent() before sending a
prompt. There is no replay buffer or event history to read back after the fact.
Interactive shell
Section titled “Interactive shell”import { AgentOs } from "@rivet-dev/agent-os-core";import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common] });
const { shellId } = vm.openShell();
vm.onShellData(shellId, (data) => { process.stdout.write(new TextDecoder().decode(data));});
vm.writeShell(shellId, "echo hello from shell\n");
// Resize terminalvm.resizeShell(shellId, 120, 40);
vm.closeShell(shellId);await vm.dispose();Networking
Section titled “Networking”import { AgentOs } from "@rivet-dev/agent-os-core";import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common] });
// Start a server inside the VMawait vm.writeFile("/tmp/app.mjs", 'import http from "http"; http.createServer((req, res) => res.end("hello")).listen(3000);');vm.spawn("node", ["/tmp/app.mjs"]);
// Fetch from itconst response = await vm.fetch(3000, new Request("http://localhost/"));console.log(await response.text());
await vm.dispose();Cron jobs
Section titled “Cron jobs”The core package supports a "callback" action type in addition to "exec" and "session".
import { AgentOs } from "@rivet-dev/agent-os-core";import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common] });
const job = vm.scheduleCron({ id: "cleanup", schedule: "0 * * * *", action: { type: "exec", command: "rm", args: ["-rf", "/tmp/cache"] },});
// Or use a callback (not available in the actor wrapper)vm.scheduleCron({ schedule: "*/5 * * * *", action: { type: "callback", fn: async () => { console.log("Custom logic every 5 minutes"); }, },});
vm.onCronEvent((event) => { if (event.type === "cron:fire") console.log("Job fired:", event.jobId); if (event.type === "cron:complete") console.log("Job done:", event.jobId, event.durationMs, "ms"); if (event.type === "cron:error") console.error("Job error:", event.error);});
console.log(vm.listCronJobs());job.cancel();
await vm.dispose();Mounts
Section titled “Mounts”Configure filesystem backends at boot time.
Native mount plugins (host directories, S3, etc.) are passed via plugin, while
JavaScript filesystem backends are passed via driver.
import { AgentOs, createHostDirBackend, createInMemoryFileSystem } from "@rivet-dev/agent-os-core";import { createS3Backend } from "@secure-exec/s3";import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common], mounts: [ // Host directory (read-only) { path: "/mnt/code", plugin: createHostDirBackend({ hostPath: "/path/to/repo", readOnly: true }) }, // S3 bucket { path: "/mnt/data", plugin: createS3Backend({ bucket: "my-bucket", prefix: "agent/" }) }, // In-memory scratch space { path: "/mnt/scratch", driver: createInMemoryFileSystem() }, ],});
const files = await vm.readdir("/mnt/code");console.log(files);
await vm.dispose();What you give up without the actor
Section titled “What you give up without the actor”- No built-in persistence. The default filesystem is in-memory and lost on
dispose(). You can configure your own mounts (S3, host directories, etc.) for persistence. - No sleep/wake. You manage the full VM lifecycle yourself.
- No event broadcasting. Events are local callbacks, not distributed to remote clients.
- No preview URLs. No built-in HTTP server for sharing VM services.
- No multiplayer. Single-process, single-client only.
- No orchestration. No workflows, queues, or scheduling integration.
- No session persistence. Session history is lost on dispose.
If you need any of these, use the agentOs() actor instead.