Date: 2026-06-03 Status: Accepted
Context
The surveyed Claude Code Workflows-style patterns expose a useful product shape:
describe a set of delegated agent tasks, run what can be parallel, wait for dependencies,
and synthesize the result. The weakness is that many implementations leave the actual
scheduler in prose. Dependencies: are labels the model reads, not edges the runtime
enforces. Read-vs-write safety is also left to human judgement or prompt convention.
Pixir already has the lower-level primitive needed for a stronger version: ADR 0011
Subagents are supervised child Sessions with explicit lifecycle tools, isolated
workspace snapshots by default, compact terminal summaries, and canonical
subagent_event evidence in the parent Log.
The open question is how much engine to add now. The earlier design note proposed a
larger Pixir.Scheduler with path-level write-set derivation, typed returns, and
possible future worktree merge-back. That is directionally right, but too large for a
first accepted surface.
Decision
Pixir adds Workflows as a deterministic runtime plan over existing Subagents.
A Workflow contains ordered step definitions with:
- a safe unique step id;
- a task prompt;
- an Agent role;
- structural
depends_onedges; - a derived posture:
read_onlyorwriter; read_setandwrite_setpath metadata;workspace_mode, defaulting tosharedfor read-only steps andisolatedfor writers.
Pixir.Workflows validates the graph before execution. Unknown dependencies and
dependency cycles fail early with ADR 0005 structured :invalid_args errors.
The scheduler is greedy and deterministic. A step becomes runnable only after all of its
dependencies have completed. Pixir starts as many runnable steps as fit under
max_concurrency, excluding any step that conflicts with already-running or same-wave
steps.
Conflict semantics are intentionally conservative:
- read-only steps have an empty write-set and may fan out together;
- writer/writer steps with overlapping write-sets serialize;
- shared-workspace writers conflict with readers whose read-set overlaps;
- isolated writers do not block readers because they mutate a child snapshot;
- a writer without an explicit write-set claims the whole workspace (
**/*).
Execution routes through the Subagents manager; Workflows do not start Sessions or Tasks directly. This preserves the single concurrency/lifecycle authority from ADR 0011: the Manager still owns child Sessions, max thread enforcement, timeouts, lifecycle events, and terminal summaries.
The model-facing surface is run_workflow, an ADR 0005-compliant Tool with dry_run/2.
It is permissioned as a mutation because it creates Subagent lifecycle state. In
:read_only mode it is denied; in :ask mode it asks; in :auto it runs.
Workflows v1 does not add a new canonical workflow_event. Durable evidence remains
the existing canonical subagent_event lifecycle entries recorded by ADR 0011, plus the
structured result returned to the caller. A future ADR may add durable workflow-level
events if Pixir needs mid-workflow resume, forkable workflow graphs, or audited workflow
decisions.
Consequences
- Pixir gets a practical version of "Workflows" without importing prose queues or a second orchestration runtime.
- The user/model can express dependencies as edges instead of hoping a dispatcher obeys textual labels.
- Read-only fan-out is cheap and explicit, while overlapping writers are serialized before they can collide.
- Writers remain safe by default because they use isolated child snapshots.
- Results are still compact prose summaries, not schema-validated typed values. Typed outputs remain future work.
- Merge-back from isolated writer snapshots remains future work. Workflows v1 can run writer subagents safely, but does not claim to automatically merge file changes back into the parent workspace.
- Whole-workflow resume is not guaranteed in v1. Parent Logs preserve child lifecycle facts, but an interrupted Workflow call itself is not yet a replayable canonical graph.
Verification
The no-network verification surface is:
mix test test/pixir/workflows_test.exs test/pixir/tools_test.exs test/pixir/permissions_test.exs
mix pixir.smoke.workflows --dry-run --json
mix pixir.smoke.workflows --json
The smoke task proves the accepted contract: structural validation, parallel read-only steps, serialized overlapping write-sets, dependency summary collection, and canonical Subagent lifecycle evidence.
The real-network smoke surface is intentionally separate and should be run manually:
mix pixir.smoke.workflows_real --dry-run --json
mix pixir.smoke.workflows_real --scenario micro_parallel --json
mix pixir.smoke.workflows_real --scenario dependency --json
mix pixir.smoke.workflows_real --scenario writer_controlled --json
It writes durable local evidence under .pixir/smoke/workflows-real/, keeps dry-run
offline and no-write, and reports actionable JSON errors for known failure modes such
as subagent step timeouts and Provider transport failures.
References
- ADR 0003: stateless Turns; local Log is source of truth.
- ADR 0004: unified Event envelope and canonical vs ephemeral events.
- ADR 0005: tool ergonomics, dry-run, structured errors, I/O discipline.
- ADR 0006: permissions and read-only posture.
- ADR 0011: BEAM-native Subagents as supervised child Sessions.
docs/design/0001-subagent-scheduler-write-set-orchestration.md.