Subsystem Search

Part 2 of 6 Working through your agent

An agent per project, handing work over

By the end of this chapter there are two repositories with an agent each, one of them has filed work for the other with the reasoning attached, the second has done it and handed it back, and the item reads as one record of one piece of work rather than four accounts of the same afternoon.

This is the thing that is hard to arrange any other way. Two agents in two checkouts cannot see each other. They can both be confidently right, in opposite directions, for a week.

The work so far

The website rebuild as A question that waits for you left it: twelve items, three documents, and the question answered.

$ 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?
…

A second repository

The checkout is a separate service in a separate repository, and the rebuild has reached it. It gets a project of its own:

$ subroutine project create api "Checkout API"
Created api - Checkout API
…

An account for its agent

The agent working in that repository gets its own account, as the website's did in the first chapter. Two things are new: the account is made in the checkout itself, and its scoping. Here the checkout is a folder of its own:

$ mkdir checkout-api
$ cd checkout-api
$ subroutine agent create apiclaude --profile collaborator --project api --project web --write api --here
Created service account apiclaude, with the contributor role.

Checked, by presenting it: apiclaude (agent), in projects (comment:read, comment:write, project:read, task:read, task:write, workspace:read), and only within api, web, writing only in api
Account parent: laurence.

Written to /home/laurence/checkout-api/.claude/settings.local.json as SUBROUTINE_TOKEN_LOCAL, readable only by your account on this machine.
Reload the window, or start a new Claude Code session there, before anything else:
…

No credential was printed. --here wrote it into the checkout's .claude/settings.local.json, under the variable Subroutine reads for this connection, and Claude Code gives that file's variables to everything it starts in the checkout: the agent's shell, and the server its tools come from. Where the folder is a git repository, it also makes git ignore the file, and says so.

You need not type it at all. In a Claude Code session in the checkout, the plugin's skill offers exactly this the first time it finds itself working as you, and with your yes it runs the same command, so the credential never passes through its conversation either.

Read the Checked line, because it is the whole design: only within api, web, writing only in api. The API repository's agent can read the website's work, because it has to agree with it, and can change only its own.

worker is the profile the first chapter used, and it means one project, writing everything under it. collaborator is this one: read several, write the ones you name.

What an agent may not do

The website's agent is still the worker the first chapter made, so it owns the website and nothing else. Give it the same reach as the other one:

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

  sr_…
…
Checked, by presenting it: claude (agent), in projects (comment:read, comment:write, project:read, task:read, task:write, workspace:read), and only within web, api, writing only in web
…

There is no Created service account line this time. The account already existed; what you issued is a new credential for it, and the old one stops working. That is how a credential is narrowed or widened, and it is the reason the account and the credential are two things rather than one.

Now it can see the checkout work. Watch what happens when it tries to file some:

{
  "mcpServers": {
    "subroutine": {
      "command": "subroutine",
      "args": ["mcp"]
    }
  }
}
subroutine_add(text="Return the basket total excluding VAT +api")
The token you used can read this project but may only write in another.

A refusal is a lesson, and this one is worth reading rather than working around. The agent reached across into another team's project and was told no, by name, without anything crashing and without a stack trace.

So decide, out loud, whether you want it to. These two repositories have to agree with each other, and the whole point of the next few minutes is one filing work for the other, so it needs to write there:

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

  sr_…
…
Checked, by presenting it: claude (agent), in projects (comment:read, comment:write, project:read, task:read, task:write, workspace:read), and only within web, api, writing only in web, api
…

Say what you just allowed, because nobody will read it again: the website's agent can now change the checkout team's work, and everything it does there will carry its name.

It files the work, with the reasoning attached

The agent was putting prices on the basket page and found that the two sides disagree about what a price is. That is not a bug in either one. It is a thing nobody wrote down:

{
  "mcpServers": {
    "subroutine": {
      "command": "subroutine",
      "args": ["mcp"]
    }
  }
}
subroutine_document(title="Prices are stored and returned excluding VAT, and each client adds it", type="decision", project="api", body="The basket page assumed the API total included VAT and the API returns net, which is where the penny differences came from. Nothing on either side said which it was. It is net, and each client adds VAT when it displays a price.")
Wrote #13  decision  Prices are stored and returned excluding VAT, and each client adds it
subroutine_add(text="Say in the basket response that the total excludes VAT +api")
Added #14  task  Say in the basket response that the total excludes VAT  (read +api)
subroutine_link(ref=13, type="documents", other=14)
#13 Documents #14  Say in the basket response that the total excludes VAT

Three calls, and the important one is the third. Without it this is a ticket that says say which it is, and whoever picks it up starts by working out why anybody cares. With it, the reasoning arrives attached to the work, written by the thing that found it, on the day it found it.

The other agent picks it up

The checkout repository has its own Claude Code, opened in its folder once the window has been reloaded, as agent create asked. The cd below stands for opening it there, and its shell is already the new agent:

$ cd checkout-api
$ subroutine whoami
apiclaude (agent), via token 'apiclaude agent' (…).
Account parent: laurence.
Narrowed to projects api, web; writing in api.
…

Its tools come from the same configuration as the website's, naming no credential at all:

{
  "mcpServers": {
    "subroutine": {
      "command": "subroutine",
      "args": ["mcp"]
    }
  }
}

That is the reload's whole point. The server its tools come from is started with the settings file's variable too, by a session that began after the file was written, while one already open may go on as before in its tools, as agent create warned. Ask it who it is:

subroutine_whoami()
apiclaude (agent), via token 'apiclaude agent' (…).
Account parent: laurence.
Narrowed to projects api, web; writing in api.
…

It asks what it can start, in its own project, and finds work it has never been told about:

subroutine_list(ready=true, project="api")
#14  task  Say in the basket response that the total excludes VAT
subroutine_show(ref=14)
#14  task  Say in the basket response that the total excludes VAT
open  +api
version 1

Read first (1)
#13  decision  Prices are stored and returned excluding VAT, and each client adds it

Documented by  #13  Prices are stored and returned excluding VAT, and each client adds it

Read first again, and this time it crossed a repository. The finding was written by an agent in another checkout that this one will never meet, and it is the first thing this one is handed.

subroutine_claim(ref=14)
Claimed #14  Say in the basket response that the total excludes VAT, until 05 Oct …
…
subroutine_comment(ref=14, body="The field is now total_net, and the response says the currency and that tax is excluded.")
Recorded on #14.
subroutine_done(ref=14)
Done: Say in the basket response that the total excludes VAT. The claim on it went back with it.

One record, not four accounts

subroutine_show(ref=14)
#14  task  done  Say in the basket response that the total excludes VAT
done 2026-10-05  +api
version 2

Read first (1)
#13  decision  Prices are stored and returned excluding VAT, and each client adds it

Documented by  #13  Prices are stored and returned excluding VAT, and each client adds it

2026-10-05  @apiclaude  The field is now total_net, and the response says the currency and that tax is excluded.

One item, and both agents are on it. The rule it was done under was written by the website's agent, in another repository, and is sitting at the top where it governs. What was actually done is the line at the bottom, signed by the one that did it. Nobody wrote a handover note, and the two of them were never in the same session.

Version 2, which is the other thing to notice: one version as it was filed, and one more when it was finished. An item's version moves only when what it says changes, and being linked, claimed and commented on changed none of that. Each is on the record where it belongs instead: the decision at the top, and the comment at the bottom with the name of the agent that wrote it.

That is the difference between a tracker two agents happen to write into and a record they share. The next chapter turns the whole of it loose: an agent given a standing instruction, working through what can be started without anybody at the keyboard.