Tasks, dependencies & parallelism
/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 cognitive aid 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 # one spec must land before anotherflowctl 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 | A whole spec needs another spec merged | Config migration before new command behavior |
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 whether a ready subset can run safely together, weighing 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 from the same execution wave.
- 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. /flow-next:work dispatches worker subagents with fresh context per task. Each worker re-anchors against the spec, task, and git state before editing. In a parallel wave, workers implement, test, commit, and return task-unique handovers without marking tasks done and without running plan-sync. The conductor joins the whole wave, integrates it, then runs the per-task review, completion, and tracker gates before deferred plan-sync runs.
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:impl-review fn-1/flow-next:work fn-2Keep 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.