Filesystem
Read and write VM files, and mount durable storage, host directories, S3, and other filesystem backends.
Every language and shell in the VM sees the same filesystem, so files written here are immediately visible to Bash, JavaScript, Python, and installed software.
import { createAgentOsClient } from "@rivet-dev/agentos";
const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" });
const vm = client.agentOS.getOrCreate(["my-vm"]);
await vm.v1.filesystem.writeFile({
path: "/home/agentos/hello.txt",
content: "Hello, world!",
});
const content = await vm.v1.filesystem.readFile({
path: "/home/agentos/hello.txt",
});
console.log(new TextDecoder().decode(content));
await vm.v1.filesystem.mkdir({ path: "/home/agentos/src", recursive: false });
await vm.v1.filesystem.writeFiles({
entries: [
{ path: "/home/agentos/src/index.ts", content: "console.log('hi');" },
{
path: "/home/agentos/src/utils.ts",
content: "export const add = (a: number, b: number) => a + b;",
},
],
});
const entries = await vm.v1.filesystem.readdirRecursive({
path: "/home/agentos",
exclude: [],
});
for (const entry of entries) {
console.log(entry.type, entry.path);
}
await vm.filesystem.writeFile("/home/agentos/hello.txt", "Hello, world!");
const content = await vm.filesystem.readFile("/home/agentos/hello.txt");
console.log(new TextDecoder().decode(content));
await vm.filesystem.mkdir("/home/agentos/src");
await vm.filesystem.writeFiles([
{ path: "/home/agentos/src/index.ts", content: "console.log('hi');" },
{
path: "/home/agentos/src/utils.ts",
content: "export const add = (a: number, b: number) => a + b;",
},
]);
const entries = await vm.filesystem.readdirRecursive("/home/agentos");
for (const entry of entries) {
console.log(entry.type, entry.path);
}
Both APIs also provide batch readFiles, stat, readdir, readdirEntries,
exists, move, remove, export for a snapshot of the root filesystem, and
listMounts. Hosted VMs report byte counts in stat and readdirRecursive as
sizeBytes; the library reports them as size. The library can also mount
and unmount filesystems on a running VM.
Root filesystem
By default, each VM uses an in-memory overlay over the bundled base image. Writes survive for the VM’s lifetime and are discarded when the VM is replaced or disposed. See Persistence to keep files across VM recreation.
Mounts
Mount additional filesystem backends at any guest path.
Hosted VMs resolve filesystem configuration through a closed registry, such as
durable storage. Unknown backends, JavaScript VFS objects, callbacks, and host
paths are rejected. The library accepts native mount plugins, each identified
by an id and a config object:
| Plugin | Backend |
|---|---|
host_dir | A directory on the host, confined to the configured path |
chunked_s3 | An S3 or S3-compatible bucket |
chunked_sqlite | The VM’s SQLite database |
google_drive | A Google Drive folder |
import { createAgentOsClient } from "@rivet-dev/agentos";
const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" });
// Mount durable storage at /data when the VM is first created.
const vm = client.agentOS.getOrCreate(["my-vm"], {
createWithInput: {
config: {
filesystem: {
mounts: [{ path: "/data", backend: { type: "durable" } }],
},
},
},
});
import { AgentOs } from "@rivet-dev/agentos-core";
// Configure filesystem backends at boot. Native mount plugins (host
// directories, S3, Google Drive, etc.) are passed via `plugin`, each identified
// by an `id` and a `config` object.
const vm = await AgentOs.create({
mounts: [
// Host directory (read-only)
{
path: "/mnt/code",
plugin: { id: "host_dir", config: { hostPath: "/path/to/repo" } },
readOnly: true,
},
// S3 bucket
{
path: "/mnt/data",
plugin: {
id: "chunked_s3",
config: { bucket: "my-bucket", prefix: "agent/", region: "us-east-1" },
},
},
],
});
await vm.dispose();
Host-backed mounts are confined to their configured root on every operation,
including symlink and .. resolution. nodeModulesMount() is a library
shortcut that exposes a host node_modules tree read-only at
/root/node_modules.
File transfers are bounded. An operation that exceeds a payload limit fails with a typed limit error that names the limit.