Releases: andrewwint/baton
Release list
v1.3.3
Patch. Closes the run-ledger fidelity gaps an end-to-end verification surfaced (known-count on a real
routed session, not a writer unit pass). No change to the frozen 1.0 contract or the enforcement gate.
- Every captured lane now carries a stable id. A live probe of the real
PostToolUsepayload showed
the spawn id is present attool_response.agentId(with top-leveltool_use_idas a fallback) — the
earlier nulltask_idwas a wrong-key extraction bug, not a payload limitation, so no new lifecycle hook
is needed.record_lane_spawn.pyandledger.pynow record that id (the same value the Agent tool
returns and a manager would cite incontract_lane). It stays a secondary signal to non-generic
subagent_typein the disposition deriver — a model-visible id never becomes the sole certifier of a
specialist. - The ledger de-duplicates a double-fired spawn. When the hook is wired in more than one settings scope
(project and user-global), one real spawn fires it twice; the ledger now records exactly one lane line
per spawn via a race-safe first-writer-wins marker keyed on the id (verified under 40-process contention).
So N routed lanes produce exactly N lane lines even in a multi-wired install. - Verified by an observed firing, not a unit pass. On real dispatch (implementer + code-reviewer +
researcher), the ledger recorded exactly 3 lane lines, each with its realagentId. The de-dup, id
population, and known-count behavior are exercised by new self-tests gated in CI (nine hook self-tests).
v1.3.2
Patch. Fixes an enforcement blind spot found on a live interactive /baton run, plus run-trail
consistency. No change to the frozen 1.0 contract.
- Interactive-path enforcement now engages (the significant fix). The close-out deriver decided whether
the spawn/triage sidecars were wired by reading only the project.claude/settings.json. But the
interactive/batonpath wires the enforcement hooks in the user-global~/.claude/settings.json, so
in an ordinary repo (no project settings) the deriver believed the sidecars were unwired and silently fell
back to record-only: the completeness gate went silent and the anti-forgery spawn-match no-op'd, even with
a real independent lane recorded. The wired-check now consults project, project-local, and user-global
settings, so both the completeness gate and the specialist spawn-match engage on the interactive path. - Inline-triaged seams can reach the machine ledger. A new manager-run recorder
(hooks/record_seam.py) writes a seam identified inline (no triage lane) to the same
triaged_seams.jsonlthe completeness gate reads, arming it — add-only (it records an obligation, never
clears one). SKILL.md/triage.md: inline triage is for non-seam work; a named seam must be machine-recorded. - The run-trail close-out count is single-source. It is now derived only from ledger.py's own recorded
lane lines (superseding 1.3.1's reconciliation with the sibling ledger), anchored to the lane-line shape,
so the count can never contradict the lines shown — in either direction. Close-out label clarified to
"lanes recorded so far" (a per-stop snapshot).task_idis documented as expected-null from Claude Code's
PostToolUse payload; the specialist match binds bysubagent_type, so it is not load-bearing.
v1.3.1
Patch. Fixes a consistency bug in the run trail surfaced by a real integration test: the Stop
close-out could print lanes recorded this session: 0 directly above the lane lines it had just
written. The count read only the sibling machine ledger (lane_spawns.jsonl, written by
record_lane_spawn.py); when that hook had not fired, the count read 0 despite ledger.py having
recorded the spawns itself. The close-out count now derives from ledger.py's own recorded lane
lines, reconciled with the sibling ledger (the higher of the two), so it is never lower than the
lines shown and a sibling-only observation is not lost. Trail-only; no change to any enforcement
verdict, the disposition gate, or the frozen 1.0 contract.
v1.3.0
Minor. Adds a bundled run-trail hook and makes baton's hooks fire on the interactive /baton path
(previously only baton's TypeScript runtime wired them), so the enforcement and trail work without the
runtime. Additive to the frozen 1.0 contract (loop and routing gate, lane map and five bundled agents,
RunRecord shape, MCP-via-.mcp.json), which is unchanged. This entry describes what ships, not what it
achieves — no efficacy claim.
- The run trail is hook-maintained, not memory-maintained. A bundled dual-event hook
(hooks/ledger.py, wired onPostToolUseandStop) keeps a session-scoped trail at
.agents/runs/ledger.mdregardless of whether the model remembers to write one: a line per real lane
spawn, and an idempotent close-out per stop. It is operability, not part of the security-enforcement
contract — its absence loses a trail, never a gate — sobaton doctorwarns (non-gating) when it is not
wired. Claude Code runsStophooks in parallel, so the close-out tolerates a not-yet-stamped verdict
(unstamped) and self-corrects on the next stop; it never derives or overrides the gate's verdict. - An absent disposition record is now explained, not silently missing. On a run where triage names no
sensitive seam, the close-out records why nodisposition.jsonexists (READY by the no-seam row), so a
correct no-seam run is distinguishable from a skipped gate. - Enforcement wires on the interactive path. A shipped self-installer (
hooks/wire_interactive.py)
wires the enforcement + trail hooks into the user-global~/.claude/settings.jsonwith absolute paths,
excluding the SessionStart guard (whose per-project verification-marker model would fail-loud in unrelated
repos). It is idempotent, preserves existing settings, and runsbaton doctorto confirm. The settings
wirer (wire_settings.py) now ships inside the skill, so an installed-only machine can self-wire with no
repo checkout — andbaton doctorpoints at that shipped path rather than a file that isn't present. - Triage names a deployment seam. An outward-facing cloud deploy that creates an IAM role, exposes a
public or no-auth endpoint, or routes data to a hosted model is adata-egress/secrets/authzseam
even when no source line changed; it travels the disposition path, not only the approval gate. - Honest labels. The plan step's
contract-readcheckpoint is labeled guardrail-strength, not
enforcement-strength — no hook can detect an unfamiliar external tool, so it stays a model-written prompt. - CI. The bundled hook self-tests (disposition, contract, doctor, session-start, wiring, self-installer,
ledger) run in the structural smoke gate, and CI triggers onhooks/**.
v1.2.0
Minor. Adds the bundled close-out enforcement the 1.1.x prose framed as "a later release" — the
disposition record's verdict is now derived and stamped by a hook, and a skipped record is structurally
detectable. Additive to the frozen 1.0 contract (loop and routing gate, lane map and five bundled agents,
RunRecord shape, MCP-via-.mcp.json), which is unchanged. This entry describes what ships, not what it
achieves — no efficacy claim.
- The verdict is derived, not declared. A bundled Stop hook (
hooks/disposition_gate.py, wired in
settings.json) re-derives the disposition verdict from the record's facts and stamps it; the model's
own token is kept as an advisoryverdict_emitted. Removing the model's authorship of the verdict is the
design — a model that disagrees can no longer re-emit a non-derivable token. - The record's existence is enforced, not asked for. A PostToolUse sidecar
(hooks/record_triaged_seams.py) records the sensitive seams triage names (theTRIAGE-SEAMSreturn-format
contract) to a session-scoped ledger; the close-out completeness gate cross-checks it, so a sensitive seam
cleared without adisposition.jsonis stampedMISSING-RECORDinstead of passing silently. A
malformed/unparseableTRIAGE-SEAMSline fails loud toUNVERIFIED-SEAM(seams indeterminate) rather than
silently shrinking what is owed a disposition. - Fabrication is caught at run time, not only post-hoc. A PostToolUse sidecar
(hooks/record_lane_spawn.py) records realTask/Agentspecialist spawns; a claimedspecialist
contract with no recorded spawn is downgraded toUNVERIFIED-SEAM— a signal the model cannot forge by
narrating. Its trust boundary is stated honestly in the hook: it proves a lane spawned, not that it did
good work. - New verdicts name two honest middles:
REVIEWED-CLEAN(a real review lane cleared a sensitive seam
that recorded no independent specialist — reviewed, nothing found, not READY) andMISSING-RECORD(the
record was never written). Both are shape-only additions — the vendored disposition-contract predicate and
itsCONTRACT_SHAare unchanged. - Install health is checkable.
hooks/doctor.pyproves the enforcement is wired and firing on the
machine (with the optional TypeScript runtime absent), and a SessionStart guard fails loud when it is not
verified. The Python hooks are the standalone floor — enforcement does not depend on the runtime. - Coupled-shape documentation.
docs/coupled-shape-spec.md(the ratifiedTRIAGE-SEAMS+ disposition
record shape) anddocs/triaged_seams.format.md(the ledger read-surface) ship as synced reference copies
of the canonical originals; the forge-proof completeness cross-check is runtime-bound, so the shape is
shared while the gate stays in the runtime.
v1.1.2
Patch. Documentation-only — one SKILL.md sentence, tense only. No schema, hook, or behavior
changes. This entry describes what shipped, not what it achieves — no efficacy claim.
- The emission-gate prose can no longer be read as a present machine-enforcement claim. The
disposition section describes a bundled close-out hook that machine-derives and stamps the verdict
from the record; the sentence was future-framed but its tail ("so the enforcement no longer depends
on the model remembering") could be misread as a present claim. In a pre-enforcement release that
reads as an unbacked enforcement claim. The wording is tightened to unambiguous future ("a later
release will add … so that enforcement will no longer depend on the model remembering").
1.1.x remains the manager's discipline — model-based derivation from the record, no machine
enforcement; the close-out hook that machine-stamps the verdict is a later release.
v1.1.1
Patch. Documentation-only — SKILL.md prose. The frozen 1.0 contract (the loop and routing gate,
the lane map and five bundled agents, the RunRecord ledger shape, and MCP-via-.mcp.json) is
unchanged, and no runtime behavior changes. This entry describes what shipped, not what it achieves
— no efficacy claim.
- The data-residency guard now travels with the shipped skill. The MCP-discovery guidance states
inline that a configured MCP server may be cloud-hosted — its calls send data off the machine — so
egress should be gated on your data-residency posture, the way you would a deploy. This caveat
previously lived only in a separatedocs/note that a global or plugin install did not carry; it
now sits inSKILL.mditself, so every install has it. - Resolvable documentation pointers. A
SKILL.mdreference todocs/research-basis.mdused a
repo-relative path that resolved only inside the source checkout and dangled from a standalone
(global or plugin) install; it is now an absolute URL. The MCP section's danglingdocs/MCP.md
pointer is removed and its behavioral rules inlined, so the skill carries what it needs to behave
correctly rather than pointing at a file that may not travel with it. - Repo Detection reshaped into capability-triggered discovery. The section is rewritten as a
short Tool & MCP discovery protocol — lexical by default; configured servers only; manager-only and
allowlisted by exact name; name a missing capability rather than proceeding silently — replacing a
hardcoded runtime-manifest list that could not stay current. - The recovery bound cites its source. The ~2-attempt recovery bound now names CodeTransOcean's
DSR@K (arXiv:2310.04951) — automated-repair gains are highest in the first round and plateau by the
third — in place of an unsourced "evidence-informed" note.
Not in this release: the enforcement build (the close-out disposition gate, doctor, and session-start
guard) and the security-review source-derivation work remain held for a later version. 1.1.1 is
documentation-only and changes no runtime behavior.
v1.1.0
Minor bump: the frozen 1.0 lane map gains a fifth bundled agent, so this is not a patch. The loop,
the routing gate, the RunRecord ledger shape, and MCP-via-.mcp.json are unchanged. This entry
describes what shipped, not what it achieves — no efficacy claim.
- Fifth bundled lane —
security-review: an independent, read-only security-contract lane the
verify step consults (as its ownsubagent_typesubagent) on a sensitive seam that has no
independent contract. It derives the seam's invariants from source and carries no ruleset of its
own; it may invoke a project/security-reviewskill for depth. This is the change to the frozen
lane map that makes this release a minor bump rather than a patch. - A disposition discipline for sensitive-seam review: on a sensitive seam class (authorization /
tenant-isolation, data egress, writes/mutations, auth gates, secrets), the verify step separates
identifying an exposure from disposing of it — the lane that finds an exposure does not clear
it; an identified exposure escalates to a named independent party. The manager records the facts
in.agents/runs/<runId>/disposition.json(seams triaged, each seam's contract source, exposures,
dispositions) and derives the review verdict from that record rather than declaring it free-hand,
failing loud (UNVERIFIED-SEAM) on a seam nobody could independently verify. This ships as
discipline inSKILL.md; a bundled close-out hook that machine-enforces the derivation is
planned for a later release, not in 1.1.0. - Installable as a Claude Code plugin:
.claude-plugin/plugin.jsonandmarketplace.jsonlet
Baton install via/pluginalongside the existing loose-skill install, reusing the nested layout
throughskills/agentspath overrides without moving any file from its 1.0 location.
Not in this release: the loop-by-default routing-gate change and the review-lane model reallocation
(update-routing-and-review) are held for a later version pending their own validation — 1.1.0's
routing gate is unchanged from 1.0; and the machine-enforcement close-out hook for the disposition
discipline (above).
v1.0.4
Additive guidance. The runtime code and the frozen contract (the loop and routing gate, the
lane map and four bundled agents, the RunRecord ledger shape, MCP-via-.mcp.json) are
unchanged. Motivated by a dogfood run where a cosmetic-looking edit to a shared CSV
serializer was triaged direct and, even when reviewed, was checked only against its own diff —
so a pre-existing tenant-scope leak on a sibling endpoint that shared the serializer was
missed. Both gaps are addressed generally, not for that case.
- Routing gate + triage — serializer/export seams are a risk trigger: a change to a
shared serializer/formatter or a data-export/response path now counts as a risk trigger, so
a small-looking output-formatting edit routes through the loop. Such a change crosses the
data-egress boundary of every endpoint it feeds, even when the edit itself looks cosmetic. - Review lane — follow a touched shared seam to its other callers: when a change edits a
helper with multiple callers (a serializer, formatter, query builder, or auth helper), its
other callers are in the blast radius, not "unrelated code." The reviewer checks each
caller of the touched seam against the boundary that seam crosses (e.g. a shared export
helper feeding several endpoints — verify each endpoint's authorization and tenant/data
scoping), and a flaw already present on a sibling caller is in scope the moment the change
touches their shared seam. - Default under uncertainty (anti-list-creep): the trigger lists are examples, not
exhaustive — when you can't tell whether a change touches a risk trigger, it does not
qualify fordirectand routes through the loop. One tie-breaker guards the unlisted tail
instead of an ever-growing trigger list. (Also aligned the three trigger enumerations — the
routing gate, the triage disposition, and the triage method step — so the data-egress
trigger appears in all three.)
v1.0.3
Additive guidance. The runtime code and the frozen contract (the loop and routing gate, the
lane map and four bundled agents, the RunRecord ledger shape, MCP-via-.mcp.json) are
unchanged.
- Plan-step guidance — research the standard first: when work targets an external
standard, spec, format, or protocol, the plan step now calls for a brief up-front research
pass to find and read the authoritative source and ground the design in it, rather than
building against an approximation and reconciling later. - Field notes Run 10: a data-science dogfood (compile CDC NHIS into a verified OKF
bundle + grounded chatbot). The execution-grounded check caught a clean-markdown,
resolving-links statistic that was wrong when run (3.66% vs the correct survey-weighted
31.96%) and quarantined it — the "execute the check, don't lint it" pattern carried into a
non-code domain. The run also surfaced the lesson this release encodes: the OKF format was
first built to an approximation and only grounded in the published v0.1 spec afterward; the
fix is the light up-front research step above.