Your delivery process is a numbered list in an onboarding document. Seven steps, all correct, written by somebody thorough. Everybody follows it, roughly, and the roughly is where the last two incidents came from.
Ask three people to walk you through it and you get three walkthroughs. Nobody disagrees with the list. A list you read is a list you rebuild from memory the next time, and what gets dropped in the rebuild is always the step whose purpose is least obvious from its name. Hand the same list to an agent and it does the same thing, faster, on every ticket.
A document is read, a command is run
The fix is not a better-written list. A better list is still read once and reconstructed forever after, and the reconstruction is where the variance lives. What changes the outcome is making the sequence something you invoke instead of something you recall.
| a document | a command |
|---|---|
| tells you the order | is the order |
| is followed roughly | runs exactly |
| goes stale in silence | breaks loudly when a step it names disappears |
| gets better when someone rewrites it | gets better when someone fixes a step |
The last row is the one that compounds. A process living in prose improves only when somebody sits down to improve the prose, which is nobody’s job. A process living in a file next to the code gets fixed by whoever just tripped over it.
The whole delivery loop, behind one word
Here is a real one, from deskspace. The entire prompt for a feature is an issue number:
/flow gh#42
Everything else is already in the repository. The issue carries the requirements
and the test scenarios. CLAUDE.md carries the architecture and the conventions.
The gates carry the definition of done. What the command file adds is the order,
and the order is not negotiable:
1. Brief issue_context.py validates and extracts the ticket
exit 1 -> not implementable, stop, do not repair the ticket
exit 2 -> tier 3, plan only, wait for a human
2. Plan requirement -> scenario -> test table, blast radius, arch check
3. Implement tech-lead subagent, test-first, enforced by a hook
4. Review reviewer subagent, read-only, requirements against tests only
5. Cycle bounded at 3 rounds, then escalate
6. Gate ./mvnw verify, then ./mvnw -Pmutation verify
7. PR pr.py create, because gh pr create is denied
Step one is the interesting one. Before a single token is spent on the work, a script decides whether the ticket can be worked at all: no context, no numbered requirements, fewer scenarios than requirements, no risk tier, and it exits non-zero. The agent is instructed not to fill the gaps by guessing, which is what it would otherwise do beautifully and invisibly.
What the file deliberately leaves out
Notice what is not in the sequence. Nothing about how to design the validator. Nothing about which package the change belongs in. Nothing about whether a requirement and its scenario actually describe the same thing, which is the one question in the whole loop that no script can answer and the one the plan step exists for.
That is the split, and it is the test of whether the line was drawn in the right place. The order is fixed because ordering is decidable. The semantics of a ticket are not, so they stay with a person or with the model, and the workflow says so out loud rather than pretending a checklist covers it.
Choosing a tool that can refuse removes one way to be wrong about the input. Naming a sequence does the same for the order. Both leave the interesting part untouched, and if encoding the sequence also encoded an opinion, the opinion did not belong in it.
What it replaces
Without the command, the same ticket starts with an agent reading the issue,
inferring what “done” means, globbing the source tree to work out where Pet
lives, and choosing its own order. It usually gets there. The variance is in
which steps it skipped and whether anybody noticed.
# before: the sequence is in somebody's head, so it is rebuilt per ticket
read the issue, guess the missing requirement, find the package,
write the code, write a test afterwards if the loop ends early enough,
open a PR whose description omits two of the four scenarios
# after: the sequence is a file, and the file is the prompt
/work gh#42
The saving is not the typing. What changed is that the set of steps which definitely ran is the same set on every ticket, and the PR that comes out is refused by a tool if it omits a scenario, rather than merged because nobody cross-references four Gherkin blocks against a markdown table at six in the evening.
Only name a sequence you have already run
A command freezes an order, and freezing the wrong order is worse than having none: it is a guess that now looks official. The test is boredom. When you have run the same steps enough times that the order is dull, that dullness is the signal it is ready to be written down and stopped being thought about.
Until then it is still a decision, and decisions belong to people.
If your delivery process lives in an onboarding document that everybody follows roughly, that’s the work I do.