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.
What makes a good task
Section titled “What makes a good task”- 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 behaviorThat 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”| Question | Source |
|---|---|
| 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 |
Dependencies
Section titled “Dependencies”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.
flowctl ready --spec fn-1flowctl next --json
flowctl spec add-dep fn-2 fn-1 # fn-2 builds on fn-1 and ships as a chain on its branchflowctl spec rm-dep fn-2 fn-1| Type | Use for | Example |
|---|---|---|
| Hard technical dependency | One task cannot compile or test before another | Data model before API route |
| Contract dependency | One task needs a stable interface from another | Backend response shape before UI |
| Review dependency | A risky decision needs approval before work continues | Security model before auth implementation |
Spec dependency (depends_on_epics) | A whole spec builds on another spec’s work | Config 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.
Running tasks in parallel
Section titled “Running tasks in parallel”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.
A worktree per cluster
Section titled “A worktree per cluster”When several agents need to edit simultaneously, give each independent cluster its own worktree:
| Worktree | Scope |
|---|---|
fn-12-api | Server contract, tests |
fn-12-ui | Client integration using agreed contract |
fn-12-docs | Docs 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 work
Section titled “Solo work”Solo concurrency is mostly about not losing context:
/flow-next:work fn-1/flow-next:work fn-2Review 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.
Signals to stop parallelizing
Section titled “Signals to stop parallelizing”- 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.