@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
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_spacess3,r2,gcs,minio,ceph,seaweedfs,wasabi,backblaze,digitalocean,tencent,aliyun,scaleway,qingstor,oci,supabase, withoutproxyqdrant: install@qdrant/js-client-restpostgres: installpgredis: any Redis over TCP, Upstash included, at aredis://orrediss://url, through Cloudflare’sconnect()email: installimapflow,mailparserandnodemailer
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_memoryon each workspace so a large write fails withDisk quota exceededbefore 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.typemust beram. 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_domainsentry 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:Classreference are the Node server’s alone. Codex’s exec-server runs here over its WebSocket.