Subsystem

Part 3 of 6 Watching and steering in a browser

Filing and steering without a terminal

By the end of this chapter you have filed work, said something on an item and changed what it says about itself, without a terminal being part of it.

Everything so far has reached this instance through a command or through an agent. Plenty of people will never do either. This chapter is for them, and for the days when you are one of them.

The work so far

Both projects as The agenda, the list and the board left them, with the dropdown markup started.

$ uv tool install subroutine
Resolved … packages in …
Prepared … packages in …
Installed … packages in …
…
Installed 2 executables: subr, subroutine
$ subroutine init
Ready. Try: subroutine add "something to do"
$ subroutine project create web "Website rebuild"
Created web … Website rebuild
…
$ subroutine agent create claude --profile worker --project web --store
Created service account claude, with the contributor role.

  sr_…
…
$ subroutine add "Write the copy for the home page +web"
Added: Write the copy for the home page  (read +web)
…
$ subroutine add "Choose a typeface for the headings by Tuesday +web"
Added: Choose a typeface for the headings  (due Tue 6 Oct)  (read +web)
…
$ subroutine add "Agree the new navigation +web"
Added: Agree the new navigation  (read +web)
…
$ subroutine add "Build the new navigation +web ~1d"
Added: Build the new navigation  (read +web ~1d)
…
$ subroutine add 'Audit the third-party scripts +web !3/2'
Added: Audit the third-party scripts  (read +web !3/2)
…
$ subroutine link 3 blocks 4
Blocks: Build the new navigation
…
$ subroutine done 3
Done: Agree the new navigation
…
$ 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."
Wrote: Navigation stays one level deep
…
$ subroutine link 6 documents 4
Documents: Build the new navigation
…
$ 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."
Wrote: Do not generate the navigation from the sitemap
…
$ subroutine link 7 documents 4
Documents: Build the new navigation
…
$ 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."
Wrote: The analytics tag loads the consent banner a second time
…
$ subroutine link 8 documents 5
Documents: Audit the third-party scripts
…
$ subroutine add "Write the dropdown markup +web" --under 4
Added: Write the dropdown markup  (read +web)
…
$ subroutine add "Check the navigation on a phone +web" --under 4
Added: Check the navigation on a phone  (read +web)
…
$ subroutine document create "The dropdown opens on click, not on hover" --type decision --project web --body "Hover has no equivalent on a touchscreen."
Wrote: The dropdown opens on click, not on hover
…
$ subroutine link 11 documents 9
Documents: Write the dropdown markup
…
$ subroutine add "Must the dropdown work without JavaScript? +web @laurence" --type question
Added: Must the dropdown work without JavaScript?  (read +web @laurence)
…
$ subroutine link 12 blocks 9
Blocks: Write the dropdown markup
…
$ subroutine comment 12 "No. The navigation is the one place we already require JavaScript."
Noted on: Must the dropdown work without JavaScript?
…
$ subroutine done 12
Done: Must the dropdown work without JavaScript?
…
$ subroutine project create api "Checkout API"
Created api … Checkout API
…
$ subroutine agent create apiclaude --profile collaborator --project api --project web --write api
Created service account apiclaude, with the contributor role.

  sr_…
…
$ subroutine agent create claude --profile collaborator --project web --project api --write web --write api --store

  sr_…
…
$ 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."
Wrote: Prices are stored and returned excluding VAT, and each client adds it
…
$ subroutine add "Say in the basket response that the total excludes VAT +api"
Added: Say in the basket response that the total excludes VAT  (read +api)
…
$ subroutine link 13 documents 14
Documents: Say in the basket response that the total excludes VAT
…
$ subroutine done 14
Done: Say in the basket response that the total excludes VAT
…
$ subroutine start 10
Started: Check the navigation on a phone
…
$ subroutine comment 10 "Checked at 360 and 390 wide. The dropdown opens and closes, and the footer links are reachable."
Noted on: Check the navigation on a phone
…
$ subroutine done 10
Done: Check the navigation on a phone
…
$ subroutine start 9
Started: Write the dropdown markup
…

Signed in, and nothing else

$ subroutine serve
Serving on http://127.0.0.1:8471
…
$ link=$(subroutine login link | grep -o 'http://[^ ]*')
$ curl -s -c /tmp/jar -o /dev/null -w '%{http_code}\n' "$link"
303

That is the sign-in of Watch it happen, followed here by something rather than a browser so that the rest of this chapter can be checked. Put the link in a browser instead and everything below is a box and a few controls.

A note on how this chapter proves itself. The build runs a terminal, not a browser, so it cannot type into a box or click a control. What it can do is make the same request the page makes, which is what the blocks below are: not commands for you to run, but the page's own traffic, so that what the page accepts is proved rather than described. The gestures are described; what they do is checked.

The box at the top

Every view has one, and it takes a sentence:

Not checked: the build does not run this.

Rewrite the basket copy +web !4/2 ~2h by friday

You type that and press return. No fields, no dialog and no project picker, and that is not a shortcut for people who like typing: it is the same sentence your agent has been sending since Filing work, and what can be started, and the same one subroutine add takes.

Here is what the box sends when you do:

$ curl -s -b /tmp/jar -X POST http://127.0.0.1:8471/v1/tasks \
    -H 'Content-Type: application/json' \
    -d '{"text": "Rewrite the basket copy +web !4/2 ~2h by friday"}' \
    -o /dev/null -w '%{http_code}\n'
201

A sentence, and nothing else. Read what came of it:

$ subroutine show 15
#15  Rewrite the basket copy
  !4/2 · 2h · due Fri 9 Oct · web
…

The shorthand belongs to the instance, not to the terminal. The title lost the four pieces of grammar and kept the sentence a person would read. +web filed it, !4/2 set importance and urgency, ~2h estimated it, and by friday became a date, which is the one worth noticing: you wrote it in the sentence and it came out as a deadline on the item.

That matters more than it looks. A browser that could only offer a form would be a second-class way in with its own vocabulary to learn. There is one vocabulary, and all three ways in speak it.

Saying something on an item

Click any item in any view and it opens in full: what binds it, what it is joined to, and everything recorded against it. At the bottom is a box for the next thing.

$ curl -s -b /tmp/jar -X POST http://127.0.0.1:8471/v1/tasks/15/comments \
    -H 'Content-Type: application/json' \
    -d '{"body": "Keeping the tone we agreed for the home page."}' \
    -o /dev/null -w '%{http_code}\n'
201

A comment made here is the same kind of thing an agent writes, in the same record, in date order, with a name against it. There is no separate human channel, which is the point: Decisions, findings and dead ends argued that what happened belongs beside the work, and it would be a poor argument if the browser kept its own copy.

Changing what it says about itself

Importance, urgency, the estimate, who it is for, when it is due, what state it is in: each is a control on the item, and each is one change.

$ curl -s -b /tmp/jar -X PATCH http://127.0.0.1:8471/v1/tasks/15 \
    -H 'Content-Type: application/json' \
    -d '{"urgency": 4}' \
    -o /dev/null -w '%{http_code}\n'
200
$ subroutine show 15
#15  Rewrite the basket copy
  !4/4 · 2h · due Fri 9 Oct · web

What happened
  2026-10-05  @laurence  Keeping the tone we agreed for the home page.
…

!4/2 has become !4/4. The copy always mattered; now it is also urgent, because Friday got closer. Importance and urgency move independently and the page keeps them apart, for the reason Filing work, and what can be started gave: a list that mixes them cannot tell a thing that matters and can wait from a thing that is trivial and due tomorrow.

Dragging the same item between board columns is the other one of these, setting its status, which the last chapter showed.

What the page is for, and what it is not

It is for the work: filing it, reading it, saying something about it, and steering what happens next. Anybody who has been given a way in can do all of that and will never need a command.

It is not for the instance. Making accounts, issuing credentials, backups, upgrades and the settings the server reads are a terminal's job on the machine that runs it, and the last part of this guide is about exactly that. That split is deliberate rather than unfinished: the page is served to whoever you have let in, and the things that decide who that is do not belong in it.

So a colleague needs no more than an address and a link. That is the next chapter, and it is the shortest one here.