# Tasks, dependencies & parallelism

Source: https://flow-next.dev/guides/tasks/

How a spec becomes an execution graph, what makes a good task, how dependencies gate work, and when parallel workers are safe.

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`](https://flow-next.dev/skills/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.

```mermaid
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:

```yaml
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

* 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:

```md
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

| 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

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

```bash
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
```

| 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](https://flow-next.dev/skills/make-pr/#dependent-specs-chains-and-stacks): 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

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.

```mermaid
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

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`](https://flow-next.dev/skills/spec-completion-review/) after integration, which is where cross-task drift gets caught.

### Solo work

Solo concurrency is mostly about not losing context:

```bash
/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.

### 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.
