Cloudflare Workers + Sandbox
Deploy to Cloudflare Workers with Durable Object sessions and Cloudflare Sandbox.
The Cloudflare target emits an unbundled Worker entrypoint, a Durable Object session store, and a Cloudflare Sandbox container binding. Wrangler owns the Cloudflare bundle; Fabric Harness just emits the entry, bindings, and config.
Status: pilot/live-gated. Build,
fh dev --target cloudflare, Workers AI binding, Durable Object session persistence, session routes, and R2-backed large artifacts are implemented. Treat production Cloudflare deployments as pilots until your account runs the live smoke workflow successfully. Full workspace backup/restore parity remains roadmap.
Quickstart
npx @fabric-harness/cli init my-edge-agent --template cloudflare
cd my-edge-agent
npm install
npx fabric-harness dev --target cloudflare --port 8787The template uses the Cloudflare Workers AI binding (env.AI) so the Worker can run inference without external model API keys.
Build
fh build --target cloudflare
cd .fabricharness/build/cloudflare
npm installOutput:
.fabricharness/build/cloudflare/
dist/worker.ts
wrangler.jsonc
Dockerfile # default Cloudflare Sandbox image
manifest.json
README.cloudflare.mdDevelop locally
fh dev --target cloudflareThis wraps wrangler dev so the same bundler runs in dev and deploy. Two reload paths run simultaneously:
- Wrangler watches the bundle's transitive import graph and reloads
workerdon body edits to your agent files. - Fabric Harness's structural watcher watches
.fabricharness/agents/and regenerates the Cloudflare entry whenever the agent set changes (a file is added, removed, renamed, or its trigger metadata changes). Wrangler picks up the new entry automatically.
Net result: you can edit agent bodies, add new agents, or change triggers: { webhook: true } without restarting the dev server.
Or if you've already built once and just want raw wrangler:
npx wrangler devDeploy
fh build --target cloudflare
cd .fabricharness/build/cloudflare
npx wrangler deployRoutes
The Cloudflare target serves the same surface as the Node server — see HTTP Server reference for the full route table:
GET /health·GET /ready·GET /manifestPOST /agents/:name/:id— invokeGET /agents/:name/:id— read sessionGET /agents/:name/:id/stream— SSE stream of typedAgentEventvaluesDELETE /agents/:name/:id— reserved (501 today)
Webhook trigger gating applies on the Worker too: in production mode (FABRIC_ENV=production), only agents with triggers.webhook === true are exposed publicly.
Choosing a Cloudflare sandbox mode
Fabric Harness supports two Cloudflare sandbox modes.
Containers / Cloudflare Sandbox
Use this mode when your agent needs Linux shell commands, package managers, language toolchains, bash, grep, read, write, and edit tools.
export default {
sandbox: {
backend: 'cloudflare',
mode: 'sandbox',
binding: 'Sandbox',
cwd: '/workspace',
},
};Shell Workspace / @cloudflare/shell
Use this mode when you want a lightweight durable Workspace and a Worker Loader-backed JavaScript code tool. It does not provide Linux shell commands; the model uses state.* inside the code tool.
export default {
sandbox: {
backend: 'cloudflare',
mode: 'shell-workspace',
loaderBinding: 'LOADER',
cwd: '/',
},
};The generated wrangler.jsonc adds:
{
"worker_loaders": [{ "binding": "LOADER" }]
}Helpers for custom setup and explicit R2 hydration are exported from @fabric-harness/cloudflare/shell.
If Cloudflare sandboxing isn't configured, the Worker falls back to Fabric's empty sandbox.
How it maps to Fabric primitives
| Fabric primitive | Cloudflare equivalent |
|---|---|
| Session store | Durable Object (one DO instance per session id) |
SandboxEnv | Cloudflare Sandbox container binding via @cloudflare/sandbox, or Cloudflare Shell Workspace via @cloudflare/shell |
| Model provider | env.AI Workers AI binding via CloudflareWorkersAIModelProvider (optional; HTTP providers also work) |
| Webhook trigger | POST /agents/:agent/:id |
| Health/manifest | GET /health, GET /manifest |
Workers AI binding (no API tokens)
@fabric-harness/cloudflare/workers-ai ships a ModelProvider that routes inference through env.AI.run() instead of HTTP. Zero API tokens, zero egress, runs at the edge. Workers AI accepts the OpenAI Chat Completions request body, so the provider serializes through the SDK's standard OpenAI helpers.
import { CloudflareWorkersAIModelProvider } from '@fabric-harness/cloudflare/workers-ai';
export default {
async fetch(request: Request, env: Env) {
const fabric = await init({
modelProvider: new CloudflareWorkersAIModelProvider({
binding: env.AI,
defaultModel: '@cf/meta/llama-3.1-8b-instruct',
// Optional: route through Cloudflare AI Gateway
// gateway: { id: 'my-gateway', skipCache: false, cacheTtl: 3600 },
}),
});
// ...
},
};Add the binding to wrangler.jsonc:
{
"ai": { "binding": "AI" }
}You can still use HTTP providers (Anthropic, OpenAI-compatible, Vercel AI Gateway) on the Cloudflare target — store the API key as a Workers Secret and reference it via env.
Live validation
For a production pilot, run the live-gated Cloudflare smoke in your account before rollout:
FABRIC_CLOUDFLARE_TEST=1 \
FABRIC_CLOUDFLARE_WORKER_URL=https://<worker>.<subdomain>.workers.dev \
FABRIC_CLOUDFLARE_ARTIFACT_DIR=/path/to/.fabricharness/build/cloudflare \
CLOUDFLARE_ACCOUNT_ID=<account-id> \
pnpm --filter @fabric-harness/cloudflare test -- live.test.tsThe smoke should verify /health, /ready, /manifest, agent invocation, session/timeline/metrics/tasks/approval/artifact routes, and R2 artifact behavior when a bucket binding is configured.
Limits and considerations
- Worker request/CPU limits apply; long-running workflows belong on the Temporal worker target.
- Sandbox container start latency depends on the Cloudflare image; warm pools help.
- Persistent workspace backup/restore is deferred — design agents to be replayable from the session log and durable object/R2 artifacts rather than disk state.
- Keep
FABRIC_HARNESS_API_TOKEN, body limits, rate limits, andFABRIC_ENV=productiontrigger gating enabled for public deployments.