Plan design
How big should a task be in an agent plan
Everything you dislike about a run traces back to task size. A task that is too big burns an hour and fails at the end with a diff nobody can review. A task that is too small pays a full session to change one field. Size is also what decides how much can run at once, and what one failure costs.
Disclosure: I build Ordewell, so the rules below are the ones its planner is instructed to follow rather than a survey of the field. The tool is free and Apache 2.0.
The unit of size is one session
The natural limit is context. Each task gets a fresh agent session, so a task is sized to what one session can hold: the files it must read, the change it makes, and the check that proves it. Put more in and the session starts compacting, and the second half of the work happens without the first half in view.
That gives a test you can apply before anything runs. Could an engineer who has never seen the repo finish the task from the prompt plus the files it names? If the prompt has to say "then the same thing at the other eight call sites", it is too big.
Cut vertically, not by layer
The most common bad plan is a horizontal one. Take "let people export a report as CSV". A layer plan looks tidy: add the export types, then the serializer and the query, then wire it into the CLI command, then write the tests.
Every one of those depends on all the earlier ones, so nothing runs in parallel, and none of them produces anything you can look at. Task 2 cannot be reviewed alone because the thing it serializes does not exist yet. Task 3 is the first point at which the feature is real, and the diff you have to judge is the sum of three sessions.
A vertical slice is narrower and deeper. One task that takes the smallest real case end to end: export a two column report to a file, with a test that runs the command and reads the file back. Then a slice for escaping, then one for the wide case. Each is demoable, each has a check that means something, and the second and third can run together once the first landed. The test of a slice is that someone can run something and see the difference. If the only way to observe a task is to read its diff, it is a layer.
Small has a floor too
The other failure is twenty tasks that each change one file. Every task pays for a session, and the session repeats research an earlier task did and did not write down. The floor: if two adjacent tasks would touch the same function for the same reason, they are one task.
Put the enabling refactor first, as its own task
Some features are awkward because of the current shape of the code. The cheapest way through is a leading task that changes no behaviour and makes the real change easy: move the branch behind a function, extract the interface the new case needs, make the constant a parameter.
"Make the change easy, then make the easy change" works because a refactor has a crisp bar of its own, which is that the suite is still green. The feature slices also stay small enough to review, since they no longer carry a rewrite inside them. Dependent slices declare it as a dependency, so they start from a repository that already has the shape they need.
The exception: refactors that span the codebase
One class of work is the exception: a rename of a shared symbol, a column type change, anything whose blast radius is the whole repository. No narrow slice of it exists, since every slice touches the same wide set of files.
That work is sequenced as expand and contract. One task adds the new form beside the old and leaves both working. Then several migration tasks, each depending on that first one, move their share of the call sites over. A final task deletes the old form. The repository works at every boundary, so a failure in one migration batch costs one batch.
The graph you get is the dependency list you wrote
Which tasks run at once falls out of the dependency edges, so the edges have to mean something. Add an edge for genuine ordering: task B reads a module task A creates, or B runs the migration A ships. Do not add one because two tasks edit the same file. In an isolated run each task gets its own git worktree and lands as its own merge, so file overlap is a merge you handle at review time, not a reason to serialize.
There is one shared file trap worth knowing. Two parallel tasks that each append to the same changelog, registry or index list will race each other's merges even when they never touch the same source file. Give that edit to the final task, or order the two by a dependency.
The last edge is the one people forget. A plan where every task passed can still be a plan where the feature is not finished, because each task was verified against its own slice. The fix is a final task that depends on every other task and is judged by commands rather than judgement: the suite goes green, plus new tests written against the original goal and exercised end to end through the public interface.
make room, no behaviour change
"make-export-easy" deps: []
two slices, both after the layout
"export-small-report" deps: ["make-export-easy"]
"export-escaping" deps: ["make-export-easy"]
wide case, ordered so the shared file is appended once
"export-wide-report" deps: ["export-small-report"]
evidence, from commands and exit codes
"verify-export" deps: [all of the above]
Honest limits
- The planner proposes, you decide. The slicing rules are instructions to a model, not a proof, and a model will sometimes hand you a layer plan anyway. This is why the plan is an editable artifact: read the graph before you approve it, and fix the fields that are wrong.
- The dependency list is the failure surface. A wrong edge is either wasted wall clock or a task reading a repository without the work it assumed. Neither is caught by a check.
- Sizing by context is a proxy. Whether a session really fits is discovered by running it. A task that looks small can still send an agent down a long exploration path.
- More tasks means more merge work. Parallel slices land as separate merges you review. Isolation moves the pain from conflicts during the run to merges after it, and does not remove it.
- The final task is only as good as the suite. A repository with no tests gets a standalone verification script instead of a framework bootstrapped during verification, so that check is only as strong as the script.
Source and design notes
The rules above are the planner's own instruction set, not a summary I wrote afterwards: the plan prompts, plan validation, and github.com/ordewell/ordewell.