flue
A visual guide to Flue, the agent harness framework
an agent is a loop.
Every agent does the same thing underneath; it just runs a loop.
The model is what does the deciding. It reads what's been said so far, weighs up what should happen next, and produces text. Sometimes that text is just text; other times it's a request to call a tool, and something else has to run the tool, hand the result back, and ask the model what to do now. This carries on, over and over, until the model decides it's done.
That something else, the part actually running the tools and keeping the history and knowing 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.
a programmable agent harness.
If you want to use a harness today, none of your options are ideal. You can reach for tools like Claude Code or Codex, but they're confined to the terminal and there's only so much you can do to customise them; you could also build on top of something like Pi, but you'll end up managing the entire harness yourself, all or nothing; or you could hand-roll your own, which is a lot of work.
Flue is a programmable harness framework that exposes just the right amount of primitives.
You get a harness with the flexibility to build exactly what you need, without having to build it from scratch, or having to manage every part of it yourself
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, that ID determines where the agent's state lives. 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.
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, which is useful for handing a sub-problem off into its own context.
the project shape.
A Flue agent is a directory, with two main files:
A small TypeScript file where you would declare the triggers, call the model, and return the result.
And a markdown file with agent instructions.
Point the same agent at a different directory and it picks up that directory's AGENTS.md. Same code, different behaviour. No imports, no config file linking things 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 <connector> | 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.
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.