Skip to main content
Fabro is a workflow engine that reads a graph definition, executes nodes one at a time (or in parallel), and uses edge selection rules to decide what happens next. Here’s the end-to-end flow.
How Fabro works: author-time inputs flow into the workflow engine, which dispatches to handlers that interact with LLMs, sandboxes, and humans

Two ways to run Fabro

Fabro has two interfaces, both backed by the same workflow engine:
  • Standalone mode (fabro run) — Run a single workflow synchronously in your terminal. Best for local development, one-off runs, and CI/CD.
  • Server mode (fabro serve) — Start an HTTP API server with a web UI, concurrent run scheduling, and team access. Best for production use and running at scale.
Both modes parse the same DOT files, use the same execution engine, and support the same sandbox providers. See Server Mode for a detailed comparison and setup guide, or Architecture for internals.

Author time

You provide three inputs:
  1. Workflow graph (.fabro) — A Graphviz DOT file defining nodes, edges, and their attributes. This is the core of what Fabro executes. See Workflows.
  2. Run config (.toml, optional) — Overrides for the default model, sandbox provider, setup commands, and variables. See Run Configuration.
  3. API keys (.env) — Provider credentials for LLM APIs. See Quick Start.

Parse and validate

When you run fabro run, Fabro:
  1. Parses the DOT file into an in-memory graph of nodes and edges
  2. Validates the graph structure (exactly one start node, one exit node, all edges point to valid nodes)
  3. Applies the model stylesheet to resolve which LLM model each node uses
  4. Merges run config defaults with CLI flags (CLI flags override the config, config overrides graph defaults)

The execution loop

The engine walks the graph starting from the start node. For each node it:
  1. Resolves context — Assembles the node’s input from prior stage outputs, run context, and the workflow goal. The fidelity setting controls how much prior context is included.
  2. Dispatches to a handler — Each node type has a handler: the agent handler runs an LLM tool loop, the command handler runs a shell script, the human handler waits for input, and so on.
  3. Collects the outcome — The handler returns a status (success, fail, partial_success), optional routing directives, and any context updates.
  4. Selects the next edge — Fabro evaluates outgoing edges using conditions, labels, and weights to pick the next node. See Transitions.
  5. Checkpoints — After each stage, Fabro writes a checkpoint so the run can be resumed if interrupted.
This loop repeats until execution reaches the exit node or an unrecoverable error occurs.
Fabro web UI run detail showing stages and workflow graph

Retries and error handling

When a node fails, Fabro consults its retry policy. If retries remain, the node re-executes with exponential backoff. If all retries are exhausted, the failure propagates to edge selection — a condition="outcome=fail" edge can route to a fix node, creating a recovery loop. For workflows with loops, Fabro tracks failure signatures to detect infinite retry cycles. If the same failure repeats beyond the configured limit, the workflow aborts rather than looping forever.

Goal gates

Before completing, Fabro checks all nodes marked with goal_gate=true. If any goal gate node didn’t succeed, the workflow fails — even though execution reached the exit node. This ensures critical quality checks can’t be skipped by routing around them.

Parallel execution

When the engine hits a parallel fan-out node, it spawns concurrent branches, each with an isolated copy of the context. A merge node collects the results according to the join policy before the workflow continues on a single path.

Sandboxes

Node handlers execute tools (bash commands, file edits) inside a sandbox. Fabro supports six sandbox providers:
SandboxDescription
localTools run directly on the host machine (default)
dockerTools run inside a Docker container
daytonaTools run in a cloud VM with SSH access
sshTools run on any existing SSH host
exeTools run in a fast ephemeral VM from exe.dev
spritesTools run in a persistent VM from Sprites
The sandbox is configured per-run via CLI flags (--sandbox docker) or the run config TOML. See Environments for details on each provider.

Events and observability

Every significant action — stage starts, LLM calls, tool invocations, edge selections, stage completions — is emitted as a structured event. These events power:
  • The web UI for real-time run monitoring
  • Retrospectives generated automatically after each run
  • DuckDB queries via fabro insights for SQL-based analysis across runs
See Observability for more on querying run data.

Resuming runs

Because Fabro checkpoints after every stage, interrupted runs can be resumed from where they left off:
fabro run --resume path/to/checkpoint.json
Or resume from a git run branch:
fabro run --run-branch fabro/runs/abc123
The engine restores the full context, node visit counts, and retry state, then continues execution from the next node.