11. The queue and milestones
After this chapter you can read a queue and write a milestone paragraph a person can check.
You can also write a line as one sentence with its suffixes, order a milestone so that its order is its priority, write on a line which line must be done before it, · after <slug>, add a line in the milestone whose paragraph needs it or under the next one, move or change a line by conversation, and turn a code change asked outside /apply into a line and a draft for its page.
And you can say what the smallest delivery costs, from its line to its commit.
The problem
A team that keeps its plan in a tracker, its decisions in a chat and its progress in someone's head cannot answer "what is left, and what was done?" without a meeting. An agent cannot answer it at all: it knows nothing at the start of a session, so what is not written where it reads does not exist for it. The queue is one file, docs/06, that says what comes next, what is in flight and what was delivered, in an order a person and an agent both read.
The line
docs/06 holds the project's milestones, each with a paragraph saying what is true when it closes, and under each one line per delivery, in order.
A line is the mark, the slug, its token when it has one, two letters that say whether its /propose and its /apply may run while the lines above it are in flight (chapter 14), one sentence of what the delivery gives, and its suffixes, such as · after <slug>, which names a line that must be done before it:
[ ] <slug> (PA) <what it delivers, one sentence> · after <slug>
The slug is the delivery's name, in lowercase words joined by hyphens (chapter 12).
It names the delivery's page, work/<slug>.md, and it is the argument of the commands, /propose <slug> and /apply <slug>, so the line, the page and the commands all point at the same delivery.
The kit asks for one sentence, and what happened goes on the page, because /propose reads the whole queue before it defines a delivery: every word on a line is read by every definition.
On Ninjobs I let the lines grow: its queue held 102 deliveries in 1,711 lines, 1,052 of them continuations of a line, decisions that belonged on the pages.
A line that grows into a paragraph is a decision in the wrong place, since the page is where the next session looks for it.
The marks
A line has one of six marks, which says where its delivery stands.
This chapter needs two of them: [ ], not yet defined, the delivery has a line and no complete page, though a draft of one may wait in work/ (below); and [x], done, it was built and its page moved to work/done/ (chapter 13).
The other four, [~], [>], [*] and [?], are chapter 14's: what each means, who sets it and at what moment, when a line is free to start, and how a line waits and leaves [?].
A line never leaves the queue; it changes mark and keeps its sentence.
So the queue is also the history of what was delivered, in the order it was planned, and what happened is on the page in work/done/ behind each [x], never added to the line.
On trunk the page waits uncommitted between the two commands, and /apply reads it from the working tree, so a fresh session finds it whether or not it was committed (chapter 18).
This is the lending library's first milestone some days into the work, written for this chapter:
## Milestone 1: a librarian lends and takes back
When it closes, a librarian can register books, their copies and members,
lend a copy to a member for 21 days and record its return; a member with
an overdue book or a suspended membership is refused.
```
[x] skeleton empty app and server, npm run verify, first screenshot
[x] catalog the librarian registers books and their copies
[x] members the librarian registers, suspends and reinstates members
[>] lend-book the librarian lends, and the rules may refuse
[ ] return-book records a return · after lend-book
[ ] m1-review the milestone checked against its paragraph
```
Anyone can read the state from it: three deliveries done, lend-book is completely defined and waits for /apply, and two lines are not defined yet, of which return-book comes after lend-book, since a copy is returned only after it was lent.
Milestones
The paragraph is a test
A milestone's paragraph says what is true when the milestone closes, in sentences a person can check against the running product. It is a test, never a theme and never a list of the lines under it: "a librarian can lend a copy to a member for 21 days" can be checked, "loans" cannot. Every sentence of the paragraph should have a line that makes it true, and every line should serve a sentence; a sentence with no line, or a line with no sentence, is a queue to fix before the work starts.
Size and order
A milestone starts with the lines its paragraph needs, then its review; for the first milestone the kit asks three to eight deliveries.
The first ones are the skeleton the others stand on: the library's skeleton creates npm run verify, which every later delivery runs.
Then each line comes after the lines it needs: a librarian cannot lend a copy before the catalog holds copies and the members exist.
Lines are added while a milestone runs: a fix a delivery finds outside its page, the review's findings, a problem you find trying the product.
So a milestone closes larger than it started, and the queue changes with the work.
This book's own queue shows it: its milestone M15 closed with 42 lines; its review was the 14th, with 28 under it.1
An agent asked about a problem tends to answer with lines, each one reasonable, so without a person judging, a milestone grows without end.
The paragraph decides where a line goes, whoever adds it, you or the agent: a line that a clause of the current milestone's paragraph needs goes in that milestone, and any other goes under the next milestone, which the agent creates when there is none, with a paragraph the line answers and its review last.
On the lending library, once return-book is built, you try the product and find that a copy whose loan is overdue cannot be taken back; the fix, a line written for this chapter, fix-overdue-return, stays in milestone 1, above m1-review, because the paragraph promises to record the return.
A finding of the milestone's own review stays in its milestone too, under the review, even when the next milestone is already in the queue (below).
What you decide is the paragraph: a line enters the current milestone only through a clause, so to bring one in you widen the paragraph by conversation first, and the line then answers the new clause.
The order is the priority. Asked which delivery matters most, you answer from the queue: the one higher in it; the next delivery is the first one free to start (chapter 14). There is no priority field and no label to keep in step with the order.
When you add a line and already know it needs another done first, you write that with it, at the end: a return needs a loan, so return-book ends with · after lend-book.
That is an order, not a wait: the line keeps its mark, [ ], and is free to start once lend-book is [x].
lend-book carries no after: the lines it needs, catalog and members, are already [x].
The review, and its findings
A milestone is planned with its review as its last line, <milestone>-review, a delivery like the others, which takes the paragraph clause by clause (chapter 15).
It fixes nothing: a person tests each clause by hand and, on the person's word, the code changed since the milestone's base is read by whoever the Milestone review slot of the project's docs/05 names, when it names anyone, the host's deep review or one read-only agent per area, and either way a checker marks each candidate before the person sees it.
Each finding becomes a [ ] line in the same milestone, under the review line, even when the next milestone already holds lines, and those lines get no second review.
Changing the queue
No command owns the queue.
A new idea becomes a line by conversation, in any session: you tell the agent, and it writes the line, with a new slug and [ ], in the milestone whose paragraph needs it, or under the next one.
The code has one owner, /apply, the command that builds a delivery (chapter 13).
A change to it asked in any other session, however small, becomes a [ ] line: the agent writes the line, writes in a draft page what you said that the line cannot hold, says so, and the answer stops there, with no file of the app changed.
Asked in an ordinary session to show the due date on the loan screen as day/month/year, and told how it should look on a narrow screen and that the catalog keeps the ISO form, year-month-day, the agent writes a line, due-date-format, and looks for where it goes.
No clause of milestone 1's paragraph needs it: the paragraph promises a loan of 21 days and a recorded return, not how a date reads.
So the line does not go above m1-review, as if arriving now made it part of the milestone; it goes under the next milestone, and with none in the queue the agent creates one, with a paragraph the line answers and its review last, written for this chapter:
## Milestone 2: loan dates read at a glance
When it closes, a member reads the due date on the loan screen as
day/month/year, on a narrow screen too.
```
[ ] due-date-format the screen shows the due date as day/month/year
[ ] m2-review the milestone checked against its paragraph
```
Milestone 1 keeps its lines, their order and return-book's · after lend-book; milestone 2 comes after it, so its line comes after all of them in priority, and the paragraph the agent wrote is yours to read and correct, like any change to the queue.
The narrow-screen rule and the catalog exception do not fit the line's one sentence, so they go into a draft work/due-date-format.md, and the answer stops there, naming /propose due-date-format, written as your host invokes it; a request the line holds whole gets no draft.
The draft is where the detail waits, and you choose where /propose due-date-format runs: in this session, whose conversation the draft already holds, or in a fresh one; either way it writes the page (chapter 12 shows /propose), and nothing you said is said twice.
The line stays [ ] with the draft beside it: a draft in work/ is not a definition, and /apply builds only a line /propose has marked [>] (chapter 14).
Saying "define it now" is the first choice: you name /propose due-date-format in your message, and it writes the page with everything said in this session still in the window, so the page must hold every decision the build needs, including what only this conversation supplied, because /apply runs in a fresh session, whose window holds the rules file, the documents and the page and nothing of this conversation.
If you choose a fresh session instead, /propose reads the draft and the documents and asks only what they leave open, never a question the draft already answers; in both, you read and correct the page in the conversation that wrote it.
A change this small still goes through the whole method, and this is what it takes.
/propose due-date-format reads the project's documents and the draft and writes this page, written for this chapter:
# due-date-format
**Objective.** A member sees a loan's due date as day/month/year on the
loan screen.
**Behaviour.**
* A loan due 2026-03-05 shows 05/03/2026, on a narrow screen too.
* A loan with no due date shows nothing where the date would be.
**Contract.** None.
**States.** The defaults.
**Visual reference.** None.
**Out of scope.** The catalog's dates, which keep year-month-day; the
overdue list's dates, a line of its own.
**Done when.** The two Behaviour lines pass as tests; verify green.
Every section is there, and three of them say only that they do not apply; the two details of the draft are a Behaviour line and an Out of scope item.
You read the page and correct it in the session that wrote it, and in a fresh session /apply due-date-format builds it: it changes the function that formats the date on the loan screen and writes one test with the two Behaviour lines, about five lines between them, runs verify until it is green, moves the page to work/done/, stages the two files with the page and the queue line, and suggests the message, also written for this chapter (chapter 13 explains its shape):
Show the due date as day/month/year
- Show nothing where a loan has no due date
work/done/due-date-format.md
You review a diff of a few lines against a page you already read, and commit it; the line now reads:
[x] due-date-format the screen shows the due date as day/month/year
That is what the rule cost: two short sessions, one review and one commit.
In return the queue says the change exists, the page says what it does and what it leaves out, and a test fails if the format ever changes back.
An edit made on the spot would have skipped the line, the page, the test and the review.
The page is as short as its change: seven sections of a line or two, and a page that needs more for a change this size is defining more than one delivery.
The rule holds in every session: during /propose the change is a new line, unless you ask for it on the page being written; during /apply, a fix found outside its page becomes a [ ] line, and only a fix the delivery needs first goes above it and makes it wait (chapter 14); and an edit made anyway, to "just change the label", is reverted before anything is committed.
Documents still change by conversation, in any session; the rule covers the code: the app's source, its tests, a migration, its configuration.
A milestone's paragraph or a line's description changes by conversation too, and the slug stays, since a page or a commit may already use it.
Moving a line up or down is changing its priority, and it happens the same way: you ask the agent to move it.
A move keeps the line's · after and re-judges the tokens the change affects, its own and those of the lines it passed, whose lines above changed (chapter 14), and a line moved into the current milestone needs a clause of its paragraph, or a paragraph you widened first, so a move never changes what a milestone promises without a word.
Lines also come from a milestone's review and, on an existing project, from its issues or roadmap.
You read the change before you commit it, as with every document, and nobody edits the queue by hand.
What the team gains
The queue is the team's shared status board and its history in one file: what is next, what is in flight, what was done and in what order, readable by a manager without a tool and by an agent at the start of every session. On Ninjobs it held 102 deliveries, done and not yet done alike, in one file. On Case A, a client project on a low-code platform, Microsoft Power Apps with Copilot Studio, the status report and the risk estimate for the project manager were written from the queue and the pages, not from memory (chapter 17).
Key points
- docs/06 holds milestones, each with a paragraph, and one line per delivery under it: a mark, a slug, its token when it has one, one sentence and its suffixes; what happened goes on the page.
- A line's mark says where its delivery stands, from
[ ], not defined, to[x], done; a line never leaves, so the queue is also the history. - A milestone paragraph is a test a person can check against the product, never a theme, over the deliveries that make it true, three to eight in the first milestone: the skeleton first, each line after the lines it needs, and last the review, whose findings become lines under it in the same milestone; lines are added while it runs, and whoever adds one puts it in the milestone whose paragraph has a clause that needs it, or under the next, created when missing with a paragraph the line answers and its review last.
- The order is the priority: the higher line matters more, moving a line changes its priority, and a dependency known when a line is added is written with it,
· after <slug>, an order, not a wait, so the line keeps[ ]. - No command owns the queue: lines and paragraphs change by conversation, in any session, with the slug kept; code changes only inside
/apply, even a five-line change gets its page, and a change asked anywhere else becomes a line, with a draft page for what the line cannot hold, and/proposein that session or a fresh one,/applyalways in a fresh one.
-
J.C. Ködel, "One Page at a Time", docs/06, the queue, milestone M15, accessed 2026-10-18, in the book's repository. https://github.com/JCKodel/focus-kit-book/blob/main/docs/06-Queue.md ↩