Repository navigation
Releases: sirkirby/routr
Release list
routr 0.9.4
2 commits since v0.9.3
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.9.3
No configuration change is needed. routr now reads briefs with Jev jev-1.14.0 instead of jev-1.13.0. If your
decision model is TypeSafe's Jev without a version named (what routr setup writes), you move to 1.14 with the update
and there is nothing to do.
If your config.json names "model": "jev-1.13.0": that version is no longer offered. routr drops that entry with
a warning, and uses the next decision model in your list, or Jev 1.14 when it was the only one. To follow Jev's new pin,
change that entry's "model" to null in config.json, keeping your other entries. The command the warning gives
removes the old entry and keeps the rest, so it brings Jev back only when nothing else is left. routr setup --decision <list> replaces the whole list, so pass every entry you want, for example --decision typesafe,cloudflare:clef.
The update reinstalls routr's skills, and two guides changed:
- the main skill's note on torn readings quotes 1.14's numbers;
- the setup guide quotes 1.14's accuracy and its
sure_at.
An agent that already loaded routr reads the older guides until it rereads the skill or starts a new session.
If you are upgrading from 0.9.2 or earlier, read the v0.9.3 notes too.
Changed
- The decision model is Jev 1.14. routr asks
jev-1.14.0about each brief, with its own measured profile: it
presents a level as sure from confidence 0.7 (1.13 used 0.8), and the note on a torn reading quotes 1.14's record
on the 36 real tasks (right 28 times; when wrong, one level too low 7 times and too high once).- What changes in the advice: 1.14 reads levels a little lower. On 339 real tasks from the maintainer's own work,
scored against how the work turned out, it read 35 fewer tasks as strong, over-rated less (9 against 14 of the 329
where the chosen level was enough) and under-rated no more (10 of the 10 that fell short below strong were read no
higher, the same as 1.13). On the maintainers' labelled briefs it was slightly lower: right on 81.5 of 104 against
82.7, pooled over six runs. - It is a maintainer decision on mixed gate results, not a clean pass: two three-run gates on the same items
disagreed, and the same version asked twice moved by about one brief, the size of the whole difference.
docs/evidence.md, "Moving the pin: Jev 1.14", has the numbers.
- What changes in the advice: 1.14 reads levels a little lower. On 339 real tasks from the maintainer's own work,
- What the gate holds (CONTRIBUTING.md): a Jev version is judged on the mean of three runs, and on what a lead
acts on: the level,standalone, and the report and reviewer verdicts. Fresh Claude Code and Codex leads rewrote
the brief whenstandaloneread no (12 of 12, 11 of 12), and mostly checked the other facts against the brief
themselves. The other facts are still in the advice; they are reported, not gated.
Verification
bun teston macOS, Linux and Windows. The tests expectjev-1.14.0as the default, and a case reads
jev-1.13.0asked by name (the gate's override) as unmeasured.- Review: an independent review by a routr worker on another model family checked every number in the docs against
the maintainers' saved results, and two verification passes; a docs audit's findings were fixed (its re-check was cut
short by the auditor's quota, and the code review's re-check covered the fixes). - Live, from source:
dispatchread a brief withjev-1.14.0, anddoctorreported it answering. In a throwaway
home, a config namingjev-1.13.0was dropped with the warning and its fix, and--decision typesafe:jev-1.13.0was
refused. - Not measured: whether the lower levels change how much rework workers need, beyond the 339 recorded tasks.
CLI and JSON compatibility
No field or flag was removed or renamed.
decision_model: with TypeSafe's Jev as the decision model, new advice and its new ledger rows namejev-1.14.0;
doctorshows it indecision[].askedand, when it answers,decision[].model. Other configured providers, and
ledger rows already written, keep their own.sure,between,notesandnext: with nosure_atof your own, Jev's bar moves from 0.8 to 0.7, so a reading
with confidence from 0.7 up to 0.8 is nowsure: true, withoutbetweenor the torn-reading note and steps. A
sure_atyou set yourself still applies.routr setup --decision typesafe:jev-1.13.0is refused as a model routr has not measured; a config entry naming
it is dropped, with a warning that names aroutr setup --decisioncommand for the entries that remain.
What's Changed
routr 0.9.3
3 commits since v0.9.2
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.9.2
No configuration change is needed, and none of your settings change.
There is one new, optional setting: launch share, for two or more metered accounts in normal use (a Claude
Enterprise seat and a ChatGPT Enterprise seat, say). If you have those, run routr setup and choose Change one
subscription's settings, then Launch share, to set how you want launches split between them. With one metered
account, or none, there is nothing to set, and setup does not ask.
The update reinstalls routr's skills, and three guides changed:
- the main skill describes the
shareandshare_duefields and how the lead uses them; - the orchestrator guide says to take
share_dueamong suitable metered options; - the setup guide has the setting and its guided question.
An agent that already loaded routr reads the older guides until it rereads the skill or starts a new session.
If you are upgrading from 0.9.1 or earlier, read the v0.9.2 notes too.
Fixed
- Guided
routr setupkept answering keys after the decision model's key question. Before, once you typed a key
or pressed Enter to skip it, the next menu ignored every key: arrow keys printed^[[B, and in the numbered
(accessible) mode no answer was taken. Someone setting up before they had a key was stuck. Each prompt now takes
the terminal back itself. (#132)
New
- A launch share between metered accounts. A metered account has no usage windows, so routr has no headroom
number for it, and two of them tied in the advice: the lead's choice fell to habit. Now you can give each a
weight:claude3 andcodex1 says you want about three workers on Claude for every one on Codex.- Set it in guided
routr setup(Launch share: no share, 1 to 5, or another weight up to 99), or with
routr setup --share claude=3 --share codex=1;--share claude=offremoves it. - It counts only for accounts that read metered and are in normal use, and only when at least two of them can
take the work. An account without a share counts as 1. Accounts with usage windows are balanced by headroom, as
before. - routr counts its own launches: each worker that took its task, or was left ready, writes one small record (the
subscription and the time) under~/.local/state/routr/launch-counts.dispatchandusageread the last 7 days.
Each metered account then shows how far it is below its target, andshare_duenames the one furthest below.
The lead still chooses model and effort fit first, and takesshare_dueamong suitable options or says why not. - Counting never fails a launch. If the history can't be read, no share is shown and the advice says why.
routr uninstallremoves the records with routr's other state. - Not measured: whether leads following
share_duereach your ratio in practice.
(#131, #132)
- Set it in guided
Verification
-
bun teston macOS, Linux and Windows. New tests cover:- the share arithmetic, ordering and ties;
- when a share applies, and the guided question's conditions, including a first run;
- the launch records: the window, the sweep, stray, damaged and unreadable files, linked folders and the uninstall
lock; - counting at launch, and
--sharein setup; - the terminal prompts after the key question, in both modes.
Each failed on the code before its fix.
-
Review: each change had an independent review by a routr worker on another model family, and a docs audit, with
a verification pass on every fix. The design was reviewed before it was built. All findings were fixed. -
By hand: guided setup driven in a real terminal (a herdr pane) with stand-in metered harnesses in a throwaway home.
It went dead after the key question on 0.9.2; it now answers, and a Launch share chosen there is saved. From
source in a throwaway home: Claude is due at 9 of 20 launches with weights 3 and 1, and the single-accountusage
view shows no share. -
Live: the launch records were written by real launches on the maintainer's machine during development.
-
Not measured: a real two-metered-seat machine using the share over days; native Windows by hand (CI only).
CLI and JSON compatibility
No field or flag was removed or renamed.
dispatchandusage:subscriptions.share_due, andshare{ weight, target, used_pct, left, launches, of }
on each normal metered row, only when a share applies. Those rows are then ordered byleftamong themselves;
headroom,usable,candidatesandmost_roomare unchanged.usage <subscription>never shows a share.setup: new--share <subscription>=<1-99>|off;shareinconfig.jsonand insetup --show.launch: writes one launch record when it endspromptedorready; its output does not change.
What's Changed
routr 0.9.2
6 commits since v0.9.1
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.9.1
No configuration change is needed, and nothing to review in routr setup: no setting is new or changed.
If you use Claude Code on a usage-based Claude Enterprise seat: routr now detects it and ranks it as metered.
If you set "billing": "metered" on that subscription by hand, you can keep it (it still wins) or remove it.
routr doctor no longer asks you to set it.
The update reinstalls routr's skills, and two guides changed:
- the harness reference has the measured Enterprise sign-in and a section on herdr's worktree folders;
- the setup guide says when a Claude Enterprise seat is detected.
An agent that already loaded routr reads the older guides until it rereads the skill or starts a new session.
If you are upgrading from 0.8.3 or earlier, read Upgrading from 0.8.3
in the v0.9.0 notes first.
Changed
-
A usage-based Claude Enterprise seat is ranked as
metered. Before, Claude on such a seat wasclass: "unknown"
on an assumed headroom, anddoctorasked you to setbillingby hand. The seat has no quota: its/usageshows
no usage windows, only usage credits spent. routr now reads"subscriptionType": "enterprise"on a first-party
claude.ailogin fromclaude auth statusasmetered, but only when/usageanswered with no windows:- an Enterprise seat with a quota keeps the same plan name, so its windows still decide;
- a
/usageread that failed, or an answer that was empty or cut short, stays a failed read, never "no quota"; - your own
billingsetting still wins.
routr keeps only the class, a fixed reason and that fixed condition from the sign-in answer, never the email, organisation or ids.
Fixed
- An Antigravity worker launched in herdr with
--worktreestarts in its worktree. routr built Antigravity's
command before herdr made the worktree, so it started with--add-dirset to the main checkout. Antigravity works
in that folder, not the pane's, so the worker could write into your main checkout. A dry run now shows
--add-dir "<worktree-path>". Other harnesses, and headless launches, were not affected. (#129, issue #22) routr cleanup --worktree <branch>no longer says "nothing to remove" when the worker left its worktree
detached (a reviewer that checked out a fetched commit, say). When no worktree is on the branch but a detached
worktree's folder is the one herdr or a headless launch names for it, cleanup refuses, names that worktree, and
gives theroutr cleanup --path <folder>command to run once you've checked it is the worker's. It never removes
one on its name alone.cleanup --workerno longer calls its own detached worktree someone else's. (#127)- A config file holding JSON
null, a list or any value that is not an object no longer crashes the advice
commands (dispatch,subagent,check,assess),usageordoctor: it is read as unreadable, and routr answers on the defaults with a note. (#125) launch --worktree --copyin a herdr pane no longer overwrites a file the commit has, or copies through a
link out of the worktree, as a headless launch already refused. On macOS and Linux,--copy, in a pane or headless, also keeps a
backslash in a file name as part of the name instead of reading it as a folder. A refused copy fails the launch before the worker
starts, with the cleanup command. (#125)- An update whose new binary hangs no longer blocks every later update as "another routr update is running": its
version check and skill install now have time limits, and a binary that outlives them is killed. (#125) - The OpenTelemetry sender no longer busy-loops for up to a minute when you set export up again while it is
sending. (#125) routr setup,routr telemetry on|offandroutr uninstallwriteconfig.jsonand Claude'ssettings.json
whole, keeping their permissions and any link to them (a dotfilessettings.json, say), so another command never
reads them half written. routr's telemetry state,telemetry.logandupdate.logare written whole too. (#125)routr usage --levelwith an unknown level lists only the real levels. (#125)
Verification
bun teston macOS, Linux and Windows. Each fix has a regression test that failed on the code before it, except
one test for #125's link handling, which guards against a regression that change could otherwise have caused. The
test that a hung update binary is killed runs on all three platforms.- Review: every change had an independent review by a routr worker on another model family and a docs audit, then a
verification pass on the fixes. All findings were fixed. - By hand on Windows 11 (a VM, a binary built from these changes): config.json written whole, through an absolute
link, through a dangling relative link, and refused for a loop of links; a file held open by another process fails
the write whole, leaving no temporary files; a hung binary is killed at the limit. - The Enterprise reading was measured on a real usage-based Enterprise seat on 2026-10-27 (Claude Code 2.1.311,
macOS):claude auth statusand/usageas described above. Then, with a fakeclaudeanswering the same way in a
throwaway home, routr read it asmetered; an Enterprise seat with windows asincluded, and a Team seat without
windows asunknown, as before. Not measured: an Enterprise seat with a quota (from Anthropic's docs). - The Antigravity fix, live in herdr: a launch with
--worktreestarted the realagywith--add-dirin herdr's
worktree folder, where it had pointed at the main checkout before. - Not measured: a hung update binary on a real user's machine (the tests use a stand-in binary).
CLI and JSON compatibility
No field or flag was removed or renamed.
usage,dispatchanddoctor --json: a usage-based Claude Enterprise seat hasclass: "metered",
usage: "metered"andheadroomandusablenull, where it hadclass: "unknown"andusage: "assumed"on the
assumed headroom. Indoctor --json,harnesses.claudehasusage_class: "metered"and
usage_source: "claude auth status", and nousage_reasonor next step. A Claude/usageanswer that exited
non-zero, was empty, was not marked a success, or had a usage line routr could not read is now a failed read
(no_responseorinvalid_responseinunavailable), where it counted as "no usage windows".cleanup --worktree: a new refusal, for a detached worktree named for the branch, carryingworktree(when
exactly one matches) and anextstep with the--pathcommand for each, where it answered ok withabsent.
cleanup --workeron its own detached worktree says what the worktree holds is not checked, instead of calling
it not the one launch made.launch --kind agy --worktreein herdr:start.argvcarries the worktree's path in place of the repository
path; on a dry run, or when launch fails before herdr makes the worktree, it shows<worktree-path>, as
would_rundoes.launch --worktree --copyin herdr: a new failure (ok: false,state: "failed") before the worker's pane
opens, when a copy would overwrite a file the worktree has or go through a link, with the cleanup command in
errorandnext; it used to answer ok after overwriting or following the link.usage --level: the refusal for an unknown or repeated level listsbasic, standard, strong, given once.
What's Changed
- Release notes for v0.9.2 (#130)
- An Antigravity worker launched with --worktree is started in its worktree, not the main checkout (#129)
- A usage-based Claude Enterprise seat is ranked as metered instead of unknown (#128)
- routr cleanup --worktree no longer says "nothing to remove" when a worker left its worktree detached (#127)
- Internal cleanup: harness usage details live in the registry, config is read once per command, and shared paths and literals are named once (#126)
- routr no longer crashes on a null config, overwrites files with a pane --copy, or hangs an update on a stuck binary (#125)
routr 0.9.1
2 commits since v0.9.0
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.9.0
No configuration change is needed, and nothing to review in routr setup: no setting is new or changed.
The update reinstalls routr's skills, and the orchestrator guide changed: it has a new "Unreadable" entry under
headless workers. An agent that already loaded routr reads the older guide until it rereads the skill or starts a new
session.
If you are upgrading from 0.8.3 or earlier, read Upgrading from 0.8.3
in the v0.9.0 notes first.
Fixed
-
A headless worker file routr can't read is now treated as unknown, never as missing. A headless worker keeps
its record (worker.json), its state (state.json: session, turns, the process group its harness ran in) and the
markers its process writes in its run folder. When one of them was there but couldn't be read (in use on Windows,
half-written, or damaged), every routr command used to act as if it weren't there:- A new worker process (started by
routr send) began from an empty state and wrote it over the real one,
losing the worker's session and turns. routr sendsaid "no session to resume; launch the work again", and skipped its check that the harness had
stopped.routr cleanup --workerandroutr stopskipped their check of the harness's process group.routr workersshowed the worker asstarting, or left it out.routr waitcould stop waiting.
Now:
- no new worker process starts over a file it can't read;
send,stopandcleanup --workerrefuse, with an error naming the file, thoughstopstill stops a worker
process that answers, andsendstill delivers to one when only the state file is unreadable;- for an unreadable record or state,
workersshowsunreadable, andwaitkeeps waiting; - for an unreadable marker,
workersshowsunreachable, andwaitreports that once; - a readable "released" marker is still taken as the worker process's word that it ended.
On Windows, a file another process is replacing is read again for up to 100 ms first. If a file stays unreadable,
routr can't tell what the worker is doing, and each refusal's next step says what to do: check the file's
permissions, or whether it's damaged; then make sure nothing of the worker still runs, finish its worktree, keep
what you need, and remove its run folder yourself. - A new worker process (started by
-
worker.json, and the filewaituses to remember what it has already reported, are now written whole, so another
command never reads them half-written.
Verification
bun teston macOS, Linux and Windows. A new test, with a fixture harness, makes a worker's record and then its
state unreadable, and checksworkers,wait,send,stop,cleanup --workerand a new worker process against
each. More cases cover unreadable claim and release markers, and a readable release beside an unreadable ready
marker. The test failed on 0.9.0's code when it was written (#123). A unit test covers the reader's Windows retry,
with a controlled clock.- Review: an independent review by a routr worker on another model family, and three verification rounds; all
findings were fixed. - Not measured: a file damaged on a real machine (the tests write broken files); on Windows, a file missing for a
moment (rather than unreadable) after the writer's retry has given up, which still reads as missing.
CLI and JSON compatibility
No field or flag was removed or renamed.
workersandwait: a worker entry'sstatecan beunreadable(record or state), orunreachablefor an
unreadable marker, as for a process that doesn't answer. When itsworker.jsonis unreadable,
kind,model,effortandcwdare null.stop:stateisunknownalso when the worker isn't running and its record or state can't be read.send,stopandcleanup --worker: new refusals, whose message names the file, with a next step for a file
that stays unreadable.
What's Changed
routr 0.9.0
14 commits since v0.8.3
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.8.3
No configuration change is needed, and none of your settings change: subscriptions, models, effort, reserves,
decision models, update channel and telemetry are read as before.
There is one new, optional setting: OpenTelemetry export, off unless you turn it on. To review it, run
routr setup and choose OpenTelemetry export. Its question defaults to no, and saying yes asks for your endpoint.
Your other choices stay as they are unless you change them. routr setup --yes alone never turns export on; only an
endpoint you give does (--otel-endpoint). If you don't use an OpenTelemetry backend, there is nothing to do.
The update reinstalls routr's skills, and the guides changed in this release:
- the setup guide has the export commands;
- the harness reference has the lead-session variables routr removes, and the trace context each harness reads;
- the orchestrator guide has
--lead-session.
An agent that already loaded routr reads the older guides until it rereads the skill or starts a new session.
If your lead agent runs with OpenTelemetry trace context (for example, Claude Code with its own tracing on gives
its shell commands TRACEPARENT): workers now get the TRACEPARENT, TRACESTATE and BAGGAGE routr was started
with, unchanged while export is off, within routr's limits: printable ASCII or tabs, at most 512 bytes for
TRACEPARENT and TRACESTATE and 8192 for BAGGAGE. A value outside them is withheld, and a warning names it. With
export on and a sampled trace, routr's launch span takes TRACEPARENT's place (below). Before, a headless worker
inherited them unchecked, and a pane worker got whatever the herdr server had. A pane's shell startup files can still
change what the worker finally gets. Nothing else about launching changes.
If you turn export on: routr workers, routr wait and routr cleanup --dry-run may then queue records and
start the detached sender, and routr launch --dry-run may queue its planned span; a dry run still runs no worker
step.
If you run routr launch --worktree in herdr: the worker now runs in a new pane split from the one herdr opens
with the worktree, and that first pane is closed, so the worker's pane can get routr's trace context. Launch's pane
is the new pane; routr cleanup works as before.
Highlights
- OpenTelemetry export, to your own endpoint.
-
Turn it on with
routr setup --otel-endpoint <url>: HTTPS, or HTTP on your own machine. Set any auth headers
withroutr key set otel-headers, which stores them as a secret. -
routr then sends OTLP/HTTP JSON:
- traces of its commands (
dispatch,launch,send,wait,cleanup,recordand the rest) and of
each headless worker turn; - logs of fixed events: a worker needing input, a warning, a failed usage read, a worker changing state;
- one gauge,
routr.subscription.headroom, for each numeric usage window of a fresh reading (none for kept,
given or assumed readings).
- traces of its commands (
-
A detached sender delivers them from a local queue and retries with backoff, so no command waits on the network.
-
routr doctorandroutr setup --showreport its status.routr setup --otel-offturns it off. -
Lineage follows OpenTelemetry's own rules:
- the launch is a child of the sampled trace context routr was started in, or starts a new trace when there is
none or it isn't valid; - a pane worker, and a headless worker's first process, get the launch span as
TRACEPARENT; a resumed headless
process, and every Cursor process, get their turn's span; - each recorded headless turn nests under its launch;
- later commands link to the launch.
A worker launched before you turned export on uses the parent it was launched with, or starts its own trace. An
unsampled parent sends no traces or logs and passes the context on unchanged. The lead's session id is
routr.lead.session_id, read from the lead harness's own variable, or from--lead-session <id>ondispatch,
subagentandlaunch. - the launch is a child of the sampled trace context routr was started in, or starts a new trace when there is
-
Sent once you turn it on: repository names, branch names, paths relative to the project, and ids.
-
Never sent: briefs, reports, prompts, replies, pane screens, keys, header values, baggage values, absolute paths.
-
Unlike routr's anonymous telemetry,
DO_NOT_TRACKand CI don't turn it off.routr setup --otel-off,
OTEL_SDK_DISABLED=trueorROUTR_OTEL=0do. -
Every span, attribute, log event and the gauge is in
docs/opentelemetry.md, pinned to
OpenTelemetry's GenAI semantic conventions (commit9ffc7e00, core conventions 1.44.0). -
It is separate from routr's anonymous telemetry, with its own setting, consent and state. An agent never turns
it on for you.
-
- Trace context reaches every worker. routr passes
TRACEPARENT,TRACESTATEandBAGGAGEto the workers it
starts: headless workers on every turn, a pane it splits, and a worktree's pane. Each one it does not pass is set
empty there, so a worker never picks up a stale trace from the herdr server. An existing--paneor an adopted
agent gets none, and launch says so. Output shows<forwarded>, never a value. - The lead's session no longer leaks into workers. Workers and usage reads used to inherit the lead agent's
session variables from Codex, Cursor, Antigravity and Kiro; before, only Claude Code's and Codex's thread id were
removed. They are now removed too, including Cursor's sudo-prompt secret, and so are herdr's pane variables. The
harness reference lists every name. - Fixes:
- On Windows, launch no longer times out when PowerShell's prompt is wider than the worker's pane, as with a long
worktree path in a half-width pane. - On Windows, a folder name with a curly quote (
Chris’s) reaches a PowerShell pane exactly; a cmd pane is refused
a path with%or!instead of getting it mangled. - Launch and Cursor's usage read no longer fail when herdr briefly can't report a new pane's processes.
- On Windows, a headless worker's saved state is far less likely to be missing for a moment while another routr
command reads it, which could makeroutr workersshow a finished worker as starting. - routr's shared file lock (the updater, headless workers, the background usage refresh) holds when a process
pauses or crashes: the lock records its owner's process, and routr frees it only once that process is gone. Where
a lock records no owner (a file system without hard links, or a lock left by an older routr), it is still freed
after ten minutes, even if its owner is only paused. - A background usage refresh that resumes late no longer overwrites a newer reading.
- On Windows, launch no longer times out when PowerShell's prompt is wider than the worker's pane, as with a long
Verification
Measured, all on 2026-10-26 unless noted:
-
Tests:
bun teston macOS, Linux and Windows. -
bun run smoke:carriers: live in herdr 0.9.5. It checks routr's own split code, carriers at their size
limits with hostile characters, a worktree pane, and the carrier left out arriving empty.- macOS (zsh): passes, including the started agent's own environment.
- Windows 11 ARM64 (PowerShell 5.1, herdr's x64 build): passes. The agent's environment can't be read on Windows,
so that part is macOS only. This run found the wrapped-prompt bug fixed above.
-
bun run smoke:otel: fixture harnesses, no subscription. Each run: 15 spans, 8 log records, the gauge, and a
sender killed mid-delivery recovering its batch.- macOS and Windows 11: pass.
- Every batch was also accepted and decoded by the reference OpenTelemetry Collector (contrib 0.120.1 and 0.136.0,
OTLP/HTTP receiver, debug exporter), with trace ids, parentage, typed attributes, the schema URL and, on 0.136.0,
each log record's event name intact.
-
Protocol checks (2026-10-25), with no prompt sent:
- Codex 0.164.0 answered
initializeandthread/startnormally with routr's request-leveltrace. - Kiro 2.34.0 answered
session/newnormally with routr's_metatrace fields.
This measures acceptance only. Acceptance on
turn/startandsession/promptwas not measured, nor was the
harnesses' own telemetry joining routr's trace. - Codex 0.164.0 answered
-
Live lineage: a real reviewer worker launched with a marker
TRACEPARENTreceived it (macOS, 2026-10-25). -
Review: every pull request was reviewed by a routr worker on another model family, and the feature as a whole
by one that had seen none of it. Its findings (the lock under a paused process, the late usage refresh,
concurrent sends, span timing, setup and docs wording) were fixed before this release.
Not measured:
- a vendor OpenTelemetry backend (only the reference Collector);
- Linux in a live herdr session (CI tests only);
- headless Kiro and Antigravity turns traced end to end with the real harness (their fixtures and protocol checks
only).
CLI and JSON compatibility
No field or flag was removed or renamed. Additions:
- New flags:
setup --otel-endpoint <url>and--otel-off;key set otel-headers;--lead-session <id>ondispatch,subagentandlaunch.
launch:start.envlists each trace-context carrier passed, as"<forwarded>".ranandwould_runshow
the split's--env NAME=<forwarded>, and--env NAME=for each carrier absent or withheld, and for--worktree
the split and the close of the root pane.workersandwait: a worker entry'scarriers_withheld, only when a carrier saved with the worker is now
outside rou...
routr 0.8.3
2 commits since v0.8.2
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.8.2
No configuration change is needed, and nothing to review in routr setup: no setting is new or changed.
The update reinstalls routr's skills, and the orchestrator guidance changed in this release (below). An agent that
already loaded routr reads the older wording until it rereads the skill or starts a new session.
Upgrading from 0.7.0
Read Upgrading from 0.7.0 in
the v0.8.0 notes first: routr launch and routr cleanup outside herdr changed in 0.8.0.
Changed
- The orchestrator guide says how to brief a fix and how to size the review after it. A fix's brief now states
the rule the fix must keep everywhere and where else that rule applies, not only the symptom the lead saw. After a
review, the next round is sized to what it found: a decision that is the user's goes to the user, a change in
behaviour goes back to the builder, and a trivial fix (one literal, a typo) the lead checks itself instead of
launching another round. Theroutr-orchestrateskill carries the same line. This came from a lead agent's report
on one orchestration (#106), where fixes briefed as their symptom took up to three review rounds each; it was
observed, not measured, and the guide says so.
Verification
bun teston macOS, Linux and Windows.- Review: by a routr worker on another model family, which found one unqualified claim; the lead removed it.
- Not measured: whether the new guidance reduces review rounds.
CLI and JSON compatibility
- No command, flag or JSON field changes. Config, saved advice, the ledger and telemetry: unchanged.
What's Changed
routr 0.8.2
3 commits since v0.8.1
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.8.1
No configuration change is needed, and nothing to review in routr setup: no setting is new or changed.
The update reinstalls routr's skills, and the guides changed in this release (below). Nothing a lead or worker must
do differently, but an agent that already loaded routr reads the older wording until it rereads the skill or starts
a new session.
If you uninstall routr: finish any headless worker first with routr cleanup --worker <name>. Uninstall now stops
and says so while one is there, and --purge also stops while a worktree a headless launch made is still under
~/.local/share/routr/worktrees.
Upgrading from 0.7.0
Read Upgrading from 0.7.0 in
the v0.8.0 notes first: routr launch and routr cleanup outside herdr changed in 0.8.0.
Fixed
routr uninstall --purgedeleted headless workers' worktrees unchecked. Since 0.8.0 the git worktrees a
headlessroutr launch --worktreemakes live under~/.local/share/routr, which--purgeremoved whole, uncommitted
work included, with none of cleanup's checks. A plain uninstall left headless workers' run folders and reports in
~/.local/state/routr, and a worker still running was left with no routr to follow or finish it. Now uninstall removes nothing,
in any mode and in a dry run, while a headless worker's run folder is there, and names the command that finishes
each (routr cleanup --worker <name>); a run folder a launch never finished writing is named by its path to look at.
With--purgeit also removes nothing while anything but empty folders is underworktrees/, in any layout, and
namesroutr cleanup --cwd <path> --path <path>, which keeps uncommitted work. A folder it cannot read stops it too.
Once nothing stops it, it also removes~/.local/state/routr.- An uninstall and a headless launch at the same moment cannot miss each other. Uninstall takes a lock before its
last check and releases it only once the rest of its state folder is gone; a launch that reserves its run folder
while the lock is held backs out, and one that comes after keeps its folder, which uninstall then keeps and says
so. A lock left by an uninstall that was stopped is never taken over: uninstall names the file to remove, and
launches go on. routr doctorno longer says orchestration needs herdr. Without herdr, workers run headless; herdr is needed for
pane workers and to read Cursor's usage, which is what doctor now says.--helpfordispatchandsubagentsays
the same.- The docs and guides say what 0.8 does. A sweep of every doc against the code after the headless-worker releases:
- the README, INSTALL, both skills and the guides describe workers in herdr panes or headless;
- an orchestrator never runs
routr subagent, in herdr or not, as the orchestrator guide already said (the skills
and thesubagentadvice'snextstep said "in herdr"); - the harness guide records how each usage reader works;
docs/contracts.mdcovers the headless commands' states, headlines and warnings;- the guarantees, troubleshooting and ranking pages cover uninstall, a headless worker's environment, the
stale-usage warning, the project.envroutr no longer loads, and kept readings; docs/evidence.mdadds the one measurement behind "delegating roughly doubles usage" and says what was not
measured for headless Claude Code;- the README now says three harnesses, not four, were measured following the skill.
Verification
- Tests: the uninstall cases driven through the CLI (a worker in every mode,
--purgewith a worktree holding an
uncommitted file, an unfinished run folder, an unreadable folder, a worktree in another layout, the plain uninstall
keeping it,--purgeonce clear), each interleaving of a launch and an uninstall the review raised, a linked state
folder, and a stale lock. Each new check fails without its fix.bun teston macOS, Linux and Windows. - By hand on macOS, in a throwaway home with no harnesses: the refusal messages, then a plain uninstall keeping the
worktree and removing the state folder. - Reviews: the doc sweep by two routr workers on other model families (an accuracy review against the code and a docs
audit), with a verification pass on the fixes; the uninstall fix by a routr worker on another model family, with
seven verification passes until it found nothing more. The briefs and reviews are kept in the maintainer's workbench,
not in this repository. - Not measured: uninstall racing a real headless launch (only the interleavings in the tests), and uninstall on
Windows beyond CI.
CLI and JSON compatibility
routr uninstallreturnsok: falsewitherror(exit 1) in the cases above, where it used to remove; a dry run
in those cases does the same. Its successful output is unchanged, and it may list~/.local/state/routras removed,
or as kept with a reason.- The
subagentadvice'snextstep reads "An orchestrator, in herdr or not, never runs routr subagent …". routr doctor's herdr line and step have new wording. Nothing else in--jsonchanges.- Config, saved advice, the ledger and telemetry: unchanged.
What's Changed
- Release notes for v0.8.2: uninstall checks headless workers and their worktrees, and the docs say what 0.8 does (#105)
- routr uninstall removes nothing while a headless worker is here, and --purge nothing while a worktree a headless launch made is (#104)
- Docs, guides and doctor say what 0.8 does: workers in herdr panes or headless, on every harness (#103)
routr 0.8.1
2 commits since v0.8.0
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.8.0
No configuration change is needed, and nothing to review in routr setup. The orchestrator and setup guides and
routr usage --help gained one clause (the usage refresh rule below); nothing an agent does changes, so a session that
already loaded routr need not reread it.
Upgrading from 0.7.0
Read Upgrading from 0.7.0 in
the v0.8.0 notes first: routr launch and routr cleanup outside herdr changed in 0.8.0. Then this release's fix
applies: Cursor or Kiro readings that 0.7.0 failed start again at the first call and show at the next.
Fixed
- Cursor stayed
unknownafter upgrading from 0.7.0. Cursor's and Kiro's usage are read in the background about
once per working session: when the last try is over 4 hours old, a call starts a fresh reading. A failed try by an
older routr counted too. On a machine where 0.7.0 failed every Cursor read (herdr 0.9.5),routr usage,routr dispatchandroutr setupunder 0.8.0 kept showing Cursor asunknownwith the assumed headroom (0.5 unless
assumed_headroomis set) for up to 4 hours, whileroutr usage cursorread it at once. Now, when the last try got
no reading and an older routr made it, the first call after the update starts a fresh reading in the background at
once (for Cursor, in a private herdr session). That call still shows the old state and says a reading is being
taken; the next call shows the new reading once it lands, a few seconds later for Cursor and about 10 s for Kiro.
Each write to the usage snapshot records the routr version that made it.
If Cursor or Kiro still shows unknown a minute after the first routr usage (or dispatch) under this version, run
routr usage cursor (or kiro): it reads now and its unavailable entry says why a reading fails.
Verification
- Reported on a macOS work machine on 0.8.0 (herdr 0.9.5, a Cursor Team plan):
routr usageshowed Cursorunknown
whileroutr usage cursorread Included 20% used, classincluded. The cause was found in the code and reproduced
by a test; the fixed build has not been run on that machine. - Tests: the case reproduced for Cursor and Kiro, with every kind of saved version (none, older, newer, the same, one
that is not a version), a failed reading after the upgrade, and a source checkout and an installed binary sharing
one cache (the newer retries once, the older never).bun teston macOS, Linux and Windows. - Review: a routr worker on another model family reviewed the code and docs in one review, and verified the fixes
three times. The brief and reviews are kept in the maintainer's workbench, not in this repository. - A test helper that could fail on Windows after its condition had held (seen once in CI) was fixed too.
CLI and JSON compatibility
Unchanged; nothing new in --json. The usage snapshot files in ~/.cache/routr gain a by field (the routr version
that last wrote them). Files without it are read as before, except that a failed try recorded in one no longer holds
back the next background reading (the fix above).
What's Changed
routr 0.8.0
11 commits since v0.7.0
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.7.0
No configuration change is needed, and none of your settings change: subscriptions, models, effort, reserves,
decision models, fallback_level, sure_at and update channel are read as before. There are no new settings, so
routr setup has nothing new to review.
The update reinstalls routr's skills, and the guides changed in this release: the orchestrator guide has a new
"Outside herdr: headless workers" section. Ask an agent that already loaded routr to reread the skill, or start a new
session. The binary and the guides update together.
If you run a lead outside herdr: routr launch used to need herdr, and routr-orchestrate outside herdr had the
lead size its own subagents instead. Now routr launch starts the worker headless (below), on that harness's
subscription, so routr-orchestrate outside herdr hands work out as it does in herdr. A lead inside Claude Code's Bash
sandbox or Codex's sandbox cannot start one: launch refuses and says how to run it outside the sandbox. Reading
Cursor's usage still needs herdr installed. A lead in herdr is unchanged: workers still run in panes.
If you run routr cleanup --worktree or --path (or the list) for a pane worker from a terminal outside herdr: it
now goes through git, cannot see a pane still working in the worktree, and does not close its herdr workspace. Run it
from inside herdr. cleanup --pane still asks herdr.
If a project of yours has a .env with ANTHROPIC_API_KEY: routr no longer loads it (below). If routr usage
or routr doctor showed Claude Code as billed per token in that project, it shows your subscription again.
Highlights
- Workers without herdr. Outside herdr,
routr launchstarts a Claude Code, Codex, Cursor, Antigravity or Kiro
worker headless, through the harness's own headless interface (Claude Code's and Cursor's-p, Antigravity's
--print, Codex's app-server, Kiro's ACP mode), on your existing sign-in: no API keys, no new
accounts. A routr process of its own holds each worker, and four new commands follow it:routr waitreturns when a worker finishes a turn, with the path of that turn's report, or fails, stops or is
lost. Name several workers to get whichever finishes first.routr sendsends a correction or a follow-up. How a correction lands depends on the harness: Claude Code and
Codex take it into the turn that is running (Claude Code: written into its input, measured mid-turn in a prototype
only; Codex: steered by its app-server); Cursor, Antigravity and Kiro run it as their next turn, in the order
sent, after the running one ends (state: "queued"). Once a worker is idle,sendresumes its session, its
context kept.routr workersshows each worker's state, turn, last tool and latest report path, never its text.routr stopends a worker through its own process, and says how many queued messages it dropped.
- Worktrees outside herdr.
routr launch --worktree <branch>makes the worker's git worktree itself, with git, on
that new branch, under~/.local/share/routr/worktrees(in herdr, herdr makes it).routr cleanup --worker <name>
removes it with the same checks as a pane worker's (nothing uncommitted, no file the worker made, no commit no branch
or tag holds), then the worker's run folder and reports. Outside herdr,routr cleanuplists and removes worktrees
through git. - What it leaves and keeps. Briefs and messages reach a worker on its standard input only, never in a command
line or a file. Each turn's report, the worker's own final message, stays in its run folder
(~/.local/state/routr/workers/<name>), owner-only on macOS and Linux, untilcleanup --worker. A Cursor worker
runs on a private copy of its config, as in a pane, and Cursor's own worker-server, which outlives each turn, is
left running and said; a directcursor-agent -prun in that folder leaves it too (seen once).
docs/guarantees.md, "Headless workers", has the
full list, including what routr cannot see. - routr no longer loads a project's
.envorbunfig.toml. In a project whose.envsetANTHROPIC_API_KEY,
routr's own Claude Code reads (sign-in status, usage) used that key instead of your subscription, so Claude Code
could read as billed per token, and a decision-model key orROUTR_*variable in that.envwas used too. Workers
thatroutr launchstarts were not affected. - Cursor with herdr 0.9.5.
routr usage cursorreads Cursor's usage again (it reportedread_failed, so routing
assumed half its headroom), androutr launch --kind cursorin a pane starts Cursor again: herdr 0.9.5 prints
nothing when it types into a pane, and routr read that as herdr not answering. The same fix coversroutr launch --paneinto a pane whose shell is in another folder, for every harness (from the code; not run live). - A usage reader that stopped working is said. When a subscription's last reading is over a day old and its last
try failed,routr dispatchandroutr usagewarn and give the command to read it again, androutr doctorlists
it, instead of quietly ranking on the assumed headroom. A metered seat, which has no reading to make, is not
flagged.
Verification
Measured (recorded in docs/evidence.md), each with the
real harness on a one-file task in a throwaway repository, the outcome read from the commits, each turn's report and
the harness's own session files, not from the worker's account:
- Claude Code: launch, report, a follow-up on the same session and cleanup on macOS, Windows ARM64 and Windows
x64; with--worktreeon macOS. 1 of 1 each. - Codex: launch, a correction sent mid-turn that changed what it committed, a follow-up that resumed its thread,
cleanup. macOS, 1 of 1. - Antigravity: launch, corrections sent mid-turn that ran as the next turns, one commit each, a follow-up that
continued its conversation, cleanup. macOS, 1 of 1. - Cursor: launch, two corrections sent mid-turn that ran as turns 2 and 3 on the same session, one commit each, a
follow-up once idle that resumed it, a stop mid-turn that dropped and counted the queued correction, cleanup with its
worker-server still running. macOS, 1 of 1. - Kiro: its ACP protocol, measured directly with Kiro itself on macOS. The loop through routr with a real Kiro
was not run (Kiro was turned off on the measuring machine): watch a Kiro worker's first turn closely.
Checked for this release:
- Cursor with herdr 0.9.5 (by hand on macOS, herdr 0.9.5, cursor-agent 2026.10.22; not in docs/evidence.md):
routr usage cursorwent fromread_failedto Included 2% used, classincluded;routr launch --kind cursor
with no task went fromherdr_unreachableto ready in its pane. 1 of 1. - Reviews: each change from #90 to #99 was reviewed before it merged by a routr worker on another model family:
#90 to #96 and #99 with a separate docs audit, #97 and #98 in one review of code and docs. The fixes were checked
again for #90 to #94, #96 and #99. The briefs and reviews are kept in the maintainer's workbench, not in this
repository. - Tests:
bun teston macOS, Linux and Windows. Headless workers on Linux, and every harness but Claude Code on
Windows, ran only against fake harnesses in CI.
Not measured:
- A fresh lead using only the guides, on real work of 30 minutes or more outside herdr.
- A correction sent mid-turn to a real Claude Code worker through routr.
- A killed holder, a background command left by a worker, stop mid-turn for Claude Code, Codex, Antigravity and Kiro
(only Cursor's was), and--worktreefor Codex, Cursor, Antigravity and Kiro. cleanup --cwdthrough git, andcleanup --worker --delete-branch, on a real worker; Kiro with a--modelother
than auto or with--effort; a hook the user trusted in Codex.
CLI and JSON compatibility
New commands: wait, send, workers and stop, for headless workers; each returns ok, headline,
unavailable, warnings and next like the others. Their fields are in
docs/contracts.md.
Changed commands:
routr launchoutside herdr (HERDR_ENVnot1) starts a headless worker instead of failing:paneis null and
workeris{ name, backend: "headless", run, session }. It needs a task (--task-fileor--task);--paneand
--directionare refused there. A--dry-runplans the pane launch as before. In herdr nothing changes.routr cleanup --worker <name>is new, with--delete-branchand--dry-run. Outside herdr,cleanup --worktree,
--pathand the list read git instead of herdr, and warn that they cannot see what runs in a worktree's folder.routr dispatchandroutr usageadd a warning and anextstep for a usage reader that stopped working;
routr doctorlists it as a step, and--jsonaddsusage_staleto that harness's entry.
Removed or renamed: nothing.
Config, saved advice, the ledger: unchanged. Advice saved by 0.7.0 is read by launch and record as before.
Telemetry: unchanged, and off unless you turned it on.
What's Changed
routr 0.7.0
9 commits since v0.6.1
Install / Upgrade
curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh # macOS, Linuxirm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex # WindowsThe same command upgrades an existing install. One standalone binary; no Node or Bun needed. Checksums are in SHA256SUMS.
Upgrading from 0.6.1
No configuration change is needed. Your settings file is read as before: a single decision model is read as a list
of one, and your subscriptions, models, effort, reserves, fallback_level, sure_at and update channel are preserved.
We recommend running routr setup once after upgrading and choosing "Decision model" from its menu, which now lets
you add a backup decision model. An agent can do the same with
routr setup --yes --decision typesafe,cloudflare:clef (the models you choose, first choice first). A backup needs its
own key: routr key set cloudflare for Clef on Workers AI; Ollama needs none. Changing the list, as with any change of
decision model since 0.6.0, drops a "sure_at": 0.8 line an older setup wrote, and setup says so, so each model's own
measured bar applies; if you chose 0.8 yourself, put it back. Upgrading without changing the list keeps it.
The update reinstalls routr's skills, and the guides changed in this release. Ask an agent that already loaded routr
to reread the skill, or start a new session. The binary and the guides update together, so a lead that rereads the
skill needs nothing else. Scripts of your own that read routr's JSON need the changes under
CLI and JSON compatibility.
Highlights
- Every handoff is advised.
routr launchrefuses to send a task withoutroutr dispatchadvice on that exact
task, reviews included, so a long-running lead can no longer skiproutr dispatchand launch at a model it fixed for itself. The
account, model and effort stay the lead's choice; dispatch always answers, with fallback advice when its decision
model cannot. Your reserves and level limits are applied in dispatch, so a launch can no longer skip them.record
refuses advice given on another task, so the ledger cannot claim advice a worker never got. - Every command says the same five things the same way. Each command a lead reads returns
ok(did it work),
headline(what happened),unavailable(what routr could not read, and why),warnings(what to know) and
next(what to do next), witherroronly whenokis false. What to do is only ever innext: exact commands that
run unchanged in bash, PowerShell and cmd, or instructions with a template. For example, a worker's folder-trust
question now carries the guide's trust rule, andrecord's next step depends on the outcome you recorded. - routr says what it could not read. When the decision model could not answer, the headline says so first, and
unavailablenames the model it tried, the reason and the fix (for a missing key, where to get one). A usage
reading routr could not make now is listed with the reading it kept and its age. - Name a backup decision model.
decisionis now an ordered list. routr asks each model in turn and the first one
that answers gives the reading; only when none can answer does it use yourfallback_level.- It moves on when a model cannot answer right now: a timeout, unreachable, a provider error, no key, a used-up
daily allowance, or a local model this machine cannot run or has not pulled. A refused key or a reply routr cannot
read stops there and is reported, because those are yours to fix. - A hosted model is cut at 8 s and the whole reading keeps one deadline. A local model is asked after every hosted
one, because it may need to load. - A backup's reading is ordinary advice, read with that model's own measured profile. The headline names the model
that answered,unavailablelists each earlier model that could not answer, andnextsays to tell the user. routr doctortests every entry and says which are ready.routr key setsaves a key and, if that provider is not
in your list, gives the setup command that adds it; it never changes your settings itself.
- It moves on when a model cannot answer right now: a timeout, unreachable, a provider error, no key, a used-up
- Outside text stays out. A decision model's reply, and herdr's and git's output, are classified where routr reads
them into a fixed set of messages. Their text never reaches routr's output, your ledger or telemetry, except a
worker's screen shown to the lead when the worker needs input. - docs/guarantees.md lists what routr reads,
writes, starts and removes on your machine, and the limits that remain. CHANGELOG.md now keeps a one-line
history of each release, linked to these notes.
Verification
Measured (recorded in docs/evidence.md):
- Why a backup model: on the model gate's 104 labelled briefs (2026-10-18), Clef on Workers AI read the level
exactly 72 times against 58 for the default constant fallback (standard), with 6 under-ratings against 22; on 36
real runs, 26 against 21. Jev, the default first choice, read 83.
Checked for this release:
- Is the output useful? Fresh Claude Code and Codex leads were each given only routr's skill and one real output,
in seven situations: a normal dispatch, the decision model down, every account at its reserve, a launch without
advice, a worker's startup question, a refused cleanup and a record revision. After three fixes, all 14 did what the
output said. - Reviews: each change was reviewed by a routr worker on another model family, which drove the CLI against fake
herdr, git and decision providers that plant marker text. No marker reached output or the ledger. The
reviews of the output contracts and the decision list broke the code on purpose 34 times, and every breakage now
fails a test. - Tests:
bun teston macOS, Linux and Windows, including the bash, PowerShell 5.1/7 and cmd command tests.
Not measured:
- How often a decision provider is down in real use, and so how often a backup answers.
- Jev 1.14: its gate on 2026-10-18 and two repeat gates on 2026-10-19 held the pin at 1.13.0. Fact readings were
less stable across repeats than on 1.13.0 in every run.
CLI and JSON compatibility
Renamed and removed output fields (no old name is kept beside its new one):
| now | was |
|---|---|
ran, would_run |
command, planned_command |
start.executable, start.argv, start.env |
argv, env |
screen |
needs_input.screen, pane_text |
id (record: the advice's id, beside run_id and ledger) |
recorded |
subscriptions.* in usage |
top-level fields |
excluded[].why |
excluded[].reason |
warnings |
config_notes, input_notes, warning |
decision[] in doctor --json, one entry per decision model |
key |
reading.* in named usage cursor and usage kiro |
top-level reading fields |
next (a list of run and do steps) |
launch's cleanup and needs_input.then, cleanup's then and refused.then, check's single next |
| removed | fallback, rule, refused, how, read_yourself |
New on every command a lead reads: ok, headline, unavailable, warnings, next. Fallback advice is now read
from a decision model entry in unavailable, not a fallback flag.
Commands:
routr launchneeds--advicefromroutr dispatchon the exact task;routr subagentadvice is refused. A
--dry-runwithout it still plans, returnsok: falseand exits 1.--trustis gone and is refused as an unknown
option.dispatchandsubagenttake--task-file; task and advice files may be UTF-8 (with or without a byte-order mark)
or UTF-16, as PowerShell saves them. An empty brief is a JSON refusal (exit 0; it was exit 2).recordneeds--subscription,--model,--effort,--verdictand--check; with--task-fileit refuses
advice given on another task.--run-idtakes a run'srun_id, not the adviceid.checkneeds--briefand--report.routr setup --decisiontakes a comma-separated ordered list;routr key setwith no provider uses the first entry
that needs a key.
Config: decision may be a list of { "provider", "model" }; a single object is still read. Bad or duplicate
entries are dropped with a warning whose setup command repairs the file.
Saved advice and the ledger: advice saved by 0.6.1 is still read by launch and record; a saved refusal is
refused. Ledger rows record the provider and model that answered, and a backup's reading is not marked as fallback.
Telemetry: unchanged, and off unless you turned it on.
What's Changed
- Release notes for v0.7.0 (#89)
- routr launch takes advice from routr dispatch only, so it cannot skip your reserves and level limits (#88)
- Name a backup decision model: routr tries your models in order before using the fallback level (#87)
- Every command says the same five things the same way: if it worked, what happened, what it could not read, what to know, and what comes next (#86)
- routr says what it could not read, and why (#85)
- Every handoff is advised, and each step says what comes next (#84)
- A changelog: one line per change, linked to each release's full notes (#83)
- A decision model's reply can no longer put its text in routr's output or your ledger (#82)
- Project rules are principles and patterns; what routr promises on your machine gets its own page (#81)