Skip to content

Repository files navigation

flue-snippets

Runnable Flue 2.0 agents and channels for Cloudflare. Each E2E script builds a Worker, deploys it, tests the live endpoint, and deletes the Worker. The tests do not use mocks.

Each snippet is a self-contained Cloudflare app. It has its own package file, Wrangler configuration, and source directory.

ci

Demo site: flue.coey.dev, a guided tour of Flue on Cloudflare, auto-generated from this repo.

examples/   one CF product per folder, the smallest Flue snippet that uses it
recipes/    compositions, Flue + multiple primitives + receipts/proofs
templates/  forkable starters, production-shape, fork-and-ship

Every deployed snippet is public on *.workers.dev and binds Workers AI, so each agent route requires the per-run SNIPPET_API_KEY sent as an x-api-key header. Each run-e2e.sh generates a fresh one and injects it with wrangler deploy --var. Without it the route answers 401. templates/github-app mounts no agent route at all: its only inbound surface is the HMAC-verified GitHub webhook.

Every snippet is a Flue agent: prompt it at POST /agents/<name>/<id>, which is answered 202, then GET the same URL to read the settled conversation. Verified provider webhook ingress uses channels (POST /channels/<name>/<suffix>). Flue 2 removed workflows; work that was a workflow step is now a tool the agent calls.

Run one

git clone https://github.com/acoyfellow/flue-snippets
cd flue-snippets

# https://dash.cloudflare.com/profile/api-tokens, Workers Scripts:Edit + Workers AI:Read
# Put them in .env (each run-e2e.sh sources it) or export them:
export CLOUDFLARE_API_TOKEN=...
export CLOUDFLARE_ACCOUNT_ID=...

bun ex:workers-ai        # from the repo root
# or: cd examples/workers-ai && bash run-e2e.sh

~60 seconds: install (first run), build, deploy, assert, delete. ~$0.0001 in Workers AI usage. Each snippet is self-contained (its own package.json + src/ + wrangler.jsonc) and installs its own deps on first run.

The agent it just ran:

// examples/workers-ai/src/agents/workers-ai.ts
'use agent';

import { type AgentProps, useModel } from '@flue/runtime';

export function WorkersAi(_props: AgentProps) {
  useModel('cloudflare/@cf/moonshotai/kimi-k2.6');
  return 'Answer each user request directly and concisely.';
}

The 'use agent' directive registers the exported function as an agent at build time. Prompt it with POST /agents/workers-ai/<conversationId> and a body of { "kind": "user", "body": "..." }, then GET the same URL for the reply.

Examples

One Flue snippet, one Cloudflare binding.

Example Cloudflare product
workers-ai Workers AI
effect-hello Workers AI + Effect v4 (small Flue agent with an Effect program)
kv Workers KV
r2 R2
d1 D1
durable-objects Durable Objects (agent: same id → same DO, isolated per instance)
ai-gateway AI Gateway
queues Queues
vectorize Vectorize
browser-rendering Browser Rendering
worker-loader Dynamic Workers
hyperdrive Hyperdrive
email-workers Email Service

Recipes

Flue compositions with Cloudflare primitives and reviewable receipt, evaluation, or observability layers (including @acoyfellow/lab, gateproof, and Braintrust).

Recipe Composes
lab-receipt Workers AI + lab
do-session Durable Objects (agent, durable session memory)
do-governor Durable Objects (workflow, repetition governor)
lab-checkpoint Durable Objects + lab
ai-gateway AI Gateway + Workers AI
gateway-lab AI Gateway + Workers AI + lab
github-triage Workers AI + structured output (valibot schema)
chat-thinking Flue + Cloudflare Think (co-hosted DO chat agent)
virtual-sandbox Flue virtual sandbox (just-bash) + R2
mcp-client Flue + co-hosted MCP server (Workers)
dynamic-workflow Durable Objects + Workflows
event-trigger Workers AI + structured output (one signed-webhook front door for Sentry / PagerDuty / GitLab CI / cron)
braintrust-trace Braintrust application tracing + Workers AI
braintrust-ai-gateway Braintrust AI Gateway + gateway logging
braintrust-eval Braintrust Evals + deployed Workers AI endpoint
braintrust-otel OpenTelemetry + Braintrust span exporter + Workers AI

Each recipe's README explains what it composes, what it proves, and how to run it. The Braintrust recipes require a BRAINTRUST_API_KEY (injected into the ephemeral Worker via wrangler deploy --var); they run explicitly with bun rx:braintrust-* rather than in the CI matrix. No ALCHEMY_PASSWORD is used. Deploys use wrangler, not alchemy.

Local scripts

bun ex:<name>    # examples/<name>/run-e2e.sh
bun rx:<name>    # recipes/<name>/run-e2e.sh
bun tpl:<name>   # templates/<name>/run-e2e.sh

See package.json for the full list.

Refresh dependencies

bun run update

That repeatable maintenance command runs bun update in the repo and in site/, refreshes the homepage's visible “Last dependency refresh” timestamp when Bun bumps package manifest versions, then runs the site production build. If the Flue CLI/runtime or a dependency used by a snippet changes shape, also update the affected example/recipe/template and run its live E2E (bun ex:<name>, bun rx:<name>, or bun tpl:<name>) before shipping.

End-to-end flow

Every run-e2e.sh does the same five things:

  1. vite build, compiles the project (agents/channels under src/) into dist/<name>/ with a Flue-generated wrangler.json. The 'use agent' scanner registers every exported agent at build time.
  2. wrangler deploy --config dist/<name>/wrangler.json, deploys the Worker, creating any per-run resource (KV/R2/D1/Queue/Vectorize) first and injecting secrets/vars with --var. Prints the URL.
  3. Warmup, POSTs the agent route (/agents/<name>/<id>) with retries until it answers 202. The retry is mandatory: a freshly deployed Worker can 500 or refuse admission for ~10s while the route propagates and Workers AI warms up. Flue has no /health route.
  4. Assert, GET the same conversation URL and read the settled snapshot (messages[].parts[], where the reply is the part with type: 'text'); recipes run a gateproof.plan.ts with a probe.ts (pure fetch + JSON).
  5. wrangler delete (and delete any created resource), then verify zero leftover Workers. Trapped on EXIT INT TERM.

Flue owns the wrangler config: the Vite plugin merges its generated bindings + DO migrations into dist/<name>/wrangler.json, and wrangler deploy ships it. Each snippet is self-contained. It has its own package.json, wrangler.jsonc, and src/.

CI

.github/workflows/e2e.yml is workflow_dispatch-only. From the Actions tab, pick all, examples, recipes, templates, or a single target. max-parallel: 1 because Workers AI rate-limits hard under parallel load on a personal account.

Secrets:

  • CF_API_TOKEN_E2E, Workers Scripts:Edit + Workers AI:Read, plus permissions for any product-specific targets you enable (R2 / D1 / KV / Queues / AI Gateway / Vectorize / Browser Rendering / Worker Loader / Hyperdrive / Email).
  • CF_ACCOUNT_ID_E2E, Cloudflare account ID.
  • EMAIL_FROM, EMAIL_TO, only needed if you enable examples/email-workers. Without them, the send call returns a structured error and the assertion still passes (it accepts either a real send or a structured E_* code).

The Braintrust recipes currently run explicitly with bun rx:braintrust-* rather than in this matrix. Enrolling them requires a BRAINTRUST_API_KEY (injected into the ephemeral Worker via wrangler deploy --var). No ALCHEMY_PASSWORD is needed. Deploys use wrangler, not alchemy.

FAQ

Does it deploy a Worker? Yes. Each run-e2e.sh runs vite build then wrangler deploy, hits a real *.workers.dev URL, then wrangler deletes it. CI does the same. The tests do not use mocks.

What does it cost? ~$0.0001 per snippet per run (one Workers AI @cf/moonshotai/kimi-k2.6 call). Check your Cloudflare plan and limits before you run the full matrix.

Do all snippets run on a stock token? Most do. A few need extra access and will otherwise report a clear, non-fatal error: hyperdrive (token needs Hyperdrive), braintrust-* (need BRAINTRUST_API_KEY; braintrust-ai-gateway also needs a model provider configured in your Braintrust AI Gateway), email-workers (a verified sender, else it returns a structured E_* code and still passes).

How does it deploy? Flue 2 owns the deploy artifact through Vite: vite build emits dist/<name>/ with a generated wrangler.json (merged bindings + DO migrations), and wrangler deploy --config dist/<name>/wrangler.json ships it. Agents live in src/agents/, routing in src/app.ts, and verified provider ingress in src/channels/.

Why does CI run sequentially? Workers AI rate-limits aggressively on personal accounts under parallel load. max-parallel: 1 keeps the matrix green.

Can I run only one? Yes, every example, recipe, and template is independent. bun ex:<name>, bun rx:<name>, or bun tpl:<name>. Or trigger a single target from the Actions dropdown.

Contributing

See CONTRIBUTING.md. Security issues: SECURITY.md.

License

MIT.

About

Real, runnable Flue agents on Cloudflare. Examples teach one product at a time; recipes compose. Every snippet ships an E2E test that deploys an ephemeral Worker, asserts, and tears it down.

Topics

Resources

Contributing

Security policy

Stars

30 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages