+250 skills, dinamita para tu productividad 🧨Explorar →

Qué es Flue 2.0, el agent harness framework de Astro

(actualizado )

La gente de Astro soltó un framework nuevo hace tres meses. Y no era para webs.

Lo dije entonces y lo repito ahora por si has leído rápido: el equipo que se ha pasado los últimos años predicando que “el HTML es lo único que tu navegador necesita” publicó algo que se llama Flue y que sirve para construir agentes de IA. Un giro de los que te hacen levantar la ceja y abrir la documentación.

La idea, en una frase, sigue siendo esta: imagínate que pudieras programar tu propio Claude Code, pero sin la TUI, sin el spinner, sin el humano detrás escribiendo prompts. Solo TypeScript.

Lo que ha cambiado es todo lo demás. El 31 de julio de 2026 salió Flue 2.0 y no es una versión mayor de cortesía: es el framework reescrito de arriba abajo. La última publicada en npm es la 2.0.3, del 4 de agosto. Si empezaste con la 0.3 que analicé en mayo, prácticamente nada de lo que escribiste compila hoy.

El timing tiene su miga. Según el informe State of AI Engineering 2026 de Datadog, la adopción de frameworks de agentes ha pasado de un 9% de organizaciones a principios de 2025 a casi un 18% a comienzos de 2026 (fuente: Datadog, 2026). Y según LangChain, el 57% de organizaciones encuestadas ya tiene agentes en producción (fuente: State of Agent Engineering, LangChain, 2026). Flue llega justo cuando los equipos de ingeniería están eligiendo en qué framework casarse.

Aquí abajo te cuento todo lo importante:

  • Qué rompe Flue 2.0 y por qué merecía romperlo
  • Cómo se escribe un agente ahora: 'use agent' y hooks, sin defineAgent
  • Por qué los sandboxes pasaron a ser opt-in y qué gana tu bundle con eso
  • Cómo evita Flue que el LLM lea tus claves de API sin el viejo defineCommand
  • La durabilidad que trae la 2.0: tools con checkpoints, idempotencia y recuperación
  • Los canales: Slack, GitHub, Telegram y 14 más como puerta de entrada
  • Cuándo merece la pena cambiar tu Claude Agent SDK por Flue

Vamos al lío.

Qué cambia en Flue 2.0 (resumen para impacientes)

Si vienes de la 0.x o de la 1.0 beta, esta es la lista corta de lo que ya no existe y lo que ocupa su sitio:

Antes (0.x / 1.0 beta) Ahora (2.0)
flue dev / flue build El plugin flue() de @flue/vite con vite dev / vite build
Rutas por convención de directorios app.ts es el mapa de rutas, explícito
defineAgent(initializer) Una función exportada en un módulo con 'use agent'
Config como objeto de opciones Hooks: useModel, useTool, useSkill, useSandbox
Workflows (defineWorkflow) Eliminados. Las conversaciones son la única unidad durable
Sandbox virtual implícito useSandbox() opt-in: sin declararlo, no hay entorno de ejecución
Roles en .flue/roles/ useInstruction() y subagentes
defineCommand para credenciales Allowlist de entorno en local({ env }) + auth en MCP
client.prompt() en el SDK createFlueClient({ url }) con send() + wait() + history()
@flue/connectors Paquetes propios por integración (28 en el monorepo)

Y hay un detalle que no aparece en ninguna tabla pero conviene que sepas: los almacenes persistidos por la 1.0 beta se rechazan. La 2.0 estampa un format_version en cada store y se niega a abrir cualquier otra cosa. No hay migración de datos. Si tenías conversaciones guardadas, se quedan atrás.

🔑 Traducción práctica: Flue 2.0 no es una actualización, es una mudanza. Léelo como si fuera un framework nuevo que resulta que se llama igual.

Qué es Flue y por qué le sale del Astro

Flue es un framework de TypeScript pensado para construir agentes autónomos. Su gran diferencia con todo lo que has visto antes es que no se vende como “otro SDK más”. Se vende como el primer agent harness framework, un sitio donde escribes tu agente una vez y lo despliegas donde quieras.

🔑 La frase con la que Fred Schott, cocreador de Astro, presentó Flue lo deja claro: es como Claude Code, pero 100% headless y programable. Sin TUI, sin GUI, sin asumir que hay un humano dándole al teclado.

El monorepo tiene hoy 28 paquetes. Los seis que vas a tocar:

Paquete Para qué
@flue/runtime El harness: hooks, sesiones, tools, sandbox
@flue/vite El plugin flue(): vite dev / vite build para Node y CF
@flue/cli El binario flue: run, init, add, update, docs
@flue/sdk Cliente para hablar con conversaciones desplegadas
@flue/react useFlueAgent() para pintar una conversación en tu front
@flue/opentelemetry Trazas y observabilidad

El resto son adaptadores de persistencia (@flue/postgres, @flue/mysql, @flue/mongodb, @flue/redis, @flue/libsql) y canales (Slack, Teams, Discord, GitHub, Telegram, Twilio, WhatsApp, Messenger, Notion, Linear, Intercom, Zendesk, Stripe, Shopify, Resend, Google Chat y Salesforce Marketing Cloud). La licencia sigue siendo Apache 2.0 y el repositorio público está en withastro/flue. Necesitas Node 22.19 o superior.

Un cambio de fontanería que se nota: la capa de modelos ahora es el protocolo de proveedores de Pi, usado directamente. Se acabaron los registerProvider con bolsa de opciones. Un proveedor custom es un objeto Provider de pi-ai que registras con setProvider(...).

Si trabajas con Astro y quieres recordar las bondades del framework principal, en Web Reactiva tenemos un bootcamp completo de Astro y un análisis de por qué Astro se ha convertido en una joya del desarrollo web. Pero hoy hablamos de algo distinto. Hoy hablamos de la apuesta del equipo que apunta al runtime de los agentes, no al del navegador.

Qué es el harness engineering y por qué importa

Antes de tocar una línea de código de Flue, conviene que entiendas la palabra que se repite en toda su documentación: harness.

Un harness es el arnés que sujeta al modelo y le da contexto, herramientas, memoria y reglas. Mitchell Hashimoto, cocreador de HashiCorp y de Terraform, fue quien puso nombre a la disciplina en febrero de 2026 con una definición muy clara: “anytime you find an agent makes a mistake, you take the time to engineer a solution such that the agent never makes that mistake again” (fuente: Mitchell Hashimoto, My AI Adoption Journey, 2026).

Días después, OpenAI publicó un informe técnico titulado Harness engineering: leveraging Codex in an agent-first world, donde describían un experimento interno de cinco meses en el que un equipo pequeño construyó un producto de aproximadamente un millón de líneas de código usando solo agentes Codex, cero código escrito a mano (fuente: OpenAI, 2026). El término se afianzó.

La fórmula que dejó Hashimoto cabe en cuatro palabras: Agent = Model + Harness. Aakash Gupta lo resumió en enero de 2026 con otra frase corta: “2025 was agents; 2026 is agent harnesses”. Anthropic, por su parte, ya describía el Claude Agent SDK en noviembre de 2025 como “a powerful, general-purpose agent harness” (fuente: Anthropic, 2025).

Boris Cherny, creador de Claude Code, habló de esto en una entrevista que ya analizamos. El argumento es que el modelo importa, pero el arnés importa más. Dos agentes con el mismo Claude Sonnet pueden comportarse de forma muy distinta dependiendo de cómo gestionen el contexto, las herramientas y las sesiones.

Aquí está el matiz que cambia el juego: hasta ahora, si querías un harness bien hecho tenías que usar Claude Code, OpenCode, Codex o Cursor tal y como vienen. Tú no podías escribir tu propio Claude Code, solo podías llamarlo desde fuera con su SDK.

🎯 Flue invierte la ecuación. Te da el harness completo en TypeScript, decides tú dónde corre, qué modelo usa y qué herramientas le das.

Si quieres entrar en detalle sobre cómo se descompone un agente moderno (modelo, herramientas, memoria, bucle de decisión), tenemos una guía de arquitectura de agentes para developers que te ahorra meses de leer papers.

La idea nueva de la 2.0: el agente ES la función

En la 0.x un agente era un objeto de configuración envuelto en defineAgent(). Le pasabas model, instructions, tools, skills, sandbox y el framework montaba el tinglado.

En la 2.0 un agente es una función exportada normal y corriente, en un módulo cuya primera sentencia es la directiva 'use agent'. El build escanea los ficheros buscando esa directiva y registra como agente cada función exportada que empiece por mayúscula. Este es el ejemplo oficial:

// agents/triage.ts
'use agent';
import { useModel, useSandbox, useSkill, useTool } from '@flue/runtime';
import { local } from '@flue/runtime/node';
import triage from '../skills/triage/SKILL.md';
import verify from '../skills/verify/SKILL.md';
import { openIssue, searchCode } from '../tools/github.ts';

// El agente ES la función. Compón el harness completo que necesita.
export function Triage() {
  useModel('anthropic/claude-sonnet-4-6');
  useSandbox(local());
  useSkill(triage);
  useSkill(verify);
  useTool(openIssue);
  useTool(searchCode);

  // El string devuelto es el documento de instrucciones del agente.
  return `
Triage a bug report end-to-end: reproduce the bug,
diagnose the root cause, verify whether the behavior is
intentional, and attempt a fix.

...`;
}

Si te suena a React, es porque el modelo mental es exactamente ese. Cuatro cosas que conviene interiorizar:

  1. La función se ejecuta antes de cada llamada al modelo. Es un render. No es un constructor que corre una vez.
  2. Lo que devuelve es la instrucción, el documento que el modelo lee como system prompt.
  3. Los hooks no pueden ser condicionales. El runtime impone invariancia estructural: si el conjunto de tools cambia entre renders de forma inesperada, la ejecución falla. Nada de desbloquear herramientas a escondidas según la fase.
  4. El nombre de la función es la identidad durable del agente. Renombrar Triage cambia dónde vive su estado. Si necesitas separar nombre de identidad, hay un static agentName.

Los hooks que vas a usar el 90% del tiempo son useModel (obligatorio, exactamente una vez), useInstruction, useTool, useSkill, useSubagent, useSandbox, usePersistentState, useMcpConnection y useInitialData. Hay más para el ciclo de vida: useAgentStart, useAgentFinish, useResponseStart, useResponseFinish, useDelivery, useDataWriter, useDispatchMessage.

Y las rutas ya no se adivinan. app.ts es el mapa, escrito a mano, con Hono debajo:

// src/app.ts
import { createAgentRouter } from '@flue/runtime/routing';
import { Hono } from 'hono';
import { Triage } from './agents/triage.ts';

const app = new Hono();

app.route('/agents/triage', createAgentRouter(Triage));

export default app;

Menos magia, más fichero que puedes leer. Cualquiera que haya perdido una tarde buscando de dónde salía una ruta autogenerada sabe lo que se gana aquí.

Cómo arrancarlo: Vite manda, la CLI adelgaza

flue dev y flue build ya no existen. Flue 2.0 es un plugin de Vite.

// vite.config.ts
import { flue } from '@flue/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [flue()],
});

Con eso, vite dev te levanta el servidor de desarrollo (que ahora carga tu juego de ficheros .env sin exportar nada en la shell), vite build genera dist/server.mjs para Node y vite preview sirve exactamente el artefacto construido. Para Cloudflare, el target se detecta solo por la presencia del plugin oficial: plugins: [flue(), cloudflare({ config: flueWorkerConfig() })], y tu wrangler.jsonc sigue siendo tuyo.

La CLI se queda con cinco comandos: run, init, add, update y docs. El interesante es flue run, que ahora es ejecución local sin transporte: ni servidor HTTP ni emulación de Cloudflare, solo tu agente corriendo bajo Node.

flue run src/agents/triage.ts -m "Reproduce el bug del issue 412"

Los eventos van a stderr, la respuesta final a stdout y te imprime el id de la conversación para que puedas continuarla con --id. Hay --json si prefieres un sobre estructurado, --data '<json>' para datos de creación y --env para cargar otro fichero. Es la puerta natural a CI.

💡 Si solo te llevas una cosa de aquí: con Flue, el código de tu agente sigue siendo minúsculo. La chicha vive en los ficheros Markdown que lo rodean. Skills, AGENTS.md e instrucciones. Es exactamente la misma filosofía que ya viste si has trabajado con Agent Skills.

Si te animas a montar tu primer agente Flue y quieres ver lo que estamos probando otros developers, cada domingo compartimos experiencias y recursos sobre IA en programación. Ya somos +6.700.

Apúntate gratis →

Skills, subagentes y estado: los hooks que hacen el trabajo

Aquí es donde Flue sigue oliendo a Claude Code, OpenCode y compañía. Quien ya haya configurado un agente con Markdown se va a sentir como en casa.

Las skills se importan, no se descubren. Importar una ruta que resuelve a un SKILL.md empaqueta ese directorio en tiempo de build y te da un SkillReference que pasas a useSkill(...). Importar cualquier otro .md te devuelve el texto plano, que puedes convertir en skill con defineSkill({ name, description, instructions }). Los with { type: 'skill' } de la 0.x desaparecieron: ahora decide el especificador.

Si ya leíste nuestra guía sobre cómo organiza el equipo de Claude sus skills en 9 categorías, todo este patrón te suena: una skill es una hoja de instrucciones reutilizable que convierte a un agente genérico en un especialista.

El fichero AGENTS.md sigue siendo la convención para contarle al modelo qué proyecto tiene delante. Software Improvement Group documentó que un AGENTS.md bien mantenido marca la diferencia: en su análisis, el código generado solo por agentes obtuvo 1,1 sobre 5 en mantenibilidad, mientras que el código con human-in-the-loop y un harness con AGENTS.md llegó a 3,1 sobre 5 (fuente: SIG, 2026).

Los roles de .flue/roles/ desaparecieron. Su trabajo lo hacen ahora dos cosas: useInstruction(), que añade bloques al documento de instrucciones desde cualquier hook, y los subagentes, que son la forma correcta de tener una personalidad especializada con su propio contexto:

'use agent';
import { useModel, useSubagent } from '@flue/runtime';

function Greeter() {
  return 'Write one warm, concise greeting.';
}

export function WithSubagent() {
  useModel('anthropic/claude-sonnet-4-6');
  useSubagent({
    name: 'greeter',
    description: 'Writes a short, warm greeting for a named user.',
    agent: Greeter,
  });
  return 'When asked to greet someone, delegate the greeting to the `greeter` subagent and report its greeting verbatim.';
}

Es el mismo patrón que Claude Code expuso con sus subagentes y que ahora tienes coordinado en Agent Teams. Aquí lo controlas tú con TypeScript en lugar de con flags de la TUI.

El estado ahora es un hook. usePersistentState(nombre, inicial) persiste de forma atómica junto a las llamadas a tools y se reevalúa fresco en cada turno. Y como los hooks se componen, puedes construir tus propias convenciones sin tocar el framework. El ejemplo support-desk del repo monta una máquina de estados completa —fases gathering → drafting → committing → done— usando solo usePersistentState y useInstruction:

export function Support() {
  useModel('anthropic/claude-sonnet-5');
  const machine = useMachine({
    name: 'phase',
    phases: ['gathering', 'drafting', 'committing', 'done'] as const,
    initial: 'gathering',
  });

  // Todas las fases están siempre montadas: se activan con guards, no con
  // control de flujo. Los hooks nunca son condicionales.
  useGathering({ check: machine.check('gathering'), onComplete: machine.enter('drafting') });
  useDrafting({ check: machine.check('drafting'), onComplete: machine.enter('committing') });
  useCommitting({ check: machine.check('committing'), onComplete: machine.enter('done') });
  useDone();

  return '# Support Agent\n\n...';
}

Fíjate en la decisión de diseño, que es la más interesante de toda la 2.0: en lugar de esconder herramientas según la fase, se montan siempre y se envuelven con guardas. Cuando el agente intenta algo fuera de sitio recibe un “Refused: that tool belongs to the drafting phase; you are in gathering” y se autocorrige. Un tool que desaparece confunde al modelo; un tool que explica por qué no toca, no.

Las tasks siguen ahí para delegar trabajo con contexto propio, y useSubagent es cómo se declaran. Lo que ya no existe son los workflows: defineWorkflow, invoke, los run stores, las rutas /runs/:runId. Las conversaciones son la única unidad durable. Un workflow, en la 2.0, es sencillamente un programa que conduce a un agente: un flue run en CI, el API start()/init() desde Node, el SDK por HTTP, o un motor externo tipo Cloudflare Workflows, Inngest o Temporal.

Sandboxes en Flue 2.0: ahora son opt-in

Este es el cambio que más te va a afectar si vienes de la 0.x. Antes, cada agente recibía un sandbox virtual en memoria con acceso completo a la red. Ahora, un agente que no declara useSandbox() no tiene entorno de ejecución. Ni bash, ni read, ni write, ni edit, ni glob, ni grep: esas seis herramientas solo se montan cuando declaras un sandbox.

No es un capricho. Es lo que permite que un agente conversacional no arrastre el peso de un sandbox que nunca va a usar. Skills y subagentes funcionan perfectamente sin sandbox, porque task y activate_skill son independientes del entorno.

La progresión sigue existiendo, del más ligero al más blindado:

1. Sandbox virtual (bash). Por debajo usa just-bash, una librería que simula un bash en memoria. Ahora lo declaras explícitamente:

useSandbox(bash(() => new Bash({ fs: new InMemoryFs() })));

2. Sandbox local (local()). Ejecuta contra el host de verdad, con child_process y node:fs. Es la opción ideal para CI: el repo ya está clonado en el runner, el agente trabaja contra él y ve el AGENTS.md real.

3. Sandbox de Cloudflare (cloudflareSandbox()). Para agentes desplegados en Workers, con getCloudflareContext() y las trazas nativas de Workers Traces que llegan sin cablear nada.

4. Sandbox de contenedor. Para coding agents serios, entornos multitenant o cualquier caso donde necesites un Linux completo. Daytona sigue siendo el conector de referencia, aunque ahora lo escribes tú como SandboxFactory a partir de su SDK, con una regla importante: la creación cara del contenedor ocurre dentro de createSandbox(), nunca en un re-render.

Y hay una mejora de fontanería que agradecerás el día que te toque: exec ahora rechaza inmediatamente al abortar. Antes, cancelar trabajo mientras corría un comando en un proveedor sin cancelación en vuelo (E2B, Daytona, Modal y casi todos) bloqueaba toda la ruta de aborto hasta que el comando terminara solo. Ahora el comando pasa a ser un huérfano documentado y el aborto sigue su camino.

⚠️ La regla de oro con sandboxes no cambia: empieza siempre por el más simple. Pasa al siguiente solo cuando notes que el actual se queda corto. Cada salto cuesta latencia, dinero o complejidad. No hay premio por usar contenedores antes de tiempo.

Cómo protege Flue 2.0 tus claves de API

Aquí va una corrección importante respecto a lo que conté en mayo: defineCommand ya no existe. Aquel patrón de conceder comandos por llamada desapareció en la reescritura.

Lo que ocupa su sitio es menos vistoso y, en la práctica, más sólido: una allowlist de entorno por defecto. El sandbox local() no hereda tu process.env. Toma exactamente catorce variables —PATH, HOME, USER, LOGNAME, HOSTNAME, SHELL, LANG, LC_ALL, LC_CTYPE, TZ, TERM, TMPDIR, TMP, TEMP— y nada más. Todo lo demás lo pasas tú, a mano y a propósito:

import { local } from '@flue/runtime/node';

// Expone una sola variable del host al entorno del agente.
useSandbox(local({ env: { GH_TOKEN: process.env.GH_TOKEN } }));

// Hereda todo (y expone tus secretos a la tool `bash` del modelo).
useSandbox(local({ env: { ...process.env } }));

El propio código del framework comenta esa segunda línea con una advertencia explícita. Y si intentas pasar env: true esperando un atajo, te salta un TypeError que te obliga a escribir el spread completo. Es fricción deliberada: para exponerlo todo tienes que teclearlo.

Para servicios externos, la vía es MCP con credenciales resueltas por petición:

useMcpConnection({
  name: 'linear',
  url: 'https://mcp.linear.app/sse',
  auth: async () => process.env.LINEAR_TOKEN,
});

El auth acepta un bearer estático o una función que lo resuelve en cada petición. Las tools del servidor se montan como mcp__<servidor>__<tool> y se leen una vez por submission, cacheadas por instancia de agente.

Y en Cloudflare sigue en pie la jugada más ambiciosa: Cloudflare Sandboxes con su proxy programable de salida, que inyecta credenciales a nivel de red para que el LLM nunca las vea.

Y no es un problema teórico. La encuesta State of Agent Engineering 2026 de LangChain confirma que el 32% de los equipos cita la calidad como su principal barrera para llevar agentes a producción, mientras que la gobernanza y la seguridad de credenciales aparecen como preocupaciones recurrentes (fuente: LangChain, 2026). Deloitte va más allá: en su State of AI 2026, el 73% de los líderes cita la seguridad y otro 73% la privacidad de datos como sus mayores preocupaciones sobre la IA agéntica (fuente: Deloitte, encuesta a 3.235 líderes en 24 países, 2026).

🛡️ El cambio de mentalidad es este: en la 0.x concedías capacidades; en la 2.0 el entorno arranca vacío y tú abres puertas de una en una. Menos elegante de leer, mucho más difícil de romper por accidente.

Durabilidad: lo que la 2.0 gana de verdad

Si tuviera que quedarme con un solo motivo para actualizar, sería este. Los agentes de la 0.x se caían y perdías el turno. Los de la 2.0, no.

Tools con checkpoints. Declara un tool como durable: true y recibe un ctx.step. Cada step.do(nombre, fn) ejecuta la función una sola vez por nombre y graba el resultado de forma durable antes de resolver. Si la ejecución se interrumpe, al recuperarse los steps completados replayean su valor grabado y solo se recalcula el código entre medias. La garantía es exactly-once-recorded, at-least-once-executed, así que los efectos externos conviene que sean idempotentes de por sí.

Entrega idempotente. Todo canal real es at-least-once: Slack reintenta eventos, los webhooks reintentan, el navegador reenvía tras perder una respuesta. Ahora pasas un idempotencyKey (máximo 256 caracteres) en dispatch(), en el POST directo o en send() del SDK, y dos entregas con la misma clave convergen en una: la segunda devuelve el mismo recibo, marcada como deduplicated.

Mensajes que se suben al tren en marcha. Un mensaje que llega mientras la conversación está ocupada ya no espera siempre en cola: en el siguiente límite de turno se une a la respuesta en curso, el agente re-renderiza con la nueva entrada delante del modelo, y el envío se responde con la respuesta a la que se unió.

Eventos de cola y recuperación de primera clase. observe() completa el vocabulario queued → running → settled con submission_queued, submission_running (con attemptCount/maxAttempts) y submission_recovery. Y cuando el runtime devuelve un 500, mina un identificador err_ que aparece a la vez en el cuerpo del error, en una cabecera flue-error-ref y en la línea de log del servidor. Quien reporte el fallo puede señalar la entrada exacta.

Cliente programático. start({ agents, db, env, providers }) monta un runtime sin transporte en cualquier proceso Node, e init(agent, { id }) te da un handle durable para una instancia: dispatch() encola y resuelve con el recibo, read(recibo) espera la respuesta asentada y se puede reenganchar desde otro proceso en cualquier momento posterior. Guardas el recibo, se cae la máquina, arrancas otra y lees la respuesta. Esa es la diferencia entre un demo y un sistema.

En el SDK, la consecuencia es que prompt() desapareció. Ahora el cliente apunta a una URL concreta:

import { createFlueClient } from '@flue/sdk';

const conversation = createFlueClient({
  url: 'https://mi-app.workers.dev/agents/triage/issue-412',
});

const admission = await conversation.send({
  message: { kind: 'user', body: 'Reproduce el bug del issue 412' },
  idempotencyKey: 'issue-412-primera-entrega',
});

const reply = await conversation.read(admission);

En React, useFlueAgent({ url }) sustituye al viejo useFlueAgent({ name, id }) y suma un refresh() para conversaciones que puedan crearse por fuera.

Canales: la puerta de entrada que faltaba

Esto es nuevo y es probablemente la razón por la que verás Flue en producción antes de lo que esperabas. Un canal convierte los webhooks verificados de un proveedor en conversaciones de agente. Hay 17 paquetes: Slack, Teams, Discord, GitHub, Telegram, Twilio, WhatsApp, Messenger, Notion, Linear, Intercom, Zendesk, Stripe, Shopify, Resend, Google Chat y Salesforce Marketing Cloud.

Se montan en app.ts como cualquier otra ruta y despachan hacia el agente:

export const channel = createSlackChannel({
  signingSecret: requiredEnv('SLACK_SIGNING_SECRET'),

  // Ruta: /channels/slack/events
  async events({ payload }) {
    if (payload.type !== 'event_callback') return;
    if (payload.event.type !== 'app_mention') return;

    const event = payload.event;
    await dispatch(Assistant, {
      id: channel.instanceId({
        teamId: payload.team_id,
        channelId: event.channel,
        threadTs: event.thread_ts ?? event.ts,
      }),
      // Se graba al crear la instancia; se ignora después.
      initialData: { channelId: event.channel, startedBy: event.user },
      message: {
        kind: 'signal',
        type: 'slack.app_mention',
        body: event.text,
        attributes: { eventId: payload.event_id },
      },
    });
  },
});

Tres detalles que enseñan cómo piensa la 2.0. El primero: dispatch() ya no recibe un input opaco, sino un message estructurado que distingue entre kind: 'user' (un turno de chat de verdad) y kind: 'signal' (un evento de sistema). El segundo: el hilo de Slack se convierte en el id de la instancia, así que la conversación del agente y la del humano son la misma cosa. Y el tercero: los datos estructurados llegan como initialData y se leen con useInitialData(), en vez de re-parsear el id. La documentación es explícita ahí: parseInstanceId bajó de patrón recomendado a escotilla de emergencia.

Casos prácticos donde Flue brilla

Triage automático de issues en GitHub Actions

Un agente que escucha el evento issues.opened, lee el código relevante, intenta reproducir el bug, asigna severidad y, si la corrección es trivial, abre un PR. Todo en un step de GitHub Actions con flue run src/agents/triage.ts -m "..." y el GITHUB_TOKEN que ya te da Actions de regalo.

Aquí useSandbox(local()) es tu aliado: el repo ya está clonado en el runner, el agente trabaja directamente contra él y descubre el AGENTS.md que tienes en raíz. Encaja con la encuesta sectorial de Q1 2026 de Digital Applied: el 71% de las agencias de desarrollo encuestadas tiene agentes de generación y refactor de código en producción, el porcentaje más alto de cualquier categoría (fuente: Digital Applied, encuesta a 250 agencias, 2026).

Soporte conversacional con canal y estado

Un agente desplegado en Cloudflare Workers que recibe mensajes de Slack o Zendesk vía canal, mantiene su fase con usePersistentState y no puede emitir un reembolso en el mismo paso en que lo propone porque una guarda se lo impide. La conversación persiste en Durable Objects: el cliente vuelve dos semanas después y el agente recuerda todo. Es literalmente el ejemplo support-desk del repositorio.

Coding agent con contenedor

El caso de uso más ambicioso. Un agente que recibe la URL de un repo y un prompt, levanta un contenedor Daytona, clona el repo, instala dependencias y empieza a iterar. Aquí tienes Linux completo, persistencia por sesión y aislamiento real entre usuarios. Con la 2.0, además, tools durables: si el contenedor se cae a mitad de un npm install de veinte minutos, no vuelves a empezar de cero.

Un dato para dimensionar la apuesta: según Grand View Research y los agregadores citados por Azumo, el segmento de coding y software development es el más rápido del mercado de agentes IA, con un CAGR proyectado del 52,4% entre 2025 y 2030 (fuente: Grand View Research vía Azumo, 2026). Construir un coding agent propio en 2026 es lo que era construir un motor de búsqueda en 2002.

Job programado sin servidor

start({ agents, db }) desde un cron de Node, sin HTTP de por medio. Encolas con dispatch(), guardas el recibo, y si el proceso muere lo reenganchas desde otro con read(). Este caso simplemente no existía en la 0.x.

Dónde puedes desplegar un agente Flue

La promesa de Astro siempre fue “Astro funciona en cualquier sitio”. Flue mantiene el guiño, y en la 2.0 suma un destino:

  • Node.js: vite build emite dist/server.mjs (autoarrancable) y dist/app.mjs (la aplicación sin listener). Lo lanzas con node dist/server.mjs, lo metes en un Dockerfile, lo despliegas en Railway, Fly o tu propio VPS.
  • Cloudflare Workers: el plugin oficial @cloudflare/vite-plugin como hermano explícito de flue(). Una clase Durable Object generada por agente, sesiones persistidas de regalo y trazas sin cablear nada: activas Workers Traces y cada respuesta lleva sus spans invoke_agent / chat / execute_tool.
  • GitHub Actions: flue run desde un step. Sin servidor, sin endpoint, sin secretos en el cliente.
  • GitLab CI/CD: el mismo patrón, con un pipeline trigger para conectar el webhook de issues al pipeline.
  • Render: destino nuevo en la 2.0, para quien quiera un host gestionado sin pelearse con workers.
  • Daytona: como entorno de sandbox remoto para agentes que necesitan contenedor.

Ojo con un detalle de la 2.0: los prompts HTTP directos son fire-and-forget. El ?wait=result desapareció y un POST /agents/:name/:id siempre devuelve un 202. Si necesitas la respuesta, la lees del transcript con history() o esperas con read().

El stack para desplegar agentes en serio cambia cada mes. En la newsletter, +6.700 developers compartimos qué está funcionando de verdad para llevar IA a producción. Gratis, cada domingo.

Quiero esa dinamita 🧨

Cómo se sitúa Flue frente a otras opciones

No vivimos en el desierto. Según el listado de frameworks que rastrea Datadog en su State of AI Engineering 2026, hay más de 35 frameworks de agentes en uso en producción ahora mismo, desde LangGraph y CrewAI hasta Mastra, OpenAI Agents, Pydantic AI y el propio Vercel AI SDK (fuente: Datadog, 2026).

Opción Punto fuerte Punto débil
Claude Agent SDK Motor probado de Claude Code, mismo modelo y harness Atado al ecosistema de Anthropic
Mastra TypeScript-first, memoria observacional, RBAC nativo Curva de aprendizaje más larga, conceptos densos
CrewAI Velocidad de prototipo, roles muy explícitos Python, opinado para multi-agente
LangGraph Control fino sobre el grafo de estados Mucha configuración para casos simples
Flue 2.0 Harness componible con hooks, durabilidad real, canales, Vite API que ya ha roto dos veces en seis meses

Flue es la opción a considerar cuando ya estás cómodo con la filosofía de Claude Code (skills, AGENTS.md, harness) y quieres llevar ese mismo patrón a algo que tú controlas. Si te has planteado migrar de Claude Code a otra herramienta, Flue es el paso siguiente: en lugar de cambiar de herramienta, construyes la tuya con las mismas piezas.

Si vienes del Claude Agent SDK y nuestro tutorial completo, la transición es suave en lo conceptual. Cambias el SDK que lanza Claude Code como subproceso por una arquitectura de framework, ganas portabilidad entre runtimes y mantienes la mayoría de tus modelos mentales.

📚 Lo digo otra vez por si acaso: entre mayo y agosto de 2026, Flue pasó de 0.3 a 0.11, luego a 1.0 beta y después a 2.0, rompiendo compatibilidad en cada salto. La 2.0 es mucho mejor framework que la 0.3. También es la prueba de que aquí todavía se rompe.

Si vienes de la 0.x o de la 1.0 beta

Traducción rápida para que sepas dónde va a doler:

  • Tu defineAgent se convierte en función. El objeto de config se reparte en llamadas a hooks dentro del cuerpo. Es un rato de trabajo mecánico, no un rediseño.
  • Tus rutas hay que escribirlas. Las convenciones de src/agents/*, src/workflows/* y src/channels/* ya no registran nada. app.ts, a mano.
  • Tus workflows hay que replantearlos. No hay stub de compatibilidad. Se convierten en programas que conducen a un agente.
  • Tus sandboxes hay que declararlos. El implícito ya no existe. Si tu agente usaba bash sin pedirlo, deja de tenerlo.
  • Tus datos persistidos se pierden. El format_version rechaza los stores de la beta. Sin migración.
  • Tu cliente cambia de dirección. baseUrl + nombre + id se convierte en una URL de conversación, y prompt() en send() + wait() + history().
  • Tus dispatch_... siguen siendo válidos. Los ids nuevos son sub_, pero los viejos no se rompen. Un pequeño detalle de cortesía en medio del terremoto.

Las costuras que conviene mirar antes de casarte con Flue

Toca ser honestos con las limitaciones, porque toda elección tiene precio.

  • La API ha roto dos veces en seis meses. El framework es mejor en cada salto, pero lo que escribes hoy puede necesitar una reescritura en el siguiente mayor. Y la 2.0 demostró que un mayor aquí puede significar “todo”.
  • Solo TypeScript. Si tu equipo vive en Python, Mastra deja de ser comparable y la conversación cambia entera.
  • MCP sigue siendo solo remoto. Soporta streamable-http y SSE legacy, pero no levanta servidores stdio locales. Si tu pipeline depende de servidores MCP locales, sigues sin poder. Para dimensionar el peso de MCP en el ecosistema actual: Digital Applied calcula que hay más de 9.400 servidores MCP públicos a abril de 2026 (fuente: Digital Applied, 2026).
  • Sin sandbox declarado no hay entorno. Es la decisión correcta, pero es también el primer sitio donde te vas a estrellar al migrar: tu agente deja de tener bash y el error, aunque es claro, llega en runtime.
  • El sandbox virtual no es un Linux real. just-bash cubre los comandos básicos (grep, glob, cat, sed, awk) pero no es un shell completo. Para coding agents serios, contenedor.
  • No aceptan pull requests. El repositorio cierra los PR automáticamente y los convierte en issues o discusiones. Puedes reportar y proponer, no puedes contribuir código.

💡 Si solo te llevas un consejo de este apartado: prueba Flue en un side-project primero. Un agente de triage para tu repo personal, un asistente que resuma tus issues, un experimento de fin de semana. Cuando entiendas la mecánica, ya valorarás si encaja en producción.

Para quién es Flue de verdad

Te resumo el perfil que mejor le va a sacar partido a Flue 2.0:

  • Trabajas con TypeScript y no quieres saltar de stack para construir agentes.
  • Has tocado Claude Code, Codex, OpenCode o Cursor y entiendes el modelo mental de skills + AGENTS.md.
  • El modelo mental de React (render, hooks, composición) te resulta natural.
  • Necesitas que tu agente viva fuera del terminal: HTTP, CI, webhooks, Slack.
  • Necesitas que el trabajo aceptado sobreviva a un reinicio, no que se pierda.
  • Quieres controlar tú las decisiones críticas (qué modelo, qué sandbox, qué herramientas) sin estar atado a un proveedor.

Y te resumo el perfil que probablemente debería esperar unos meses:

  • Tu equipo es Python-first y no quiere tocar TypeScript.
  • Necesitas garantías de estabilidad de API para el trimestre que viene.
  • Ya tienes algo en producción sobre la 1.0 beta y no puedes permitirte perder los datos persistidos.
  • Tu caso de uso pide multi-agente con coordinación compleja al estilo CrewAI o Agent Teams.

Preguntas frecuentes sobre Flue

Qué es Flue exactamente

Flue es un framework de TypeScript creado por el equipo de Astro para construir agentes de IA autónomos. Se autodefine como agent harness framework y permite escribir un agente una vez y desplegarlo en Node.js, Cloudflare Workers, GitHub Actions, GitLab CI/CD o Render. La versión actual es la 2.0.3 (agosto de 2026) y el repositorio público está en withastro/flue bajo licencia Apache 2.0.

Qué cambia en Flue 2.0 respecto a la 1.0

Prácticamente todo. Un agente pasa de ser un defineAgent() con objeto de configuración a una función exportada en un módulo con la directiva 'use agent', configurada con hooks. flue dev y flue build se sustituyen por el plugin flue() de Vite. Las rutas por convención de directorios desaparecen en favor de un app.ts explícito. Los workflows se eliminan por completo. Los sandboxes pasan a ser opt-in. Y los almacenes persistidos por la 1.0 beta se rechazan sin migración posible.

Qué es un agent harness

Un agent harness es el conjunto de mecanismos que rodean a un modelo LLM para hacerlo fiable: skills, contexto en AGENTS.md, sesiones, memoria, herramientas, sandbox y reglas de validación. Mitchell Hashimoto popularizó el término en febrero de 2026 con la fórmula “Agent = Model + Harness”. Según OpenAI, un equipo pequeño usando agentes Codex sobre un harness bien diseñado generó aproximadamente un millón de líneas de código sin escribir nada a mano (fuente: OpenAI, 2026).

Qué son los hooks de Flue

Son funciones que llamas dentro del cuerpo de tu agente para componer sus capacidades: useModel (obligatorio, exactamente una vez), useInstruction, useTool, useSkill, useSubagent, useSandbox, usePersistentState, useMcpConnection y useInitialData, además de los de ciclo de vida. La función del agente se ejecuta de nuevo antes de cada llamada al modelo, igual que un render de React, y los hooks no pueden ser condicionales: el runtime impone invariancia estructural y falla la ejecución si el conjunto montado cambia de forma inesperada.

En qué se diferencia Flue del Claude Agent SDK

El Claude Agent SDK lanza Claude Code como subproceso y te expone una API para hablar con él. Funciona muy bien dentro del ecosistema de Anthropic. Flue, en cambio, es runtime-agnóstico: puedes elegir el modelo (Claude, GPT, Kimi, etc.), el sandbox (virtual, local o contenedor) y el host de despliegue. Flue te da el harness completo en TypeScript, no un SDK que envuelve a un agente externo.

Qué necesito para empezar a usar Flue

Node.js 22.19 o superior, una clave de API de un proveedor de modelos (Anthropic, OpenAI o cualquiera de los soportados por OpenRouter) y los paquetes @flue/runtime, @flue/vite y @flue/cli. Con flue init scaffoldeas el esqueleto del proyecto de forma interactiva, con vite dev levantas el servidor de desarrollo y con flue run src/agents/mi-agente.ts -m "hola" ejecutas un agente en local sin transporte.

Flue es gratis

Sí. Flue se publica bajo licencia Apache 2.0 y es de código abierto. Lo único que pagas es el consumo del modelo que uses (Claude, GPT, Kimi, etc.) y el coste del host donde despliegues (Cloudflare, Railway, Render, Fly, AWS, GitHub Actions). El framework en sí no tiene coste.

Puedo usar Flue con modelos open source

Sí, mediante OpenRouter, que actúa de pasarela común para decenas de modelos. También puedes apuntar a modelos servidos en local con compatibilidad OpenAI. La capa de modelos de la 2.0 es el protocolo de proveedores de Pi usado directamente: un proveedor custom se construye con createProvider(...) y se registra con setProvider(...).

Cómo evita Flue que el LLM lea mis claves de API

El sandbox local() no hereda tu entorno: parte de una allowlist de catorce variables (PATH, HOME, USER, SHELL, TZ, TERM, TMPDIR…) y todo lo demás lo expones explícitamente con local({ env: { GH_TOKEN: process.env.GH_TOKEN } }). Para servicios externos, useMcpConnection acepta un auth que resuelve la credencial por petición sin ponerla en contexto. En Cloudflare Sandboxes hay además un proxy de salida que inyecta credenciales a nivel de red. El defineCommand de la 0.x fue eliminado en la 2.0.

Flue funciona en producción

La 2.0 trae por fin las piezas que hacían falta: conversaciones durables, tools con checkpoints, entrega idempotente, recuperación tras caída y observabilidad nativa. Técnicamente es apta para producción. El riesgo que queda no es de fiabilidad, es de estabilidad de API: el proyecto ha roto compatibilidad dos veces en seis meses y la 2.0 rechaza los datos persistidos por la versión anterior. Presupuesta el coste de migración antes de comprometerte.

Qué frameworks compiten con Flue

Los más relevantes en TypeScript son Mastra (con memoria observacional y RBAC), Vercel AI SDK (más enfocado a chat), el Claude Agent SDK y OpenAI Agents. En Python compiten LangGraph, CrewAI, AutoGen y Pydantic AI. Datadog lista más de 35 frameworks activos en producción en 2026 (fuente: Datadog, 2026).

Cuándo se lanzó Flue

El anuncio público de Flue lo hizo Fred Schott, cocreador de Astro, el 1 de mayo de 2026 en X. La 1.0 llegó en beta a mediados de junio y la 2.0.0 se publicó el 31 de julio de 2026, con la 2.0.3 el 4 de agosto. El término agent harness que popularizan se cristalizó como disciplina apenas tres meses antes del lanzamiento, en febrero de 2026, cuando Mitchell Hashimoto y OpenAI publicaron sus respectivos textos fundacionales.

Cierre: la apuesta que se lee entre líneas

Que Astro publique un framework para agentes no es un capricho. Es una lectura de hacia dónde va el desarrollo web. Si la próxima década de aplicaciones se construye con agentes que escriben, despliegan y operan código, los frameworks que lideren no van a ser los que pinten más HTML, sino los que orquesten mejor a esos agentes.

Y la 2.0 dice algo más concreto: que el equipo estaba dispuesto a tirar su propia API a la basura tres meses después de presentarla. Eso duele si tenías algo montado. También es la razón por la que el framework de hoy es mucho mejor que el de mayo. Un defineAgent con veinte campos de configuración era cómodo de escribir y un callejón sin salida; una función con hooks es exactamente lo que necesitas cuando quieres que la comunidad construya sus propias abstracciones encima, como hace el ejemplo support-desk montando una máquina de estados completa sin tocar el framework.

Los datos respaldan el sitio al que apunta todo esto: Grand View Research valora el mercado global de agentes de IA en 10,91 mil millones de dólares en 2026 y proyecta 50,31 mil millones para 2030, con un CAGR del 45,8% (fuente: Grand View Research, 2026). LangChain ve un 57% de organizaciones con agentes en producción. Datadog confirma que la adopción de frameworks se ha duplicado año contra año.

Fred Schott y compañía han apostado a que Flue va a ocupar ese hueco. Y han apostado con la misma filosofía que les funcionó con Astro: dame el problema y te doy una herramienta que se sale de tu camino.

¿Te animas a desplegar tu primer agente Flue 2.0 antes del próximo domingo?

Fuentes

  • Flue, framework oficial — flueframework.com y repositorio withastro/flue
  • Flue, CHANGELOG — entradas 2.0.0 (31 de julio de 2026) a 2.0.3 (4 de agosto de 2026)
  • Flue, ejemplos oficiales hello-world, support-desk y slack-channel
  • Datadog, State of AI Engineering 2026datadoghq.com/state-of-ai-engineering
  • LangChain, State of Agent Engineering 2026langchain.com/state-of-agent-engineering
  • Mitchell Hashimoto, My AI Adoption Journey (febrero de 2026) — mitchellh.com
  • OpenAI, Harness engineering: leveraging Codex in an agent-first world (Ryan Lopopolo, febrero de 2026)
  • Software Improvement Group, What is harness engineering?softwareimprovementgroup.com
  • Digital Applied, Agentic AI Adoption: 250-Agency Survey 2026 y AI Agent Adoption 2026: 120+ Enterprise Data Points
  • Deloitte, State of AI 2026
  • Grand View Research, datos de mercado de AI Agents 2025-2030 (vía Azumo y Ringly aggregators)
  • Anthropic, descripción del Claude Agent SDK (noviembre de 2025) — anthropic.com
  • Princeton University, IIT Delhi, Georgia Tech & Allen Institute for AI, GEO: Generative Engine Optimization (arXiv:2311.09735)

🧨 Última oprtunidad para recibir la dinamita que mereces sobre programación con IA el próximo domingo: Suscríbete gratis a Web Reactiva en https://webreactiva.com/newsletter

Imagen de Daniel Primo
Claude, IA de Anthropic

Escrito con la ayuda de la IA generativa de Claude, fuentes fidedignas y con un human in the loop:
Dani Primo.

CEO en pantuflas de Web Reactiva. Programador y formador en tecnologías que cambian el mundo y a las personas. Activo en linkedin, en substack y canal @webreactiva en telegram

12 recursos para developers cada domingo en tu bandeja de entrada

Además de una skill práctica bien explicada, trucos para mejorar tu futuro profesional y una pizquita de humor útil para el resto de la semana. Gratis.