herdr version bumps
Shepherd drives an exact, measured herdr surface. HERDR_LAST_SUPPORTED_VERSION in
src/herdr-capabilities.ts is a verified ceiling, not a guess: every release above it is
unknown territory until this procedure has run against it. Twice a herdr record-shape change
silently killed husk reapers that kept compiling and logging nothing (#721, #2029); 0.8.0
changed last-tab teardown semantics underneath a best-effort closeTab (#2039). This SOP exists
so the next bump measures instead of assumes.
Trigger: a herdr stable release above the ceiling (the in-app updater shows “blocked”,
the preflight banner warns). Open the check from the issue form “herdr compatibility check”
(.github/ISSUE_TEMPLATE/herdr-compat.yml, label herdr-compat). Preview builds only on
explicit request — the protocol allowlist deliberately skips preview-only protocols (18 never
shipped stable).
Non-negotiables
Section titled “Non-negotiables”- The ceiling moves only in a PR that carries
docs/herdr-compat/<version>.md— the reportbun run herdr:compatwrites — with zero FAIL and every REVIEW triaged in writing (in the report or the PR). HERDR_SOCKET_SUPPORTED_PROTOCOLS(src/config.ts) is an explicit allowlist, not a floor. Admit a new protocol by number, after the schema diff shows what it changed.- Floors are floors.
HERDR_EXTERNAL_REGISTRATION_VERSION(0.7.5) andHERDR_FIRST_PANE_CONTROL_VERSION(0.7.3) never move for a ceiling bump.HERDR_LAST_FULL_SANDBOX_STATUS_VERSION(0.7.4) moves only when the L7 probe shows herdr #1716 actually fixed (an externally-registered agent’s--state idlelanding onidle, notdone) — re-verify by hand before touching it. - Never touch the operator’s live daemon. All live verification runs against isolated
headless servers (own
HOME/XDG_*/HERDR_SOCKET_PATH);scripts/herdr-compat/isolated-server.tsis the recipe. If you find yourself pointing a probe at~/.config/herdr/herdr.sock, stop. - Declining a version is a valid outcome. If a FAIL can’t be addressed, the issue documents why (as #2039 documented 0.8.0’s teardown change), the ceiling stays, and the blocked updater is correct behaviour.
Procedure
Section titled “Procedure”- Read the candidate’s release notes (
https://github.com/herdrdev/herdr/releases), watching for: tab/pane/agent/workspace lifecycle, close/teardown semantics, socket API or protocol, CLI flags, status/detection, install/update/asset changes, org or licence moves. - Run the check:
bun run herdr:compat -- --candidate <version>. Static half: schema diff (a removed method or result variant is FAIL only when Shepherd’s code outsidesrc/generated/references it as a quoted literal, otherwise REVIEW —scripts/herdr-compat/consumers.ts), the #2032 record-shape gate (TabInfo/PaneInfo/AgentInforequired/nullable drift = FAIL), and a--helpdiff over every subcommand Shepherd invokes. Live half: candidate vs. baseline (= current ceiling) as isolated servers, probes L1–L11 (reaper assumptions from #2029/#2032, tab-id reuse #569, last-tab behaviour #1760, the external-registration spawn replay #1890, the #1716 idle probe, the status surface, the terminal contract viascripts/verify-herdr-terminal.ts, whether a duplicate--agentregistration collides #2033, and whether a self-reported agent outlives its process herdr #4687). Report:docs/herdr-compat/<version>.md, exit 1 on FAIL. - Triage every REVIEW, fix or consciously accept every FAIL. Behavioural changes get code (as #2056’s last-tab guard did) and a test pinning the new behaviour.
- Regenerate the vendored protocol against the candidate:
HERDR_BIN=~/.cache/shepherd/herdr-compat/<version>/herdr bun run gen:herdr-schema && bun run gen:herdr-types, thenbun run gen:herdr-fixturesagainst a live candidate server (check:herdr-typesgates CI). - Walk the bump-PR checklist below, extend the bump-history table, run
bun run lintandbun run test, and ship — ceiling bump, verification report and behavioural fixes in one PR.
Bump-PR checklist
Section titled “Bump-PR checklist”Every past bump touched more than the constants. From #2056’s diff:
-
src/herdr-capabilities.ts—HERDR_LAST_SUPPORTED_VERSION,HERDR_LAST_SPAWNABLE_VERSION(+ version pins intest/herdr-capabilities.test.ts) -
src/config.ts— extendHERDR_SOCKET_SUPPORTED_PROTOCOLSby name if the protocol moved -
src/generated/herdr-schema.json+src/generated/herdr-protocol.tsregenerated -
test/fixtures/herdr-responses/manifest.jsonrecaptured (gen:herdr-fixtures) -
docs/herdr-compat/<version>.md— the report, committed -
README.md“supports herdr up to” +docs-site/src/content/docs/getting-started.md -
docs-site/scripts/gen-cli-reference.ts—EXPECTED_HERDR_VERSIONpin + regenerated CLI pages (the check-generated-docs gate fires on the source edit) - What’s-New entry
ui/src/lib/feature-announcements/entries/v<next>-herdr-<version>.ts+ EN/DE keys (see the feature-catalog rule; the update modal blocks silently otherwise — the entry is where the operator learns the ceiling moved) - Bump-history table below extended with what this version taught us
Bump history (extend with every bump)
Section titled “Bump history (extend with every bump)”| Version | What broke / what we learned | Fix | Ref |
|---|---|---|---|
| 0.6.x | Record-shape change silently killed a husk reaper — code compiled, logged nothing | Reaper fixed; lesson became #2032’s gate | #721 |
| 0.7.5 | agent start reshaped (canonical launcher); Shepherd’s spawn broke |
External-registration spawn path: tab create → pane run → report-agent |
#1890, #1893 |
| 0.7.5 | Externally-registered agents can’t report idle (lands on done) — sandbox status stuck |
HERDR_LAST_FULL_SANDBOX_STATUS_VERSION floor at 0.7.4 + two-path downgrade advisory |
herdr #1716, #1898 |
| 0.7.5 | pane.label / agent.name went optional; FOUR reapers dead at once, silently |
Key reapers on the tab label; fixture-shape regression tests | #2029, #2034 |
| 0.8.0 | Closing a workspace’s last tab destroys the workspace (was: refused) — closeTab swallowed the refusal harmlessly before |
Last-tab guard at the closeTab choke point, both drivers; teardown rebuilds via ensureWorkspace |
#2039, #2056, herdr #1760 |
| 0.8.0 | Protocol 18 never shipped stable | Allowlist admits protocols by name, never >= |
#2039 |
| 0.8.0 | Upstream org rename (ogulcancelik → herdrdev) — install/downgrade hung off a GitHub redirect |
All three URL sites in herdr-install.ts moved (incl. the shell template that builds its own URL) |
#2039, #2056 |
| 0.8.2 | Protocol 20 is additive; the driven CLI/records and live behaviour are unchanged, while #1716 remains unfixed | Admit protocol 20 by name, keep the external-registration path and the sandbox-status floor at 0.7.4 | #2096 |
| 0.9.1 | Nothing on the driven surface moved (protocol stayed 22, schema only gained pane.link.resolve, no record or --help drift) — but the release’s real changes hide behind UNCHANGED flags, which S4 cannot see |
Read the notes, not just the diff: the 30s terminal-observer disconnect lands on the default-OFF socket terminal, whose onAbnormalExit reads a missing close record as version skew |
herdr #3612, #4123; docs/herdr-compat/0.9.1.md |
| 0.9.2 | The schema dropped pane.graphics.*, which Shepherd never used, yet the all-FAIL S2 blocked on it; and herdr #4687 now drops a self-reported agent once its pane’s shell is idle, so a sandboxed session loses its record on exit, and a registration landing before the typed command forks would be cleared for good |
S2 FAILs a removal only when Shepherd references it (else REVIEW); L11 probes the record after exit; both drivers register only once the pane has left its shell; poller tests pin reap-to-done, husk never stranded |
herdr #4561, #4687; docs/herdr-compat/0.9.2.md |
| 0.9.3 | A hotfix confined to the attached client’s stdin escape framer (herdr #4751), a path Shepherd never feeds (it writes through pane send-keys/send-text and the socket terminal). The first run still came back REVIEW: the isolated servers inherited the operator’s $SHELL, and zsh’s newuser wizard under the empty HOME ate every typed pane run command, so L7 read undetermined on both sides |
startIsolatedServer pins SHELL=/bin/sh; an undetermined on BOTH sides points at the probe environment, not herdr |
herdr #4751; docs/herdr-compat/0.9.3.md |
| 0.9.4 | Nothing on the driven surface moved (protocol 22; schema, records, --help and fixture manifest identical). The one spawn-adjacent change is macOS-only and invisible to the Linux probes: pane run/agent start now reject a typed line longer than the tty’s canonical limit instead of truncating it (herdr #4988). Closing a workspace’s only pane now asks first, but in the TUI only (#5173) |
No code change: Shepherd types only sh '<script>' (#1967), pinned under Darwin’s MAX_INPUT by test/spawn-script.test.ts; CLI/API closes stay immediate. Trace platform- or TUI-only notes by hand and cite the pin that covers them |
herdr #4988, #5173; docs/herdr-compat/0.9.4.md |
| 0.9.5 | A hotfix whose driven surface didn’t move (protocol 22; schema, records, --help and fixture manifest identical). Its changes sit in herdr’s agent-detection manifests and integration assets: Codex turn hooks are gone and Codex status is screen-detected again (#5278), and Claude questions in --name//rename sessions now read blocked (#5192) |
No code change: Shepherd never runs herdr integration install or names its Claude sessions; sandboxed sessions push their own state. Trace detection- and integration-only notes against how Shepherd launches agents, not the schema |
herdr #5192, #5278; docs/herdr-compat/0.9.5.md |
| any | tab_ids must not be reused across a close |
Probed on every bump (L4) | #569 |
| any | A pane-inherited HERDR_SOCKET_PATH can override an explicit HERDR_SESSION |
Session socket wins; scrub HERDR_ENV in isolated probes |
#1596 |
| any | The terminal NDJSON contract (socket-pty-bridge) can drift without a schema change |
scripts/verify-herdr-terminal.ts runs as probe L9 |
#1639 |
Opportunities file
Section titled “Opportunities file”Release notes often carry chances, not just risks (#2039 flagged HERDR_PROCESS_DETECTION=child-groups
as a path to retiring the sandbox advisory). Note them in the compat issue under “Opportunities” —
they become follow-up issues, never scope creep in the bump PR.