Skip to main content
← Back to Cookbooks

AI Agent Workspaces

Give every AI agent its own computer: a persistent agent workspace with a filesystem, processes, shells, networking, and coding agent sessions on a lightweight in-process VM. Run AI generated code, persist session transcripts across restarts, and mount a full sandbox when agents need native binaries.

Working examples

If you need a reference implementation, read the raw working example code in these templates.

Install skill for coding agents

npx skills add rivet-dev/skills -s ai-agent-workspace

Supports Claude Code, Codex, Cursor, and other AI coding assistants.

Patterns for giving every AI agent its own computer with agentOS: one Rivet Actor per agent that owns a portable, lightweight in-process OS running on Wasm and V8. Use it for code interpreters that keep state between runs, agents that ship artifacts behind shareable preview URLs, per-user dev environments, and scheduled maintenance agents. agentOS is in preview and the API is subject to change.

This entry is about giving an agent a workspace. For conversation memory, message queues, and streaming chat patterns, see AI Agent.

Starter Code

The agent-os collection is reference code, one sub-example per capability; treat it as patterns to copy into your project rather than a turnkey app. The agent-os-e2e example is the complete end-to-end walkthrough.

ExampleStarter CodeUse When
Hello WorldGitHubYou want the minimal loop: boot a VM lazily on the first action, write a file, read it back.
FilesystemGitHubThe agent needs the full file surface: recursive listing, stat, move, delete, and custom mounts.
GitGitHubThe agent works with real git repos inside the workspace: init, commit, branch, and clone via exec.
ProcessesGitHubThe agent runs shell commands with pipes and long-lived spawned programs.
NetworkGitHubThe agent serves HTTP inside the VM and you need vmFetch or signed preview URLs.
CronGitHubThe workspace runs scheduled commands or recurring agent work.
ToolsGitHubYou want your backend functions exposed as CLI commands inside the workspace.
Agent SessionGitHubYou drive a Pi coding agent session inside the workspace. Requires ANTHROPIC_API_KEY.
Sandbox MountingGitHubThe agent needs native binaries or a real OS, mounted into the VM from a Docker-backed sandbox. Requires Docker.
End-to-End WalkthroughGitHubYou want one runnable script covering files, processes, preview URLs, and a streaming Pi agent session.

Setup

The whole backend is one registry with one agentOs() actor:

import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";

const vm = agentOs({
  options: { software: [common, pi] },
});

export const registry = setup({ use: { vm } });
registry.start();

See the Quickstart for the client side and project layout.

Workspace Model

  • One actor per workspace, key as identity. client.vm.getOrCreate(["my-agent"]) gives each agent its own workspace; key by user id for per-user dev environments. Each workspace has its own filesystem, processes, and networking with no shared state and no cross-contamination (see the overview).
  • Software packages choose what is installed. agentOS starts with no commands installed. The software option installs packages such as @rivet-dev/agent-os-common (a meta-package of Wasm command-line tools: coreutils, sed, grep, gawk, findutils, diffutils, tar, and gzip), @rivet-dev/agent-os-git (git), and @rivet-dev/agent-os-pi (the Pi coding agent). See Software.
  • The VM boots lazily and sleeps when idle. The first action boots the VM (clients see a vmBooted event); when nothing is active, the actor sleeps and broadcasts vmShutdown, then wakes on the next action.

What survives a sleep/wake cycle (see Persistence):

DataAcross sleep/wake
Session transcripts and event historyPersist in actor SQLite as events stream. listPersistedSessions and getSessionEvents read them back without booting the VM, and resumeSession picks a session back up in a rebooted VM.
Signed preview URL tokensPersist in actor SQLite. Requests are validated against the stored token and the VM reboots lazily to serve them, so preview URLs keep working after sleep.
FilesPersist when the mount is backed by a persistent driver (database-backed, S3, or a sandbox mount). In-memory mounts come back empty on wake.
Processes, shells, and cron jobsDo not persist. Restart long-running processes and reschedule cron jobs on wake (recommended extension).

The actor holds itself awake while sessions, processes, shells, or hooks are active, then sleeps after a grace period.

Capability Tour

AreaUse It ForKey ActionsDocsExample
FilesystemGive the agent a file tree to read and writereadFile, writeFile, mkdir, readdir, moveFilesystemGitHub
ProcessesRun commands and long-lived programsexec, spawn, waitProcess, killProcessProcessesGitHub
ShellsInteractive terminals with streamed outputopenShell, writeShell, resizeShell, closeShellProcessesNo standalone example
Networking and preview URLsReach services inside the VM and share them externallyvmFetch, createSignedPreviewUrl, expireSignedPreviewUrlNetworkingGitHub
CronScheduled commands and recurring agent sessionsscheduleCron, listCronJobs, cancelCronJobCronGitHub
Agent sessionsDrive a coding agent inside the workspacecreateSession, sendPrompt, resumeSession, closeSessionSessionsGitHub

Two details worth knowing up front:

  • createSignedPreviewUrl returns a relative path plus the token and expiry. Build the full URL with the client handle’s getGatewayUrl() method; it is a client method, not an actor action.
  • Schedule cron jobs through the actor with the exec and session action types only. Callback cron actions are defined in server code and do not serialize through listCronJobs.

Driving a Coding Agent Session

Only the Pi agent (@rivet-dev/agent-os-pi) is currently supported as a session agent; Amp, Claude Code, Codex, and OpenCode are coming soon. See Sessions.

  1. createSession("pi", { env: { ANTHROPIC_API_KEY } }) returns a sessionId. The VM does not inherit the host process.env, so API keys are passed explicitly per session or kept server-side through the LLM gateway.
  2. Open a realtime connection and subscribe to sessionEvent to stream the agent’s output, such as message chunks, as it works.
  3. sendPrompt(sessionId, ...) starts a turn; cancelPrompt stops one in flight.
  4. When the agent asks to use a tool, clients receive a permissionRequest event and answer with respondPermission, or the server auto-approves with the onPermissionRequest config hook (see Permissions).
  5. Transcripts are persisted automatically in the universal transcript format (Agent Communication Protocol, ACP). After sleep, resumeSession continues a session in the rebooted VM, and listPersistedSessions plus getSessionEvents read history without booting the VM at all.

Host Tools

Expose your backend functions to the agent as CLI commands inside the workspace. Define a toolkit with toolKit() and hostTool() (Zod-schema’d JavaScript functions on the host), pass it via agentOs({ options: { toolKits: [...] } }), and it is installed as a command such as agentos-weather forecast --city Paris --days 3 and injected into the agent’s system prompt. The agent calls your backend with no HTTP endpoints or MCP servers to stand up, and CLI-shaped tools are code mode compatible for large token savings. See Tools and the tools example.

When to Mount a Full Sandbox

agentOS is not a replacement for sandboxes; it is designed to work alongside them. When a workspace needs native binaries, browsers, compilation, or desktop automation, use sandbox mounting: start a Docker-backed sandbox with SandboxAgent.start({ sandbox: docker() }), project its filesystem into the VM as a native directory (for example /sandbox) with createSandboxFs, and expose sandbox process control as host tools with createSandboxToolkit. Filesystem actions like writeFile and readFile project transparently through the mount while heavy workloads run in the container.

See Sandbox Mounting for the hybrid model and agentOS vs Sandboxes for when each side wins: the lightweight VM has a near-zero cold start (~6 ms) and installs with npm install, while sandboxes are full Linux environments billed per second of uptime.

Architecture

TopicSummary
TopologyOne vm[workspaceId] actor per agent or per user; the actor key is the workspace identity.
IngressActor actions for files, processes, networking, cron, and sessions; a realtime connection for streamed events.
StreamingsessionEvent per agent event, processOutput and processExit for spawned processes, shellData for interactive shells.
PersistenceSession transcripts, event history, and preview tokens in actor SQLite; files persist through persistent mounts.

Actors

Lifecycle

sequenceDiagram participant C as Client participant A as vm actor participant V as agentOS VM participant P as Pi session C->>A: getOrCreate(["my-agent"]) C->>A: writeFile("/tmp/hello.txt", ...) Note over A,V: first action boots the VM A-->>C: vmBooted C->>A: exec("echo hello | tr a-z A-Z") A->>V: run command V-->>A: {exitCode: 0, stdout} C->>A: spawn("node", ["/tmp/server.mjs"]) C->>A: createSignedPreviewUrl(8080, 60) A-->>C: {path, token, expiresAt} C->>A: fetch(gatewayUrl + path) Note over A: token checked in SQLite, request proxied into the VM network C->>A: createSession("pi", {env}) A->>P: start session C->>A: sendPrompt(sessionId, ...) loop streamed agent output P-->>A: agent event A-->>C: sessionEvent end Note over A: idle, sleeps after grace period (vmShutdown) C->>A: resumeSession(sessionId) Note over A,V: wake reboots the VM, restoring transcripts, preview tokens, and persistent mounts

Security Checklist

  • Authenticate connections: Add the onBeforeConnect hook in the agentOs() config so only authorized callers reach a workspace. Signed preview URL requests deliberately skip it because the token is the credential; browsers navigating a preview URL cannot supply actor connection params.
  • Gate agent tool use with permissions: Session permission requests broadcast as permissionRequest events for human-in-the-loop approval via respondPermission, or run a server-side onPermissionRequest policy for automated pipelines. See Permissions.
  • Treat preview URLs as bearer credentials: Tokens are randomly generated 32-character values with a default expiry of 1 hour and a maximum of 24; revoke early with expireSignedPreviewUrl. Preview responses carry permissive CORS headers, so do not serve private data on a preview port without app-level auth.
  • Keep LLM credentials off the browser: Create sessions from trusted server code with the key in createSession env, or keep keys entirely server-side with the LLM gateway. Session keys are injected into the session environment inside the VM and are never stored in actor config or SQLite.
  • Treat mounted sandboxes as their own trust boundary: A mounted sandbox is a full Linux environment outside the workspace’s Wasm and V8 isolate. Scope what its network and filesystem can reach before projecting it into an agent’s VM.
  • Set resource and cost limits: Cap per-workspace memory and CPU (maxMemoryMb, maxCpuPercent, see Security). Active sessions, processes, and shells hold the actor awake, so add per-workspace session caps and token budgets as a recommended extension.