The method
Connect
Say what each piece of work truly waits on, and nothing else. Readiness follows from that.
Connect records what each piece of work waits on, and nothing else. It produces edges between tasks, references to things outside the graph, and waits. From those, Flow computes what can start now (P5), so an honest edge is worth more here than a tidy one.
How to do it
Pick the weakest connection that is still true. How Flow works describes each one, and the vocabulary lists every kind.
| If the truth is | Record |
|---|---|
| B literally cannot start until A is done | A blocks B |
| A is the reason B holds, or the choice B records | A justifies B, or A decides B |
| A replaces B as the current version of the same thing | A supersedes B |
| A and B are related, or B builds on A but could start first | mentions, or nothing |
| The thing lives outside the graph: an issue, a PR, a commit, a URL | A reference on the task, with its role |
| A date holds the task | A scheduled wait with the date |
| A person or event outside your control, with no task, holds it | An external wait naming who or what, with until as the date to chase on |
blocks is the only edge that holds work up, so it is the one to be strict about. Every false blocks removes a task from the ready set for no reason.
Where a piece of work belongs is a different question from what it waits on. It is answered by which Flow project it is in and by its tags, and neither holds anything up.
No sub-tasks
There is no parent task and no nesting. An outcome is reached when the work that blocks it is done, and one piece of work can block several outcomes. Waiting on something is not the same as belonging to it, and a tree forces you to choose one parent when the truth is often two.
Moving work “into another feature” is not a restructuring either. You change what it blocks.
Decisions are tasks
An open question that holds work up waits on whoever answers it. Where it waits depends on how much it holds.
A question that holds one task is that task’s wait. The task moves to waiting, with an external wait on whoever decides, whose reason states the question, the options and a recommendation. The person answers by moving the task, or by telling the agent, whose move cites their words as its basis. The question, the answer and the move stay on the one task they are about, and nothing else needs writing.
A question that holds several tasks, or will decide later ones too, is a task of kind decision. It blocks everything that cannot proceed until it is answered, and closing it is what unblocks them, so there is no second step to remember. The answer goes in the decision’s outcome, and records that follow from it cite it with decides or justifies.
Decide, then build. A PRD waiting for sign-off, with the tasks that build it, is a decision followed by the work it decides. The decision is kept as it was answered while the work moves through its statuses, so they are separate records:
| Record | kind | status | Carries |
|---|---|---|---|
| “Which queue backs the export?” | decision |
waiting, with an external wait naming who decides |
the PRD as a spec reference |
| “Build the export job” | commitment |
active |
the same PRD, also as spec |
| “Build the export screen” | commitment |
active |
the same PRD, also as spec |
The decision blocks each piece of work. upsert-tasks writes all three, and the edges between them, in one call: each item gives itself a ref, and each work item’s link names the decision as { "ref": "decide" } because none of them has an id yet.
The decision waits on a person, so it is never offered to an agent as ready work, and the work behind it stays active and blocked:dependency. When the person answers, the decision closes as completed with the answer in its outcome, and the work becomes ready. A different answer later is a new decision that supersedes the first. It is never an edit.
Closing the decision frees the work whatever the answer was. If the answer is “don’t build it”, the work does not cancel itself, and an agent does not cancel it either: it proposes the cancel, with the decision as the basis. Decide, then build runs the whole sequence.
Standing rules for agents are decisions too (roles).
The person
- Settle the edges that are really decisions. “Should the export wait for the new schema?” is not a fact an agent can find. Answer it on the task that waits for it, or make it a
decisiontask that blocks both. - Decide what a cycle means. When two tasks block each other, one of those dependencies is wrong. Only you know which.
- Keep one task per piece of intent. When a change spans three repositories, ask for three references on one task, not three tasks.
The agent’s side is the protocol: GTF-N1 to GTF-N6.
Failure modes
blocksfor “seems related”. The ready set shrinks, agents sit idle, and nothing in the graph says why.- One task per repository. The intent splits into pieces that each look done while the whole is not. Use one task and several references.
- A dependency written as prose. “After #312 lands” in a task body, or in a wait’s reason, gates nothing and is computed by nobody. Make it an edge.
- Nesting by habit. Filing work “under” a feature as if it were a folder. Say what it blocks instead, and tag it.
In Flow
| To | Call |
|---|---|
| Link two tasks | update-tasks with links |
| Write several linked tasks at once, all or none | upsert-tasks |
| Withdraw an edge, keeping its history | retract-link |
| Point a task at an issue, PR, file or URL | update-tasks with references |
| Withdraw a reference | retract-reference |
| Set or clear a wait | update-tasks |
See the blocks graph as ordered waves, and any cycles |
get-order |
| Everything still open before one goal | get-order or get-next with upstream_of |
| Draw a neighbourhood of the graph | render-graph |
Links and references can also be written inline when a task is created with upsert-tasks, so “I finished A and two issues came out of it” is one call. Tasks that link to each other before any of them exists are the same call, each naming the others by ref.
Examples:
- Break a feature into waves: record what each piece truly waits on, and the order shows how many agents can start at once.
- File a milestone: name the goal, point the work at it, and “what is left” becomes a query.