Declarative flows: describe a DAG once as a list of Baton.Flow.Steps, then
either build it into an executable Baton workflow or project it into a
node/edge graph for display. Single-sourcing the two means they can't drift.
A step names its worker, its logical deps, and an optional Baton.Flow.FanOut
(one node per item in a collection). Everything here is domain-agnostic: the
build subject is an opaque term threaded only to the fan-out functions, and
consumer-specific data (prompt keys, payloads, …) rides on each step's opaque
meta, which project/1 echoes but never interprets. So the whole flow layer
is reusable by any Baton consumer, not just one app.
Build
Baton.Flow.build(steps, subject, base_args, name: "rating:42") |> Baton.insert!()Each node's args are base_args plus "logical_step" — the step name the node
was expanded from (equal to the node name except under fan-out), so a worker
can look up its own step without restating it.
Project
%{nodes: nodes, edges: edges} = Baton.Flow.project(steps)One node per step (a fan-out step stays a single badged node — its per-item
expansion depends on a concrete subject and belongs to a run view). Nodes carry
the generic shape plus the worker's introspected output_schema/0 and the
opaque meta; layout is by topological layer.
Summary
Functions
Build (but do not insert) the Baton workflow for steps.
Recover the immutable logical definition that produced a stored flow run.
The logical graph for steps — one node per step, laid out by layer.
Return the stored logical and compiled projections for a flow run.
Types
@type proj_node() :: %{ id: String.t(), label: String.t(), kind: :llm | :function, description: String.t() | nil, deps: [String.t()], fan_out: %{gate: atom()} | nil, worker: module(), output_schema: map() | nil, has_schema: boolean(), meta: map(), layer: non_neg_integer(), pos_x: float(), pos_y: float() }
Functions
@spec build([Baton.Flow.Step.t()], term(), map(), keyword()) :: Baton.t()
Build (but do not insert) the Baton workflow for steps.
subject is the domain object fan-out collections read (pass nil when no
step fans out). base_args is the string-keyed map every node carries. Options:
:name— the workflow name (required).
Recover the immutable logical definition that produced a stored flow run.
@spec project([Baton.Flow.Step.t()]) :: projection()
The logical graph for steps — one node per step, laid out by layer.
Return the stored logical and compiled projections for a flow run.