Skip to content

Releases: sirkirby/routr

routr 0.9.4

Choose a tag to compare

@github-actions github-actions released this 28 Oct 01:16
e0118ab

2 commits since v0.9.3

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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.0 about 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 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 when standalone read 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 test on macOS, Linux and Windows. The tests expect jev-1.14.0 as the default, and a case reads
    jev-1.13.0 asked 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: dispatch read a brief with jev-1.14.0, and doctor reported it answering. In a throwaway
    home, a config naming jev-1.13.0 was dropped with the warning and its fix, and --decision typesafe:jev-1.13.0 was
    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 name jev-1.14.0;
    doctor shows it in decision[].asked and, when it answers, decision[].model. Other configured providers, and
    ledger rows already written, keep their own.
  • sure, between, notes and next: with no sure_at of 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 now sure: true, without between or the torn-reading note and steps. A
    sure_at you set yourself still applies.
  • routr setup --decision typesafe:jev-1.13.0 is refused as a model routr has not measured; a config entry naming
    it is dropped, with a warning that names a routr setup --decision command for the entries that remain.

What's Changed

  • Release notes for v0.9.4 (#135)
  • routr reads briefs with Jev 1.14.0; the gate holds what a lead acts on (#134)

routr 0.9.3

Choose a tag to compare

@github-actions github-actions released this 27 Oct 20:35
5b504cb

3 commits since v0.9.2

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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 share and share_due fields and how the lead uses them;
  • the orchestrator guide says to take share_due among 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 setup kept 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: claude 3 and codex 1 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=off removes 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. dispatch and usage read the last 7 days.
      Each metered account then shows how far it is below its target, and share_due names the one furthest below.
      The lead still chooses model and effort fit first, and takes share_due among 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 uninstall removes the records with routr's other state.
    • Not measured: whether leads following share_due reach your ratio in practice.
      (#131, #132)

Verification

  • bun test on 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 --share in 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-account usage
    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.

  • dispatch and usage: subscriptions.share_due, and share { weight, target, used_pct, left, launches, of }
    on each normal metered row, only when a share applies. Those rows are then ordered by left among themselves;
    headroom, usable, candidates and most_room are unchanged. usage <subscription> never shows a share.
  • setup: new --share <subscription>=<1-99>|off; share in config.json and in setup --show.
  • launch: writes one launch record when it ends prompted or ready; its output does not change.

What's Changed

  • Release notes for v0.9.3 (#133)
  • Guided setup asks for the launch share, and keeps answering keys after you skip the key question (#132)
  • A share setting splits work between metered accounts by a ratio you choose (#131)

routr 0.9.2

Choose a tag to compare

@github-actions github-actions released this 27 Oct 18:43
ebd0c56

6 commits since v0.9.1

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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 was class: "unknown"
    on an assumed headroom, and doctor asked you to set billing by hand. The seat has no quota: its /usage shows
    no usage windows, only usage credits spent. routr now reads "subscriptionType": "enterprise" on a first-party
    claude.ai login from claude auth status as metered, but only when /usage answered with no windows:

    • an Enterprise seat with a quota keeps the same plan name, so its windows still decide;
    • a /usage read that failed, or an answer that was empty or cut short, stays a failed read, never "no quota";
    • your own billing setting 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 --worktree starts in its worktree. routr built Antigravity's
    command before herdr made the worktree, so it started with --add-dir set 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 the routr cleanup --path <folder> command to run once you've checked it is the worker's. It never removes
    one on its name alone. cleanup --worker no 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), usage or doctor: it is read as unreadable, and routr answers on the defaults with a note. (#125)
  • launch --worktree --copy in 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|off and routr uninstall write config.json and Claude's settings.json
    whole, keeping their permissions and any link to them (a dotfiles settings.json, say), so another command never
    reads them half written. routr's telemetry state, telemetry.log and update.log are written whole too. (#125)
  • routr usage --level with an unknown level lists only the real levels. (#125)

Verification

  • bun test on 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 status and /usage as described above. Then, with a fake claude answering the same way in a
    throwaway home, routr read it as metered; an Enterprise seat with windows as included, and a Team seat without
    windows as unknown, as before. Not measured: an Enterprise seat with a quota (from Anthropic's docs).
  • The Antigravity fix, live in herdr: a launch with --worktree started the real agy with --add-dir in 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, dispatch and doctor --json: a usage-based Claude Enterprise seat has class: "metered",
    usage: "metered" and headroom and usable null, where it had class: "unknown" and usage: "assumed" on the
    assumed headroom. In doctor --json, harnesses.claude has usage_class: "metered" and
    usage_source: "claude auth status", and no usage_reason or next step. A Claude /usage answer 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_response or invalid_response in unavailable), where it counted as "no usage windows".
  • cleanup --worktree: a new refusal, for a detached worktree named for the branch, carrying worktree (when
    exactly one matches) and a next step with the --path command for each, where it answered ok with absent.
    cleanup --worker on its own detached worktree says what the worktree holds is not checked, instead of calling
    it not the one launch made.
  • launch --kind agy --worktree in herdr: start.argv carries 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_run does.
  • launch --worktree --copy in 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
    error and next; it used to answer ok after overwriting or following the link.
  • usage --level: the refusal for an unknown or repeated level lists basic, 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

Choose a tag to compare

@github-actions github-actions released this 26 Oct 17:06
f698c42

2 commits since v0.9.0

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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 send said "no session to resume; launch the work again", and skipped its check that the harness had
      stopped.
    • routr cleanup --worker and routr stop skipped their check of the harness's process group.
    • routr workers showed the worker as starting, or left it out.
    • routr wait could stop waiting.

    Now:

    • no new worker process starts over a file it can't read;
    • send, stop and cleanup --worker refuse, with an error naming the file, though stop still stops a worker
      process that answers, and send still delivers to one when only the state file is unreadable;
    • for an unreadable record or state, workers shows unreadable, and wait keeps waiting;
    • for an unreadable marker, workers shows unreachable, and wait reports 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.

  • worker.json, and the file wait uses to remember what it has already reported, are now written whole, so another
    command never reads them half-written.

Verification

  • bun test on macOS, Linux and Windows. A new test, with a fixture harness, makes a worker's record and then its
    state unreadable, and checks workers, wait, send, stop, cleanup --worker and 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.

  • workers and wait: a worker entry's state can be unreadable (record or state), or unreachable for an
    unreadable marker, as for a process that doesn't answer. When its worker.json is unreadable,
    kind, model, effort and cwd are null.
  • stop: state is unknown also when the worker isn't running and its record or state can't be read.
  • send, stop and cleanup --worker: new refusals, whose message names the file, with a next step for a file
    that stays unreadable.

What's Changed

  • Release notes for v0.9.1 (#124)
  • A headless worker's state that routr cannot read is treated as unknown, never as none (#123)

routr 0.9.0

Choose a tag to compare

@github-actions github-actions released this 26 Oct 15:18
3ecefdd

14 commits since v0.8.3

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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
      with routr 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, record and 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).
    • A detached sender delivers them from a local queue and retries with backoff, so no command waits on the network.

    • routr doctor and routr setup --show report its status. routr setup --otel-off turns 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> on dispatch,
      subagent and launch.

    • 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_TRACK and CI don't turn it off. routr setup --otel-off,
      OTEL_SDK_DISABLED=true or ROUTR_OTEL=0 do.

    • Every span, attribute, log event and the gauge is in
      docs/opentelemetry.md, pinned to
      OpenTelemetry's GenAI semantic conventions (commit 9ffc7e00, 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, TRACESTATE and BAGGAGE to 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 --pane or 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 make routr workers show 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.

Verification

Measured, all on 2026-10-26 unless noted:

  • Tests: bun test on 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 initialize and thread/start normally with routr's request-level trace.
    • Kiro 2.34.0 answered session/new normally with routr's _meta trace fields.

    This measures acceptance only. Acceptance on turn/start and session/prompt was not measured, nor was the
    harnesses' own telemetry joining routr's trace.

  • Live lineage: a real reviewer worker launched with a marker TRACEPARENT received 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> on dispatch, subagent and launch.
  • launch: start.env lists each trace-context carrier passed, as "<forwarded>". ran and would_run show
    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.
  • workers and wait: a worker entry's carriers_withheld, only when a carrier saved with the worker is now
    outside rou...
Read more

routr 0.8.3

Choose a tag to compare

@github-actions github-actions released this 24 Oct 20:03
034230b

2 commits since v0.8.2

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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. The routr-orchestrate skill 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 test on 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

  • Release notes for v0.8.3: the orchestrator guide says how to brief a fix and size the review after it (#108)
  • The orchestrator guide says to brief a fix by the rule it must keep, and size review rounds to what they found (#107)

routr 0.8.2

Choose a tag to compare

@github-actions github-actions released this 23 Oct 21:22
a2dd6b6

3 commits since v0.8.1

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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 --purge deleted headless workers' worktrees unchecked. Since 0.8.0 the git worktrees a
    headless routr launch --worktree makes live under ~/.local/share/routr, which --purge removed 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 --purge it also removes nothing while anything but empty folders is under worktrees/, in any layout, and
    names routr 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 doctor no 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. --help for dispatch and subagent says
    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 the subagent advice's next step said "in herdr");
    • the harness guide records how each usage reader works;
    • docs/contracts.md covers 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 .env routr no longer loads, and kept readings;
    • docs/evidence.md adds 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, --purge with a worktree holding an
    uncommitted file, an unfinished run folder, an unreadable folder, a worktree in another layout, the plain uninstall
    keeping it, --purge once 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 test on 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 uninstall returns ok: false with error (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/routr as removed,
    or as kept with a reason.
  • The subagent advice's next step reads "An orchestrator, in herdr or not, never runs routr subagent …".
  • routr doctor's herdr line and step have new wording. Nothing else in --json changes.
  • 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

Choose a tag to compare

@github-actions github-actions released this 23 Oct 04:39
5361285

2 commits since v0.8.0

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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 unknown after 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 dispatch and routr setup under 0.8.0 kept showing Cursor as unknown with the assumed headroom (0.5 unless
    assumed_headroom is set) for up to 4 hours, while routr usage cursor read 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 usage showed Cursor unknown
    while routr usage cursor read Included 20% used, class included. 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 test on 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

  • Release notes for v0.8.1: Cursor and Kiro usage read again at once after an update (#102)
  • After an update, routr usage reads Cursor and Kiro again at once (#101)

routr 0.8.0

Choose a tag to compare

@github-actions github-actions released this 23 Oct 03:38
d06c87e

11 commits since v0.7.0

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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 launch starts 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 wait returns 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 send sends 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, send resumes its session, its
      context kept.
    • routr workers shows each worker's state, turn, last tool and latest report path, never its text.
    • routr stop ends 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 cleanup lists 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, until cleanup --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 direct cursor-agent -p run 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 .env or bunfig.toml. In a project whose .env set ANTHROPIC_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 or ROUTR_* variable in that .env was used too. Workers
    that routr launch starts were not affected.
  • Cursor with herdr 0.9.5. routr usage cursor reads Cursor's usage again (it reported read_failed, so routing
    assumed half its headroom), and routr launch --kind cursor in 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 covers routr launch --pane into 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 dispatch and routr usage warn and give the command to read it again, and routr doctor lists
    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 --worktree on 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 cursor went from read_failed to Included 2% used, class included; routr launch --kind cursor
    with no task went from herdr_unreachable to 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 test on 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 --worktree for Codex, Cursor, Antigravity and Kiro.
  • cleanup --cwd through git, and cleanup --worker --delete-branch, on a real worker; Kiro with a --model other
    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 launch outside herdr (HERDR_ENV not 1) starts a headless worker instead of failing: pane is null and
    worker is { name, backend: "headless", run, session }. It needs a task (--task-file or --task); --pane and
    --direction are refused there. A --dry-run plans the pane launch as before. In herdr nothing changes.
  • routr cleanup --worker <name> is new, with --delete-branch and --dry-run. Outside herdr, cleanup --worktree,
    --path and the list read git instead of herdr, and warn that they cannot see what runs in a worktree's folder.
  • routr dispatch and routr usage add a warning and a next step for a usage reader that stopped working;
    routr doctor lists it as a step, and --json adds usage_stale to 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

  • Release notes for v0.8.0: workers without herdr, on every harness (#100)
  • Outside herdr, routr launch starts headless Cursor workers, one process a turn (#99)
  • Outside herdr, routr launch starts headless Kiro workers...
Read more

routr 0.7.0

Choose a tag to compare

@github-actions github-actions released this 19 Oct 19:41
e065346

9 commits since v0.6.1

Install / Upgrade

curl -fsSL https://raw.githubusercontent.com/sirkirby/routr/main/install.sh | sh     # macOS, Linux
irm https://raw.githubusercontent.com/sirkirby/routr/main/install.ps1 | iex     # Windows

The 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 launch refuses to send a task without routr dispatch advice on that exact
    task, reviews included, so a long-running lead can no longer skip routr dispatch and 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), with error only when ok is false. What to do is only ever in next: 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, and record'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
    unavailable names 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. decision is 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 your fallback_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, unavailable lists each earlier model that could not answer, and next says to tell the user.
    • routr doctor tests every entry and says which are ready. routr key set saves a key and, if that provider is not
      in your list, gives the setup command that adds it; it never changes your settings itself.
  • 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 test on 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 launch needs --advice from routr dispatch on the exact task; routr subagent advice is refused. A
    --dry-run without it still plans, returns ok: false and exits 1. --trust is gone and is refused as an unknown
    option.
  • dispatch and subagent take --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).
  • record needs --subscription, --model, --effort, --verdict and --check; with --task-file it refuses
    advice given on another task. --run-id takes a run's run_id, not the advice id.
  • check needs --brief and --report.
  • routr setup --decision takes a comma-separated ordered list; routr key set with 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)