flue

A visual guide to Flue, the agent harness framework

an agent is a loop.

Every AI agent is doing the same thing underneath; running a loop.

The model does the deciding. It reads the conversation, judges what to do next, and produces text. Sometimes that text is a request to call a tool. Something else has to run the tool, take what comes back, hand it to the model, and ask what's next. Over and over, until the model says it's done.

That something else (the part that runs the tools, keeps track of the conversation, knows when to stop) is the harness.

An agent is what you get when a model is put inside a harness and the loop is started. The model decides what to do; the harness does it.

Prompt
Model
Result
Tool
Response

a programmable agent harness.

Writing a harness from scratch takes a decent amount of work. The only other options are slop-forking someone else's, or reaching for tools like Claude Code or Codex, but most of them don't give you the flexibility you need, since their harnesses aren't programmable.

Flue is the same harness, pulled out. Programmable. Ready to run wherever you need it to run.

It's the right level of abstraction; you're not writing the harness from scratch, you also not adopting someone else's whole tool. Just the primitives, small and simple to use.

SANDBOX
TOOLS
SESSIONS
LOOP
SKILLS
TASKS

a workspace.

Every agent in Flue has a name and an ID. When something triggers it (a webhook, a CLI command), the ID determines which agent runs. State is scoped by ID, so the same ID → same agent, new ID → new agent. Simple enough.

Files written and conversation history stick around, across requests, across deploys.

Under the hood, the ID is the shard key. On Cloudflare it maps to a Durable Object: one DO per agent ID, which is where the workspace state lives. On Node, it's a key into an in-memory store, or a custom session store if you wire one up.

1 workspace
trigger
id
id: repo-123
workspace
src/auth.ts
src/db.ts
.env
state

state nests further.

Inside an agent, two more things nest.

A session is a conversation thread. Many sessions can live inside the same agent. They share the same files, but each has its own message history.

A task is a child agent inside a session. It shares the parent's files but keeps its own message history. Useful for handing a sub-problem off into its own context.

1 agent · 1 session · 0 tasks
agent: repo-123
workspace
shared filesystem
src/auth.ts
src/db.ts
.env
package.json
sessionsseparate histories
fix-bug-1
msgs0
empty
empty

the project shape.

A Flue agent is a directory. Inside it, two things matter:

A small TypeScript file where you would declare the triggers, call the model, and return the result.

And a markdown file with agent instructions.

Composition is filesystem-driven. Where you point the agent's `cwd` decides which `AGENTS.md` and which skills it picks up. Drop a folder somewhere and you've changed the agent's personality. No imports, no config file linking it together.

The same idea extends to integrations. If you need a third-party service like Cloudflare Sandbox, you don't install a package; you run `flue add | opencode`. The CLI streams a markdown recipe straight into your coding agent, which reads it and writes the TypeScript adapter into your project. Only the adapter ends up in your repo; the recipe never does.

run, then watch the project change
pathmy-agent
triage.tsentry point
triager.mdnamed skill
AGENTS.mdsystem prompt overlay
package.json
thin typescript · thick markdown

same code, anywhere.

The same Flue agent can run as a webhook handler, a scheduled job, or a one-off CLI command. The framework figures out where it's running and adjusts the plumbing (where session memory lives, how requests come in) without the agent code changing.

On Cloudflare, you get Durable Object-backed persistence for free. On Node, sessions live in memory by default, or in a custom store when you wire one up. CI runs are ephemeral by design.

Triggers are declared in the agent file itself: one line each, no separate routing config.

What changes per target is the session store, the request adapter, and the environment binding. What doesn't change is the agent code, the AGENTS.md, the skills, or the tool signatures.

Write the agent once. Trigger it from wherever makes sense.

target
your code
project files
identical, regardless of target
agent.ts
wiring
AGENTS.md
behaviour
skills/
named prompts
tools/
signatures
framework adapts— plumbing for the active target
target: CLOUDFLARE
plumbing
SESSIONSDurable Objects
ADAPTERfetch handler
BUILDWorker entry
Built by Mohamed Hassan.