Mounting
Archil.MountDisk(disk, { path, mode }) returns a mount reference: the fields of a sandbox mounts entry, plus mount(). Where it mounts depends on the host it’s bound to.
In a program sandbox
Section titled “In a program sandbox”An Archil.Sandbox with main mounts the disk itself. The binding adds it to the sandbox’s mounts, and the disk is there when the program starts:
const dataset = yield* Archil.MountDisk(Dataset, { path: "/data", mode: "read-only" });const names = yield* fs.readDirectory(dataset.path);On your own hosts
Section titled “On your own hosts”On a Cloudflare Container or an ECS task on EC2, the binding installs the Archil client into the host’s image, and the plan fails if the host can’t provide FUSE. mount() runs the client:
export default class Indexer extends Cloudflare.Container<Indexer>()( "Indexer", { main: import.meta.url }, Effect.gen(function* () { const dataset = yield* Archil.MountDisk(Dataset, { path: "/data", mode: "read-only" }); const fs = yield* FileSystem.FileSystem; return { fetch: Effect.scoped( Effect.gen(function* () { const path = yield* dataset.mount(); const entries = yield* fs.readDirectory(path); return yield* HttpServerResponse.json(entries); }), ), }; }).pipe(Effect.provide(Archil.MountDiskLive)),) {}The mount lasts as long as its scope. Closing the scope flushes writes and unmounts.
The host gets a disk token for Dataset only, so it can’t mount any other disk and never holds an API key. With mode: "read-only" the token is read-only too.
Start the Container with internet access
Section titled “Start the Container with internet access”The Archil client talks to Archil over the network, and a Cloudflare Container has no outbound network unless the Durable Object that starts it asks for one:
export class IndexerObject extends Cloudflare.DurableObject<IndexerObject>()( "IndexerObject", Effect.gen(function* () { const indexer = yield* Indexer; return Effect.gen(function* () { const { fetch } = yield* indexer.getTcpPort(3000); return { list: () => Effect.gen(function* () { yield* indexer.start({ enableInternet: true }); const response = yield* fetch(HttpClientRequest.get("http://container/")); return yield* response.text; }), }; }); }),) {}Without enableInternet: true, mount fails after 60 seconds with the client’s output.
Mount disks named at run time
Section titled “Mount disks named at run time”MountDisk() takes the disk and its token per call, e.g. from a Worker that created the disk:
const archil = yield* Archil.MountDisk();const path = yield* archil.mount({ disk: job.diskId, token: job.token, path: "/work" });The Worker makes the token with home.createToken(name) and revokes it with home.removeToken(id).
Sharing a disk between hosts
Section titled “Sharing a disk between hosts”mode picks how this mount shares the disk. An exclusive mount, the default, locks the whole disk for one writer, and every other client can only mount it read-only:
const dataset = yield* Archil.MountDisk(Dataset, { path: "/data", mode: "shared" });exclusive (the default) owns writes; shared lets many clients mount and write only paths they check out; conditional lets many clients write anywhere; read-only never writes. Mount a branch with branch: "session-42". shared, branch, and force are FUSE-client options: a sandbox mounts with exclusive, conditional, or read-only, and takes queueMs.
Pass a mount to a sandbox
Section titled “Pass a mount to a sandbox”A mount reference has the same fields as a sandbox mounts entry, so it goes straight into a sandbox created at run time:
const workspace = yield* Archil.MountDisk(Workspace, { path: "/workspace", mode: "conditional" });const sandboxes = yield* Archil.CreateSandbox();const sandbox = yield* sandboxes.create({ name: `task-${id}`, mounts: [workspace] });ECS tasks
Section titled “ECS tasks”ECS tasks need the EC2 launch type, since Fargate has no FUSE:
export default class Reader extends AWS.ECS.Task<Reader>()( "Reader", { main: import.meta.url, port: 3000, requiresCompatibilities: ["EC2"], networkMode: "bridge" }, Effect.gen(function* () { const dataset = yield* Archil.MountDisk(Dataset, { path: "/data", mode: "read-only" }); const fs = yield* FileSystem.FileSystem; return { fetch: Effect.scoped( Effect.gen(function* () { const path = yield* dataset.mount(); const entries = yield* fs.readDirectory(path); return yield* HttpServerResponse.json(entries); }), ), }; }).pipe(Effect.provide(Archil.MountDiskLive)),) {}Alchemy adds /dev/fuse and SYS_ADMIN to the task’s container.