Skip to content

Designing pipelines

Writing good agents is about scoping one agent well. This guide is the same judgment call one level up: how many steps a pipeline should have, and which of VectorStep’s composition mechanisms — sequential, parallel:, fan_out:, or a sub-pipeline — fits a given decomposition.

The reason to split rather than cram two jobs into one step’s prompt isn’t stylistic — a step gets its own confidence score, its own verifier, its own grounding check, its own calibration bucket, its own row in pipeline_steps. A step doing two things blends two different decisions into one number, the same argument Writing good agents makes about agent scope, applied to pipeline structure instead. If a step’s prompt reads as “investigate X, then decide whether to Y,” ask what happens when it gets the first half right and the second half wrong — one confidence score can’t say that, but two steps can.

Sequential when order matters, parallel when it doesn’t

Section titled “Sequential when order matters, parallel when it doesn’t”

Use plain sequential steps when a later step genuinely needs an earlier one’s output — its summary, its next_step_context, a field from its own JSON. Reach for a parallel: group specifically when branches are independent and the branch set is fixed at authoring time: a fixed list of sources to check (runbook, Grafana, recent deploys), each contributing its own finding, joined back into one effective confidence before flow control applies. See Parallel groups & fan-out for the join strategies (all_must_pass, any_must_pass, weighted_average) that decide how those branch scores combine.

fan_out: is the dynamic version of the same idea, not a different idea — same join strategies, same confidence-then-flow-control shape, except the branch count is a list a step returns at runtime rather than something written into the YAML. Reach for it when you don’t know how many things there are to check until the alert tells you — see Fan out over multiple services for the mechanics and Designing dynamic fan-out for inferring that list well.

Reach for a sub-pipeline only when logic is genuinely shared

Section titled “Reach for a sub-pipeline only when logic is genuinely shared”

executor: pipeline isn’t just “more steps in a different file.” A sub-pipeline gets its own run_id linked back via parent_run_id, its own trace, its own row in pipeline_runs, and — if it’s promoted independently — its own stage. That independence is the whole point when the same multi-step logic (a shared triage phase, say) is called from more than one pipeline: each caller gets a real, queryable sub-run, and the shared logic can be tested and promoted on its own schedule.

It’s the wrong tool for making one pipeline’s own YAML shorter. A sub-pipeline used purely for readability inherits a real cost the split doesn’t buy back: cost/token accounting on the parent step only sees the sub-pipeline’s final step, so a multi-step sub-pipeline can silently undercount against a parent’s budget: guardrail — a real trap for a one-off cosmetic split, not just an edge case. See Chaining pipelines for that and the other gotchas (trigger matching, stage independence) that don’t show up until you go looking.

The step library is for repeated shapes, not for hiding complexity

Section titled “The step library is for repeated shapes, not for hiding complexity”

use: (see Step library) is the right tool when the same step config is genuinely reused across pipelines — the deep-merge on executor_config lets a dozen pipelines share an agent and session-key pattern while each overrides just a threshold or a prompt. It’s the wrong tool for making a single pipeline’s own YAML feel shorter by moving a one-off step somewhere else to look at less often. A step nobody else references gains nothing from living in the library except an extra file to open — and the step library’s own UI, which shows exactly which pipelines reference each entry, makes a single-use step easy to spot as never having been shared in the first place.

Every step is a calibration bucket that needs its own history before its confidence number means anything, a readiness tier that needs its own evidence before the pipeline can promote, a line in the Trust panel a human has to read during an incident. More granularity is only a win if each new step is actually a decision worth auditing on its own — not a reflex (“smaller steps are always better software engineering”). A step that never disagrees with the one before it, never gets its own verifier, and never shows up separately in an incident review is a step paying calibration and review cost without buying back any of the auditability point one above is about. When in doubt, start with fewer, coarser steps and split a step only once you can name the specific decision inside it that deserves a score of its own.

  • Parallel groups & fan-out — the mechanical reference for both composition mechanisms.
  • Step library — use:, deep-merge rules, and per-pipeline step analytics.
  • Executors — the pipeline executor’s full reference.
  • Chaining pipelines — the deeper hands-on guide for point 3 above, including the gotchas that don’t show up until you go looking (trigger matching, cost accounting, and stage independence between a sub-pipeline and whatever calls it).
  • Designing dynamic fan-out — the deeper companion for fan-out specifically, once the branch list is genuinely runtime-determined rather than fixed at authoring time.