coilDocs

Built on Cloudflare

coil docs

Agent threads with their own computer, running on your own Cloudflare account.

What coil is

coil gives every agent thread its own Linux computer in the cloud. The thread has an agent, terminals, a real Chrome window, and a disk. You and the agent use the same ones, from any device.

coil is one Cloudflare Worker. It is a working showcase of the Developer Platform primitives, each doing the job it is built for:

WorkersThe front door: UI, API, MCP, and sign-in.
Durable ObjectsOne per thread. Runs the Pi agent, keeps the transcript, schedules loops, and survives restarts mid-turn.
ContainersOne Linux computer per thread, with a disk that is snapshotted on pause.
Workers AIOpen models, on the account that signs in.
AI GatewayFrontier models such as Claude, with the account’s logs, limits, and billing.
Sign in with CloudflareOAuth, so each person brings their own account.

Bring your own Cloudflare

On an instance in cloudflare mode, people sign in with their Cloudflare account. coil then runs their model calls on their Workers AI and AI Gateway. The instance owner never pays for anyone else’s inference, and never needs their keys.

This is the part that makes coil a template, not only an app. Anyone can ship a product on Cloudflare that runs on its users’ inference. Every new user is a Cloudflare account doing real work on Workers AI and AI Gateway.

What happens when you sign in

  1. coil sends you to Cloudflare’s consent screen. You pick one account.
  2. coil receives a token limited to these scopes: user-details.read, account-settings.read, ai.read, ai.write, aig.read, aig.run, and offline_access to stay signed in.
  3. coil lists the account’s AI Gateways and uses one with authentication turned on. It prefers the instance’s COIL_USER_GATEWAY, then default, then the first one.
  4. Each turn, coil refreshes the token if needed and calls the gateway with it. If the grant is gone, the turn fails. It never falls back to the instance’s own AI.
Set up your account once. In the dashboard, open AI → AI Gateway, pick or create a gateway, and turn on Authenticated Gateway. For Claude and other provider models, add unified billing credits or a provider key to that gateway.

Errors you might see

no AI Gateway with authentication turned onTurn on authentication for a gateway in that account, then sign in again.
402 Insufficient unified billing creditsThe gateway works, but the account has no credits for provider models. Add credits, or pick a Workers AI model.
x-api-key header is requiredThe gateway has authentication turned off, so it ignored the Cloudflare token. Turn it on.
Sign in with Cloudflare againThe grant was revoked or expired. Sign in again.

Sign out and revoke

Sign out at the bottom of the sidebar ends the session, revokes coil’s token with Cloudflare, and deletes the stored grant. You can also revoke coil at any time from your Cloudflare profile.

Check which account a session uses at /oauth/me.

Quickstart

  1. Sign in. Choose the Cloudflare account coil should use.
  2. Start a thread. Optionally give it a Git repository; coil clones it into /workspace.
  3. Pick a model from the chip under the message box. Models that start with gateway/ go through your AI Gateway.
  4. Ask for something real. For example: “Build a counter page, serve it on port 3000, open it in the browser and click plus three times.”
  5. Watch the computer on the right: terminals, files, and the live Chrome window the agent drives.
  6. Pause when you are done. The disk is saved. Come back later and the thread resumes.

Threads and computers

A computer per thread/workspace is a git repository. bash, git, node, python3, curl, ripgrep, and jq are installed. The image’s git refuses force-push.
TerminalsAs many as you want. Each is a tmux session the agent can use too. Reload the page and the shell is still there.
A real browserHeaded Chrome in the same computer, shown over VNC. It reaches the agent’s localhost. The agent drives the same window you see.
PauseSaves the disk and stops the computer. Idle threads pause on their own after 9 minutes.
ForkStarts a new thread from this disk plus a summary of the conversation.
CompactRecords a summary and a disk snapshot together, so they always match.
Child threadsThe agent can hand a side task to a child thread with its own computer, and wait for its answer.
LoopsRun a prompt on a schedule until a gate command exits 0, a run count is reached, or you stop it.
Pi extensionsLoad vanilla Pi extensions into a thread from a Git URL or a path. They run inside the computer, unchanged.

Models

Pick a model per thread from the chip under the message box, or with the thread_model capability.

@cf/...Workers AI models, run on the signed-in account.
gateway/claude-opus-5-5 and other gateway/*Provider models through AI Gateway on the signed-in account.
On an access instance, models run on the instance’s own account instead, through its AI binding or a configured gateway.

Drive coil from an agent

Everything in the UI is also a capability. The same list drives MCP, the coil_run code tool, REST, and the reference below.

MCP

Point an MCP client at /mcp. Call coil_describe for a TypeScript declaration of the coil object, then coil_run with the body of an async function:

const t = await coil.thread_create({ title: "demo" });
await coil.thread_exec({ name: t.name, command: "echo '<button>+</button>' > index.html && (busybox httpd -p 3000 &)" });
await coil.browser_open({ name: t.name, url: "localhost:3000" });
const page = await coil.browser_snapshot({ name: t.name });
await coil.thread_pause({ name: t.name });
return { thread: t.name, page };

REST

curl -X POST https://<host>/api/capabilities/thread_send \
  -H 'content-type: application/json' \
  -d '{"name":"thread-abc123","text":"run the tests"}'

Signing in

Every call must be signed in. Behind Cloudflare Access, send an Access token in the cf-access-token header. With Sign in with Cloudflare, send the session cookie from /oauth/login. Without it, the API and /mcp answer 401.

Plain text for agents is at /llms.txt.

Deploy your own

One command per instance. Each instance has one config file that never leaves your machine.

You need

  • Bun and Docker (builds linux/amd64).
  • A Cloudflare account on Workers Paid with Containers and Workers AI, and npx wrangler login.
  • A zone in that account for the hostname.
  • The nix-cf-proof base image in the account’s registry.

Ship

git clone https://github.com/acoyfellow/coil && cd coil && bun install
cp deploy/example.conf deploy/mine.conf
$EDITOR deploy/mine.conf
bun run ship -- deploy/mine.conf

ship runs the type check, lint, and tests, builds the computer image, deploys, and fails unless the URL answers with the sign-in mode you chose.

Choose how people sign in

COIL_AUTH=accessA Zero Trust Access application in front. Everyone admitted shares the instance’s AI.
COIL_AUTH=cloudflareSign in with Cloudflare. Each person’s inference runs on their own account. No Access application on the host.

Sign in with Cloudflare setup

  1. Create an OAuth client under Manage Account → OAuth clients: response type code, grants authorization_code and refresh_token, auth method client_secret_basic, redirect URL <your host>/oauth/callback on https.
  2. Add the scopes Workers AI (Edit, Read), AI Gateway (Run, Read), User Details (Read), and Account Settings (Read).
  3. Set COIL_AUTH=cloudflare and COIL_OAUTH_CLIENT_ID in your config.
  4. Store the secrets on the instance account:
CLOUDFLARE_ACCOUNT_ID=<id> npx wrangler secret put OAUTH_CLIENT_SECRET -c wrangler.mine.local.jsonc
openssl rand -hex 32 | CLOUDFLARE_ACCOUNT_ID=<id> npx wrangler secret put SESSION_SECRET -c wrangler.mine.local.jsonc
To let anyone sign in, verify your domain with the DNS TXT record shown on the client, add a logo, and change the client to public. That change is permanent.

Limits

  • Passkeys and security keys do not work in the cloud browser. Password and TOTP logins work and stay logged in.
  • A resumed computer gets its disk back, not its processes. Terminals reopen in the same folders. Servers the agent started are gone until something starts them again.
  • The browser comes back on its last page, not its state. Chrome reopens the last web page it had open, with its cookies. The page reloads, so anything held only in the page starts over.
  • Agent commands stop after 120 seconds. Start servers in the background. API and MCP commands stop after 10 minutes.
  • A Pi extension tool call stops after about 280 seconds. Only tools load; extension commands and shortcuts are reported as unsupported.
  • Computers have internet access. coil is not a sandbox for hostile code.
  • The browser view is 1280×800, scaled to fit.

API reference

Every capability is an MCP tool, a coil_run call, and POST https://coil.coey.dev/api/capabilities/<name>.

Threads

thread_list

List your threads, newest activity first.

thread_create

Create a thread: its own agent and its own Linux computer. repo is an optional git URL.

thread_send

Send a message to the thread agent and wait for the turn to finish. Reuse requestId to retry safely.

thread_status

Phase, transcript, compaction pairs, turns, and recent commands of a thread.

thread_fork

Start a new thread from this thread's disk and a summary of its conversation.

thread_message

Send a message from one thread to another. The receiver starts a turn now, or queues it until its current turn ends. Returns at once.

thread_wait

Wait until a thread finishes its turn, up to seconds, and return its last answer.

thread_context_budget

Set a smaller context window for a thread, in tokens, or 0 for the model limit. The thread compacts at 75% of it and continues from its HANDOFF: note.

model_list

List the models you can pick: the gateway models plus every Workers AI text model with tool use on your account, newest first. Refreshed from Cloudflare every hour.

thread_model

Choose the model for a thread, for example gateway/claude-opus-5-5 or a Workers AI model id. With Sign in with Cloudflare it runs on your own account.

thread_stop

Stop the agent turn now. A running tool call ends at once and the thread stays awake.

Shell

thread_exec

Run a shell command in the thread computer, in /workspace.

Files

thread_read_file

Read a file from the thread computer.

thread_write_file

Write a text file into /workspace on the thread computer, for example to upload a local pi extension folder file by file.

Browser

browser_open

Load a URL in the thread's browser. localhost is the thread computer.

browser_snapshot

List clickable elements as refs (e1, e2, ...) plus the page text.

browser_click

Click an element by its ref from browser_snapshot.

browser_type

Type text, optionally into an element ref first.

browser_eval

Run a JavaScript expression in the page and return the result.

Computer

thread_compact

Summarise the conversation and save the disk, as one recorded pair.

thread_pause

Save the disk and turn the computer off. The next call resumes it.

thread_resize

Change the container size. A running computer is paused and restarted at the new size.

Pi extensions

thread_extensions

Load stock pi extensions into the thread. Each source is an https git URL (optionally #ref) or a ./path inside /workspace, for example an uploaded folder. Their tools run inside the thread computer and the agent can call them from its next turn. An empty list removes them.

Warm bases

base_prepare

Clone a repo, run a setup command once, and snapshot it. New threads on that repo start warm.