fabro/lib/components/fabro-workflow/README.md
Bryan Helmkamp 467087998d
Read workflow graphs through Petri's DOT parser
Fabro's own DOT parser was left with one job after create-time compile
moved to Petri: walking a workflow's file references for the bundler and
the workflow-version store, and reading a name, a goal and two counts.
Petri's frontend parses the same language, so the parser goes and a small
crate reads the graph through Petri's.

`fabro-dot` is that crate: `WorkflowGraph::parse` over
`petri_frontend_attractor::dot` and its semantic model (defaults applied,
subgraphs flattened, chains expanded), `references(position)` as the one
walker over the static-reference vocabulary (each reference with its node
and position, file references checked to be template-free), and
`normalize_for_graphviz`, the re-emit of Fabro DOT with dotted attribute
keys quoted, which the SVG render needs. It sits beside `fabro-petri`
rather than inside it because `fabro-petri` depends on `fabro-workflow`,
which depends on `fabro-workflow-version`: the version store cannot reach
`fabro-petri` without a cycle, and the bundler should not pull the engine
in to read a graph.

Deleted: `fabro-graphviz`'s lexer, grammar, AST, semantic pass and
`parse_ast` (1,829 lines, plus the `nom` dependency); the DOT model in
`fabro-types::graph` (`Graph`, `Node`, `Edge`, `AttrValue`,
`shape_to_handler_type`), with only `ReferenceKind` kept, moved to
`fabro_types::reference`; `fabro-template`'s `visit_graph_references` and
the `GraphReference`/`GraphPosition` types, with the template-syntax rule
(`validate_static_reference`) kept there; the pull-request body's DOT
fallback summary, which was unreachable because the DOT source only
travels with the run spec whose display graph the summary already reads.
`fabro-graphviz` is now the render alone, over `fabro-dot`.

Parity: the old and new walkers were run over every `.fabro` and `.dot`
file in the repository (118) before the deletion. Every reference set is
identical. Five files differ in what Petri reads more correctly: a
backslash before a newline inside a quoted string is a line continuation
(four files, inline prompt text only), and a node named only by an edge
counts as a node (`test/edge_only_node.fabro`, 3 nodes rather than 2, so
the `fabro validate` snapshot moves). The checked-in bundles' shapes and
references are pinned by a snapshot in `fabro-dot`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 12:23:57 -04:00

1.5 KiB

fabro-workflow

Fabro's platform half of a workflow run: what Fabro does around the engine.

Petri compiles and executes every run. fabro-petri is the crate that talks to the engine (fabro-dot reads a graph's shape and file references through Petri's parser), and this crate keeps what Fabro itself owns:

  • operations — creating a run around Petri's admission (materialize_admitted_run, persist_create_run), and the other run operations: fork, rewind, retry, and the timeline they resolve targets on. The run's display graph (fabro_types::RunGraph) is read off the graph Petri admitted; the DOT the workflow was written in is persisted beside it as graph_source.
  • workflow_bundle — the bundle a run is created from: every workflow of the version closure with its settings file and its files, and the RunDefinition the run records.
  • git, sandbox_git — the Git helpers a run's platform effects use, on the host and inside a sandbox.
  • pull_request — pull request creation for a finished run.
  • run_tools, services — the run tools an agent session calls.
  • web_search — the built-in web search backend.
  • run_lookup — resolving a run selector to a run.

The run records and status vocabulary are fabro_types'. Workflow diagnostics are Petri's: fabro validate, fabro preflight and the create handler report Petri's codes (attractor.*, unsupported.*, deprecated.*, info.*), plus Fabro's fabro.model.no_ready_provider when a model node has no provider ready to run it.