Historical handoff (2026-07-11 snapshot; predates Mastra joining scope). Still the most detailed spec for unbuilt phases, but not maintained: the living plan is docs/plan.md, and each section gets promoted into docs/architecture.md / docs/test-plan.md / docs/deployment.md as its phase starts. When this doc and a living doc disagree, the living doc wins.
Date: July 11, 2026
Goal: Build one repository that compares Eve and Flue as product-agent frameworks, while also demonstrating how Smithers can orchestrate either framework and how either framework can launch a bounded Smithers workflow.
Create a working, documented monorepo that answers:
- How do Eve and Flue compare when implementing the same durable product agent?
- Which differences come from the framework versus the surrounding platform?
- What is the practical migration boundary between them?
- How can Smithers integrate with both without conflating the baseline comparison?
- Which stack is preferable for a user-facing product agent, and which pieces should remain framework-neutral?
The primary comparison is Eve vs. Flue. Smithers is a separate orchestration layer and must not be inserted into the baseline request path.
Eve is a filesystem-first durable agent framework. An agent is authored under agent/ with instructions, tools, skills, subagents, connections, channels, schedules, and sandbox configuration. It exposes a durable HTTP session API and a typed eve/client client. On Vercel, it integrates closely with Workflows, Sandbox, AI Gateway, Connect, and Agent Runs.
Flue is a programmable TypeScript agent harness. It has persistent agents, finite workflows, tools, skills, subagent profiles, sandboxes, schedules, SDK clients, and Node/Cloudflare targets. It is more explicit and infrastructure-selectable than Eve.
Smithers is a durable agent-workflow runtime. It can execute SDK and CLI agents through a common AgentLike interface, persist workflow steps, pause for approvals, retry, stream events, and rewind or fork runs.
There is no known first-party Smithers-to-Eve or Smithers-to-Flue adapter. Implement thin local adapters.
Implement two distinct integration directions.
Implement:
EveRemoteAgent implements AgentLikeFlueRemoteAgent implements AgentLike
A Smithers <Task> can then use either framework as its agent worker.
Use this for:
- side-by-side A/B runs;
- parallel independent answers;
- model/framework review workflows;
- fallback experiments;
- durable evaluation pipelines.
Add equivalent narrow tools to both agents:
start_smithers_workflowget_smithers_runsubmit_smithers_approval- optionally
cancel_smithers_run
These call the Smithers HTTP server.
Use this for:
- a product agent delegating a long-running bounded operation;
- a user-facing session launching an implementation/research workflow;
- preserving the product agent conversation while Smithers owns the child workflow.
For this repo, use the Smithers HTTP server rather than MCP for Eve/Flue → Smithers.
Smithers’ built-in MCP server is documented as a stdio server. Eve’s MCP connection expects a remote Streamable HTTP or SSE server, and Flue’s connectMcpServer() also expects a remote HTTP/SSE endpoint. A transport bridge could be added later, but it is unnecessary for the initial demo.
For every operation, designate one owner.
Smithers owns:
- workflow graph;
- retries;
- approvals;
- run state;
- task sequencing.
Eve or Flue performs one bounded worker generation per Smithers task.
Eve or Flue owns:
- user conversation;
- session continuity;
- agent tool loop;
- product-facing stream.
Smithers owns only the bounded child workflow launched by a tool.
Do not allow Smithers and Eve/Flue to independently retry the same external side effect. The shared effect service must require an idempotency key and enforce uniqueness in the database.
Use a Turborepo-style monorepo. Prefer pnpm at the root. Smithers code may execute under Bun while using dependencies installed in the workspace.
eve-flue-smithers-demo/
├── apps/
│ ├── web/ # Next.js comparison UI; deploy to Vercel
│ ├── eve/ # Eve agent application
│ ├── flue/ # Flue Node service
│ └── smithers/ # Smithers Gateway/HTTP control plane
│
├── packages/
│ ├── contracts/ # shared Zod schemas and API contracts
│ ├── domain/ # framework-neutral business operations
│ ├── effects/ # idempotent external-effect service
│ ├── persistence/ # Drizzle schema/client
│ ├── prompts/ # shared behavioral requirements
│ ├── evals/ # common test cases and scoring
│ ├── eve-adapter/ # web/server client for Eve
│ ├── flue-adapter/ # web/server client for Flue
│ └── smithers-adapters/ # AgentLike wrappers for Eve and Flue
│
├── .smithers/ # Smithers authoring pack/skills
├── docs/
│ ├── architecture.md
│ ├── test-plan.md
│ ├── findings-template.md
│ └── deployment.md
│
├── turbo.json
├── pnpm-workspace.yaml
├── package.json
├── .env.example
└── README.md
If Eve’s scaffold strongly expects a project-root agent/ directory, preserve its generated layout inside apps/eve rather than forcing an abstraction that fights the framework.
Next.js web http://localhost:3000
Eve http://localhost:3001
Flue http://localhost:3002
Smithers HTTP/Gateway http://localhost:7331
Postgres shared product/effect data
Use separate ports and one root pnpm dev command.
Vercel:
apps/web
apps/eve
Persistent Node/container host:
apps/flue
Bun-capable container initially:
apps/smithers
Shared managed Postgres:
product records, approvals, effects, comparison metrics
Do not force Flue or Smithers into a Vercel runtime merely to say everything is deployed on Vercel. The web app may proxy all runtimes behind one UI.
Smithers’ current serverless documentation says the Bun container path is supported, while Node/Vercel Function engine support is still in progress. Treat Smithers as a Bun service for the first pass.
Before changing code, inspect the current official docs because all three projects are moving quickly.
Use the current official scaffold, presently documented as:
npx eve@latest init <directory>The current tutorial requires Node 24 or newer.
Install and initialize the Node target using the current documented flow:
pnpm add @flue/runtime
pnpm add -D @flue/cli
pnpm exec flue init --target nodeCurrent Flue docs list Node >=22.19.0.
From the repository root:
bunx smithers-orchestrator initSelect Codex when prompted, or run non-interactively if appropriate. Keep the generated Smithers skill/MCP configuration project-scoped where possible.
- Install current package versions.
- Pin exact resolved versions in the lockfile.
- Record them in
docs/findings-template.md. - Do not blindly use API snippets in this handoff when the installed types disagree.
- Prefer imported public types and
satisfieschecks over copied interfaces.
Implement the same research-and-publish agent in Eve and Flue.
The agent should:
- accept a research request;
- clarify only when the request is unusably ambiguous;
- generate a short research plan;
- delegate one focused subtask to a subagent;
- use a deterministic mock research tool;
- create a structured draft;
- request application-owned approval before publication;
- publish through an intentionally flaky but idempotent effect;
- survive interruption/restart;
- continue later in the same session;
- report the final artifact and effect receipt.
It exercises:
- persistent conversation;
- tools;
- skills;
- subagents;
- structured outputs;
- approvals;
- side effects;
- retries;
- durability;
- observability;
- frontend streaming.
Avoid live web search in the first baseline. Use a deterministic fixture corpus so framework behavior is comparable. Add live search as a later optional test.
The following logic must not depend on Eve, Flue, or Smithers:
packages/domain/
create-research-plan.ts
search-fixture-corpus.ts
create-draft.ts
create-publication-proposal.ts
approve-proposal.ts
publish-artifact.ts
packages/contracts/
research-request.ts
research-plan.ts
research-result.ts
publication-proposal.ts
publication-receipt.ts
agent-events.ts
Example domain boundary:
export interface PublishArtifactInput {
proposalId: string;
idempotencyKey: string;
title: string;
body: string;
}
export interface PublishArtifactResult {
publicationId: string;
created: boolean;
checksum: string;
}
export async function publishArtifact(
input: PublishArtifactInput,
deps: PublishArtifactDeps,
): Promise<PublishArtifactResult> {
// Transactionally insert by unique idempotency key.
// Return the existing receipt on duplicate invocation.
}The agent framework adapter validates tool input, supplies trusted identity/context, and calls this function.
Use Postgres and Drizzle for shared application state.
Minimum tables:
demo_threads
id
backend eve | flue
external_session_id
continuation_state_json
created_at
updated_at
publication_proposals
id
thread_id
title
body
status pending | approved | denied | published
created_at
decided_at
publication_effects
id
proposal_id
idempotency_key UNIQUE
request_checksum
result_json
attempt_count
created_at
updated_at
comparison_runs
id
prompt
eve_thread_id
flue_thread_id
smithers_run_id
metrics_json
created_at
Smithers can use its own SQLite database locally. Add Postgres for Smithers only after the local integration works.
Do not mix Smithers’ internal run tables with application-owned product state.
Create the Eve agent using its native project conventions:
apps/eve/
├── agent/
│ ├── agent.ts
│ ├── instructions.md
│ ├── tools/
│ │ ├── search_fixture_corpus.ts
│ │ ├── create_publication_proposal.ts
│ │ ├── get_publication_status.ts
│ │ ├── publish_artifact.ts
│ │ └── start_smithers_workflow.ts
│ ├── skills/
│ │ └── research-and-publish/
│ │ └── SKILL.md
│ ├── subagents/
│ │ └── researcher/
│ └── channels/
│ └── eve.ts
└── ...
Requirements:
- Use the typed
eve/clientclient from server-side callers. - Persist Eve
SessionStateunder the application thread record. - Persist rendered conversation events separately; Eve session state is a cursor/resume handle, not the transcript.
- Use the same model/provider and behavioral instructions as Flue.
- Keep publication approval in the shared application database for the baseline.
- Add an optional second path demonstrating Eve-native durable approval only after the portable baseline works.
- Export health/info checks for adapters and tests.
- Enable traces and record how much setup is automatic on Vercel.
Create a Node-target Flue service:
apps/flue/
├── agents/
│ └── research-publisher.ts
├── src/
│ ├── skills/
│ │ └── research-and-publish/
│ │ └── SKILL.md
│ ├── subagents/
│ │ └── researcher.ts
│ ├── tools/
│ │ ├── search-fixture-corpus.ts
│ │ ├── create-publication-proposal.ts
│ │ ├── get-publication-status.ts
│ │ ├── publish-artifact.ts
│ │ └── start-smithers-workflow.ts
│ └── ...
├── flue.config.ts
└── ...
Requirements:
- Expose a persistent named agent.
- Use
@flue/sdkfrom the web app and Smithers adapter. - Map the application thread ID to a stable Flue agent instance ID.
- Use the same model/provider, prompts, fixtures, schemas, and domain functions as Eve.
- Configure persistence appropriate for durable local testing.
- Add a subagent profile and use
session.task(...)or the current public equivalent. - Record observability and run-inspection setup.
- Keep approvals application-owned in the baseline.
Create one Next.js page with four modes:
/direct/eve
/direct/flue
/smithers/compare
/smithers/child-job
Provide the same UI:
- thread selector/new thread;
- transcript;
- live event stream;
- tool activity;
- subagent activity;
- pending approval card;
- approve/deny controls;
- final artifact;
- backend badge.
Do not use a UI abstraction that hides framework-specific events. Normalize common events, but preserve a raw event inspector.
Launch a Smithers workflow that sends the same prompt to both remote adapters, then shows:
- Eve output;
- Flue output;
- timing;
- token/cost data where available;
- tool traces;
- reviewer verdict;
- raw Smithers execution tree.
Allow either direct agent to call a tool that launches a Smithers workflow. Display:
- parent backend/session;
- Smithers child run ID;
- run status;
- pending Smithers approvals;
- final child output.
Create packages/smithers-adapters.
Implement the current imported AgentLike contract rather than copying its shape.
Behavior:
preflightcalls Eve health/info.generatecreates or restores an Eve client session.- Send
args.prompt. - Forward useful stream text to Smithers callbacks when practical.
- Return the final text or structured result.
- Propagate
abortSignaland timeout. - Default to a fresh Eve session per Smithers task.
- Support an explicit stable session key only for tests that require continuation.
- Initially set native structured-output support to false unless mapping Smithers’ schema to Eve’s current output-schema API is straightforward and tested.
Use:
import { Client } from "eve/client";Do not expose the Eve continuation token to the model.
Behavior:
preflightchecks the Flue endpoint.generatecalls the persistent agent using the current@flue/sdkAPI.- Use a deterministic instance ID derived from Smithers run/task IDs.
- Forward stream output when practical.
- Propagate cancellation and timeout.
- Initially set native structured-output support to false unless a tested direct mapping exists.
Use the current equivalents of:
import { createFlueClient } from "@flue/sdk";
client.agents.prompt(agentName, instanceId, {
message: prompt,
signal,
});- successful generation;
- unavailable backend fails in
preflight; - cancellation;
- timeout;
- session isolation;
- stable-session continuation;
- malformed response handling;
- no credential leakage;
- output-schema fallback.
Create:
apps/smithers/workflows/compare-eve-flue.tsx
Logical graph:
Input prompt
├── Eve task
└── Flue task
↓
Normalize outputs
↓
Independent reviewer
↓
Persist comparison result
Requirements:
- Run Eve and Flue tasks in parallel.
- Use the two custom
AgentLikeadapters. - Reviewer must receive both outputs without knowing which is which for one blinded score.
- Also produce an unblinded operational comparison.
- Persist metrics in
comparison_runs. - Expose run events through Smithers Gateway/HTTP.
- Include retry policy only around safe remote generation calls.
- Do not retry the shared publication effect from this workflow.
Create a second workflow:
apps/smithers/workflows/fallback.tsx
It should try one backend, classify the failure, and invoke the other only for configured transient failures. Do not use it in the baseline scoring.
Implement the same logical tools in both frameworks over a shared client package.
packages/domain/src/smithers-client.ts
Minimum client operations:
interface SmithersClient {
startRun(input: {
workflowPath: string;
input: unknown;
idempotencyKey: string;
}): Promise<{ runId: string }>;
getRun(runId: string): Promise<SmithersRunSummary>;
submitApproval(input: {
runId: string;
approvalId: string;
decision: "approve" | "deny";
}): Promise<void>;
cancelRun(runId: string): Promise<void>;
}Use the authenticated Smithers HTTP API. Keep the bearer token in trusted server code.
Model-facing tools must not accept:
- arbitrary URLs;
- arbitrary filesystem workflow paths;
- arbitrary auth headers.
Instead, expose a fixed allowlist:
research-report
validate-artifact
compare-backends
Map each public workflow name to a trusted internal workflow path.
Use one application-owned approval flow for both frameworks.
Agent creates proposal
↓
DB row status=pending
↓
UI renders approval
↓
User approves/denies
↓
Agent is notified or polls through a bounded tool
↓
Publish tool revalidates status and executes idempotently
This holds the product policy constant.
After this passes, optionally add separate framework-native approval demonstrations. Keep their results out of the baseline reliability score because they are not equivalent APIs.
Add deterministic environment-controlled failure modes:
DEMO_FAIL_PUBLISH_ATTEMPTS=2
DEMO_CRASH_AFTER_EFFECT=true
DEMO_AGENT_TIMEOUT_MS=...
DEMO_FORCE_SUBAGENT_FAILURE=true
publishArtifact must:
- increment attempt count;
- fail for the configured first N attempts;
- insert or retrieve by unique idempotency key;
- return the same receipt on duplicate calls.
Add a development-only endpoint or script to terminate each runtime at defined checkpoints.
Automate the following for both Eve and Flue.
- same prompt and deterministic fixtures;
- same model/provider/settings;
- same tools and schemas;
- same skill content;
- one delegated subagent task;
- same final structured artifact.
- terminate during model work;
- terminate after tool success but before next model step;
- restart while approval is pending;
- resume a saved conversation;
- disconnect and reconnect stream;
- submit duplicate user input;
- submit duplicate approval;
- invoke duplicate publication request.
- user A cannot resume user B’s thread;
- tool cannot publish an unapproved proposal;
- tool cannot change publication destination;
- agent never receives raw provider or Smithers credentials;
- arbitrary Smithers workflow paths are rejected;
- sandbox cannot access unrelated host files.
- Smithers invokes Eve as a worker;
- Smithers invokes Flue as a worker;
- both run in parallel;
- one backend failure does not corrupt the other task;
- Eve launches a Smithers child run;
- Flue launches a Smithers child run;
- Smithers approval can be completed from the web UI;
- parent session can retrieve final child output.
Record:
Implementation
setup time
framework-specific LOC
shared LOC
adapter LOC
number of custom infrastructure components
Runtime
first-token latency
total latency
model calls
input/output tokens
estimated cost
tool calls
duplicate-effect count
recovery time
Developer experience
local setup
type quality
docs accuracy
debugging clarity
event readability
approval ergonomics
subagent ergonomics
sandbox ergonomics
deployment effort
Portability
framework-neutral business logic percentage
UI coupling
persistence coupling
auth coupling
observability coupling
in-flight migration feasibility
Do not claim a winner based only on elapsed time from one run. Run the deterministic eval suite multiple times and separate framework behavior from model variance.
Treat these as hypotheses to test, not conclusions:
- Eve will likely be faster to integrate into a Vercel-hosted product surface.
- Eve will likely have the most cohesive built-in session, frontend, sandbox, and observability path on Vercel.
- Flue will likely expose more harness/runtime choices directly in TypeScript.
- Flue will likely require more assembly for auth, product UI, and operations.
- Flue will likely be easier to move across infrastructure providers.
- Smithers can orchestrate both effectively through thin remote
AgentLikeadapters. - Smithers is not a substitute for either baseline product-agent runtime; it is an optional durable outer workflow or bounded child-workflow engine.
The repository is complete when:
pnpm installsucceeds from a clean checkout;pnpm devstarts all four services;- the same conversation can be run against Eve and Flue;
- each implementation uses a skill, tool, subagent, durable session, approval, and idempotent effect;
- the UI can approve and resume both;
- restart tests pass;
- Smithers can invoke Eve and Flue through
AgentLikeadapters; - Eve and Flue can each launch a Smithers child workflow through HTTP;
- no raw secret is exposed in model context or browser payloads;
- tests prove the publication side effect occurs exactly once;
- deployment instructions are documented;
docs/findings.mdcontains measured results and unresolved issues.
Follow this order and commit after each phase:
- scaffold monorepo and services;
- add shared contracts/domain/persistence;
- implement deterministic fixture tools and idempotent effect;
- implement Eve baseline;
- implement Flue baseline;
- implement shared web comparison UI;
- add durability/failure tests;
- initialize Smithers;
- implement Smithers remote-agent adapters;
- implement Smithers comparison workflow;
- add Eve/Flue → Smithers HTTP tools;
- add deployment configs;
- run full matrix and write findings.
Do not begin Smithers integration until direct Eve and direct Flue behavior passes the same baseline tests.
- Read current official documentation before using each public API.
- Prefer the framework’s current scaffold over manually reproducing old examples.
- Keep framework-specific code thin.
- Do not refactor shared behavior into a lowest-common-denominator agent abstraction that prevents testing native framework ergonomics.
- Share domain operations, contracts, fixtures, effect logic, and evaluation inputs.
- Preserve separate native event streams.
- Add TODOs with links when a current framework limitation blocks parity.
- Never hide a failed parity test by weakening the test.
- Commit small, reviewable phases with descriptive messages.
- At the end of every phase, update
docs/findings.mdwith:- what worked;
- what differed from docs;
- framework-specific workarounds;
- unresolved issues;
- measured LOC/setup/runtime data.
Create .env.example with at least:
# Shared model configuration
DEMO_MODEL_PROVIDER=
DEMO_MODEL_ID=
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
AI_GATEWAY_API_KEY=
VERCEL_OIDC_TOKEN=
# Service URLs
NEXT_PUBLIC_APP_URL=http://localhost:3000
EVE_BASE_URL=http://localhost:3001
FLUE_BASE_URL=http://localhost:3002
SMITHERS_BASE_URL=http://localhost:7331
# Auth
EVE_SERVICE_TOKEN=
FLUE_SERVICE_TOKEN=
SMITHERS_API_KEY=
# Persistence
DATABASE_URL=
# Failure injection
DEMO_FAIL_PUBLISH_ATTEMPTS=2
DEMO_CRASH_AFTER_EFFECT=false
DEMO_FORCE_SUBAGENT_FAILURE=falseUse one direct model provider for the baseline if possible, so the comparison does not accidentally become AI Gateway versus direct-provider access. Add AI Gateway as a separate Eve platform-integration experiment.
Use these as starting points and verify their current content before implementation:
- Eve concepts: https://vercel.com/docs/eve/concepts
- Eve repository/docs: https://github.com/vercel/eve
- Eve TypeScript client: https://github.com/vercel/eve/blob/main/docs/guides/client/overview.mdx
- Eve MCP connections: https://github.com/vercel/eve/blob/main/docs/connections/mcp.mdx
- Flue getting started: https://flueframework.com/docs/getting-started/quickstart/
- Flue agents: https://flueframework.com/docs/guide/building-agents/
- Flue tools and MCP: https://flueframework.com/docs/guide/tools/
- Flue SDK agents: https://flueframework.com/docs/sdk/agents/
- Smithers getting started: https://smithers.sh/guide/get-started
- Smithers AgentLike API: https://smithers.sh/reference/agents
- Smithers HTTP server: https://smithers.sh/integrations/server
- Smithers MCP server: https://smithers.sh/integrations/mcp-server
- Smithers serverless deployment: https://smithers.sh/deployment/serverless
- Smithers production hardening: https://smithers.sh/deployment/production-hardening