Skip to content
/

Flue

flue · withastro/flue · ★ 3.7k · last commit 2026-05-26

Primitive shape
No installable primitives
00

Summary

Flue — Summary

Flue is a TypeScript agent harness framework created by the Astro.build team, positioning itself as "the Next.js or Astro for agents" — a framework-style abstraction rather than a library. Agents are TypeScript files in .flue/agents/ or agents/ that define triggers (webhook, CI) and a default export handler; the flue CLI builds, runs, and deploys them. The core primitive is a harness (init()) + session (harness.session()) pair, with sessions being durable per-agent-instance rather than per-run. Flue's standout feature is first-class multi-runtime sandboxing: agents can run against a virtual sandbox (just-bash, fast and free), a local sandbox (host filesystem for CI), Cloudflare Worker sandbox (durable SQLite workspace + R2), or a container sandbox (Daytona). The framework supports valibot-typed structured results, named roles (sub-agents defined as .flue/roles/*.md), MCP server connections, and Cloudflare-native deployment. Version 0.7.1.

Compared to seeds, Flue is unlike all 11 seeds: where seeds are either prompt packs (superpowers, BMAD), task management harnesses (taskmaster-ai), or CLI scaffolding tools (agent-os), Flue is a TypeScript server framework for building deployable headless agent services — closer to an API framework than a developer productivity tool.

01

Overview

Flue — Overview

Origin

Developed by the Astro.build team (withastro organization). Version 0.7.1, described as experimental. Positioned as a TypeScript framework for building deployable headless agent services.

Philosophy

From the README:

"Flue is The Agent Harness Framework. If you know how to use Claude Code (or Codex, OpenCode, Pi, etc)... then you already know the basics of how to build agents with Flue."

"Flue isn't another AI SDK. It's a proper runtime-agnostic framework — think Astro or Next.js, but for agents. Write once, build, and deploy your agents anywhere (Node.js, Cloudflare, GitHub Actions, GitLab CI/CD, etc)."

"But using Flue feels like using Claude Code. The agents you build act autonomously to solve problems and complete tasks. They require very little code to run — most of the 'logic' lives in Markdown: skills, context, and AGENTS.md."

Key Concepts (from AGENTS.md)

Agent (definition)              — `agents/<name>.ts`; named by its file
└─ AgentInstance                — URL `<id>`; durable runtime scope
   └─ Run                       — one HTTP invocation; exposed as `ctx.runId`
      └─ Harness                — one `init({ name })` call
         └─ Session             — one `harness.session(name?)`
            └─ Operation        — one `session.prompt` / `skill` / `task` / `shell` call
               └─ Turn          — one LLM round-trip inside pi-agent-core

Design Goals

  • Headless-first: No TUI, no GUI. Pure TypeScript runtime
  • No baked-in assumption requiring a human operator
  • Write once, deploy anywhere: Node.js, Cloudflare Workers, GitHub Actions, GitLab CI
  • Skill-based: most logic in Markdown, not code
  • Typed results: valibot schemas enforce structured output contracts

Deployment Targets

Node.js (local + CI), Cloudflare Workers (durable sessions via Cloudflare Durable Objects), GitHub/GitLab CI triggers.

02

Architecture

Flue — Architecture

Distribution

  • Type: npm packages (@flue/runtime, @flue/cli)
  • Version analyzed: 0.7.1
  • Status: Experimental
  • Install: pnpm add @flue/runtime + pnpm add -D @flue/cli
  • CLI binary: flue (from @flue/cli, bin/flue.mjs)
  • Required runtime: Node.js >=22.18 (native TS support), Bun (for internal packages)

Repository Layout (Turbo monorepo)

packages/
├── runtime/                    # @flue/runtime
│   └── src/
│       ├── harness.ts          # init() — harness factory
│       ├── session.ts          # session() — session management
│       ├── agent.ts            # agent definition utilities
│       ├── sandbox.ts          # sandbox abstraction
│       ├── mcp.ts              # connectMcpServer()
│       ├── roles.ts            # named roles (sub-agents)
│       ├── compaction.ts       # context compaction
│       ├── context.ts          # FlueContext type
│       ├── result.ts           # typed result handling
│       ├── types.ts            # Type exports
│       ├── cloudflare/         # Cloudflare-specific sandboxes
│       └── node/               # Node.js-specific sandboxes
├── cli/                        # @flue/cli
│   ├── bin/flue.mjs            # CLI entry point
│   └── (build, dev, run, init, add, logs commands)
├── sdk/                        # SDK utilities (unknown)
connectors/                     # Connector adapters (e.g., daytona.ts)
apps/                           # Example/test applications
.flue/                          # Default project config dir
├── agents/                     # Example agents
└── lib/                        # Shared utilities
.opencode/                      # OpenCode AI tool config
AGENTS.md                       # AI agent documentation

Config Files

  • flue.config.ts (or .mts, .mjs, .js, .cjs, .cts) — project config
  • wrangler.jsonc — Cloudflare Workers config (for Cloudflare target)
  • .flue/ directory — project-level agents, roles, and skills

Key Runtime Dependencies

  • just-bash ^2.14.2 — virtual sandbox (lightweight bash execution)
  • hono ^4.8.3 — HTTP server framework for the agent server
  • valibot ^1.1.0 — schema validation for typed results
  • @modelcontextprotocol/sdk ^1.29.0 — MCP client support
  • @cloudflare/codemode, @cloudflare/shell — Cloudflare-specific sandbox
  • @earendil-works/pi-agent-core, @earendil-works/pi-ai — underlying agent turn execution runtime

Sandbox Types

Sandbox Runtime Use Case
Virtual (just-bash) any Default; fast, cheap, no container
Local Node.js CI/CD; direct host filesystem + shell
Cloudflare cf-shell Cloudflare Durable SQLite workspace + optional R2
Daytona container Daytona Full Linux environment for coding agents
03

Components

Flue — Components

Core Runtime API (@flue/runtime)

Function/Type Purpose
init(params) Initialize a harness with model, sandbox, cwd
harness.session(name?) Create or resume a named session
session.prompt(text, opts?) Send a message, get response; result: for typed output
session.skill(name, opts?) Invoke a named skill (Markdown file)
session.task(name, opts?) Delegate to a named role/sub-agent
session.shell(cmd, opts?) Execute a shell command in the sandbox
connectMcpServer(name, opts) Connect to a remote MCP server
FlueContext Type for the agent handler ctx argument
Type Re-export of valibot types

CLI Binary: flue

Subcommand Purpose
flue dev Long-running watch-mode dev server (port 3583 default)
flue run <agent> One-shot: build + invoke once + exit
flue build Produce deployable dist/ artifact
flue init Scaffold a new Flue project
flue add <connector> Install a connector (e.g., flue add daytona)
flue logs Stream agent logs

Agent Definition Format

TypeScript file in .flue/agents/<name>.ts:

  • export const triggers — declares how the agent is invoked ({ webhook: true }, {} for CLI-only)
  • export default async function({ init, payload, env }) — handler with FlueContext

Role Files (Sub-Agent Prompts)

Markdown files in .flue/roles/<name>.md:

  • Referenced in session.skill('role-name', ...) or session.task(...)
  • AGENTS.md in the project root provides project-level context

Sandbox Modules

Module Import
Virtual sandbox (default, no import)
Local sandbox @flue/runtime/nodelocal()
Cloudflare workspace @flue/runtime/cloudflaregetDefaultWorkspace(), getShellSandbox(), hydrateFromBucket()
Daytona connector ../connectors/daytonadaytona(sandbox)

No Hooks, No Slash Commands

Flue ships no Claude Code hooks, no .claude/ files, and no slash commands. It is a pure TypeScript library + CLI framework.

05

Prompts

Flue — Prompts

Excerpt 1: Support Agent with Cloudflare (from README, verbatim)

// .flue/agents/support.ts
import type { FlueContext } from '@flue/runtime';
import {
  getDefaultWorkspace,
  getShellSandbox,
  hydrateFromBucket,
} from '@flue/runtime/cloudflare';
import * as v from 'valibot';

export const triggers = { webhook: true };

export default async function ({ init, payload, env }: FlueContext) {
  const workspace = getDefaultWorkspace();

  // Hydrate once per agent instance. R2 is a source, not a live mount.
  if (!(await workspace.exists('/.hydrated'))) {
    await hydrateFromBucket(workspace, env.KNOWLEDGE_BASE);
    await workspace.writeFile('/.hydrated', new Date().toISOString());
  }

  const harness = await init({
    sandbox: getShellSandbox({ workspace, loader: env.LOADER }),
    model: 'openrouter/moonshotai/kimi-k2.6',
  });
  const session = await harness.session();

  return await session.prompt(
    `You are a support agent. Use the code tool to search the hydrated
    workspace for articles relevant to this request, then write a helpful response.

    Customer: ${payload.message}`,
    { role: 'triager' }
  );
}

Prompting technique: Inline system prompt in the session.prompt() call, combined with a role parameter that loads a named Markdown role file (.flue/roles/triager.md). The role file provides the specialization; the inline prompt provides task context. Knowledge base is pre-hydrated into a durable workspace before the prompt runs.

Excerpt 2: Issue Triage CI Agent (from README)

const { data } = await session.skill('triage', {
  args: { issueNumber: payload.issueNumber },
  result: v.object({
    severity: v.picklist(['low', 'medium', 'high', 'critical']),
    reproducible: v.boolean(),
    summary: v.string(),
    fix_applied: v.boolean(),
  }),
});

Prompting technique: session.skill() loads a named Markdown skill file and injects args as template variables. The result schema defines what structured data the skill must return, functioning as an output contract enforced by valibot.

Prompting Architecture

  • Agent handlers: TypeScript files with inline session.prompt() calls
  • Skill files: Markdown files in .flue/agents/skills/ or AGENTS.md-adjacent directories
  • Role files: Markdown files in .flue/roles/ providing named sub-agent personas
  • Valibot schemas: define typed output contracts for structured results
  • No static system prompts in config — prompts are built dynamically in TypeScript code
09

Uniqueness

Flue — Uniqueness

Differs from Seeds

Flue is unlike all 11 seeds. Seeds are developer-productivity harnesses for AI coding assistants (Claude Code, Cursor, Codex); Flue is a TypeScript server framework for building deployable headless agent services. The closest analogy is claude-flow in being an npm package with a CLI and sub-agent support, but even this comparison breaks down: claude-flow wraps Claude Code's agent loop; Flue builds its own harness abstraction that can deploy to Cloudflare Workers or Node.js servers independent of any human-facing AI IDE. The "Astro/Next.js for agents" metaphor is accurate — it is a framework for shipping agent-powered API endpoints, not for augmenting an AI coding session.

Distinctive Position

  1. Only Cloudflare-native agent framework in the batch: first-class Cloudflare Workers + Durable Objects integration for durable session persistence
  2. Framework metaphor from Astro team: agent definitions as TypeScript files with exported triggers and handlers — directly borrowed from the Astro component model
  3. Valibot typed results: structured output contracts enforced by schema validation, not prompt instructions
  4. Connector system: flue add daytona installs a connector that writes connectors/daytona.ts — a plugin-style extensibility not seen in other batch members
  5. Virtual sandbox (just-bash): lightweight bash execution without containers, making it "dramatically faster, cheaper, and more scalable" for high-traffic agents
  6. Multi-harness in one agent: a single handler can spawn multiple independent harnesses (e.g., setup harness + project harness sharing the same sandbox)

Explicit Anti-Patterns

  • Interactive chat / back-and-forth (Flue is non-interactive by design)
  • Assuming Cloudflare R2 is a live bucket mount (it's a hydration source)
  • Using OAuth callbacks with connectMcpServer() (not supported in v0.7.1)
  • Auto-detecting MCP transports (Flue does not auto-detect; must specify transport: 'sse' for legacy)

Observable Failure Modes

  • Experimental status: APIs may change between minor versions
  • Cloudflare-specific features require Cloudflare accounts (not portable to other clouds)
  • @earendil-works/pi-agent-core dependency is an external AI company's runtime — supply-chain risk and potential breaking changes
  • Node.js >=22.18 requirement limits CI environments running older Node
  • No built-in human-in-the-loop mechanism — not suitable for workflows requiring human approval

Inspired By

Claude Code (agent loop pattern), Astro (framework metaphor, project structure), Next.js (file-based routing concept).

04

Workflow

Flue — Workflow

Agent Development Lifecycle

Phase Command Artifact
Scaffold flue init .flue/agents/, flue.config.ts
Develop flue dev (watch mode, port 3583) Live server, hot reload
Run one-shot flue run <agent> --id <instance-id> [--payload '<json>'] Stdout result
Build flue build dist/ deployable artifact
Deploy (Cloudflare: wrangler, Node: any Node host) Deployed agent service

Agent Handler Pattern

// .flue/agents/my-agent.ts
import type { FlueContext } from '@flue/runtime';
import * as v from 'valibot';

export const triggers = { webhook: true };  // or {} for CLI-only

export default async function ({ init, payload }: FlueContext) {
  const harness = await init({ model: 'anthropic/claude-sonnet-4-6' });
  const session = await harness.session();

  const { data } = await session.prompt(
    `Translate to ${payload.language}: "${payload.text}"`,
    {
      result: v.object({
        translation: v.string(),
        confidence: v.picklist(['low', 'medium', 'high']),
      }),
    }
  );

  return data;
}

Approval Gates

None built-in. Flue is headless-first; there is no human-in-the-loop mechanism by default. Agent execution is fully autonomous.

Multi-Harness Pattern

A single agent handler can create multiple harnesses within one run:

// Setup harness (clones repo, installs deps)
const setupHarness = await init({ sandbox: daytona(sandbox), model: '...' });
const setup = await setupHarness.session();
await setup.shell('git clone ...');

// Project harness (discovers AGENTS.md from cloned repo)
const projectHarness = await init({
  name: 'project',
  sandbox: daytona(sandbox),
  cwd: '/workspace/project',
  model: '...',
});
const session = await projectHarness.session();
return await session.prompt(payload.prompt);

Cloudflare Durable Sessions

On Cloudflare deployment, session state is automatically persisted by Cloudflare Durable Objects. Sessions can be resumed days/weeks/years later by using the same agent instance ID.

06

Memory Context

Flue — Memory and Context

Session Persistence

  • Node.js: session state persists within a process run; not durable across process restarts without external store
  • Cloudflare Durable Objects: automatic durable session persistence — message history and session state are persisted by Cloudflare infrastructure. Sessions can be resumed "days, weeks, or years later" by using the same agent instance ID

Workspace (Cloudflare)

  • getDefaultWorkspace() — Cloudflare Durable SQLite-indexed filesystem
  • Files written to the workspace survive across runs
  • R2 is an optional hydration source (not a live mount); use hydrateFromBucket() to copy R2 objects into the workspace before the agent runs
  • State API: workspace.exists(), workspace.writeFile(), etc.

Context Compaction

  • compaction.ts in the runtime source — suggests built-in context compaction support
  • Implementation details: unknown from public README

Harness-Level Isolation

Each init() call creates an independent harness with its own model, sandbox, and cwd. Multiple harnesses within a single agent run share the same sandbox but have independent session namespaces.

Cross-Session Handoff

On Cloudflare: built-in via Durable Objects (same instance ID resumes the same session) On Node.js: not built-in; requires external state store

AGENTS.md Discovery

The harness auto-discovers AGENTS.md and skills from process.cwd() (or the cwd override in init()). This provides project-level context injection without explicit configuration.

07

Orchestration

Flue — Orchestration

Multi-Agent Pattern

Flue supports role-based sub-agent delegation via session.task() and session.skill():

  • Named roles in .flue/roles/<name>.md act as sub-agent specifications
  • session.task(name, opts) invokes a named role
  • Multiple harnesses within one agent handler enable multi-step setups (setup harness → project harness)

Pattern: sequential or task-decomposition-tree (each session prompt can call further tasks)

Multi-Model

Each init() call specifies a model parameter independently. Different harnesses within the same agent handler can use different models:

const setupHarness = await init({ model: 'openai/gpt-5.5', ... });
const projectHarness = await init({ model: 'anthropic/claude-opus-4-7', ... });

No config-file-level model routing; it is TypeScript-code-level.

MCP Integration

connectMcpServer(name, opts) connects to remote MCP servers:

  • Defaults to modern streamable HTTP transport
  • transport: 'sse' for legacy SSE servers
  • Does NOT auto-detect transports, spawn local stdio MCP servers, or handle OAuth callbacks (first version)
  • MCP tools are passed to init({ tools: github.tools }) and available in the session

Sandbox Isolation

Flue's primary isolation mechanism is the sandbox abstraction:

  • Virtual sandbox (just-bash): no filesystem isolation, but lightweight
  • Local sandbox: direct host access — the runner IS the isolation boundary (suitable for CI)
  • Cloudflare sandbox: isolated Durable SQLite workspace
  • Container (Daytona): full Linux container isolation

Execution Mode

one-shot (via flue run) or event-driven (webhook triggers on deployed server). Background mode is available via Cloudflare Durable Objects persistent sessions.

No Hooks, No Auto-Validators

Flue ships no Claude Code lifecycle hooks and no built-in test runners or validators. Quality gates are the developer's responsibility.

08

Ui Cli Surface

Flue — UI/CLI Surface

CLI Binary: flue

  • Binary name: flue (from @flue/cli, bin/flue.mjs)
  • Install: pnpm add -D @flue/cli
  • Is thin wrapper: No — it is its own build system and dev server
  • Default port: 3583 ("FLUE" on a phone keypad)
  • Subcommands:
    • flue dev — long-running watch mode dev server
    • flue run <agent> — one-shot agent execution (build + invoke + exit)
    • flue build — produce deployable dist/ artifact
    • flue init — scaffold a new project
    • flue add <connector> — install a connector adapter
    • flue logs — stream agent logs

Local UI

None. Flue is explicitly headless-first. No web dashboard, no TUI, no GUI.

Dev Server

flue dev starts an HTTP server at port 3583. HTTP agents are accessible at http://localhost:3583/<agent-name>/<instance-id>. The server hot-reloads on file changes.

IDE Integration

  • .opencode directory in the repo root — suggests OpenCode AI tool integration
  • AGENTS.md at repo root — standard cross-tool agent documentation
  • No .claude/ files, no Cursor config, no VS Code extension

Deployment

Target Method
Node.js server flue buildnode dist/
Cloudflare Workers flue build --target cloudflarewrangler deploy
GitHub Actions CI flue run <agent> in workflow
GitLab CI flue run <agent> in pipeline

Cross-Tool Portability

medium — Flue works with any openrouter or provider-specific model (Anthropic, OpenAI, Cloudflare AI). The sandboxes are pluggable. However, it targets headless/CI/API deployments rather than interactive AI coding tools.

Related frameworks

same archetype · same primary tool · same memory type

claude-mem (thedotmack) ★ 78k

Background worker service captures every tool call as an observation, AI-compresses sessions, and auto-injects relevant past…

pi (badlogic/earendil) ★ 55k

A minimal, hackable, multi-provider terminal coding agent that adapts to your workflows via npm-installable TypeScript Extensions…

Agent Skills (Addy Osmani) ★ 46k

Encodes senior-engineer software development lifecycle as 23 auto-routed skills and 7 slash commands for any AI coding agent.

wshobson/agents Plugin Marketplace ★ 36k

Single Markdown source for 83 domain-specialized plugins that auto-generates idiomatic artifacts for five AI coding harnesses.

TabbyML/Tabby ★ 34k

Self-hosted AI coding assistant server (alternative to GitHub Copilot) with admin dashboard, RAG-based completions, and multi-IDE…

Compound Engineering ★ 17k

Make each unit of engineering work compound into easier future work via brainstorm→plan→execute→review→learn cycles.