Skip to main content
@struktoai/mirage-cloudflare runs Mirage on Cloudflare Workers. A workspace runs in the Worker’s own isolate: the shell, the commands built on Rust, and python3 on Monty, all in one thread. The Worker needs nodejs_compat for Node’s buffer, crypto, path, process and util modules. Wrangler loads Mirage’s Rust module and Monty as compiled WebAssembly.Module imports.

Install

wrangler.toml

Run a workspace

src/worker.ts
python3 runs on Monty in the isolate’s own thread, where no timer can interrupt it, so Monty’s own clock stops a run: at the line’s time limit, which ends the line with exit 124, or after 30 seconds with TimeoutError if that comes first. A loop that never ends leaves the isolate free for the next line. For anything else from core, import its subpaths (@struktoai/mirage-core/vfs/registry), not its package root: the root also imports optional packages, such as Pyodide, that a Worker bundle cannot resolve.

Serve the server API

createApp answers the HTTP routes, MCP and RPC as the server does, over the workspaces the isolate holds:
src/worker.ts
A workspace outlives the request that created it, so a later request finishes work an earlier one started; no_handle_cross_request_promise_resolution above lets it. It checks each request the way the server does, from the same MIRAGE_AUTH_MODE, MIRAGE_AUTH_TOKEN and MIRAGE_JWT_* variables. Without a token or a JWT issuer it serves nothing, since a Worker’s URL is public.
wrangler.toml
/v1/workspaces/:id/codex-exec serves Codex’s exec-server over a WebSocket, as the server does, so codex exec-server forward runs its tools in a workspace on the Worker.

Keep a workspace’s files

A Worker’s memory goes with its isolate. To keep a workspace’s files and sessions, put them in SQL: SqlVFS over a Durable Object’s own storage or a D1 database, and SqlWorkspaceStateStore over the same driver for each session’s working directory, variables and functions. One database holds one filesystem, so a Durable Object per workspace gives each workspace its own.

Mounts and CLIs

Mounts:
  • ram, github, gdrive, gdocs, gsheets, gslides, gcal, gmail, onedrive, sharepoint, box, airtable, linear, trello, langfuse, wandb, mem0, dify, slack, discord, notion, dropbox, jaeger, databricks_volume, tidb_filesystem, hf_models, hf_datasets, hf_spaces
  • s3, r2, gcs, minio, ceph, seaweedfs, wasabi, backblaze, digitalocean, tencent, aliyun, scaleway, qingstor, oci, supabase, without proxy
  • qdrant: install @qdrant/js-client-rest
  • postgres: install pg
  • redis: any Redis over TCP, Upstash included, at a redis:// or rediss:// url, through Cloudflare’s connect()
  • email: install imapflow, mailparser and nodemailer
chroma does not run on Cloudflare. CLIs: airtable, discord, gh, git, gws, hf, himalaya, linear, mcp, ntn, search, slack, trello.

Limits

  • A Worker’s isolate has 128 MB of memory and no disk. Set max_memory on each workspace so a large write fails with Disk quota exceeded before the isolate runs out.
  • The server API’s workspaces live in the isolate’s memory. A request routed to another isolate does not see them, and they are gone when the isolate is evicted. store.type must be ram. A workspace built in code keeps its files and sessions in SQL, as above.
  • Network rules judge each request by host name: the isolate never sees the address a name reaches, so a denied_domains entry naming an address or a range is refused, and jwt mode’s block on cloud metadata addresses covers only a request made to the address itself.
  • SSH, FUSE, policy and script files read by path, and runtimes or CLIs loaded by a source:Class reference are the Node server’s alone. Codex’s exec-server runs here over its WebSocket.