Skip to main content
Reference

Core Package

Use @rivet-dev/agent-os-core standalone for direct VM control without the Rivet Actor runtime.

  • Standalone SDK for programmatic VM management without the actor runtime
  • ID-based flat API where sessions are referenced by ID strings
  • No persistence by default. Filesystem and sessions live in memory only.
  • No event broadcasting, sleep/wake, or preview URLs. You manage the lifecycle.

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)
PersistenceIn-memory by default (pluggable via mounts)Persistent filesystem and sessions
Sleep/wakeManual dispose() / create()Automatic with 15 min grace period
EventsDirect callbacksBroadcasted to all connected clients
Preview URLsNoneBuilt-in signed URL server
SessionsID-based (vm.prompt(sessionId, ...))ID-based flat API over RPC
MultiplayerN/AMultiple clients on same actor
OrchestrationN/AWorkflows, queues, cron

Use the core package when you want direct VM control in a script, CLI tool, or custom runtime. Use the actor when you want persistence, multiplayer, and the full Rivet platform.

Install

npm install @rivet-dev/agent-os-core

Boot a VM

import { AgentOs } from "@rivet-dev/agent-os-core";
import common from "@rivet-dev/agent-os-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();

Filesystem

import { AgentOs } from "@rivet-dev/agent-os-core";
import common from "@rivet-dev/agent-os-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

import { AgentOs } from "@rivet-dev/agent-os-core";
import common from "@rivet-dev/agent-os-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();

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 "@rivet-dev/agent-os-common";

const vm = await AgentOs.create({ software: [common] });

const { sessionId } = await vm.createSession("pi", {
  env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});

// Stream events
vm.onSessionEvent(sessionId, (event) => {
  console.log(event.method, event.params);
});

// Handle permissions
vm.onPermissionRequest(sessionId, (request) => {
  console.log("Permission:", request.description);
  vm.respondPermission(sessionId, request.permissionId, "once");
});

// Send a prompt
const response = await vm.prompt(sessionId, "Write a hello world script");
console.log(response);

// Configure the session
await vm.setSessionModel(sessionId, "claude-sonnet-4-6");
await vm.setSessionMode(sessionId, "plan");

// Event history (returns SequencedEvent[] with .sequenceNumber and .notification)
const events = vm.getSessionEvents(sessionId);
for (const event of events) {
  console.log(event.sequenceNumber, event.notification.method);
}

vm.closeSession(sessionId);
await vm.dispose();

Interactive shell

import { AgentOs } from "@rivet-dev/agent-os-core";
import common from "@rivet-dev/agent-os-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();

Networking

import { AgentOs } from "@rivet-dev/agent-os-core";
import common from "@rivet-dev/agent-os-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();

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 "@rivet-dev/agent-os-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

Configure filesystem backends at boot time.

import { AgentOs, createHostDirBackend, createInMemoryFileSystem } from "@rivet-dev/agent-os-core";
import { createS3Backend } from "@rivet-dev/agent-os-s3";
import common from "@rivet-dev/agent-os-common";

const vm = await AgentOs.create({
  software: [common],
  mounts: [
    // Host directory (read-only)
    { path: "/mnt/code", driver: createHostDirBackend({ hostPath: "/path/to/repo" }), readOnly: true },
    // S3 bucket
    { path: "/mnt/data", driver: 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

  • 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.