
The most interesting AI-infrastructure launch of early May did not come from a foundation lab. It came from the co-founder of a web framework. On May 1, Fred K. Schott (Astro co-founder) posted a sixteen-line pitch for a new TypeScript project called Flue: a framework that treats the agent harness as a first-class build target. Six weeks later, on June 16, Flue shipped its 1.0 Beta — and the version of Flue you can install today is a different, larger, more opinionated thing than the one that went viral in May.
This piece has been updated for that 1.0 rewrite and the betas that have come fast behind it. The thesis survived intact; almost all the code did not. So the right way to read Flue now is in two layers: the durable bet (the harness is the framework), and the June reality (a 335-commit reorganization, then beta.3 and beta.4 adding a fourth primitive, a React package, and a telemetry overhaul, alongside a Cloudflare runtime deal and a Vercel-backed rival that did not exist when Flue launched). The version you install today, 1.0.0-beta.4, is days old; the framework is moving faster than most teams can adopt it, which is itself a fact worth pricing in.
What 1.0 actually changed
The 1.0 Beta is not a version bump. The v0.11.1...v1.0.0-beta.1 compare is 335 commits across 300 files — a ground-up reorganization of the public surface. Three things moved:
| Area | May launch (0.3.x) | 1.0 Beta (June) |
|---|---|---|
| Core package | @flue/sdk/client | @flue/runtime (harness, sessions, tools, sandbox) |
| Agent shape | export default async ({ init, payload }) => {...} | export default defineAgent(() => ({ model, tools, skills, sandbox, instructions })) |
| Top-level primitives | one (the agent function) | three — Agents, Workflows, Channels |
| Skills | discovered from disk at runtime | imported as typed modules with import s from "./SKILL.md" with { type: "skill" } |
| Workflow input | payload everywhere | input everywhere (SDK, CLI --input, RunRecord) |
The announcement frames it as a consolidation: Flue’s “core primitives (agents, workflows, sandboxes, channels) have come together into a cohesive story.” In practice it means the May post’s fifteen-line example no longer compiles, and the mental model shifted from “an agent is a function you export” to “an agent is a configuration you declare.” That is a meaningful upgrade, because the declarative form is what lets the same agent definition run across Node, Cloudflare, and CI without edits. But it is also a hard break six weeks after launch, which is exactly the kind of thing a 1.0-beta label is supposed to warn you about.
Flue in 2026, current API
The smallest current Flue agent declares a config object and returns it from defineAgent. From the repository README, here is the canonical bug-triage agent:
import { defineAgent, type AgentRouteHandler } from '@flue/runtime';import { local } from '@flue/runtime/node';import triage from '../skills/triage/SKILL.md' with { type: 'skill' };import verify from '../skills/verify/SKILL.md' with { type: 'skill' };import * as githubTools from '../tools/github.ts';
const instructions = `Triage a bug report end-to-end: reproduce the bug,diagnose the root cause, verify whether the behavior isintentional, and attempt a fix.`;
// Expose (and protect) your agents over HTTP:export const route: AgentRouteHandler = async (_c, next) => next();
export default defineAgent(() => ({ model: 'anthropic/claude-sonnet-4-6', tools: [...githubTools], skills: [triage, verify], sandbox: local(), instructions,}));Read what the declaration carries. model is a string, not a configured client, so Flue resolves the provider. tools is a spread of typed functions. skills are markdown files imported as modules, so the build can typecheck that the skill exists instead of failing at runtime when a path is wrong. sandbox: local() wires the host filesystem; swapping it for a Cloudflare or Daytona backend is a one-line change. route is the HTTP guard — the seam where you add auth before the agent is reachable. Everything that was implicit in the May API (the session, the tool registration, the default sandbox) is now explicit and composable.

Getting started: zero to a running agent
The canonical triage agent above is the destination. Here is the shortest path to a working agent on your own machine, taken straight from Flue’s own getting-started doc (reviewed for 1.0 Beta). You need Node.js >=22.19.0 and one model provider key.
First, install the runtime and the dev CLI, drop your key in .env, and initialize a target. flue init writes a flue.config.ts; the --target flag picks where the agent will run — node for a local server, cloudflare for a Worker:
npm install @flue/runtimenpm install --save-dev @flue/cliecho 'ANTHROPIC_API_KEY="your-api-key"' > .envnpx flue init --target node # or: --target cloudflareAdd .env to .gitignore before you commit — the credentials boundary is your responsibility, not the framework’s. Cloudflare’s cloudflare/* models need no key at all, which is the cheapest way to kick the tires.
Next, the smallest possible agent. The filename is the registration — agents/hello-world.ts becomes the agent named hello-world, no manifest, no router entry:
import { defineAgent } from '@flue/runtime';
export default defineAgent(() => ({ model: 'anthropic/claude-sonnet-4-6', instructions: 'Tell a funny "hello world" engineering joke.',}));Then run one prompt against it. flue run spins up a temporary Node or Cloudflare runtime, invokes the agent through the real application path (your app.ts and middleware included, so what you test is what you ship), prints the result, and exits:
npx flue run hello-world --input '{"message":"Tell me a joke."}'That is the whole loop: install, declare, run. The jump from here to the triage agent at the top of this piece is additive, not structural — you swap instructions for skills, add tools, set sandbox: local(), and bolt on a route guard. Every primitive in the rest of this post snaps onto the four lines above. (One caveat the breakage section earns: these commands track 1.0 Beta, and Flue has renamed core verbs twice in five weeks — pin your version and check the changelog before copying tutorials older than the current beta.)
The harness, named
The bet that survived the rewrite is the one Flue was built to make. The word “harness” came into the lexicon in Vivek Trivedy’s LangChain post from late 2025, the one Fred links from the Flue homepage. Trivedy’s definition is simple: “Agent = Model + Harness. If you’re not the model, you’re the harness.” Everything that isn’t the LLM (the loop, the tool execution, the filesystem, the sandbox, the orchestration) is the harness. Until Flue, every TypeScript framework in the space (Mastra, Vercel AI SDK, LangGraph.js, Genkit) treated those layers as plumbing: necessary, but assembled by the user. Flue’s bet is that the harness should be the framework.
The architectural commitment runs deeper than the slogan. The package tells you what they actually depend on: Mario Zechner’s pi agent core for the agent loop — now published as @earendil-works/pi-agent-core and @earendil-works/pi-ai after a mid-June namespace move off @mariozechner/* — just-bash for the in-memory virtual sandbox, @modelcontextprotocol/sdk for MCP tool adapters, and a runtime layer that now spans Node, Cloudflare Workers, GitHub Actions, GitLab CI, Daytona, and Render. The novel contribution is the assembly — one orchestration shape that survives every deploy target.
@prince_twets caught the through-line in mid-June, after the rewrite landed:
withastro/flue caught my eye today. It is a TypeScript agent framework with built in sandboxes, durable execution, and subagents. I like that it treats the harness as the product, not just the model wrapper.
— @prince_twets June 18, 2026
“The harness as the product, not just the model wrapper” is the whole thesis in nine words.
Agents, workflows, channels, actions
1.0 launched with three primitives; the betas since have made it four. They map to different shapes of work, and the distinction is the clearest articulation Flue has produced of what it is for.
Agents are autonomous. You give them instructions and tools and trust them to decide the path. Workflows are structured — your code guides the agent’s reasoning from a defined input to a finished result, calling the model where you want judgment and keeping control where you want determinism. Channels are the inbound edge: verified events from Slack, Teams, Discord, and GitHub, dispatched to an agent. Actions, added in beta.3, are the newest and the most interesting; they get their own section below, because they quietly rewired how the other three fit together.

A workflow makes the agent-as-subroutine pattern concrete. From the repository’s Braintrust example:
import { defineAgent, defineWorkflow, defineTool, type WorkflowRouteHandler } from '@flue/runtime';import * as v from 'valibot';
export const route: WorkflowRouteHandler = async (_c, next) => next();
const agent = defineAgent(() => ({ model: 'anthropic/claude-haiku-4-5' }));
const lookup = defineTool({ name: 'lookup_weather', description: 'Look up current weather for a city.', input: v.object({ city: v.string() }), run: async ({ input }) => `${input.city}: sunny, 72 F`,});
export default defineWorkflow({ agent, input: v.object({ city: v.optional(v.string()) }), async run({ harness, input }) { const session = await harness.session(); const city = input.city ?? 'San Francisco'; const response = await session.prompt( `Use the weather tool to report current weather in ${city}.`, { tools: [lookup] }, ); return { message: response.text }; },});The run function is plain TypeScript. It owns control flow; the model owns the reasoning inside each session.prompt(). Most production agent failures happen at exactly this seam, where an LLM is asked to make a routing decision it has no business making, and Flue’s workflow primitive moves that seam back to the host language. A tool is a Valibot schema plus a run handler (the parameters/execute pair from the May API was renamed to input/run in beta.1, and Flue now validates and snapshots a declared output schema for you); the model can only call what you hand it in tools.
Subagents are first-class too. Declare a profile, attach it, and delegate with session.task():
const editor = defineAgentProfile({ name: 'editor', instructions: 'Rewrite the supplied sentence in a clearer, shorter form.',});const agent = defineAgent(() => ({ model: 'anthropic/claude-haiku-4-5', subagents: [editor] }));// inside run():const response = await session.task(`Rewrite this sentence: ${draft}`, { agent: 'editor' });Actions: the primitive that rewired the rest
The most consequential change since 1.0 is not a feature on top of the existing model. It is a new noun underneath it. beta.3 introduced Actions, defined with defineAction(), and then rebuilt workflows on top of them.
An Action is reusable, schema-validated agent logic with one execution path. It declares an optional Valibot input, an optional output, and a run({ harness, input, log }) handler that orchestrates a session:
import { defineAction } from '@flue/runtime';import * as v from 'valibot';
export const summarize = defineAction({ name: 'summarize_document', description: 'Summarize a document clearly and concisely.', input: v.object({ text: v.string() }), output: v.object({ summary: v.string() }), async run({ harness, input }) { const session = await harness.session(); const response = await session.prompt(`Summarize this text:\n\n${input.text}`); return { summary: response.text }; },});The reason this matters is composition. The same Action definition has two call sites:
// 1. Bind it to a workflow → runs as an inspectable, recorded job.export default defineWorkflow({ agent: defineAgent(() => ({ model: 'anthropic/claude-haiku-4-5' })), action: summarize,});
// 2. Or hand it to an agent → the model decides when to call it,// and Flue runs it in an isolated child harness.export default defineAgent(() => ({ model: 'anthropic/claude-sonnet-4-6', instructions: 'Help the user edit and understand their documents.', actions: [summarize],}));When the model calls it, Flue presents the Action as a framework-managed tool and runs it in a child harness that shares the parent’s sandbox, filesystem, and policy but keeps its own sessions. One definition, two call sites, with validation and snapshotting handled once.

That is a real answer to the seam problem the workflow primitive was already chasing. A tool is a single function call. A skill is instructions. An Action sits in between: a multi-step, agent-backed operation you want to behave the same way every time, whether your code invokes it or the model does. The cost is conceptual surface. A builder now picks among five overlapping nouns (tool and skill, then workflow versus subagent versus Action) and the boundaries between the last three take a careful read of the docs to keep straight. The benefit is that the reliability-critical middle of an agent finally has a named home instead of living as ad-hoc code inside a run() closure.
The rewrite that brought Actions also renamed the declaration verbs for consistency — createAgent() became defineAgent() (with a deprecated alias), createWorkflow() became defineWorkflow() (no alias) — and bumped session persistence to version 8. The pace is the story as much as the primitive: this is a beta tearing up its own two-week-old API to get the abstraction right, again.
Markdown logic, TypeScript orchestration
The line in the original launch that landed hardest is the one about logic location: “Most of the ‘logic’ lives in Markdown: skills and context and instructions.” The 1.0 rewrite hardened this rather than softening it. Skills are no longer discovered loosely from a directory; they are imported as typed modules:
import triage from '../skills/triage/SKILL.md' with { type: 'skill' };A Flue project’s structure looks like this:
my-agent/├── agents/│ └── triage.ts # 20 lines of orchestration├── skills/│ └── triage/│ └── SKILL.md # the actual instruction set├── tools/│ └── github.ts # typed tools└── flue.config.ts
The .ts file is twenty-to-fifty lines: which model, which tools, which sandbox, what the agent returns. The instruction sets (the part that says what the agent should actually do) live in markdown. This is the same shape as Claude Code skills, Cursor rules, and Anthropic’s published skill protocol. Flue is not inventing a convention. It is taking the one that emerged from the Claude Code ecosystem and saying: this is also how you build non-interactive agents that ship to production. The with { type: 'skill' } import assertion is the upgrade — it means a missing or malformed skill is a build error, not a 2 a.m. production surprise.
beta.3 added an escape hatch that does not undercut the convention: defineSkill() lets you declare a skill entirely in TypeScript, with the same progressive-disclosure activation and lazy file access as a SKILL.md directory:
import { defineSkill } from '@flue/runtime';
export const review = defineSkill({ name: 'code-review', description: 'Reviews code changes. Use when evaluating a patch.', instructions: 'Inspect the patch for correctness, then summarize risks.', metadata: { version: '1' }, files: { 'references/checklist.md': 'Check error handling, tests, and naming.', },});That files map carries the same supporting references — text or binary — a folder skill would keep on disk, loaded lazily only when the skill activates. The point is single-file agents: when you want the whole thing in one module rather than a folder tree, you no longer have to give up the skill abstraction to get there. The markdown-first default stands; the TypeScript form is for when a directory is more ceremony than the job warrants. One caveat that landed in the same release: skill names must now follow the spec’s ASCII rules (1–64 lowercase letters, numbers, single hyphens), so any Unicode-named skills from the May era need renaming before you upgrade.
The Cloudflare deal is the real June story
The 1.0 announcement got the GitHub stars. The more consequential June event was Cloudflare’s June 17 post positioning its Agents SDK as the runtime layer underneath harnesses — and naming Flue as the first. Cloudflare’s framing is blunt about why now:
2026 is the year agent harnesses go to production. The software that controls the model’s access to the outside world — harnesses like Codex, Claude Code, OpenCode, Pi, and Project Think — has matured to the point where teams are deploying agents as real, load-bearing infrastructure.
— Thomas Gauvin, Cloudflare, June 17, 2026
This separates the stack into three layers owned by three different parties: the framework (Flue, where you write the agent), the control loop (Pi, the agent core Flue is built on), and the runtime (Cloudflare Agents SDK + Durable Objects, where it actually executes and persists). @stretchcloud read the move correctly:
Every serious agent demo eventually hits the boring failure mode … the “AI” problem quietly becomes a distributed systems problem. That is why this Cloudflare move is more interesting than another framework launch. They are trying to make the Agents SDK the runtime layer under different harnesses.
— @stretchcloud June 17, 2026
That is the durability gap from Flue’s launch week, the “is stream reconnect on the roadmap?” question, being answered not by Flue alone but by pushing the hard distributed-systems problem down to a runtime built for it. Durable Objects already solve session persistence across requests; leaning on them is the pragmatic answer to “what happens when the process dies mid-task.”

Same agent code, multiple backends
The thing reviewers kept noticing on launch night was the sandbox abstraction, and it survived the rewrite as @flue/runtime backends. From @curonianai: “sandbox as primitive, not adapter. Mastra and AI SDK make you BYO the sandbox. Same agent code, multiple backends. Filesystem composition becomes native, which is the actual lever.”
| Sandbox | Implementation | Use case |
|---|---|---|
virtual (default) | just-bash in-memory bash + filesystem | Stateless agents, high-traffic webhooks, no container overhead |
local() | Host filesystem | CI runners with the repo already checked out |
| Daytona | @daytona/sdk Linux container | Full Linux env, persistent filesystem, real shell |
| Cloudflare Sandbox | @cloudflare/sandbox Durable Object container | Per-session container on Cloudflare with persistence |
The agent declaration does not change when the backend does. The default (virtual) is the lever Mastra and Vercel AI SDK do not give you: most agent work needs a filesystem, not a full container, and spinning up a container per webhook destroys agent unit economics. Flue makes the cheap path the default and the expensive path opt-in.
@flue/react closes the loop to the frontend
For its first six weeks Flue stopped at the server. You wrote the harness, exposed it over HTTP, and built whatever UI you wanted on top of @flue/sdk. The 1.0 line added a first-party answer for the most common one: @flue/react, a package that turns Flue’s durable event streams into live React state.
The surface is two hooks. useFlueAgent() gives you a continuing conversation with an agent instance; useFlueWorkflow() observes a finite workflow run. A chat UI is about a dozen lines:
import { useFlueAgent } from '@flue/react';
export function Chat({ conversationId }: { conversationId: string }) { const agent = useFlueAgent({ name: 'support-assistant', id: conversationId }); return ( <Thread status={agent.status}> {agent.messages.map((m) => ( <Bubble key={m.id} role={m.role} parts={m.parts} /> ))} <Composer onSend={(text) => agent.sendMessage(text)} /> </Thread> );}useFlueAgent reconstructs the transcript from the durable event log (the latest 100 events by default; pass history: 'all' for the full thread), then follows new events live. Both hooks subscribe to the same persisted stream the runtime already keeps, so the UI reads the authoritative record rather than a best-effort socket. The message shape is parts-based — text, reasoning, tool activity, images — and deliberately mirrors AI SDK v5’s UIMessage without depending on ai at runtime or implementing its transport. sendMessage() resolves when the server admits the prompt, not when generation finishes, and the stream then reconciles that optimistic message with its durable copy. beta.4’s release note is a tell about how carefully this seam is built: the hook “keeps optimistic messages in their canonical transcript position when durable echoes arrive.” That is the language of someone who has been bitten by chat UIs that double-render a message when the optimistic update and the server echo disagree. Transport defaults to Durable Streams long-polling; pass live: 'sse' for a single SSE connection instead.
This is a meaningful widening of scope. With React in the box, the same durability machinery that survives a dropped server process now also drives a chat transcript that survives a page reload, because both read the one event log. It also sharpens the contrast with eve, whose pitch leans on Vercel’s frontend gravity: Flue is reaching for the frontend too, but on the write-once-deploy-anywhere terms it set for everything else.

Where Flue actually came from
Frameworks invented from first principles tend to look like it — answers to questions nobody is asking, gaps where the real work is. Flue does not have that smell, and the reason is in the git history.
On February 11, 2026, Fred opened PR #15476 on the Astro monorepo titled “Experiment: Automatic triage for new GitHub issues.” It was in-house infrastructure: the Astro repo gets a steady stream of issues, the maintainers cannot triage them all, and a Claude-Code-style agent could do the first pass. The PR added 14 files, +831 lines. Two weeks later, PR #15545 was 19 files of “security improvements, sandbox updates, skill refinements” — exactly the unglamorous edges that only show up after the thing is running on real traffic.
By March those skills had been generalized far enough that they no longer looked like Astro-specific infrastructure. Mario Zechner (author of the underlying pi-agent-core library) got his hands on it, the response was “holy shit it’s built on pi?!”, and Fred extracted the abstraction:
ok, i already posted this but holy shit it’s built on pi?! … this makes me super happy!
— @badlogicgames May 1, 2026
This origin rules out the most common failure mode in the category: a clean abstraction nobody used in production. Flue’s harness ran on the Astro repo’s issue triage for two months before it had a name. Every primitive was added because the maintainers needed it to ship one specific feature. That the 1.0 rewrite then reorganized those primitives is not a contradiction — it is what happens when a tool built for one repo gets generalized for everyone, and the original shape turns out to be too narrow.
The rival that did not exist in May: Vercel’s eve
The biggest change to Flue’s world is not in Flue’s repo. On June 17, at Vercel Ship London, Vercel open-sourced eve — its own agent framework, built on the same core idea that an agent is a directory of files. The framing is nearly identical to Flue’s: markdown instructions, typed TypeScript tools, skills, sandboxes, durable workflows. Vercel pitches it as “Next.js, for agents.”
The two frameworks now define the poles of the TypeScript agent-framework debate:
| Flue | eve (Vercel) | |
|---|---|---|
| Backer | Astro team (Fred Schott) | Vercel (Guillermo Rauch) |
| Core pitch | Write once, deploy anywhere, any LLM | Scaffold to running agent in under a minute |
| Deploy gravity | Node, Cloudflare, CI, Daytona, Render | Vercel Functions + Sandbox (portable, but Vercel-native) |
| Maturity (June 23) | 1.0 Beta (beta.4 shipped), ~6,495 stars, 4 months old | 0.11.x, ~2,400 stars, 6 days old |
| LLM routing | Provider-agnostic strings | AI Gateway (OIDC, no keys on Vercel) |
The honest contrast is portability versus gravity. Flue’s whole value proposition is that your agent code does not care where it runs; eve’s is that on Vercel, the deploy story disappears entirely (OIDC means no API keys, the sandbox and workflow engine are wired in). Reviewers have already flagged the tradeoff — eve’s speed-to-first-agent comes with deploy-gravity that becomes a portability bill later, which is precisely the bill Flue is built to never charge.
They are not purely adversarial. shadcn’s agentcn, launched June 20, builds on both:
Introducing agentcn 🤖 by @shadcnlabs — Built on Eve by @vercel and @flueai — Zero config, one command setup. @shadcn/ui compatible … 10+ production-ready agent recipes.
— @alaymanguy June 20, 2026
When the most influential component-library author in the React ecosystem treats two competing frameworks as interchangeable backends, it tells you the category has won even before either framework has. The harness-as-framework idea is now the consensus shape; Flue and eve are arguing over who hosts it. (We cover eve’s architecture in depth in the companion piece on Vercel’s framework.)
The contrarian read: is the sandbox the right primitive?

Not everyone agrees the harness-as-framework framing is the unit that matters. The sharpest pushback came not from a foundation lab but from a fellow framework author. Sam Goodwin, who builds the infrastructure-as-code framework Alchemy, looked at Flue’s design and argued that Flue picked the wrong thing to make first-class:
Alchemy.Agent is a type-safe string template capturing Prompt and Tools together. It’s the “interface”. Cloudflare.Agent() implements it with a DO. The “Sandbox” feature of Flue is simply a Layer. It isn’t first-class.
— @samgoodwin89 June 19, 2026
The critique is worth taking seriously because it inverts Flue’s own marketing. Flue sells the sandbox as a framework-level primitive, the thing Mastra and the Vercel AI SDK leave to the user. Goodwin’s claim is the opposite: the agent interface, prompt and tools captured as a type, is the real primitive, and the sandbox is just one runtime layer you compose underneath it, no more privileged than a database binding. Read that way, Flue and Alchemy disagree about which abstraction deserves to be the noun. Flue says the harness; Alchemy says the agent-as-typed-interface, with the runtime (a Cloudflare Durable Object, a sandbox, whatever) as a swappable implementation detail. This is not a small quibble. It is the same argument the frontend world had about whether the component or the route is the primitive, and it will shape which of these frameworks composes cleanly into larger systems. Flue’s answer is defensible — for an agent that writes files, the sandbox genuinely is load-bearing — but the fact that a serious infra author looked at the design and reached for a different noun is the clearest sign the category’s foundations are still being argued, not settled.
The disagreement got pointed since: at some point in the post-1.0 churn, Flue’s own repo tagline changed from “the agent harness framework” to “the sandbox agent framework.” Flue is leaning harder into the exact noun Goodwin says is only a layer. And yet the same betas that doubled down on the sandbox in the headline also shipped Actions — a primitive defined precisely as schema-typed input, output, and a handler, which is a long step toward the typed-interface-as-primitive idea Goodwin was arguing for. The honest read is that Flue is hedging in code what it is asserting in marketing: the sandbox stays the marquee noun, but the type-first interface keeps gaining surface underneath it.
Mapping Flue against the rest of the TypeScript agent stack
The category has gotten crowded fast. Six frameworks worth comparing on the dimensions Flue actually cares about:
| Framework | Sandbox primitive? | Markdown-first? | Deploy targets | Secrets boundary |
|---|---|---|---|---|
Flue (@flue/runtime) | First-class (4 backends) | Yes (skills as typed modules) | Node, Cloudflare, GitHub Actions, GitLab CI, Daytona, Render | Per-call command grants |
| eve (Vercel) | First-class (Vercel Sandbox) | Yes (instructions + skills) | Vercel-native (portable) | Runtime OAuth (Connect) |
| Mastra | BYO container | Workflows-as-code | Node, Cloudflare, hosted | Tool-level config |
| Vercel AI SDK | None | No | Vercel, Edge | Tool-level config |
| LangGraph.js | BYO | No | Node, hosted | Per-tool |
@earendil-works/pi-agent-core (Flue dependency) | BYO | TUI/CLI focused | Node | Per-tool |
Two columns matter most. The “sandbox primitive?” column is what @curonianai flagged: Flue ships sandbox backends as part of the framework contract, where Mastra and Vercel AI SDK leave it to the user — the right call for a chat product, the wrong call for an agent that writes files. The “markdown-first?” column is the cultural commitment to skill files as the unit of agent capability, the same skill working in Claude Code, in Cursor, and in production without translation. The arrival of eve in the first two rows is the headline: the dimensions Flue chose to compete on are now the dimensions the whole category is converging toward.
What you can build with Flue right now
Ten things that are plausible weekend projects given 1.0’s primitives, ranked by how cleanly the framework’s pieces snap together.
| Buildability | Idea | Why it fits Flue |
|---|---|---|
| 🟢 High | GitHub issue triage bot | Flue’s own origin story. A triage skill + the GitHub channel + local() sandbox is the entire setup. Replaces Dosu / Greptile / CodeRabbit at near-zero infrastructure cost. |
| 🟢 High | PR review agent | Same shape, different skill. Channel fires on pull_request_review_comment, agent runs git diff, posts review comments. |
| 🟢 High | Customer support agent with persistent sessions | Cloudflare backend, R2-backed knowledge base mounted as the agent’s filesystem, Durable Object sessions for continuity across messages. |
| 🟢 High | CI auto-fix workflow | A defineWorkflow branching on a triage result severity into an auto-fix skill. Best at high-confidence dependency bumps and lint fixes. |
| 🟢 High | Docs Q&A agent | R2 bucket of markdown docs, virtual sandbox, grep/glob/read over the bucket as filesystem. No vector DB needed for small corpora. |
| 🟡 Medium | Slack/Discord/Teams agent | The channel primitive verifies inbound events; the agent itself is twenty lines. Signed-request verification is handled by the channel, not your code. |
| 🟡 Medium | Code-review concierge for a private repo | Daytona backend gives a real container with the repo cloned. Coordination across PRs is the hard part. |
| 🟡 Medium | Data-analyst agent with mounted CSVs | Virtual sandbox with Python enabled, mount a directory of datasets, ask questions. Charts via matplotlib written back to the filesystem. |
| 🟡 Medium | Multi-agent research pipeline | A parent agent delegating to declared subagents via session.task(), each a focused profile. |
| 🔴 Low | Mid-stream-resumable hour-long agent | The Cloudflare runtime deal addresses session persistence, but mid-prompt() stream resumption across a dropped connection is still the frontier. |
The pattern across the green tier is consistent: a channel or CI trigger, a virtual or local sandbox, a markdown skill, scoped secrets, a typed result. Twenty lines of TypeScript and a fifty-line markdown file. That is the shape of a Flue agent at its most useful, and 1.0’s job was to make that shape feel obvious across more runtimes.

What is honestly still missing
Four real gaps, named by name.
It is a beta, and the breakage has not stopped. The 1.0.0-beta label is doing real work. The June 16 rewrite renamed core APIs (createAgent → defineAgent, payload → input) and bumped session persistence to a new on-disk format. Then beta.3 did it again: tools moved to input/output/run, workflows were rebuilt on Actions, session persistence jumped to version 8 (version 6 data is unsupported and must be cleared or migrated), channel handlers switched to provider-native payloads, and the public /openapi.json route was removed. Anyone who shipped on the May API has now migrated twice in five weeks. The announcement is explicit that this is the cohesive-but-not-frozen moment, not GA — more breaking changes are possible before 1.0 final.
The velocity itself is a risk. This is the flip side of all the progress above. A framework that adds a fourth primitive, a frontend package, and a telemetry overhaul across two same-week betas is a framework whose documentation, examples, and community tutorials are perpetually a version behind. Several of Flue’s own docs pages still carry an “AI-generated, awaiting review” banner. For a team evaluating Flue today, the gap to price in is not a missing feature; it is that the thing you learn this week may be renamed next week. That is the tax of building on the bleeding edge, and Flue is squarely on it.
Stream reconnect is still partial. The Cloudflare deal pushes session durability down to Durable Objects, which covers state across requests, and @flue/react now hydrates a transcript from the exact durable checkpoint. But resuming a single in-flight prompt() whose HTTP stream drops mid-generation remains a per-runtime concern rather than a framework primitive. For research and coding agents that run for minutes per call, this is the edge users will hit.
TypeScript only. The Python agent ecosystem (LangChain, LlamaIndex, CrewAI, and AutoGen, among others) is enormous and not coming. Flue’s bet is that the developer pool willing to write agents in TypeScript is the one growing fastest. With Vercel now backing eve in the same language, that bet looks better than it did in May — but it is still definitionally not the AI-research crowd.
Where Flue lands
Agent harnesses are the unglamorous middle of the AI stack. The model gets the headline, the deploy target gets the press release, and the harness (the loop, the sandbox, the filesystem, the secrets boundary, the orchestration) is the thing every team rebuilds from scratch and nobody calls a framework.
Flue named the harness as a build target first. The May launch proved the idea resonated; the June 1.0 rewrite proved the team would tear up its own API to get the shape right; the betas since proved it would do it again within the week — adding Actions, a React package, and an OpenTelemetry overhaul on top of a still-unfrozen core; the Cloudflare deal proved a major infrastructure company believes the harness/runtime split is real enough to build a product around; and Vercel’s eve proved the category is big enough to attract the most distribution-heavy player in frontend. Four months in, the question is no longer “is the harness a real category?” It is “which framework hosts it, and on whose runtime?”
For builders, the call has actually gotten easier since May. The framework is more capable, the runtime story is more credible, and the existence of a serious rival means the patterns are converging fast enough that learning one teaches you most of the other. The thing you give up by waiting is the same as it was at launch — the chance to be one of the first hundred teams who ship on it, learn its shape, and end up writing the patterns the next ten thousand will copy. The harness moment is no longer latent. Two frameworks and a CDN are now fighting over it in public. The right move is still to build something on it.