DEV Community

Cover image for Developers don't hate visual workflows. They hate the magic.
Ricardo Morais
Ricardo Morais

Posted on

Developers don't hate visual workflows. They hate the magic.

Hey, I'm Ricardo. I've been building Flow Weaver, a TypeScript workflow compiler. I've been working on it solo for nearly two years as a side project, and I'm finally sharing it.

Every workflow tool I've come across has asked me to leave my code behind. Use their editor, their format, their runtime. I never actually used them. I'd see the demo, think about what I'd lose, and close the tab.

The thing is, I don't think developers hate visual workflows. I think they hate what they have to give up to get them. Your types, your linter, your version control, your ability to just read the code and understand what's happening.

What if your code was the workflow, and the visual was just a view on top?

The code is the workflow

That's Flow Weaver. You write TypeScript functions, add one annotation, and the compiler turns them into workflow nodes. The visual representation is generated from your code, not the other way around.

Step 1: Write your node functions

These are plain TypeScript functions. The only thing special about them is the annotation. The @expression shorthand handles execute/onSuccess/onFailure automatically, so you just write the transform.

/** @flowWeaver nodeType @expression */
function greet(name: string): { greeting: string } {
  return { greeting: `Hello, ${name}!` };
}

/** @flowWeaver nodeType @expression */
function shout(text: string): { result: string } {
  return { result: text.toUpperCase() + '!!!' };
}
Enter fullscreen mode Exit fullscreen mode

You can call these directly, test them with vitest, import them anywhere. They're just functions. The greet function translates to a node (a box in the graph) type with the following ports (connection points for the node):

Port Direction Type What it is
execute in boolean Control signal that starts the node
name in string The parameter you defined
onSuccess out boolean You set this to true when the node succeeds. Expression nodes set it automatically: true if the function returns without throwing
onFailure out boolean You set this to true when the node fails. Expression nodes set it automatically: true if the function throws
greeting out string The return property you defined

Step 2: Wire them into a workflow

The workflow annotation connects node instances together. @connect wires ports between nodes. @path is a shortcut so you don't have to write the step connections one by one. @path Start -> g -> s -> Exit is equivalent to connecting Start.onSuccess -> g.execute, g.onSuccess -> s.execute, s.onSuccess -> Exit.onSuccess manually.

/**
 * @flowWeaver workflow
 * @node g greet
 * @node s shout
 * @path Start -> g -> s -> Exit
 * @connect Start.name -> g.name
 * @connect g.greeting -> s.text
 * @connect s.result -> Exit.message
 */
export function helloWorld(
  execute: boolean,
  params: { name: string }
): { onSuccess: boolean; onFailure: boolean; message: string } {
  throw new Error('This body is replaced by the compiler. Run: npx flow-weaver compile <file>');
}
Enter fullscreen mode Exit fullscreen mode

Start and Exit are virtual nodes. Start receives the workflow inputs, Exit collects the outputs. Everything lives in one .ts file.

Step 3: See what you built

npx flow-weaver diagram hello.ts --format ascii
Enter fullscreen mode Exit fullscreen mode

ASCII diagram of the helloWorld workflow showing Start, greet, shout, and Exit nodes connected in sequence

You can also generate SVG for documentation, Mermaid for GitHub, or open an interactive HTML version in your browser.

Step 4: Validate

The compiler checks your workflow graph before generating anything. Port types, missing connections, dead-end branches, all caught at compile time.

npx flow-weaver validate hello.ts
Enter fullscreen mode Exit fullscreen mode
✓ 1 file valid in 248ms
Enter fullscreen mode Exit fullscreen mode

And when something is wrong, it tells you exactly what and where:

✗ [line 11] Unknown Input Port: Port 'wrong_port' doesn't exist on node Exit.
⚠ How to fix: Check the port name in the @connect annotation.
Enter fullscreen mode Exit fullscreen mode

These are structured diagnostics with error codes, source locations, and fix suggestions. They're also machine-readable, which means your AI assistant can fix issues automatically.

Step 5: Compile

npx flow-weaver compile hello.ts
Enter fullscreen mode Exit fullscreen mode
  Compiling Workflows

✓ hello.ts 278ms

  1 file compiled (ESM) in 278ms
Enter fullscreen mode Exit fullscreen mode

The compiler generates the execution logic inside your workflow function, between @flow-weaver-body-start and @flow-weaver-body-end markers. Your node functions are never touched. The compiled output is standalone TypeScript. No imports from Flow Weaver. You could remove the package and the code keeps running.

Step 6: Run

npx flow-weaver run hello.ts --params '{"name":"World"}'
Enter fullscreen mode Exit fullscreen mode
✓ Workflow "helloWorld" completed in 1ms

  Result

{
  "onSuccess": true,
  "onFailure": false,
  "message": "HELLO, WORLD!!!!"
}
Enter fullscreen mode Exit fullscreen mode

Or just tell your AI assistant

Everything above, your AI assistant can do through conversation, you don't have to know the syntax by heart, Flow Weaver was designed to work smoothly with AI. You can ask your assistant to use the CLI directly. It gives you direct expertise through the fw context and fw docs command. Or, if you prefer, use the available MCP tools that work with Claude Code, Codex, Copilot, Cursor, Windsurf, and any MCP-compatible editor.

npx flow-weaver mcp-setup --tool claude
Enter fullscreen mode Exit fullscreen mode

Personally I use the CLI directly, so it is always up-to-date with the available version, up to you.

Then you talk to it:

The first thing you'll want to do is ask your AI to load the Flow Weaver context:

"Load the Flow Weaver context core"

The AI calls fw context core and gets the full annotation syntax, node patterns, CLI commands, and a tutorial. From that point on it knows how to build workflows without guessing. There are other presets to choose based on the context you want to give it:

Preset What's included When to use
core concepts, annotation syntax, tutorial Getting started
authoring core + advanced annotations, built-in nodes, scaffolding, node conversion, patterns Building real workflows
ops CLI reference, compilation, deployment, debugging, error codes Deploying and debugging
full everything (16 topics) When you want the AI to know it all

You can then ask about how it works, and what it can do for you. It will have the context and will be able to pull up documentation and try things out on your behalf.

Then, when you are ready to use it:

"Build a support agent that classifies customer messages and routes to LLM reply or human escalation"

The AI scaffolds the workflow, adds nodes, wires connections, validates, and compiles. When the compiler finds issues, the AI reads the structured diagnostics and fixes them in a loop until the workflow is valid.

If you still don't understand the inner details and want to dig deeper, just visit the source code at Flow Weaver's GitHub.

Routing

The expression nodes above are great for simple transforms. When you need branching, you use the full node signature. The runtime calls your function when the node receives an execute signal. You return which path fires next:

/**
 * @flowWeaver nodeType
 * @label Validate Input
 * @input data - Data to validate
 * @output validated - Validated data
 * @output errors - Validation errors
 */
function validate(execute: boolean, data: any) {
  if (!execute) return { onSuccess: false, onFailure: false, validated: {}, errors: [] };

  if (!data || !data.name || data.name.length < 3) {
    return { onSuccess: false, onFailure: true, validated: {}, errors: ['Name too short'] };
  }
  return { onSuccess: true, onFailure: false, validated: data, errors: [] };
}
Enter fullscreen mode Exit fullscreen mode

No routing engine, no config file, just a return value from a function you control.

Agent workflows

The hello world is intentionally simple. For real use cases, Flow Weaver ships with templates for LLM agents, RAG pipelines, conversational memory, human approval gates, and more.

npx flow-weaver create workflow ai-agent my-agent.ts
Enter fullscreen mode Exit fullscreen mode

Each template generates a complete working workflow with mock providers so you can compile and run immediately without any API keys.

I'll do a deeper walkthrough of the agent workflow patterns in a future post. For now, run npx flow-weaver templates to see what's available.

Packs

Flow Weaver is extensible through npm packages called packs. They add deploy targets, node types, CLI commands, and MCP tools.

npx flow-weaver market search        # see what's available
npx flow-weaver market install <pack>
Enter fullscreen mode Exit fullscreen mode

Deploy

The compiled output is standalone TypeScript, so it runs anywhere TypeScript runs. For specific platforms, install a deploy pack and export:

Serverless functions

Workflows can be serverless functions on your provider.

npx flow-weaver export agent.ts -t inngest -o deploy/
npx flow-weaver export agent.ts -t vercel -o deploy/
npx flow-weaver export agent.ts -t lambda -o deploy/
npx flow-weaver export agent.ts -t cloudflare -o deploy/
Enter fullscreen mode Exit fullscreen mode

CI/CD pipelines (experimental)

Workflows can also define CI/CD pipelines

npx flow-weaver export pipeline.ts -t gitlab-ci -o deploy/
npx flow-weaver export pipeline.ts -t github-actions -o deploy/
Enter fullscreen mode Exit fullscreen mode

Version control that makes sense

When someone changes a workflow, the PR diff looks like this:

- @path Start -> g -> s -> Exit
+ @path Start -> g -> validate -> s -> Exit
+ @connect g.greeting -> validate.input
+ @connect validate.output -> s.text
Enter fullscreen mode Exit fullscreen mode

That's a real diff you can review. And for deeper analysis, the semantic diff engine compares workflow versions at the graph level:

npx flow-weaver diff hello-old.ts hello.ts
Enter fullscreen mode Exit fullscreen mode
═══════════════════════════════════════════════════════════════
  WORKFLOW DIFF - Impact: BREAKING
═══════════════════════════════════════════════════════════════

  SUMMARY
  ───────────────────────────────────────────────────────────
  Node Types:   +1 added, -0 removed, ~1 modified
  Instances:    +1 added, -0 removed, ~0 modified
  Connections:  +4 added, -2 removed

  INSTANCES
  ───────────────────────────────────────────────────────────
  + v

  CONNECTIONS
  ───────────────────────────────────────────────────────────
  + g.greeting → v.text
  + v.validated → s.text
  + g.onSuccess → v.execute
  + v.onSuccess → s.execute
  - g.greeting → s.text
  - g.onSuccess → s.execute
Enter fullscreen mode Exit fullscreen mode

It classifies the overall impact as critical, breaking, minor, or cosmetic. So you know not just what changed, but whether it matters.

There is a visual editor

I still believe in the visual side, that's what started all of this. I built a Studio where you can see the graph and edit it on a canvas. It's still experimental, but core editing with the canvas, terminal, and diagnostics is live. Edit code and the graph updates. Edit the graph and the code updates.

Flow Weaver Studio showing a workflow graph on the canvas with a code editor and terminal panel below

Flow Weaver Studio showing the node type browser panel alongside the visual workflow editor

But you don't need it. The CLI and your text editor work fine on their own. The visual is there when it helps you reason about what you're building, not as something you're forced to use. That's the whole point.

Works inside OpenClaw too

If you use OpenClaw, Flow Weaver runs as a native plugin. Tell your assistant what you want automated, and it builds, validates, and compiles the workflow for you. The agent uses AI for individual steps like classification or summarization, but the routing between steps is compiled and deterministic. No skipped steps, no wrong routing, same result every run.

openclaw plugins install @synergenius/flow-weaver-openclaw
Enter fullscreen mode Exit fullscreen mode

The plugin is on ClawHub and npm.

Where things stand

Flow Weaver is in beta and real world usage will make it stronger. Even if you are skeptical, just give it a try. I'd really appreciate it, and negative feedback is just as welcome as positive.

Breaking changes may still happen during the beta. If you run into issues, the Discord is the best place to reach out. Every message gets read and responded to.

If you've been looking for a way to build workflows without giving up your code, try it. Two commands, first workflow running in under two minutes:

npm install @synergenius/flow-weaver
npx flow-weaver init hello
Enter fullscreen mode Exit fullscreen mode

Be one of the first people to use it.

GitHub · Website · Features · Studio · Discord

Top comments (0)