Flows
A flow is a named, ordered composition of tools: a plan that says "read the document, run these steps in this order, write the result." A tool does one thing. A flow assembles several into an end-to-end workflow (leverage from memory, look up terminology, translate the remainder, check quality) and gives it a name, so you can run it again and share it.
A flow describes the chain, and the pipeline executor
runs it concurrently. kapi flows and the Command Reference list
the flows that ship in a given build.
In the CLI, a flow is the abstraction behind kapi run <flow>: one named
flow, one pass. kapi up loops the project's default flow (defaults.flow,
or the built-in default when none is set) until the project's gates are met.
Understanding the CLI layers explains how the
two verbs relate and where the raw tool layer sits.
A flow is a sequence of tools
At its simplest, a flow is a list of tools that Parts stream through in order. The framework models this directly:
type Flow struct {
Name string
Tools []tool.Tool // for single-document / sequential execution
ToolFactories []ToolFactory // for parallel: a fresh tool chain per document
}
The Builder provides a fluent API for assembling one in Go:
f, err := flow.NewFlow("translate").
AddTool(tools.NewMemoryLeverageTool(memoryCfg)).
AddTool(terms.NewTermLookupTool(tb, termCfg)).
AddTool(aitools.NewAITranslateTool(provider, translateCfg)).
AddTool(tools.NewRuleCheckTool(checkCfg)).
Build()
A flow built this way holds concrete tool instances. For running the same flow over many documents at once, a flow can instead hold tool factories: each document then gets its own fresh tool chain, so per-document state never leaks between concurrent runs.
The two authored representations
A flow can be authored in two equivalent forms, and both compile to the same executable graph.
Steps: the human-authored form
The steps format is a YAML list of tools. It is the form people write by hand:
steps:
- tool: recycle
label: Apply memory matches
config:
fuzzyThreshold: 70
- tool: translate
label: Translate the rest
config:
provider: anthropic
- tool: qa
label: Quality checks
Each step names a tool and optionally configures it. Steps run sequentially: each tool's output channel feeds the next tool's input channel. At run time the flow above becomes this chain, with the ends bound when you run it:
A flow carries only its steps. Where content comes from and goes to is a binding you choose when you run it (see Source and sink).
A project declares its flows in kapi.yaml, inline under flows:, or as one
steps file per flow in the directory the recipe names with flows_dir: (see
Flow files). kapi flows lists both
kinds beside the built-in flows, and kapi run <name> runs either over the
project's collections.
A check such as qa is a read-only step. It attaches
findings to each block as annotations and leaves the content as it is, so it
usually sits last, where a CI gate reads its result.
To run several checks, list them in order:
steps:
- tool: create-target
config: { copySource: true }
- tool: qa
- tool: term-check
- tool: xml-validation
Transformers
Some tools rewrite the source itself: redaction replacing sensitive spans with placeholders, a simplifier rephrasing for clarity, a normalizer. These transformers are ordinary steps in the same ordered list as everything else:
steps:
- tool: redact # rewrites the source in place
- tool: translate # translates the redacted source
- tool: qa
A transformer is a read-only edit producer. It returns an edit plan, and a single framework-owned applier performs the rewrite atomically: it applies the edits, rebases surviving run-anchored overlays (segments, term and entity spans) onto the new runs, vaults any secrets fail-closed, and bounds-checks the result. Because the applier mutates inline and in order, each transformer settles the source before later steps observe it.
A placement pass checks the step order of every flow at build and load
time. It rejects a transformer placed after a step that produces a
committed target (rewriting source would orphan the targets; unredact is
exempt because it rewrites both sides), rejects a recoverable transformer such
as redact placed after a step that sends source to a remote service (except
a step producing an input the transformer's configuration requires), and warns
when a transformer sits later than its earliest valid slot, since every
overlay present at apply time must be rebased. See
the tool system AD for the model.
A flow that declares the removed source_transforms: field is rejected at
load with a migration error: list the transformers as ordered steps instead.
Graph: the canonical form
Internally a flow is a directed graph of tool nodes connected by edges:
type FlowDefinition struct {
ID string
Name string
Nodes []FlowNode // tool nodes
Edges []FlowEdge // directed connections
}
The graph is what the visual flow editor reads and writes. Compilation from
steps to graph is mechanical: StepsToGraph creates a tool node for each step,
chained by edges. Cycles are rejected, and kapi runs the tool nodes as one
ordered chain, each tool's output feeding the next. The flow's ends (where
content enters and leaves) are bindings, covered next.
Because both forms compile to the same graph, the steps you write by hand and the graph you build in the editor are interchangeable: a hand-written flow opens in the editor, and an editor-built flow runs from the CLI.
Assemble a flow in the same node editor the desktop app uses (add, remove, and
reorder tool nodes), then press Run flow to execute it on a file and step
through the result. The graph is serialized to a kapi.yaml recipe and run with the
real kapi engine in your browser via WebAssembly.
Source and sink: the flow's ends
A flow processes a stream of blocks; where that stream comes from and where the
result goes are its source and sink bindings. The same flow runs over a
loose file, the blocks already in a project, a .kpz workspace, or content
imported from an interchange file; only the binding changes:
| Binding | As source | As sink |
|---|---|---|
file (default) | read + parse a file | write a file (round-trip via skeleton) |
store / kpz | existing blocks + overlays | commit overlays; no file |
| interchange | import from XLIFF / PO / a bilingual .kpz | emit interchange for a translator |
none | (none) | discard (analysis / checks only) |
Bindings are resolved when you run the flow, by precedence: an explicit -i / -o
flag, then the project or .kpz you're in, then the flow's own intent, then
auto-detection from the path. A plain path is detected (.kpz → workspace,
.xliff → interchange, a document → file); a scheme: is explicit
(-o store:, -o xliff:hand.xliff). kapi run <flow> --explain prints the
resolved source → sink without running anything.
A flow declares only intrinsic intent (a check flow that produces no document
sets sink: none), never a path. Inside a project, a run with no -o
lands its work in the store (process-only); kapi merge materializes files when
you're ready. See E-04 for the
full model.
Running a flow
A flow is run against a source. The runner resolves the source and sink bindings,
instantiates the tool chain, and hands it to the executor. Composed (multi-tool)
flows run with kapi run; single-tool flows are exposed directly as their tool's
command:
# Run a composed flow (two or more tools) on a file
kapi run translate-qa -i app.xliff --target-lang fr
# List the composed flows available in this build
kapi flows
The demo below runs the pseudo-translate flow: source → pseudo-translate → sink. Because it is a single-tool flow, it is invoked directly as kapi pseudo-translate. The left pane is the CLI invocation; the right pane is the
framework's result, the same file with its source strings replaced by accented
look-alikes:
Built-in flows
The framework ships a set of built-in flows covering common workflows:
AI translation, AI translation with a quality pass, pseudo-translation for
layout testing, memory leverage, rule-based checks, a redact-translate-restore flow
for sensitive content, and media-to-subtitles flows that
turn audio and video into translated subtitle tracks (see
Translate audio & video). For the full list,
run kapi flows or see the Command Reference; both are generated
from the live flow set.
Related reading
- Tools: the units a flow composes.
- Pipeline: how the executor runs a flow's graph concurrently.
- Flow Authoring: the full steps-format reference and more examples.