Skip to content
GitHub Get Started
Reference

Core Package

The agentOs() actor (from rivetkit/agent-os) wraps the core package and adds:

Core (@rivet-dev/agent-os-core)Actor (rivetkit/agent-os)
PersistenceIn-memory by default (pluggable via mounts)Persistent filesystem and sessions
Distributed stateManage yourselfBuilt-in distributed statefulness
Stateful VMsComplex to run yourselfBuilt into Rivet
Sleep/wakeManual dispose() / create()Automatic
EventsDirect callbacksBroadcasted to all connected clients
Preview URLsNoneBuilt-in signed URL server
MultiplayerN/AMultiple clients on same actor
OrchestrationN/AWorkflows, queues, cron
Agent-to-agent communicationCustomBuilt into Rivet Actors
AuthenticationSet up yourselfDocumentation

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.

Terminal window
npm install @rivet-dev/agent-os-core
import { AgentOs } from "@rivet-dev/agent-os-core";
import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({
software: [common],
});
// Run a command
const result = await vm.exec("echo hello");
console.log(result.stdout); // "hello\n"
await vm.dispose();
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();
import { AgentOs } from "@rivet-dev/agent-os-core";
import common from "@agent-os-pkgs/common";
const vm = await AgentOs.create({ software: [common] });
// One-shot execution
const result = await vm.exec("ls -la /home/user");
console.log(result.stdout);
// Long-running process with streaming output
await 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 stdin
vm.writeProcessStdin(proc.pid, "some input\n");
// Stop or kill
vm.stopProcess(proc.pid);
await vm.dispose();

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 permissions
vm.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 session
await 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.

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 terminal
vm.resizeShell(shellId, 120, 40);
vm.closeShell(shellId);
await vm.dispose();
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 VM
await 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 it
const response = await vm.fetch(3000, new Request("http://localhost/"));
console.log(await response.text());
await vm.dispose();

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();

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();
  • 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.