Filesystem
Read, write, mount, and manage files inside agentOS, all backed by a virtual filesystem isolated from the host disk.
Each VM has its own filesystem that the agent works in. Guest fs calls never touch the host disk, and it persists automatically across sleep/wake with no setup. See Persistence for the details.
Mounts
Back a guest path with external storage by adding it to the mounts config. Each mount takes a path and an optional readOnly flag, and the guest only ever sees the mounted subtree, never the wider host.
Project a real host directory into the filesystem, Docker-style. The guest sees only the mounted subtree, never the wider host filesystem. Path-escape attempts (symlinks, .., path aliasing) are confined to the mount root.
import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "./software/pi";
const vm = agentOS({
software: [pi],
mounts: [
{
path: "/mnt/code",
plugin: { id: "host_dir", config: { hostPath: "/path/to/repo" } },
readOnly: true,
},
],
});
export const registry = setup({ use: { vm } });
registry.start();
Mount an S3 bucket with the built-in s3 plugin. Pass an optional prefix to scope storage to a key path within the bucket, useful for sharing one bucket across multiple agents.
The backend is a block store, not a one-object-per-file mapping: file contents are split into fixed-size chunks (4 MB by default) stored as individual S3 objects, with a separate metadata layer mapping each file to its chunks. This keeps large files, partial reads and writes, and snapshots efficient without rewriting whole objects.
import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "./software/pi";
const vm = agentOS({
software: [pi],
mounts: [
{
path: "/mnt/data",
plugin: {
id: "s3",
config: {
bucket: "my-bucket",
prefix: "agent-data/",
region: "us-east-1",
},
},
},
],
});
export const registry = setup({ use: { vm } });
registry.start();
The s3 plugin config also accepts credentials ({ accessKeyId, secretAccessKey }) and a custom endpoint for S3-compatible providers.
Mount a Google Drive folder with the built-in google_drive plugin.
import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "./software/pi";
const vm = agentOS({
software: [pi],
mounts: [
{
path: "/mnt/drive",
plugin: {
id: "google_drive",
config: {
credentials: {
clientEmail: process.env.GOOGLE_DRIVE_CLIENT_EMAIL!,
privateKey: process.env.GOOGLE_DRIVE_PRIVATE_KEY!,
},
folderId: process.env.GOOGLE_DRIVE_FOLDER_ID!,
},
},
},
],
});
export const registry = setup({ use: { vm } });
registry.start();
Use the built-in memory plugin for an ephemeral mounted directory in the native RivetKit agentOS() actor.
Use mountFs() for a callback-backed JS filesystem driver. The driver must live in the same JS process as the AgentOs instance, such as direct core usage or a custom RivetKit actor that owns an AgentOs instance.
import { AgentOs, createInMemoryFileSystem } from "@rivet-dev/agentos-core";
const vm = await AgentOs.create({ defaultSoftware: false });
const driver = createInMemoryFileSystem();
vm.mountFs("/home/agentos/scratch", driver);
await vm.writeFile("/home/agentos/scratch/hello.txt", "hello");
The native agentOS() actor cannot accept { driver } mounts in config because JS callback objects are not serializable across the native plugin boundary. Use plugin mounts there.
File operations
These operations are primarily what the agent uses inside the VM, and are also available from the client to seed inputs and read results. For large or read-only inputs (a repo, a dataset), a read-only host mount is faster than copying files in. Programs that need stdin or live output use exec instead (see Core).
Read and write
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");
// Write a file (string or Uint8Array)
await agent.writeFile("/home/agentos/hello.txt", "Hello, world!");
// Read a file (returns Uint8Array)
const content = await agent.readFile("/home/agentos/hello.txt");
console.log(new TextDecoder().decode(content));
Batch read and write
// Batch write (creates parent directories automatically)
const writeResults = await agent.writeFiles([
{ path: "/home/agentos/src/index.ts", content: "console.log('hello');" },
{ path: "/home/agentos/src/utils.ts", content: "export function add(a: number, b: number) { return a + b; }" },
]);
// Batch read
const readResults = await agent.readFiles([
"/home/agentos/src/index.ts",
"/home/agentos/src/utils.ts",
]);
for (const result of readResults) {
console.log(result.path, new TextDecoder().decode(result.content ?? new Uint8Array()));
}
Directories
// Create a directory
await agent.mkdir("/home/agentos/projects");
// List directory contents
const entries = await agent.readdir("/home/agentos/projects");
// Recursive listing (entries carry path, name, and type)
const tree = await agent.readdirRecursive("/home/agentos");
for (const entry of tree) {
console.log(entry.type, entry.path, entry.name);
}
File metadata
// Check if a path exists
const fileExists = await agent.exists("/home/agentos/hello.txt");
// Get file metadata
const info = await agent.stat("/home/agentos/hello.txt");
console.log(info.size, info.isDirectory, info.mtimeMs);
Move and delete
// Move/rename
await agent.move("/home/agentos/old.txt", "/home/agentos/new.txt");
// Delete a file
await agent.deleteFile("/home/agentos/new.txt");
// Delete a directory recursively
await agent.deleteFile("/home/agentos/temp", { recursive: true });
Permissions
Filesystem access is governed by the VM permission policy. The filesystem scope is granted by default; restrict it by path, for example to deny a sensitive directory:
const vm = agentOS({
permissions: {
fs: {
default: "allow",
rules: [{ mode: "deny", operations: ["*"], paths: ["/home/agentos/secrets/**"] }],
},
},
});
See Permissions for the full configuration.
Sandboxes
For heavier or untrusted workloads, run a full Linux sandbox alongside the VM and mount its filesystem into agentOS. The agent then reads and writes the sandbox’s files through the same fs APIs while the sandbox handles execution. See Sandbox Mounting for setup.
Default layout
With no mounts configured, every VM boots an Alpine-based root filesystem with the standard POSIX directories:
/home/agentos: the agent’s home directory ($HOME) and default working directory (pwd) when spawned, where it reads and writes (mounts land under it, e.g./home/agentos/data)./bin,/sbin,/usr: installed commands (common POSIX utilities by default, plus any software you add)./etc,/lib,/opt,/root,/run,/srv,/tmp,/var,/mnt: standard system paths.
It is backed by the VM’s own filesystem and persisted across sleep/wake. Nothing comes from or touches the host disk.