Flue: the open framework for building AI agents
A guide to Flue, the open TypeScript framework for AI agents and workflows from Astro co-founder Fred Schott, covering agents, workflows and durability.
Fred Schott, the co-founder of Astro, just shipped a new framework. It’s not for websites. It’s for AI agents.
It’s called Flue, and version 1.0 Beta landed this week.
The pitch: Flue is to agents what Astro is to websites. A TypeScript framework with good developer experience, built on open pieces, and not locked to any one vendor.
In this post I’ll walk through what Flue is, the problem it solves, and how its main parts fit together.
What is Flue?
Flue is a TypeScript framework for building AI agents and workflows.
You pick any LLM, write your agent, and deploy it anywhere. That’s the whole pitch.
A few things set it apart:
- Open. You’re not tied to one model provider or one cloud.
- Durable. Agents survive restarts and outages, and pick up where they left off.
- Familiar. It’s built on tools you already use, like Vite.
Under the hood, Flue runs on Pi, an open “agent harness” used by tools like OpenClaw. (A harness is the thing that actually runs the model in a loop, calling tools and feeding results back.) It uses Vite to build, and a system called Durable Streams to move events around without losing them.
You don’t need to know any of that to use Flue. It’s just good to know the foundation is solid.
The problem Flue solves
A demo agent is easy. You wire up an LLM, give it a prompt, and it works.
A production agent is hard. Servers restart. Model providers time out. A tool call gets cut off halfway. A conversation that was going fine loses its history.
That last mile, getting an agent stable enough for real use, is the part teams keep struggling with. Flue exists to handle it for you.
The two main ideas: workflows and agents
Flue has two ways to build. The whole framework makes more sense once you see the difference.
- A workflow is a recipe. You write the steps, and the model fills in the smart parts.
- An agent is more like an employee. You hand over a goal and let it figure out the steps itself.
Same engine underneath, different amount of control. Let’s look at both.
Workflows: you write the steps
A workflow is good when you know exactly what should happen, and in what order. Your code is in charge, and you call the model when you need its help.
Here’s a workflow that summarizes some text:
// src/workflows/summarize.ts
const writer = createAgent(() => ({ model: 'anthropic/claude-sonnet-4-6' }))
export async function run({ init, payload }) {
const harness = await init(writer)
const session = await harness.session()
const response = await session.prompt(`Summarize: ${payload.text}`)
return { summary: response.text }
}
Read it top to bottom: start the harness, open a session, send a prompt, return the result. Your code drives every step.
The init and payload come from the Flue context that gets passed to every workflow. payload is the input you send in.
That one file is automatically both an HTTP endpoint and a CLI command:
flue run summarize --payload='{"text": "Lorem ipsum..."}'
Agents: you hand over the goal
Sometimes you don’t want to write the steps. You want to give the model a goal and let it work.
That’s an agent. You don’t write a procedure. You give it context, and it runs on its own:
// src/agents/triage.ts
export const route = (c, next) => next()
export default createAgent(() => ({
model: 'anthropic/claude-sonnet-4-6',
tools: [replyToIssue],
skills: [triage, verify],
sandbox: local(),
instructions,
}))
The default export is the agent. Everything inside is the context it works with: the model, the tools it can call, the skills it can use, the sandbox it runs in, and the instructions that tell it the goal.
The route export is the front door. It decides who’s allowed to reach your agent over the internet. We’ll come back to it.
So which do you use?
- A workflow when you know the steps.
- An agent when the problem is open-ended.
My advice is to start with a workflow when you can. The more your code decides, the fewer surprises. Reach for an agent when the task is too open-ended to script.
What goes into an agent
An agent is only as good as the context you give it. Let’s go through the pieces.
Instructions
Instructions are the job description, in plain English. This is where you say what “done” looks like:
const instructions = `
Triage a bug report end-to-end: reproduce the bug,
diagnose the root cause, verify whether the behavior is
intentional, and attempt a fix.`
Tools
A tool is an action the agent can take: call an API, query a database, reply to an issue.
You write a normal TypeScript function:
import { replyToIssue } from '../tools/github.ts'
List it in the agent’s tools, and now the model can choose to call it. The model decides when, you decide what’s available.
Skills
A skill is a reusable bit of know-how. If you’ve used skills with coding agents, this is the same idea.
A skill is a SKILL.md file you import and hand to the agent:
import triage from '../skills/triage/SKILL.md' with { type: 'skill' }
import verify from '../skills/verify/SKILL.md' with { type: 'skill' }
The agent pulls in a skill when a task needs that specific guidance. Skills can be imported from npm now too.
Sandboxes
A sandbox is a safe, walled-off computer the agent can work in. It can run commands and edit files there without touching your real machine.
You choose where it runs:
sandbox: local()
Local, a virtual environment, or a remote container with a provider like Daytona or E2B.
Subagents
For big jobs, an agent can hand work to subagents. You set up specialized roles, and the main agent passes each task to the right one. It’s a team, where each member is good at one thing.
Channels: connecting agents to Slack and friends
An agent is no use if nobody can reach it. A channel is the doorway between your agent and a place like Slack, GitHub, Linear, Discord, or Teams.
The channel handles the incoming events and the verification boilerplate, so you don’t have to.
Here’s an agent wired up to answer Slack mentions:
// src/channels/slack.ts
import { dispatch } from '@flue/runtime'
import { createSlackChannel } from '@flue/slack'
import assistant from '../agents/assistant.ts'
export const channel = createSlackChannel({
signingSecret: process.env.SLACK_SIGNING_SECRET,
async events({ payload }) {
const event = payload.event
await dispatch(assistant, {
id: event.channel,
input: { type: 'slack.mention', text: event.text },
})
},
})
The channel checks that the event really came from Slack, then dispatch sends it to your assistant agent. The same pattern works for every channel.
Durability: agents that don’t lose their memory
This is the part I like most.
A real agent has to survive failure. The server restarts, a provider times out, a tool call gets cut off. A durable agent rides through all of that and keeps going, without losing the conversation.
How? Flue borrows a trick from databases: the log is the source of truth.
Picture a flight recorder. Every prompt, every model response, every tool result gets written down to a record that only ever gets added to. That record is what Durable Streams gives you.
So when one process dies, another reads the record and continues from the last step. The user’s conversation isn’t lost.
In practice:
- Work that was accepted is never lost.
- Interrupted sessions resume on their own.
- Clients reconnect without starting over.
And you don’t write any of that recovery code. You get it for free.
A frontend with @flue/react
Once your agent runs, you’ll usually want a UI. That’s what @flue/react is for.
It gives you hooks that stream live data into your React app, so you don’t have to wire up the realtime part yourself:
import { createFlueClient } from '@flue/sdk'
import { FlueProvider, useFlueAgent } from '@flue/react'
const client = createFlueClient({ baseUrl: '/api' })
function Chat() {
const { messages, status, sendMessage } = useFlueAgent({
name: 'triage',
id: 'ticket-8472',
})
// ...
}
useFlueAgent() connects to a running agent and streams its messages. There’s a useFlueWorkflow() hook too. Vue and Svelte versions are on the way.
If you’re not using React, @flue/sdk lets you talk to a deployed agent from anywhere: another service, a script, whatever you have.
A CLI built for coding agents
Adding an integration to a framework used to mean a package, a setup guide, and an installer that did a few fixed steps. The real work, fitting it into your actual project, was still on you.
Flue takes a different route. flue add hands your coding agent a Markdown guide with everything it needs to finish the job inside your real codebase:
flue add channel slack
flue add channel linear
flue add sandbox daytona
flue add database postgres
flue add tooling opentelemetry
Your coding agent reads the guide and wires the integration into your project. To upgrade one later, run flue update.
The team calls it “shadcn, for your agents.” That’s a fair way to picture it.
More in 1.0 Beta
There’s more in the release:
- Observability — send telemetry to OpenTelemetry, Braintrust, Sentry, or your own.
- Databases — adapters for Postgres, MySQL, Redis, MongoDB, and Supabase.
- Image inputs — agents can take images, not just text.
- npm skills — share and reuse skills as packages.
- Offline docs — a CLI command so your coding agent can search Flue’s docs locally.
On deploying: agents scale as needed on Cloudflare today. On Node.js, Flue runs on a single machine for now, with multi-machine support planned before the stable 1.0.
Getting started
The quickest way to start is to let your coding agent do it. Flue gives you a prompt to paste in:
Read https://flueframework.com/start.md then help create my first agent…
Your agent reads the guide and scaffolds the project.
Want to set it up yourself? Install the packages and run init:
npm install @flue/runtime
npm install -D @flue/cli
npx flue init
From there, workflows go in src/workflows/, agents in src/agents/, and channels in src/channels/.
My take
What I like about Flue is the philosophy. It’s open, it works with any LLM, it deploys anywhere, and it’s clearly built by someone who cares about how it feels to use.
If you’re building agents and you’ve hit the wall of getting them to production, Flue is worth a serious look.
The full announcement and docs are at flueframework.com.