Part 2 of 6 Working through your agent
A standing instruction
By the end of this chapter the rebuild has a beta and a launch on its roadmap, and your agent is working toward them without you: it asks what can be started, takes one thing so that nothing else takes it too, does it, writes down what happened, and hands it back. Then it does it again.
Everything up to here has had you in the loop, saying what to file and what you concluded. This is the chapter where the list itself becomes the instruction.
The work so far
Both repositories as An agent per project, handing work over left them: fourteen items, two projects, two agents, and the checkout work done.
uv tool install subroutine
subroutine init
subroutine project create web "Website rebuild"
subroutine agent create claude --profile worker --project web --store
subroutine add "Write the copy for the home page +web"
subroutine add "Choose a typeface for the headings by Tuesday +web"
subroutine add "Agree the new navigation +web"
subroutine add "Build the new navigation +web ~1d"
subroutine add 'Audit the third-party scripts +web !3/2'
subroutine link 3 blocks 4
subroutine done 3
subroutine document create "Navigation stays one level deep" --type decision --project web --body "One level, and the four second-level links go in the footer."
subroutine link 6 documents 4
subroutine document create "Do not generate the navigation from the sitemap" --type dead_end --project web --body "It goes stale the moment a page moves, and the build cannot tell."
subroutine link 7 documents 4
subroutine document create "The analytics tag loads the consent banner a second time" --type finding --project web --body "Both are injected by the tag manager."
subroutine link 8 documents 5
subroutine add "Write the dropdown markup +web" --under 4
subroutine add "Check the navigation on a phone +web" --under 4
subroutine document create "The dropdown opens on click, not on hover" --type decision --project web --body "Hover has no equivalent on a touchscreen."
subroutine link 11 documents 9
subroutine add "Must the dropdown work without JavaScript? +web @laurence" --type question
subroutine link 12 blocks 9
subroutine comment 12 "No. The navigation is the one place we already require JavaScript."
subroutine done 12
subroutine project create api "Checkout API"
subroutine agent create apiclaude --profile collaborator --project api --project web --write api
subroutine agent create claude --profile collaborator --project web --project api --write web --write api --store
subroutine document create "Prices are stored and returned excluding VAT, and each client adds it" --type decision --project api --body "It is net, and each client adds VAT when it displays a price."
subroutine add "Say in the basket response that the total excludes VAT +api"
subroutine link 13 documents 14
subroutine done 14
{
"mcpServers": {
"subroutine": {
"command": "subroutine",
"args": ["mcp"]
}
}
}
What the work counts toward
Before you leave it alone, say what the work is for. The rebuild goes in front of the team as a beta first, and live after that. Ask your agent to hold both as milestones:
subroutine_add(text="Beta for the team by 16 October +web", type="milestone")
subroutine_add(text="New site live by 30 October +web", type="milestone")
A milestone is what work counts toward, never work itself. Its date is a deadline, written with by as any other is, and it can go overdue. What counts toward it is an includes link, from the milestone to the work: the beta needs the new navigation's markup and a check on a phone, and going live needs the copy, the typeface and the script audit.
subroutine_link(ref=15, type="includes", other=[9, 10])
subroutine_link(ref=16, type="includes", other=[1, 2, 5])
And one comes before the other:
subroutine_link(ref=15, type="precedes", other=16)
precedes is a plan, and blocks is a fact. Only blocks holds anything up, and it is what the list of what can be started reads, so the work a milestone counts is still offered as ready, and the launch planned after the beta is not waiting on it. Read in date order, the milestones are the rebuild's roadmap:
subroutine_list(filter={"type.eq": "milestone"}, order="due_at")
Each row counts how much of what its milestone includes is done. In your own terminal the same roadmap is subroutine list --type milestone --order due_at.
The instruction
It is a paragraph, and this is the whole of it:
Example not checked: it is not run when this site is built.
Work through the website rebuild. Each time round: ask what can be started,
take the most important one, do it, write down what you did on the item, and
finish it. If something needs a decision only Laurence can make, file it as a
question for him and carry on with the next thing. Stop when nothing is
startable.
Where that paragraph lives is your coding agent's business rather than Subroutine's: a project instruction file, a saved prompt, a scheduled run. What matters here is that every sentence in it is a call the agent already knows how to make, and that none of them needed teaching. It has been making them since the first chapter.
Read it again as the five verbs it is: ask, take, do, write down, finish. That is the loop, and the rest of this chapter is one turn of it.
Ask what can be started
subroutine_list(ready=true)
This is the call the whole thing rests on, and it is the one an unattended agent cannot get wrong. It is not a list of everything: it leaves out what is blocked, what is deferred to a later date and what somebody else is holding. Every line in it is something that can genuinely be picked up right now, and neither milestone is among them: nothing offers a milestone as the next thing to start, so an agent working through the list never tries to do one.
An agent given the whole backlog instead will pick something blocked, do half of it, and file a comment explaining why it could not finish. That is the failure this replaces.
Take it, so that nothing else takes it too
subroutine_claim(ref=10)
A claim is a lease, not a lock. It has an expiry on the face of it, and that is the design rather than an implementation detail. An unattended agent is exactly the thing that dies halfway: the session is killed, the context ends, the machine reboots. A lock taken by something that no longer exists has to be found and broken by a person. A lease runs out.
Every write to something an agent holds pushes the expiry out, so an agent that is working never has to think about it, and one that stopped stops renewing. Nothing is stranded, and nothing needs an administrator.
The answer also tells it what it has not said. The claim says who has this; the status says work has begun. They are different facts and an agent that has only claimed something has not started it:
subroutine_update(ref=10, status="in_progress")
Its first line now carries both: in_progress and claimed by @claude. Anybody looking at the list, or the board in the browser, can see the difference between work somebody is on and work somebody is merely holding.
Write down what it did
subroutine_comment(ref=10, body="Checked at 360 and 390 wide. The dropdown opens and closes, and the footer links are reachable.")
This is the sentence that makes the loop worth running. Without it you get a list of things marked done by a machine overnight and no way to tell a real check from a plausible one. With it, the item says what was actually looked at, and you can disagree with it in the morning.
Anything it concluded rather than did belongs in a document, exactly as in Decisions, findings and dead ends. The rule does not change because nobody is watching.
Finish it
subroutine_done(ref=10)
The claim goes back with the work, so there is no releasing step to forget. That matters most here: the end of an unattended run is a killed process rather than a moment anybody is present for, and an obligation that falls there is one nobody meets.
Then it asks again, and the list is one item shorter.
What you read in the morning
You were asleep. The question is not what is left, which the list answers, but what happened:
subroutine_changes(since=42)
That is the loop, written down by the thing that ran it: took it, started it, said what it did, finished it, let it go. Five lines for one piece of work, and the last one happened without being asked for, because finishing hands the claim back.
subroutine changes says what moved. It is cheap, it resumes from a number, and the last line is why: an agent picking up after time away passes that number back as since and is told only what it missed.
It reports that a comment exists without saying a word of what it said. subroutine journal is the other reading of the same events, with the bodies joined on and each actor named, asked for a period rather than from a cursor. Reach for changes to pick up where you left off, and for journal to find out what a night contained. Asking changes to summarise a week tells you that fourteen comments exist and nothing about any of them.
And the roadmap has moved, without anybody touching it:
subroutine_list(filter={"type.eq": "milestone"}, order="due_at")
The beta counts one of its two done, because the phone check it includes is what the agent finished overnight. Nothing completes a milestone by itself. When everything it includes is done its row says so, and whether it has been reached is still yours to say, with subroutine done.
That is Part 2. Your agent files work and knows what can be started, writes down what it concluded where the next one will meet it, raises what it cannot settle rather than guessing, hands work to another agent with the reasoning attached, and works through a list unattended while the roadmap counts what it finished. All of it is one instance, and none of it needed you to be at a terminal.
Which raises the question the next part answers: what does any of this look like when you are not?