A visual editor for Claude Code workflows. Drag nodes onto a canvas, wire them
together, and Flowpiler compiles the graph into a ready-to-run workflow.js — and
parses your existing workflow.js back into a graph. Test it with mocked agents for
free, then run it for real and watch every subagent light up live.
Think Pentaho Kettle, but for Claude workflows — a node-graph front end for the imperative script the
Workflowtool expects.
Palette · canvas · inspector + live workflow.js — all three update together.
Claude Code Workflows orchestrate dozens of subagents to do things one context can't — exhaustive code reviews, repo-wide migrations, multi-source research, audit sweeps. They're powerful, but they ship as JavaScript:
const reviews = await parallel([
() => agent(`Review the diff for correctness bugs…`, { phase: `Review`, schema: REVIEW_BUGS_SCHEMA }),
() => agent(`Review the diff for performance regressions…`, { phase: `Review`, schema: REVIEW_PERF_SCHEMA }),
])
const findings = reviews.filter(Boolean).flatMap(r => r.findings)
const verified = await pipeline(findings, (prev, item) => agent(`Adversarially verify…`, …))And in practice most of these scripts are AI-generated — which means the human in the loop spends their time reading, trusting, and tweaking a script they didn't write. That's exactly the friction Flowpiler removes:
- See it at a glance. A wall of
parallel/pipeline/awaitbecomes a graph you can read in seconds — phases, fan-outs, verify loops, branches. - Edit safely. Change a prompt, swap a model, add a verify stage — in form fields, not by hand-editing nested template literals. The code regenerates as you type.
- Test for free. Dry-run the whole thing with mocked agents to catch broken control flow, undefined variables, and unbounded loops — before spending a cent on real subagents.
- Run for real, and watch. Execute through your local
claudeand stream each node's state · tokens · duration · full output right onto the canvas. - Round-trip. Import any
workflow.js, edit visually, export it back.
Codify the recurring multi-agent jobs your team does by hand into reusable, visual, testable workflows — then tune them in plain language and re-run on demand:
| Maintenance task | Shape in Flowpiler |
|---|---|
| PR / diff review across dimensions | parallel finders → dedup code → pipeline adversarial verify |
| Dependency / license / security audit | parallel scanners → if (findings?) → report |
| Log & incident triage | fan-out over services → summarize → return ranked list |
| Docs / dead-link / TODO sweep | pipeline over files → fix-suggestion agent |
| Flaky-test hunt | while loop-until-dry → confirm → patch proposal |
Build it once, dry-run to prove the wiring, run it live when you need it, and hand the
exported workflow.js to teammates or a cron.
npm install
npm run dev # → http://localhost:5180
npm run build # type-check + production bundle into dist/Open the app and hit Load sample to drop in the review-changes example shown
throughout this README, or start from the seed graph and drag nodes from the palette.
Run live / AI edit are dev-mode features. They call your local
claudethrough a Vite dev-server endpoint, reusing your existing Claude Code auth — Flowpiler never sees an API key. They're available undernpm run dev, not in the staticdist/build.
Select any node to edit its fields on the right. Prompts, labels, phase, model,
worktree isolation, structured-output JSON Schema — all editable, and the
workflow.js panel below rewrites itself on every keystroke.
▷ Test run executes your workflow in a sandboxed worker with mocked agents: no
subagents are spawned, no tokens are spent. You get the exact call order, plus errors
and unbounded-loop detection — and the canvas lights up to show what ran.
After a run, the overlay stays on the canvas: nodes that ran glow, observable nodes
that didn't run dim, and fan-outs / loops get an ×count badge. It clears the moment
you edit.
✦ AI edit — describe a change ("make the extract step a parallel fan-out over
clusters", "give every agent a budget-aware while loop", "switch the review agents to
opus") and it runs your local claude -p, rewrites the workflow.js, and re-imports it
as a fresh graph.
● Run live actually executes the workflow through
claude -p --output-format stream-json, parsing workflow_progress and streaming each
node's real state, tokens, duration, and result onto the same overlay. Pick the
working directory the agents run in, pass optional JSON args, and the slide-out drawer
tracks every agent as it goes.
Each agent row (and the inspector's "last run") is click-to-expand: Flowpiler reads the subagent's on-disk transcript and shows the full prompt and output — not just the truncated preview the live stream carries.
- Tabs + autosave — keep multiple workflows side by side (click to switch,
double-click to rename,
+for a new one); every change is persisted tolocalStorageand restored on reload. Download names the file after the tab. - Import — paste or upload an existing
workflow.js; it's parsed back into a node graph (anything it can't classify lands in acodenode rather than failing). - Live validation — empty meta name/prompt, invalid schema JSON, empty containers,
unwired nodes, and phase/
metamismatches are flagged as you build; click an issue to jump to and highlight its node.
Pick one from the top-bar dropdown:
| Sample | What it shows |
|---|---|
| review-changes | the canonical fan-out → dedup → adversarial-verify review pattern |
| MAGI · Eva three-sage | a majority-vote decision engine (read on 👇) |
In Neon Genesis Evangelion, MAGI is the supercomputer that runs NERV. Its creator
split her own psyche across three units — MELCHIOR-1, BALTHASAR-2, CASPER-3 (the
scientist, the mother, the woman) — and the system decides by majority vote of the
three. It's basically a multi-agent system with deliberately diverse perspectives… which
is exactly a Claude parallel + majority pattern.
Flowpiler ships it as a runnable sample. Three agents judge the same proposal through
three different lenses, in parallel; a code node tallies the votes; a 2-of-3 majority
becomes the verdict:
phase("Deliberate")
const votes = await parallel([
() => agent(`…as MELCHIOR-1 (SCIENTIST) — judge on logic & feasibility… Proposal: ${args.proposal}`, { schema }),
() => agent(`…as BALTHASAR-2 (MOTHER) — judge on protection & safety… Proposal: ${args.proposal}`, { schema }),
() => agent(`…as CASPER-3 (WOMAN) — judge on intuition & human impact… Proposal: ${args.proposal}`, { schema }),
])
const approvals = votes.filter(Boolean).filter(v => v.vote === "APPROVE").length
const decision = approvals >= 2 ? "APPROVED" : "REJECTED"
phase("Resolve"); log(`MAGI verdict: ${decision} (${approvals}/3 approve)`)
return { decision, approvals, votes }
Try it: Load MAGI → ▷ Test run (or ● Run live) and pass a proposal as
args — either JSON {"proposal":"ship on Friday"} or just plain text. Watch the three
sages deliberate and the verdict come back. It's a tiny, fun template for any
“get N independent opinions, then decide” task — design reviews, go/no-go calls, risk
sign-offs.
The graphic above is an original homage, not a screenshot from the show.
| Node | Emits |
|---|---|
| meta / Start | export const meta = { name, description, whenToUse?, phases } |
| agent() | const v = await agent(prompt, { label, phase, model, isolation, agentType, schema }) |
| parallel() | const v = await parallel([() => …, …]) — branches run concurrently (barrier), or map mode fans one template over a collection |
| pipeline() | const v = await pipeline(items, (prev, item, i) => …, …) — items through ordered stages |
| phase() | phase('title') |
| log() | log('message') |
| while loop | while (cond) { …body… } |
| if branch | if (cond) { …then… } else { …else… } |
| code / return | raw JS — declarations, transforms, return … |
- Execution order at every level follows the connecting hops (topological), falling back to top-to-bottom canvas position for the start and any unconnected nodes.
- parallel children run concurrently — no wiring needed between them. map mode
emits
parallel(items.map((item, i) => () => …))for dynamic fan-outs. - pipeline / while / if children are ordered by their internal hops.
- Nesting is unlimited — drop a container inside a container (e.g. a
parallelas apipelinestage); the drop targets the innermost box and the nestedparallel/pipelineis emitted inline as an expression. ifhas then / else — eachifbox is split into a then column and an else column; drop a node into either side (or flip it in the inspector).- agent prompts and labels are emitted as template literals, so
${item},${prev.x},${i}interpolation works inside loops and stages. - Schemas entered on agent nodes are validated as JSON and hoisted to named
*_SCHEMAconsts at the top, then referenced from the agent's opts — matching the convention in the Workflow examples.
src/
├─ components/ # all React UI
│ ├─ App.tsx # layout, canvas, drag-drop + re-parent, tabs, import/export, tidy
│ ├─ Palette.tsx # left sidebar, draggable node templates
│ ├─ Inspector.tsx # right sidebar, per-kind field editors
│ ├─ nodes.tsx # React Flow node components + nodeTypes registry
│ └─ *Dialog.tsx # Test / RunLive / AiEdit / Detail dialogs
├─ compiler/ # graph ↔ workflow.js
│ ├─ codegen.ts # graph → workflow.js (the compiler)
│ └─ parser.ts # workflow.js → graph (the importer)
├─ runtime/ # execution + telemetry
│ ├─ runtime.ts # shared run model + node attribution
│ ├─ simulate.ts/ # dry-run: mocked-agent execution in a Web Worker
│ │ simWorker.ts
│ ├─ runLive.ts # live run: stream-json telemetry + on-disk transcript reads
│ └─ aiEdit.ts # plain-language edit via local claude -p
├─ state/ # zustand store + React contexts
│ ├─ store.ts # multi-tab graphs + localStorage persist
│ ├─ types.ts # node-data model + defaults
│ └─ *Context.ts # run / validation / detail contexts
├─ graphUtil.ts # absolute positions, nesting hit-tests, resize-aware sizing
├─ validation.ts # static checks → issues
├─ sample.ts # bundled samples (review-changes, MAGI)
├─ main.tsx # entry
└─ styles.css # dark IDE theme
vite.config.ts # dev-server endpoints: /api/edit, /api/run, /api/pickdir,
# /api/agent-output — all spawn your local `claude`
codegen.ts is the heart: it finds the meta node, hoists schema consts, then walks the
top-level nodes in hop order, recursing into containers. parser.ts is its inverse — a
bracket/string/template/regex-aware scanner that reads the JS subset Flowpiler emits.
parallel/pipelinethunk/stage bodies are expected to be agent, code, or a nested parallel/pipeline (things that are expressions). Awhile/ifcan't be inlined as a thunk body (it isn't an expression).- The importer targets the JS subset Flowpiler emits; arbitrary hand-written control
flow it can't classify lands in a
codenode rather than failing. - Imported graphs get an automatic layout — readable, but you'll likely tidy positions by hand.
- Run live and AI edit require a local
claudeCLI onPATHand run only in dev mode. The folder picker is Windows-only (type the path manually elsewhere).






