Milestone Plan
Ask an agent for the whole app and you get an unreviewable blob that sort of works. It runs. It demos fine. Then you open the diff, find forty files you have never seen, realize you have no way to tell which parts are right, and accept all of it because the alternative is reading forty files. Ask for one milestone against a spec and you get a diff you can actually judge, in an afternoon, with a test suite that tells you whether it landed.
A milestone plan is that list of slices, in order, written before the first one starts. Each row names what gets built, what a person can see or hear when it is done, and the gate that has to be green before you are allowed to move on. It is the difference between a project with a shape and a project that is just a pile of prompts in chronological order.
8BEETY went M0 through M9: scaffold, MIDI import, the compiler, poly modes, the UI, the Game Boy chip, exports, regions, chord assist, polish. Post-launch work used the same structure. Every one of those milestones ended with the full test suite and a production build green, which is the only reason M8 was a feature and not an archaeological dig.
# Milestone plan: [project name]
Spec: `SPEC.md`. Every deliverable below points at a section of it, and the
acceptance criteria live there, not here.
| ID | Deliverable | Ships | Green gate |
| --- | --- | --- | --- |
| M0 | Scaffold: repo, toolchain, test runner, build, one placeholder screen | The app runs and shows an empty state | `[test cmd]` and `[build cmd]` green; app boots clean |
| M1 | [get real input into the system: import, ingest, auth, whatever the front door is] | [what a person sees: "the file loads and its contents show up on screen"] | `[test cmd]` + [named check, e.g. a fixture round-trips] |
| M2 | [the core transform: the part that is actually your product] | [the first output that is recognizably the real thing] | `[test cmd]` + [the spec's acceptance check for this milestone] |
| M3 | [the second mode or the second entity, once the first one works end to end] | [what changes on screen] | `[test cmd]` + [named check] |
| M4 | [the real UI, replacing whatever placeholder got you this far] | [a person who has never seen it can operate it without you] | `[test cmd]` + [manual pass: someone else drives it] |
| M5 | [the way work leaves the system: export, publish, send, deploy] | [a file, a link, or a record that exists outside the app] | `[test cmd]` + [the output opens correctly in [the real target]] |
## Standing rules
1. One milestone at a time. You do not start M3 because M2 got boring.
2. Every milestone ships something a person can see, hear, or click. "Refactor
the service layer" is not a milestone, it is a task inside one.
3. Every milestone ends with the verification commands actually run, with the
real output pasted. An agent reporting "all tests pass" is a claim, not a
result.
4. A milestone you cannot describe in one sentence is two milestones. Split it
before you start, not halfway through.
5. M0 is always scaffold. Nothing else is allowed in it.
6. When a milestone is done, the spec's acceptance criteria for it are checked
off in the spec, and the next milestone starts in a fresh session.Adaptation notes:
- Size a milestone by trying to write its deliverable in one sentence with no "and". If the sentence needs an "and", you have two milestones and you will find that out later at a worse time.
- M0 is always scaffold, and it is always worth its own slot even on a small project. It is the milestone that proves your test command and your build command exist and pass, and every later gate is written in terms of those two commands.
- When a milestone turns out to be two, stop and split it in the plan file before continuing. Renumber, or add M4a and M4b if renumbering would break references you have already written. Do not quietly let it grow, because the gate at the end of an oversized milestone is the one you will be tempted to skip.
- The "Ships" column is the one people leave blank, and it is the one doing the most work. If you cannot name what a person perceives at the end of a milestone, you have planned a chunk of code rather than a slice of product.
- Keep this file in the repo next to the spec and update it as you go. It doubles as the status report anyone can read without asking you how it is going.