Skip to content

Tasks, dependencies & parallelism

For a ready spec with no tasks, /flow-next:work <spec-id> --no-plan is the default. Plan is chosen only on a positive signal: you asked for a plan, separate human owners will implement, or delivery is staged across several PRs. Risk, size, and file count never trigger plan on their own. Resolve material product or authority ambiguity through /flow-next:refine first; /flow-next:plan-review reviews the design before any tasks exist.

/flow-next:plan decomposes a spec into task files under .flow/tasks/. Each task is sized for one work iteration, declares its dependencies, and maps back to the spec’s acceptance criteria.

flowchart TB
  S["fn-1 add oauth"]
  S --> T1["fn-1.1 create schema"]
  T1 --> T2["fn-1.2 implement auth routes"]
  T1 --> T3["fn-1.3 add UI states"]
  T2 --> T4["fn-1.4 document setup"]
  T3 --> T4

Tasks carry acceptance mapping:

satisfies: [R1, R3]
requires: [fn-1-add-oauth.1]

The graph gives agents a deterministic execution order and gives reviewers traceability from requirement to evidence.

  • It satisfies a small, named set of R-IDs.
  • It has explicit dependencies.
  • It can be reviewed from one diff chunk or one module cluster.
  • It lists expected evidence.
  • It does not hide product decisions inside implementation instructions.

Naming the evidence before the task starts is what makes “done” concrete:

Evidence expected:
- Unit test for invalid dependency references
- `flowctl validate --all`
- Updated docs page for dependency behavior

That list is also what the PR briefing renders later.

What the plan should let a reviewer answer

Section titled “What the plan should let a reviewer answer”
QuestionSource
What can start now?Ready tasks with no unmet dependencies
What is blocked?requires edges
Which acceptance criteria are uncovered?Task satisfies mapping
Which tasks can run in parallel?Independent branches of the graph
Which files are high-risk?Plan notes and review findings

A task becomes ready only when all required tasks are done. Most of the time you see this through /flow-next:work; flowctl exposes the lower-level state.

Terminal window
flowctl ready --spec fn-1
flowctl next --json
flowctl spec add-dep fn-2 fn-1 # fn-2 builds on fn-1 and ships as a chain on its branch
flowctl spec rm-dep fn-2 fn-1
TypeUse forExample
Hard technical dependencyOne task cannot compile or test before anotherData model before API route
Contract dependencyOne task needs a stable interface from anotherBackend response shape before UI
Review dependencyA risky decision needs approval before work continuesSecurity model before auth implementation
Spec dependency (depends_on_epics)A whole spec builds on another spec’s workConfig migration before new command behavior

A spec dependency orders the work; it does not wait for the parent’s merge. Once the parent’s tasks are done and its branch is on origin, the dependent spec starts as a chain: its branch forks from the parent’s tip, its PR targets the parent’s branch, and the parent still merges first. A dependency whose parent is mid-work still blocks, as does one with two open parents (chains are linear).

Model real ordering constraints, and nothing else. Four common fakes:

  • “Alice owns this first.” That is assignment, not dependency.
  • “This seems easier first.” That is priority, not dependency.
  • “The agent might get confused.” Split or clarify the spec instead.
  • “Everything depends on setup.” If every task hangs off one setup task, the setup task is probably too broad.

A healthy graph has a small number of ready tasks: not every task ready, not every task blocked. Ready tasks should be independent enough to hand to separate workers or worktrees.

Waves are candidates, not a schedule. /flow-next:plan reports parallel candidates as execution waves; /flow-next:work decides at runtime what runs together. By default it uses a rolling scheduler: each time a worker returns, it admits the next ready task, in its own worktree. The wave loop, which joins a whole wave before the next, is the fallback for a task-id run, a sequential chain, or planSync.enabled. Either way it weighs dependencies, declared files, shared resources, worker capacity, workspace isolation, and integration risk. If the safe subset has one task, it serializes and says why.

flowchart LR
  Spec["Reviewed spec"] --> API["Worker 1: API"]
  Spec --> UI["Worker 2: UI"]
  Spec --> Docs["Worker 3: docs"]
  API --> Review["Impl review"]
  UI --> Review
  Docs --> Review

Parallelism is safe on:

  • Different specs on different branches.
  • Independent tasks on the same ready frontier.
  • Isolated mutable workspaces for concurrent writers.
  • Atomic claims, so no two workers own the same task.
  • A conductor-owned join and integration step.

Worker isolation. One task is built inline by your conversation. Several tasks, or a task you send to a chosen model, go to worker subagents with fresh context per task. Each worker re-anchors against the spec, task, and git state before editing, then implements, tests, commits, and returns a task-unique handover without marking the task done. The conductor integrates each handover and runs the per-task review and tracker gates, then completion review once every task is done.

A successful task claim is an ownership lock, not a filesystem or Git lock. If two tasks touch the same high-churn module, share mutable resources, or cannot get isolated workspaces with a safe integration path, prefer serial execution or split the boundary first.

When several agents need to edit simultaneously, give each independent cluster its own worktree:

WorktreeScope
fn-12-apiServer contract, tests
fn-12-uiClient integration using agreed contract
fn-12-docsDocs and examples

Join all workers before integrating. Merge back through the same spec branch, complete the normal per-task gates, then run /flow-next:spec-completion-review after integration, which is where cross-task drift gets caught.

Solo concurrency is mostly about not losing context:

Terminal window
/flow-next:work fn-1
/flow-next:work fn-2

Review already runs inside work, by risk, so there is no separate review step.

Keep one spec in active implementation unless the second is truly isolated. If you switch, re-anchor before editing: read the spec, ready tasks, branch diff, and current review receipts.

  • Two workers repeatedly touch the same files.
  • Review findings mention conflicting assumptions.
  • A task needs a product answer that is not in the spec.
  • Tests only pass in one worktree.
  • The PR body cannot explain acceptance coverage cleanly.

When these show up, serialize the risky part and improve the spec before restarting.