Connecting to Subroutine
There are seven ways to reach a Subroutine instance, and the one that is right for you follows from two questions: where does your work live, and who is asking for it - you in a browser, you at a terminal, an agent in your editor, or the calendar application you already keep your week in.
This page is organised by the answer. Find yourself in the table, read that one section, and ignore the rest. docs/hosting.md is the other end of most of them - it is for whoever is standing the server up, and if that is also you, read it first.
| Your work lives | You are | Read |
|---|---|---|
| On a server | In a browser, or as an app on a phone | Just a web page |
| On this machine | At a terminal | Just this machine |
| On a server | At a terminal | Your terminal here, your work there |
| On this machine | An agent in your editor | An agent, on the machine holding the work |
| On someone else's server | An agent in your editor | An agent, with nothing installed |
| On a public server | Claude on the web | Claude on the web |
| Anywhere | Your calendar application | Your work in your calendar |
Two of these can be true at once and that is normal. Your own list on this laptop and your
team's on a server is one arrangement, not two - subroutine agenda asks every instance you can
reach and merges the answers, so the dentist and the stand-up land in one list. Reading spans
everything; only writing has to pick.
Just a web page
Nothing to install, and nothing to configure. If somebody runs an instance and has given you an account on it, they can hand you a sign-in link - one address that signs you in and then works no more. Open it, and you are in.
Ask them for subroutine login link --username <you>. What arrives looks like this:
https://subroutine.example.com/signin?link=…
It is good for half an hour and works once. If it has gone stale by the time you get to it, that is ordinary - ask for another.
After that the browser stays signed in while you keep using it. A fortnight of not touching it ends the session and you sign in again the same way; using it puts the fortnight back. So a browser you open most days never asks again, and a device somebody else has stops working two weeks after they took it.
Treat it like a password while it is alive, because for those thirty minutes it is one: anybody who has the link can become you. It travels in a web address, so it reaches whatever carried the message, and it is worth not pasting into anywhere that keeps a history.
A token is not a substitute. If you have been given something starting sr_, that is for a
terminal or an agent, and pasting it into a browser will not sign you in. Ask for a link
instead - they are different credentials for different doors, and having one does not get you
the other.
What you can do there: read and add work, change what an item says, move it through its statuses, comment, link items together, and search. If you also want a terminal or an agent, every section below still applies and you want a token as well as a link.
Unless your account is a viewer, in which case you read and nothing else. The page is drawn from what you are allowed to do, so the controls for writing are absent rather than present and refused - no capture box, no Complete, no Edit, no comment box. If that is not what you expected, it is a role and not a fault: ask whoever set you up.
A read-only account is also how a wall display or a kiosk is done, which is worth knowing if you are the one being asked to set a screen up rather than the one using it. That is in hosting.md, because it is the instance owner's end.
On a phone or tablet
The same address installs as an app. You get an icon on the home screen, a window of its own with no address bar and no tabs, and an entry in the app switcher beside everything else. There is nothing to download from a store and nothing to sign up for - the instance serves what the browser needs to do it.
Sign in first, then install, and it takes five steps:
-
Get a sign-in link -
subroutine login link --username <you>, run wherever the instance is. It works once and lasts half an hour. -
Open the browser you want the app in, and paste the link into its address bar. Copy it rather than tapping it: a tapped link opens in whatever the device treats as the default browser, and the link is used up by whichever browser opens it.
-
Check you can see your work. The app inherits this browser's session, so this is what there is to get right.
-
Install it from the browser's own menu. It is called Install, Install app or Add to Home Screen depending on the browser, and it is never a control on the page.
-
Open it from the home screen. It comes up signed in, in a window of its own, with no address bar.
If your browser's menu offers nothing, try another one. Browsers differ about when they will install a page, and about what they make when they do - some write a bookmark that opens in a tab rather than an app with a window of its own. There is nothing to change on this end and nothing you have done wrong.
It needs the network, exactly like the page does. Everything you see comes from the instance, so there is nothing stored on the device and no offline mode.
Use a browser that remembers you. Firefox Focus and anything else that erases cookies when you leave will need a fresh sign-in link every time, and a link works once and lasts half an hour.
What we have checked ourselves: Brave on an Android tablet installs it and it works, and a real Chromium reads the manifest without complaint. Other browsers we have not tested - tell us what yours does, either way.
Signing out is the same as in a tab: Sign out in the menu under your name, or ask whoever
runs the instance to run subroutine login revoke for you, which ends every browser and every
installed app you are signed in on at once. Removing the icon does not sign you out.
What to ask for, if somebody else runs the instance
Three things, and the third is often forgotten:
- The address. For a terminal, the instance's base address -
https://subroutine.example.com. For an agent, the same with/mcpon the end. - A token. It starts
sr_. It says who you are, so what you file is attributed to you rather than to whoever set the server up, and it decides what you are allowed to do. It is shown once, by the person issuing it, and stored nowhere - so if it is lost, the answer is a new one rather than a lookup. - The workspace, if the instance holds more than one. A workspace is a wall between two bodies of work - a client, a company, a side project. Most instances have one and you will never hear the word. On an instance with several, a session that has not been told which one it is in has its first read refused, and an agent has no way to guess.
Nothing else. There is no account to create on your side, no key to exchange, and no configuration file you have to write by hand.
Just this machine
You are the only person who needs this, your work stays on your own disk, and nothing is served to anybody. This is the ordinary case and it is the one to start from.
uv tool install subroutine # or: pipx install subroutine
subroutine init
subroutine add "Call the dentist before Sunday"
subroutine
What it needs: Python 3.11 or newer, and nothing else. The database is a SQLite file under
your own data directory, made by init. There is no server, no port, no token and no login -
the file permissions on that database are what protect it.
You know it worked when subroutine prints the task you just added.
If it does not: subroutine doctor prints where this installation keeps its configuration,
its database and its state, and says whether they are coherent. Run it before believing anything
else about the machine.
You will not meet the words workspace, instance or connection on this path, and you never have to. They are what the next four sections are about.
Your terminal here, your work there
Somebody runs Subroutine on a server - your company, or you on a machine that is always on - and you want it in your own terminal, beside whatever is already on this laptop.
Install the program here, then add the server as a connection:
uv tool install subroutine # or: pipx install subroutine
subroutine connections add work --url https://subroutine.example.com
It asks for the token, reaches the instance with it, and writes nothing until both work. A mistyped address or a revoked credential is refused there and then, rather than becoming a line of failure the next time you list something. The name it reports back is the one that instance knows you by - which is the only thing that confirms you pasted the token you meant to, since a token carries no clue about whose it is.
What it needs: the program on this machine, the address, and a token from whoever runs the instance.
You know it worked when subroutine list shows the server's work:
subroutine list
If this machine has nothing of its own, it looks different and that is right. Somebody
given a token who installs the program and never runs init has one connection, so there is
nothing to tell apart and nothing to prefix - the list is bare, with no Local heading:
subroutine list
connections add says so at the time, on a line the transcript above does not have because
that machine had a list already:
The name - work here - is yours. It becomes the first part of every address that
instance's items print as, and two people reaching one server may call it different things.
Your own database does not go anywhere. It is a connection too, called local, and it is
still where subroutine add files things - unless this machine has no list of its own, in which
case connections add points writes at the server and says so. subroutine use work moves them
either way, and it never changes what you can see: reads always span everything you can reach,
which is what makes switching safe.
If it does not: subroutine connections lists what this machine reaches and, for each,
which of the four places its token came from. It is worth knowing about because it stays out of
subroutine --help until a second connection exists - which is to say, until the thing you are
checking has already worked. connections add is hidden alongside it, which is why this page
names them both.
An agent, on the machine holding the work
Your work is on this machine and you want your coding agent to plan, file and close it.
uvx subroutine init
claude plugin marketplace add simonholliday/subroutine
claude plugin install subroutine@subroutine
What it needs: uv, and not
Subroutine. Your editor starts the plugin through uvx, which fetches the package on first
use and caches it - roughly five seconds once, then a fraction of a second. Nothing is
permanently installed and nothing has to be on your PATH.
Already ran uv tool install subroutine? That copy is used instead of a download, so the
two arrangements do not fight. Running from a checkout or a virtualenv? The plugin cannot
point at it - uvx takes the package name as its first argument and there is no way to omit
that - so use claude mcp add subroutine -- /path/to/subroutine mcp instead, which is better
for development anyway: the plugin's copy is cached and lags until you refresh it.
And Git, for the third command. The marketplace is a repository and claude plugin marketplace add clones it, so without a git binary that step refuses before anything of ours
runs. A machine already set up to install Python packages nearly always has it.
This one runs a program on your machine, so it does not work in a browser. claude.ai cannot start it, because there is nothing on that side to start anything on. The plugin still installs and still reports success, and the only sign of a problem is an absence - so it is worth knowing in advance rather than diagnosing.
Claude Code is tested; a desktop app that can start a local program is not. We have not driven that combination, and this page used to say we had. It is the only route we know of for somebody who will not use a terminal, so it is worth trying and worth telling us about - but do not plan an afternoon around it on our word.
You know it worked when claude mcp list shows the server connected, or when you ask the
agent to run subroutine_whoami and it answers. Installing a plugin and starting its server are
separate moments and only the first one reports, so the second is worth checking once.
If you keep more than one instance - your own and a client's, say - the plugin's Which instance field takes the name of a connection you have already set up, and the section above is how you set one up.
If you work in several projects, each project's agent can be somebody of its own while the rest of the machine keeps this one - A different agent in each project is how.
A different agent in each project
You work in several repositories, and you want each one's agent to be somebody of its own -
so that work done in web is recorded as the web agent's, is kept to that project, and can be
revoked without touching the rest - while an agent anywhere else on the machine carries on as
the one you already have.
It is an exception, not a second setup. The machine keeps its general agent. A project that names a credential of its own overrides it inside that project, and nowhere else.
What it needs: Claude Code, and the subroutine plugin from An agent, on the machine
holding the work. It works whether the work is on
this machine or on a server you reach as a connection. It does not reach
subroutine-remote, whose token is a plugin setting - and a plugin's settings apply to every
project at once, which is why this uses the project's own settings instead.
1. Make an agent for each project
One command per project:
subroutine agent create web --profile worker --project web
subroutine agent create api --profile worker --project api
worker gives each agent its project and everything filed under it, and nothing else. An agent
that reads a neighbouring project for context and changes only its own is --profile collaborator --project web --project api --write web. Saying what the credential is
for has all four profiles, and --title names the
credential if web agent is not what you want to read later.
Leave --store off. It records a credential as this machine's agent, and a connection has
one of those - so it would replace your general agent everywhere, where this adds an exception
in one place.
Each command prints its credential once. Keep it for the next step, and put it nowhere else.
2. Put the credential in that project's local settings
In the project's own directory, add an env block to .claude/settings.local.json, creating
the file if there is none:
{
"env": {
"SUBROUTINE_TOKEN_LOCAL": "sr_…"
}
}
The name after SUBROUTINE_TOKEN_ is the connection's, upper-cased, with anything that is
not a letter or a digit as an underscore. The instance on this machine is local; a server you
added as work makes it SUBROUTINE_TOKEN_WORK. subroutine connections lists the names.
Why that file. Claude Code gives every env entry to everything it starts in that project -
the agent's shell as well as the plugin's server - so one line covers both of the ways an agent
reaches an instance, and an agent that can also run a
shell is why both matter. It is the half of a
project's settings meant for this machine alone. Check that the repository ignores it before
you save a credential there - git check-ignore .claude/settings.local.json prints the path
when it does, and nothing when it does not.
Why that variable, rather than SUBROUTINE_TOKEN. A variable naming the connection is the
first place a credential is looked for, so it wins over the plugin's own token field and over an
agent stored on this machine. And it applies to that connection alone, so a second instance you
reach from the same project keeps its own credential.
3. Start a new session there, and check
A session reads its environment when it starts, so one already open in that project keeps the identity it began with. Start a new one, or reload the window.
You know it worked when the agent's shell, in that project, names the project's agent:
subroutine whoami
and subroutine_whoami, asked through the agent's tools, names it too. Then ask the same in a
session in any other project: it should name your general agent. The pair is the check -
either answer alone can be right for the wrong reason.
If it does not, run subroutine connections from the agent's shell in that project. It says
where each connection's credential came from, and the project's variable is named there when it
arrived:
subroutine connections
Anything else in that column means the session never got the variable: it started before the file was saved, or the file is not in the directory the session was opened in.
What it does not do
- It is a record and a bound, not a wall. The project's credential makes the right name the default and bounds what that name can touch, and Giving an agent a token is where the bound is set. It cannot stop an agent that runs commands from finding a different credential and presenting that instead.
- An agent kept to one project cannot write anywhere else, a comment on another project's
item included. Where one agent's work genuinely spans two, give it
--writefor each rather than widening it back to everything. - Only what Claude Code starts in that project reads the file. A terminal or a scheduled job
it did not start, and
subroutine-remote, go on as before.
To undo it, remove the env entry and start a new session: that project is back to the
general agent. subroutine token revoke <prefix> stops the credential working anywhere, and
subroutine token list shows the prefix.
An agent, with nothing installed
Somebody else runs Subroutine, they have given you an address and a token, and you want your agent working against it this afternoon. This is the freelancer's case, and it needs nothing on your machine at all - no Python, no package, no configuration file.
claude plugin marketplace add simonholliday/subroutine
claude plugin install subroutine-remote@subroutine
Then fill in two fields - the address, ending in /mcp, and your token. In a terminal, run
claude, then /plugin inside the session, and choose the plugin. Once set they are read by
every session, editor included.
That terminal is not optional, and this is the step that catches people out. /plugin is
not available in the VS Code extension, and claude plugin has no configure subcommand -
run claude plugin --help if you want to check that for yourself, and it is worth a look,
because that is a claim about somebody else's program and it may stop being true. So a plugin
can be installed from the editor and cannot be set up there, and nothing says so:
the install reports success, the fields are simply never asked for, and the only evidence is
that no tools appear.
If you have no terminal at all, the values are ordinary settings and you can write them
yourself. In ~/.claude/settings.json:
{
"pluginConfigs": {
"subroutine-remote@subroutine": {
"options": {
"url": "https://subroutine.example.com/mcp?workspace=projects",
"token": "the token you were given"
}
}
}
}
Two things to know before you do. That file is not a secret store - your token sits in it
in plain text, which is the same trade as credentials.toml and worth a deliberate decision
rather than a discovery. And this is where the values land rather than a documented
interface, so /plugin is the route that will keep working. Verified on Linux with the
editor reading a plugin configured exactly this way.
Then reload the window, or start a new session. MCP servers are attached when a session begins, so one that was already open when you configured the plugin keeps the tool list it started with - everything will look correctly set up and there will be no tools.
You know it worked when claude mcp list shows the server connected and the agent can run
subroutine_whoami. Check both: a session that predates its configuration shows ✔ Connected
and has no tools, which reads as a broken product and is not one.
What it needs on the instance's side: an address and a token. That is the whole list, and it is the part somebody else hands you.
On your own machine you need Claude Code and Git - the marketplace is a repository, and
claude plugin marketplace add clones it. Nothing of Subroutine's is installed: no Python, no
package, no configuration file of ours.
Your editor connects from this machine, so an instance on your own network or behind a VPN is as reachable as a public one. Your editor stores the token, not Subroutine, and where it puts it depends on the editor and the machine - on Windows it is a file under your home directory. Treat it as you would any password there; if it is exposed, ask for a new one rather than moving this one somewhere safer.
If your token reaches more than one workspace, the address has to say which one. A token
pinned to one workspace needs nothing here, however many the instance holds - whoever issues it
chooses, with subroutine token create --workspace. Otherwise put it on the end:
https://subroutine.example.com/mcp?workspace=acme
Without it, the agent's first read comes back refused - "This request could be about any of several workspaces, so it needs to say which" - with the workspaces it can reach listed. It can recover by naming one on every call, but it will do that for the whole session and the next session will start over. One word in the address settles it permanently. Ask which workspace your work belongs in at the same time as you ask for the token.
You know it worked when the agent can answer "who am I on this instance?" - it has a
subroutine_whoami tool for exactly that, and the answer names the account the token belongs to
and the workspaces it reaches.
If it does not: an empty address is not an error. The plugin sits idle and this session simply has no Subroutine tools, so it can be installed before anybody has told you where to point it. A wrong token or a wrong address both report clearly in the editor; a token is not something to edit around, so ask for a new one rather than guessing.
This one is tested in Claude Code and nowhere else. The transport is different from the section above - this one needs nothing installed - but the same caution applies to where it runs. It does not run on the web, which is structural. Whether a desktop app will take an HTTP plugin configured with a pasted token we have not driven, and the section on Claude on the web is why we doubt it.
Another MCP client
The plugin is a convenience, not the mechanism. The instance speaks MCP itself over ordinary
HTTP, so any client that takes a URL and a header can reach it: point it at the same /mcp
address with Authorization: Bearer sr_…. There is no session to establish and nothing to
install on either side.
What such a client does not get is the plugin's skill - the working practice for using this well, which ships with the plugin rather than with the instance. The instance offers four documents as MCP resources instead: a guide written for an agent arriving with nothing, worked examples, this installation's own vocabulary, and the decisions this workspace has taken. Those are enough to work from. The skill is the part that says how to work well, and it ships with the plugin - so it reaches wherever the plugin does, which is Claude Code for certain and the desktop apps untested (above).
Claude on the web
You want your instance in claude.ai, or in a desktop app talking to it directly, as a connector. This is not built yet, and saying so is more useful than a page that implies otherwise.
It is a different problem from the ways above rather than a bigger one. A connector's traffic comes from Anthropic's servers rather than from your machine, so:
- the instance has to be reachable from the public internet - a laptop or a machine behind a VPN can never be one;
- the credential cannot be a token you paste, because it is not your machine holding it.
That makes it an authorisation flow rather than a field in a settings box, which is why it is its own piece of work rather than a variation on the section above.
Until then, there is one route and it is not the one that looks easiest. The two plugins work differently, they are not interchangeable, and only one of them has been driven end to end by us:
| What it is | Where it is known to work | |
|---|---|---|
| An agent, with nothing installed | an HTTP server, reached with a token you paste | Claude Code - tested. Not the desktop apps: a connector there wants an authorisation flow rather than a pasted token, which is the whole of what is unbuilt above. |
| An agent, on the machine holding the work | a program started on your own machine | Claude Code - tested. A desktop app that can start a local program, untested by us - if you try it, we would like to know. |
So somebody who does not use a terminal has one path: install uv, then the local one. It
is a real path and it is not a nothing-to-install path, and this page said otherwise until
2026-08-27 - which is the sentence somebody would have spent an afternoon on. A plugin that
cannot connect reports success and shows no tools, so the failure is an absence rather than an
error and nothing would have said what went wrong.
Marked as untested rather than quietly asserted. Everything else on this page is a command somebody ran; a claim about what another program can do is the same promise one step out, and this page has no way to keep it. Saying which half we have driven is worth more than a sentence that is confidently wrong.
Your work in your calendar
A seventh way in, and the only one that is not really a way in. Anything here with a date can appear in Google Calendar, Apple Calendar, Outlook or Thunderbird, beside the rest of your week - so a deadline you filed at a terminal turns up on your phone without you doing anything else about it.
You need a terminal once, to make the subscription:
subroutine calendar create "My work"
That prints one address ending .ics. Paste it into whatever you keep your diary in, under
whatever it calls subscribe to a calendar or add by URL. From then on it updates on its own,
every quarter of an hour or so, and you never touch it again.
Make it with a credential nothing narrows. A feed reads with its owner's own sight rather than with the narrowing on the credential that made it, so one narrowed to a project, to some permissions or to one workspace is refused - "A bounded credential cannot mint a calendar feed" - and one that expires can only make a feed that stops no later than it does. Narrow the feed itself instead, as below.
Nothing comes back. Moving an event in your calendar changes nothing here, and deleting one there does not complete anything. That is the trade for it working in every calendar application without an account: the feed is a copy, kept up to date, and the work still lives here.
The address is a password. Anybody who has it can read everything the feed shows, for as long as it works, and nobody here can tell that they are - a fetch from somewhere unexpected looks exactly like one from your phone. So paste it into the calendar application and nowhere else, and if it gets out:
subroutine calendar reset <reference>
which gives that subscription a new address and stops the old one that instant. The
subscription keeps its name and its scope; you re-add it in your calendar and carry on.
subroutine calendar revoke <reference> stops one for good.
It is shown once. Nothing recovers it afterwards, including the instance - what is kept is a fingerprint. If you lose it before you have subscribed, reset the feed and paste the new one.
Narrow it if the whole workspace is too much, which it usually is:
subroutine calendar create "The web rebuild" --project ui
subroutine calendar create "Just mine" --mine
subroutine calendar create "Deadlines" --type bug --type feature
--project takes everything filed under that project too. --mine shows only what is assigned
to you. --expires stops a feed working on a day you name, which is worth setting for anything
temporary.
What shows up: an item's start, an item's deadline, and both where it has both - the day you
meant to do it and the day it is due are different facts, so a calendar showing one would hide
the other. A deadline reads Due: <title>. An item that repeats on a fixed schedule arrives as
a repeating event, so your calendar draws the whole series without this instance sending four
hundred copies of it.
A week of the recent past, and a year or so ahead. The past is kept on purpose: most calendar applications delete an event the moment a feed stops sending it, so dropping finished work would erase a meeting from your calendar's history the moment you ticked it off.
It shows what you can see, asked afresh every time. Losing access to a project takes it out of the feed the same day. There is no way to make a feed of somebody else's work.
If subroutine calendar create says it has no address to give you, the instance has not
been told its own - ask whoever runs it to set public_url, then reset the feed. It is not
broken; it simply cannot say where it lives. And if the command is refused outright, feeds may
be turned off on that instance, which is a decision its operator is entitled to make.
Which is which, if you have lost track
subroutine doctor- what this machine's installation is, and whether it holds together.subroutine connections- every instance this machine reaches, and where each token came from. No token is ever printed.subroutine whoami- who you are on the instance you are pointed at, and which versions of the plugin, the program and the instance are in play. It says so when two of them disagree.claude mcp list- whether your editor actually started a Subroutine server, which is a different question from whether the plugin installed.subroutine explain connecting- the short version of this page, without leaving the terminal.