An editable flow is UTF-8 TOML. Compilation recursively validates referenced resources and emits an immutable graph interpreted by the installed VIA release.
name = "company/change"
[inputs.task]
description = "Decision-complete task."
accepts = ["text", "file"]
[inputs.repository]
description = "Repository context."
accepts = ["directory"]
[limits]
node_attempts = 3
contract_repair_attempts = 2
[nodes.implement]
uses.action = "company/implement"
agent = "company-maker"
[nodes.implement.inputs.task]
from = "$task"
[nodes.implement.inputs.repository]
from = "$repository"
[nodes.implement.outputs.patch]
description = "Candidate patch."
kind = "file"
[nodes.review]
uses.action = "company/review"
agent = "company-reviewer"
needs = ["implement"]
restart_from = "implement"
human_approval = true
[nodes.review.inputs.patch]
from = "implement.patch"
[nodes.review.outputs.review]
description = "Review evidence."
kind = "file"
[nodes.review.limits]
node_attempts = 2
contract_repair_attempts = 1
[outputs.patch]
description = "Approved patch."
from = "implement.patch"
path = "change.patch"| Field | Contract |
|---|---|
name |
Non-empty logical flow name |
limits |
Required retry budgets |
inputs |
Optional public input contracts |
nodes |
At least one node |
outputs |
Optional public publication bindings |
Unknown fields produce one aggregated warning per file and do not block parsing.
[inputs.brief]
description = "Approved brief."
accepts = ["text", "file"]Kinds are text, file, and directory. File and directory bindings must
exist inside the project and contain no symlinks. Every declared flow input is
required at compile time; undeclared bindings are rejected.
Node inputs are explicit:
[nodes.write.inputs.brief]
from = "$brief"
[nodes.review.inputs.document]
from = "write.document"$brief references a public flow input. write.document references a declared
output of another source node. A node-output reference automatically implies a
data dependency. needs may still state the same dependency for readability;
the compiler deduplicates it.
A node uses exactly one resource.
Action:
[nodes.write]
uses.action = "./actions/write.md"
agent = "writer"Nested flow:
[nodes.verify]
uses.flow = "company/verify"
[nodes.verify.inputs.change]
from = "write.bundle"
description = "Candidate selected for final verification."
[nodes.verify.outputs.evidence]
description = "Verification evidence used by this flow."
kind = "file"Process:
[nodes.compile]
uses.run = [
"via",
"flow",
"compile",
"{inputs.source}/flow.toml",
"--output",
"{outputs.graph}",
]
[nodes.compile.inputs.source]
from = "write.bundle"
[nodes.compile.outputs.graph]
description = "Compiled graph."
kind = "file"Virtual all-approved gate:
[nodes.review_gate]
uses.gate = "all-approved"
needs = ["architecture_review", "code_review"]
restart_from = "implement"Only action nodes declare agent. Every source node declares the inputs it
binds. Action and process nodes declare the outputs they produce:
[nodes.write.outputs.bundle]
description = "Generated source bundle."
kind = "directory"Output kinds are file or directory. A nested-flow call repeats the callee's
public output keys and kinds so the call contract is visible during manual
audit. Compilation rejects missing, extra, or mismatched output declarations.
Descriptions at the callsite explain the caller's use of each input and
output. The callee still owns its public contract.
Executable nodes may declare no outputs. This is normal for coding nodes whose result is a validated worktree side effect rather than a portable asset. Creating a Git commit is also an explicit project policy: if required, model it as a separate node after review or approval. Reusable software flows do not commit implicitly.
An action result may also return safe supplemental artifacts that were not
declared. They are retained as evidence and shown to downstream dependencies,
but they cannot be referenced by a static node.output binding or published
as a public flow output. This keeps the executable contract explicit while
allowing useful dynamic diagnostics.
uses.run is an argv array, never a shell expression. A path-like program must
be an executable regular file inside the project without symlinks; a bare
program is resolved through PATH at execution. Every declared run input and
output must appear as an {inputs.<key>} or {outputs.<key>} placeholder. The
program element itself cannot contain placeholders.
needs = ["prepare"]
restart_from = "prepare"
[nodes.review.if]
node = "prepare"
outcome = "approved"Dependencies must exist and be acyclic. A condition references a dependency
and matches its latest accepted outcome. A false condition makes the node
inapplicable without blocking terminal state.
restart_from must identify a strict ancestor. A restart result sends exact
review feedback and accepted artifacts back to that target. Unordered restart
nodes are rejected when either restart segment can invalidate the other;
ordered loops, independent branches, and branches proven mutually exclusive by
exact conditions remain valid.
An all-approved gate has at least two action dependencies and no agent,
inputs, outputs, conditions, approval, or limits. Its restart_from is a
common strict ancestor of every dependency. Dependencies return complete with outcome
approved or rejected: all approved completes the gate, while any rejection
restarts the target with the latest accepted artifacts from every dependency.
A blocked dependency leaves the gate pending and the run blocked.
Set human_approval = true on an action, process, or nested-flow source node
when downstream work must wait for explicit user confirmation:
[nodes.review]
uses.action = "company/review"
agent = "company-reviewer"
human_approval = trueCompilation lowers the declaration to an internal checkpoint after all
terminals of that source. Nested flows are otherwise fully inlined: they have
no independent run, publication root, or runtime boundary. human_approval
cannot be combined with if.
[limits]
node_attempts = 3
contract_repair_attempts = 2node_attempts >= 1: automatic semantic attempts per node.contract_repair_attempts >= 0: result-contract repair operations inside one node attempt.
Node [limits] may override either field. The CLI owns attempt numbers.
[outputs.bundle]
description = "Approved bundle."
from = "write.bundle"
path = "."from must reference a declared node output. path is a relative canonical
destination inside the run's publication root. path = "." publishes the
contents of a directory bundle. Runtime validation checks declared key,
presence, kind, containment, and symlink safety before accepting an output.
Only the root flow's public outputs are published. A nested flow's path
values do not create a nested publication root and are ignored after its
public output contract has been checked.
| Form | Resolution |
|---|---|
package/resource |
`.via/packages/package/{flows |
local/resource |
`.via/local/{flows |
./resource, ../resource |
Relative to the containing flow |
| absolute path | Only inside the project |
Namespaced locator segments use letters, digits, _, and -. Relative
locators may traverse only while remaining inside the project.
via flow validate company/change
via flow compile company/change \
--input task=file:task.md \
--input repository=directory:. \
--output graph.tomlNormal user execution uses via run create --flow ..., which performs
compilation internally and stores the graph inside the run. The explicit
compile command is for validation, package fixtures, and debugging.