Running workflows side by side
Fan a phase out into lanes, each running another workflow, then merge the results.
Some work splits cleanly. Ship the same feature on Android and iOS.
Try three approaches and compare. Run a security audit alongside the
implementation. A workflows step does that: each lane runs
another of your project's workflows, at the same time, in its own
container on its own branch.
- type: workflows
onLaneFailure: fail # fail (default) or continue
lanes:
- workflow: android-feature
- workflow: ios-feature
- type: prompt
prompt: |
The lane branches are fetched locally and described in
.peractor/lane/lanes.json. Merge both, reconcile the shared API
client, then run the suite and fix what breaks at the seams.
With one lane it is not parallelism at all but reuse — a shared test-pass or security-audit workflow dropped into ten pipelines instead of copy-pasted phases.
How the phase splits
The phase stops at the step, the lanes run, and it resumes at the next step once every lane has settled.
Nothing uncommitted survives that gap, and neither does the agent's session. The steps after the fan-out start fresh, and they learn about the lanes from what is put in front of them, not from memory.
What the next step gets
- Every lane branch fetched as a local ref, so
git diff,merge, andcherry-pickbetween them just work — they share a fork point. .peractor/lane/lanes.jsonlisting each lane's id, branch, status, whether it changed anything, and its summary..peractor/lane/<id>/report.mdfor each lane.
There is no mechanical merge action. The agent merges with plain git, guided by your prompt.
Lane names
A lane is named after the workflow it picks — Android feature becomes
android-feature, with -2 and -3
when the same workflow appears twice. The name ends that lane's branch
and labels its rows in the run, and you can type your own over it — which
is what tells three lanes on one workflow apart.
A lane already running keeps the name it started with, so renaming a workflow mid-run is safe.
When a lane fails
onLaneFailure: fail — the default — fails the whole step
if any lane dies. Shipping two platforms out of three and calling it done
is what that prevents.
continue lets the survivors carry on, and the failed lane
is still fetched and listed, because half-finished work is sometimes
worth salvaging.
While the step is open, each settled lane has a Run again button — not only failed ones, so a result you dislike can be redone. Once the step has finished you retry the whole phase instead.
Reviews and the board
Gates, questions, and previews are honoured per lane: a lane that needs you stops on its own while its siblings keep going, and you are notified per lane.
More than one lane can move the task's status. Which status a phase
sets is configured per workflow, so lanes running different workflows are
usually moving the task on different boards; where two really do drive
the same board, the last to finish wins. Set
ownsStatus: false on a lane — or on the component workflow
itself — for one whose progress should not show on the task at all.
What it costs
Lanes are real runs. Three lanes are three runs' worth of compute, counted against your quota, each taking a slot like any run — so a concurrency limit smaller than the lane count simply runs them a few at a time.
A lane's workflow may fan out again, bounded by one limit on the peak number of containers a single run can need. The editor totals it live and will not save over it, circular references are refused, and a lane can only reference a workflow in the same project.
Trying several approaches to one task and comparing them is a different feature: start parallel attempts from the task itself, each with its own workflow, prompt, model, or persona, and read the comparison panel when they settle. See The run lifecycle.