@staix/agent-hub 0.12.35 → 0.12.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +8 -6
  3. package/docs/agent-notes/adapters.md +4 -1
  4. package/docs/agent-notes/budget.md +1 -1
  5. package/docs/agent-notes/bus.md +3 -0
  6. package/docs/agent-notes/daemon.md +6 -2
  7. package/docs/agent-notes/tasks.md +11 -1
  8. package/docs/agent-notes/tests.md +5 -1
  9. package/docs/operations.md +40 -16
  10. package/docs/quickstart.md +6 -8
  11. package/docs/sdlc.md +46 -5
  12. package/docs/security.md +5 -1
  13. package/docs/specs/2026-09-19-agent-hub-design.md +76 -1
  14. package/docs/verification/2026-10-19-0.12.36.md +63 -0
  15. package/docs/verified.json +18 -14
  16. package/package.json +1 -1
  17. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  18. package/plugins/agent-hub/server.js +385 -29
  19. package/src/adapters/claude-print.ts +230 -0
  20. package/src/adapters/definitions/builtin-metadata.ts +17 -1
  21. package/src/adapters/definitions/native-cli-entry-claude.ts +17 -3
  22. package/src/adapters/definitions/native-cli-entry-jcode.ts +3 -2
  23. package/src/adapters/definitions/native-cli-entry-kimi.ts +3 -2
  24. package/src/adapters/definitions/native-cli-entry-types.ts +2 -0
  25. package/src/adapters/definitions/native-factories.ts +7 -0
  26. package/src/adapters/registry-types.ts +8 -2
  27. package/src/adapters/registry.ts +13 -1
  28. package/src/cli/help.ts +5 -0
  29. package/src/cli/identity.ts +2 -1
  30. package/src/cli/launch.ts +19 -6
  31. package/src/cli/main.ts +38 -4
  32. package/src/cli/reset.ts +4 -2
  33. package/src/cli/statusline-tee.ts +5 -2
  34. package/src/cli/terminal-recovery.ts +7 -2
  35. package/src/cli/upgrade-runtime.ts +18 -15
  36. package/src/hub/board.ts +29 -7
  37. package/src/hub/bus.ts +11 -5
  38. package/src/hub/claude-state.ts +37 -0
  39. package/src/hub/cost-governance.ts +76 -0
  40. package/src/hub/daemon.ts +181 -73
  41. package/src/hub/hub-tools.ts +20 -1
  42. package/src/hub/instances.ts +17 -3
  43. package/src/hub/review-brief.ts +175 -0
  44. package/src/hub/routing.ts +17 -2
  45. package/src/hub/sdlc.ts +205 -4
  46. package/src/hub/status-roster.ts +10 -0
  47. package/src/hub/task-sweep.ts +143 -0
  48. package/src/hub/tasks.ts +544 -26
  49. package/src/hub/usage.ts +57 -20
@@ -1696,7 +1696,11 @@ distinct from the completed-message baseline recorded at that start. Later tool
1696
1696
  activity does not move this turn-start boundary. Missing start evidence or a
1697
1697
  start from another session, launch or channel claim leaves completion unknown.
1698
1698
  Accepted completion consumes that start before the peer becomes idle, so another
1699
- message cannot reuse it. A valid bound Stop request receives one prompt
1699
+ message cannot reuse it. The completion and the baseline are read from the last
1700
+ 4 MiB of the transcript, whatever its size (#517): the 32 MiB cap applies only to
1701
+ usage accounting, so a long session still ends its turns. A Stop refused because
1702
+ no completion is found tells the console once per turn start that the peer stays
1703
+ busy and its messages wait in its queue. A valid bound Stop request receives one prompt
1700
1704
  acknowledgement with pending=true, within the existing two-second hook deadline.
1701
1705
  The acknowledgement records observation only, never completion. After the hook
1702
1706
  can return, a deferred observer waits up to 1200 monotonic milliseconds for its
@@ -3554,6 +3558,43 @@ keep their exact scope. It performs no filesystem or package lookup.
3554
3558
  - `ahub sdlc export`: a plain off lifecycle (no retired setting) keeps the #257 export bytes (schema 1, `workflow: "none"`, `phase: null`). An enabled or retired-setting lifecycle emits schema 2: sanitized state (id, state, stage, criteria view or a private stub), `stateHash` and `sourceHash`, without the workflow field. In off, a `phase` receipt write also keeps its #257 bytes (`tasks: []`); task import stays retired in every mode, so a non-empty list is refused.
3555
3559
  - Contract amendment, seeds (419 before and after: 414 byte-unchanged, 3 modified, 2 removed, 2 added; the registry baseline is unchanged). Modified, each with the same id, test file, test name and mutation intent: `workflow-reviewer-only` (the criteria/phase check), plus `override-local-schema` and `lifecycle-native-schema`. The person approved the last two on 2026-10-18, because the `lifecycleCriteria` plumbing changed their call sites. Removed with the code they mutated: `workflow-exact-after` and `lifecycle-phase-view-required`. Added for the new guards: `criteria-task-import-retired` and `sdlc-workflow-window-closes`. Tests that pinned the retired gsd-lite behaviour (task import, phase naming, the workflow projection, the implement id stored in an enabled config) are amended in the same PR; every other test is unchanged.
3556
3560
  - S0/S8 implement none of S1-S7 and S9-S11. The issue stays the spec, Tasks owns mutations and GitHub owns PR, check and tag facts.
3561
+ ## Reviewer separation amendment (#450, hub task #223)
3562
+
3563
+ Owner decision 2026-10-18 (#450 comment 6248184754), R1-R5. R3's mechanism, chosen by the person: a new headless Claude session per review request.
3564
+
3565
+ - **Declaration.** `"claude-review": { "kind": "claude", "roles": ["reviewer"], "start_mode": "headless" }` declares a headless reviewer. `start_mode: "headless"` on a Claude instance is accepted only when the roles are exactly `["reviewer"]`; `worktree` stays refused. It resolves to a fixed builtin variant of the claude definition (hub-native transport, env MCP identity, a headless factory); the builtin `claude` keeps its terminal-only definition, and external definitions cannot declare a variant. A channel instance (I3, no `start_mode`) may still hold reviewer; it is started from a terminal and its verdicts are recorded as `continuing`.
3566
+ - **Start.** `ahub claude --as <id>` asks the running hub to start the reviewer (the console and dashboard Start do the same); it takes no launch arguments, runs nothing in that terminal, and `ahub stop <id>` stops it. It holds no process while idle.
3567
+ - **R3, one session per verdict.** For each `review` envelope the peer runs one `claude -p` child (own process group, watchdog, `peerChildEnv(<id>)`) with: `--output-format stream-json --verbose --no-session-persistence --session-id <new uuid> --strict-mcp-config --mcp-config <agent-hub tools-mode server for <id>> --setting-sources "" --tools Read,Grep,Glob --allowedTools mcp__agent-hub__hub_review mcp__agent-hub__hub_task_show Read Grep Glob --permission-mode dontAsk`, prompt on stdin. It never passes `--resume` or `--continue`, so no session sees an earlier round. No user or project settings, hooks or plugins load. A delta review also runs fresh (R3 allows continuing; not needed). The child's final text is not published; the verdict is the `hub_review` call.
3568
+ - **R2, review-only delivery.** A declared instance whose effective roles are exactly `["reviewer"]` (headless or channel) receives only hub `review` envelopes, hub `task` envelopes addressed to it and the person's own messages. Every other item (agent chat, digests, presence, budget, `[FYI]`) is discarded and journaled with that reason; an agent that addressed it directly is told why. A headless reviewer starts a session only for a review request; anything else it receives settles without one. The headless reviewer's prompt is built by the hub from facts, not from the envelope text: the task title and detail, the linked spec issue, refs (branch, head commit), check results, the earlier `changes_requested` notes and unmet items, and a diff of the head bounded in size (ponytail: a cap, the reviewer reads files with Read/Grep/Glob for the rest). The implementer's done summary is builder narrative and is left out.
3569
+ - **R4, recorded context.** `hub_review` writes `reviewContext` on its history entry, set by the hub: `fresh` when the verdict comes from a headless reviewer's child started for that task's review, `continuing` from any other peer, absent from the person.
3570
+ - **R1/R5, routing.** `assign()` prefers a dedicated reviewer (holds `reviewer`, not `planner`) among the eligible peers, busy or not; family independence and the PII rule (the person reviews) are unchanged. When a dedicated reviewer is declared but not eligible (offline, not started, paused) the planner reviews as before and the assignment note says `reviewer=planner (fallback)`. With no dedicated reviewer declared nothing changes. The reviewer is chosen at assignment, as before (ponytail: a task assigned during a fallback keeps the planner; re-pick at done if that matters).
3571
+ - **Budget.** The reviewer shares the `claude` account and its pauses; usage from each child's `result` event is added to the peer's tokens. No quota is classified from its text.
3572
+ - **Privacy.** The diff lists changed paths first, with rename and copy detection, and leaves out every change touching a path that `local.deny` or `pii.paths` covers (a move or copy whole, when either side is private), noting only how many were withheld (ponytail: git's 50% similarity decides what counts as a move); a diff that matches a private-data pattern is withheld whole. Those entries are also passed to the child as Claude `Read` deny rules (Claude evaluates them, not the hub's path policy). A private review is never given to it.
3573
+ - **Narrative on the read tool.** `hub_task_show` from a review-only instance returns the task with history notes kept only on `approved` and `changes_requested` entries; the done summary and other notes are dropped.
3574
+ - **Verdict authority.** A headless reviewer's `hub_review` is accepted only while the child that started for that task still runs (a per-child token, so a replacement child for the same task is a new authority). It is captured when the call starts and rechecked before every write, after each await. The leader's exit, a watchdog or a stop revokes it first. A review ends only when the child's whole process group is confirmed gone; survivors hold the delivery as `needs_review` and keep the peer busy with its handle: a stop fails and leaves it busy (never offline), and a start is refused, until they exit.
3575
+ - **Settlement.** A start failure before any review in a delivery ran is `failed_safe`; after one ran, the delivery is held as `needs_review`. A failing facts or verdict-check callback is logged, and the review counts as without a recorded verdict.
3576
+ - **Never an owner.** The reviewer variant carries `routing.reviewOnly`; assignment refuses it as an owner for every task class and when named.
3577
+
3578
+ ## Review brief amendment (#520, hub task #228)
3579
+
3580
+ ahub builds the review brief that the workspace gate used to take from `ocr delegate preview` and `rule`, and gives the same brief to every reviewer.
3581
+
3582
+ - **Range.** The task's commit (`refs.commit`, resolved to its full SHA) against its merge base with the remote default branch (`origin/HEAD`, else `origin/main`, else `origin/master`). There is no fallback to the checkout's `HEAD`, which may be the head itself or another session's branch: without a default branch, or when the commit has no changes against it, the brief is unavailable. Any failed git read makes it unavailable too, never partial. git only, bounded (500 files, 8 rule files of at most 32 KB each); the brief never touches the board.
3583
+ - **Files.** Each change comes with its status and line counts; a rename or copy lists both sides. A change touching a `local.deny` or `pii.paths` path, or a path that fails the private-data screen, is withheld whole (both sides of a move) and only counted. Excluded only when every side of a change is (a move keeps its source's obligation), with the reason, status and both sides shown: files marked `linguist-generated` in `.gitattributes`, lockfiles (a fixed list) and binary files. They are listed so a reviewer can still read them. Unlike `ocr delegate preview`, markdown and test files stay reviewable: the workspace gate required reading them anyway, and coverage now records it. Compared on PR #506 (head e305a17e against 3f258a41), OCR excluded 3 markdown and 3 test files and kept the generated bundle; ahub keeps those 6 and excludes the bundle once the `.gitattributes` this PR adds is on the default branch.
3584
+ - **Rules.** `REVIEW.md` applies to every reviewable file. A path whose `.gitattributes` entry sets `ahub-review-rules=<repository path>` also gets that file, and a move gets the rule files of both sides. Files are grouped by the rule files that apply. Attributes and rule files are read at the merge base, not the head, and every diff the brief runs uses `git --attr-source=<merge base>`, so a checkout at the head cannot reclassify files either (for example `* -diff` making them binary): a change cannot lift its own review obligations (marking everything generated, weakening `REVIEW.md`); its own edits apply from the next change after it merges. A rule file's name and whole body pass the private-data screen before any cut; a file that fails is named but not shown. A configured rule file the brief cannot load (missing at the merge base, or beyond the 8-file cap) is listed with the reason; a private or non-nameable rule path is left out unnamed. Deviation from the issue: per-path settings are git attributes, versioned with the change, instead of new `review.exclude` and `review.rules` config keys.
3585
+ - **Cross-check.** The plain `--name-only --no-renames` list of the same range is compared with the brief. A path it shows that the brief does not list is named for a direct read.
3586
+ - **Contract.** The review request already carries the spec issue reference, the task plan and the detail. The brief does not fetch the issue body: the hub reads issue metadata only (S1), so the acceptance checklist stays in the issue.
3587
+ - **Delivery.** `sendReview` appends the rendered brief to the review request (after #215's admission, body only). `hub_task_show` adds a `brief` field while the task is `in_review`. `ahub review brief <id>` prints it for a person. A task without a commit, or a private task, has no brief.
3588
+ - **Coverage gate.** `hub_review` takes `coverage: { reviewed: [paths], skipped: [{ path, reason }] }`. An approval must account for every reviewable path. The gate follows the lifecycle mode (deviation from the issue, which refuses always): `enforce` refuses before any write, naming the paths, and also refuses when the brief is unavailable (an unknown inventory is never an empty one); `advise` records `Coverage gap (N): ...` or `Coverage unknown: ...` in the verdict note; `off` and a person's own verdict skip it. The commit under review is the task's commit, else the head the verdict names, else the head its lifecycle receipt records. Code work (a task with a commit, branch or PR) for which none of these is known, or whose brief cannot be built, has an unavailable brief. Work with no commit, branch or PR is exempt, with nothing to account for. So is a `Tasks` built without a brief provider (library use and tests; the daemon always provides one). One head throughout: the head the verdict names, or the `reviewedHead` it would inherit from an earlier review, must equal the brief's head (with a PR, the lifecycle approval gate already binds the reviewed head to the PR head). The task's commit and its lifecycle receipt (which holds the inherited `reviewedHead`) are pinned when coverage is checked and rechecked before every write after an await, so a commit or receipt that moves during the verdict is refused.
3589
+
3590
+ ## Claude peer instances I3 amendment (#450)
3591
+
3592
+ - A declared instance of a channel-plugin kind (Claude) is admitted when its declaration names `roles`, reviewer and/or planner only. `start_mode` and `worktree` are refused: the instance starts only from the person's terminal with `ahub claude --as <id>`, so the hub never starts, watches or owns writes for it, and it is neither startable nor reserved from external admission.
3593
+ - The launcher sets the child's `AGENTHUB_PEER_ID` to the instance id; the channel plugin and the statusline tee already key on it. Launch, session and context state files stay `claude-launch.json`, `claude-session.json` and `claude-context.json` for the builtin and become `<base>.<id>.json` for an instance (`src/hub/claude-state.ts`). Account usage stays shared. The daemon's context and usage readers, the permission-launch check, the facts handler, terminal recovery (project root, no worktree), the upgrade blocker check and `ahub reset` read each instance's own files.
3594
+ - The Claude version probe stays on the builtin peer (ponytail: instances are reviewers started by hand); zero-turn detection reads each peer's own evidence, as below.
3595
+ - Status, which the console and dashboard read, lists each declared instance right after its kind. `ahub <kind> --as <id>` starts only an instance the running daemon bound at startup (status `activeInstances`); otherwise it asks for a restart or an upgrade before any effect.
3596
+ - Each Claude peer reads only its own `terminal-recovery.json` row. Transcript evidence comes from the path that peer's status line reported; an instance without one counts as persisted, because the hub cannot see its `CLAUDE_CONFIG_DIR`. Upgrade runs plugin setup once per distinct Claude profile, under that profile.
3597
+
3557
3598
  ## Headless peer instances I2 amendment (#450)
3558
3599
 
3559
3600
  `instances` is a person-authored, machine-local object in an untracked
@@ -3657,3 +3698,37 @@ and mutant result, per the reviewer's explicit ruling.
3657
3698
  - Launchers that check membership before starting (`ahub jcode`, `ahub kimi --mode tui`) read it through `rosterInStatus` in `src/hub/status-roster.ts` (no imports, so the registry's native CLI entries add no cycle). A reply without the field (an older hub) is unknown: the launcher stops with an upgrade-or-restart remedy and starts nothing. It never reads unknown as off (the jcode bug) or as on (the dead kimi guard; daemon admission still refused off-roster Kimi, so that one was harmless).
3658
3699
  - `settings_get` stays console-only.
3659
3700
  - With declared headless instances, status includes each startup-bound extra id as well as every built-in and optional peer, with its own roster membership. No undeclared suffix acquires a row.
3701
+
3702
+ ## Amendment: planner plan review and board governance, 2026-10-18 (#481 S9)
3703
+
3704
+ - The person's mode-boundary ruling separates board governance from lifecycle enforcement. WIP-at-accept and planner/person return of accepted work without work evidence apply in every `sdlc.mode`; only the current plan-review receipt gate uses enforce/refuse, advise/report and off/no gate. Existing lifecycle schema aliases and ordinary off-mode receipts are unchanged.
3705
+ - Tasks owns plan-review receipts, accepted-untouched returns and all offers/acceptances. Review evidence contains the planner, planning revision, recorded time and fixed-query GitHub issue metadata. An issue body or comments are never fetched or stored by this readback. A changed body edit time or planning revision invalidates the receipt; missing evidence remains unknown. The synchronous acceptance API cannot bypass the fresh enforce readback.
3706
+ - S1 person spec acceptance and S9 planner review remain independent. `acceptReviewed` reads both against one task snapshot before the acceptance write. A `done` that implicitly accepts proposed work checks WIP and both readbacks before any cohort or board write; the missing-spec refusal retains precedence over missing-plan admission. Off keeps its synchronous ungated acceptance path apart from the all-mode WIP rule.
3707
+ - The accepted-untouched exception is a distinct, revision-bound return transition with a screened reason. It preserves history and planning fields, withdraws former role requests and enables replanning. Historical acceptance still protects cancellation and undo. Done/check/review/integration evidence or branch/commit/PR/local/review artifacts refuses this exception; it does not grant a general planner unassign permission.
3708
+ - Grooming is an ids/codes-only read projection with repository-scoped comparisons, explicit unknown/truncated evidence and person-only actions rendered as commands. It does not infer a ruling from arbitrary task prose, fetch issue bodies, mutate dependencies or invoke a model. Limits are 500 task rows, 256 findings and eight metadata reads within four seconds; a future paginated repository resolver supplies exhaustive coverage.
3709
+ - Existing seeds and the registry baseline remain byte-identical. Source guards retain the original ordinary backlog and dependency floors outside the explicit untouched-return branch. S10/S11 and the remaining lifecycle slices are not implemented here.
3710
+
3711
+ ## Amendment: the daemon's plugin bundle in status, 2026-10-18 (#502)
3712
+
3713
+ - The authenticated `status` reply carries `pluginBundle`, the absolute path of the plugin bundle the running daemon serves and checks against. It is additive, with no protocol bump.
3714
+ - `ahub jcode` and `ahub kimi --mode tui` write that path into their project MCP entries, read through `bundleInStatus` in `src/hub/status-roster.ts`, which accepts only an absolute path ending in `plugins/agent-hub/server.js`. Before this, they wrote the path of the CLI copy on PATH, which can be a different install than the daemon's (for example a global install against a retained release), so the daemon refused Jcode's entry as stale. A hub that reports no bundle gets the CLI's own copy, as before. Kimi's headless start removes the entry, so no path is involved.
3715
+
3716
+ ## Amendment: spec acceptance, 2026-10-18 (#481 S1)
3717
+
3718
+ - `ahub sdlc accept <task> --issue <n> [--repo owner/repository]` is person-only (console-role `sdlc` op `accept`; agent shells and live tests are refused). The daemon reads `lastEditedAt` and `updatedAt` with a fixed GraphQL query and `Tasks.acceptSpec` stores `{repo, issue, lastEditedAt, updatedAt, acceptedAt}` as the receipt's `acceptance`; no issue body is fetched or stored. `hub_sdlc_record` refuses the field, and a receipt relinked to another repository or issue drops it.
3719
+ - Build entry (an `implement` or `bulk_edit` task's acceptance, its `hub_task_done` without a separate accept, a self-claim, or a non-person stage change into a build base) in enforce needs a current acceptance. `Tasks.accept` refuses a missing one synchronously; the daemon awaits `Tasks.specGate` first, and `done` and `specStageGate` await the same reread, which refuses a changed body (`lastEditedAt` differs; comments move only `updatedAt`) or an unreadable one. A self-claim without an acceptance stays assigned to the claimant, still proposed, until the person accepts the spec and the claimant accepts the task. A task that changed during a readback (flow, link, acceptance, owner or privacy) is refused before any write. Advise notifies instead, stage changes included; off reads nothing. PII tasks never read the issue, so in enforce their accepted spec reads as unknown, like their PR evidence.
3720
+ - Status shows `spec: {issue, state}` when the lifecycle is enabled and the receipt names an issue. It is not a readiness blocker, so existing approval and merge gates are unchanged.
3721
+
3722
+ ### S9 redo admission clarification (#481, hub task #214)
3723
+
3724
+ An acceptance by the current owner since the latest ownership change retains its WIP slot for both in_progress updates and changes_requested redo, including re-accept and implicit done, in every mode. An unaccepted offer does not block that redo. Acceptance from a former ownership span gives no exemption. In enforce, changes_requested re-acceptance and done still re-read spec acceptance and plan-review freshness: an issue body edit requires renewed person acceptance and planner review before resubmission. This WIP exemption does not waive lifecycle review gates.
3725
+
3726
+ S9 privacy and notice ceilings: private build work with an issue ref remains inadmissible in enforce because its issue metadata cannot be read, with no metadata-free person override. Grooming pointers are coalesced per queued board revision but have no minimum delivery interval.
3727
+
3728
+ ### S10 cost governance amendment (#481, hub task #215)
3729
+
3730
+ - Task plans carry explicit review scope (none/delta/full, bounded reviewer count) and CI scope (focused/full/reuse); S9 receipts copy the planner-selected values. None uses zero reviewers; other scopes use one to eight. Legacy scope is unspecified, readable and never guessed. Advise reports the gap; new enforce receipts require both scopes, while old scope-less receipts remain valid to their next planning revision. Omitted cost keys on an owner file-list update retain the reviewed scope; explicit prospective drift refuses enforce acceptance. Scope does not change reviewer authority or bypass CI; S2 owns actual conformance comparison.
3731
+ - Review admission is separate from #520 brief/coverage. Before done/cohort writes, enforce requires the task's exact PR head, successful configured checks (native default: both OS checks and seeded guards), and no unanswered pending bot thread. Resolution settles a thread; an unresolved thread needs a user reply after the last bot comment. Only metadata is fetched. Advise reports gaps, including a generic unknown-readiness notice when a private turn finishes its own PII task without remote metadata; ordinary work remains refused during a private turn. Off adds no readback. Identity/privacy/owner and runtime authority are rechecked across awaits and each external read. Background role maintenance may retain a saved role while holding an unadmitted review envelope; a manual reviewer resend performs fresh admission.
3732
+ - Whole-workflow repository serialization closes the admission race, keeping required check names and read-only permissions; queue:max retains up to 100 pending controllers instead of canceling the previous pending one. Identical-tree successful full proof is reused for PR and push. Reuse expands both OS matrix names and reports the required seeded aggregate, using only a `Reuse verified identical-tree full gate` marker step with the original run id. These successful reporting jobs and skipped jobs are not fresh full proof; duplicate active full gates and unknown active coverage refuse admission. Pending controllers do not run gates. CI proof searches are bounded; missed older success can require a new gate, never invent green evidence.
3733
+ - Cost reporting is read-only over bounded current public board links plus merged-PR/check metadata: review handoff rounds and elapsed time, CI run ids and extra attempts, full re-reviews versus deltas, and unknown scope. Private/relinked counterparts are excluded at each read and projection. Pure band-breach proposal data is delivered here; the S7 baseline/configuration/automatic board-card scheduler is deliberately not implemented in S10.
3734
+ - Nonblocking policy ceilings stay unchanged and are recorded in hub task #230: fail-closed metadata errors, repository-wide queue fairness, unknown thread author kinds, and strict advise readback races. Their planner-reviewed alternatives are deferred.
@@ -0,0 +1,63 @@
1
+ # 0.12.36 release verification
2
+
3
+ This record covers release preparation and source review. It does not claim publication, installation, a running-hub restart or native/live acceptance.
4
+
5
+ ## Candidate
6
+
7
+ Version 0.12.36, control protocol 16 (unchanged), from merged main `6e39b616`. The person directed the release once every open PR had merged (2026-10-18/19).
8
+
9
+ - #502 (PR #504): the Jcode and Kimi TUI launchers write the running daemon's plugin bundle into their MCP entries; `status` reports the bundle.
10
+ - #481 S1 (PR #503): person-only spec acceptance bound to the issue edit time; in enforce, build work starts only from a current acceptance.
11
+ - #450 I3 (PR #505): declared Claude reviewer and planner channel instances with per-instance launch, session, context and recovery records.
12
+ - #481 S9 (PR #518): planner grooming, plan-review receipts, WIP admission in every lifecycle mode, untouched-work return.
13
+ - #450 / hub task #223 (PR #506): a headless Claude reviewer that runs a fresh `claude -p` session per review, with review-only delivery, verdict authority fenced to the running child, and process-group cleanup.
14
+ - #517 (PR #521): Claude turn completion read from the transcript's last 4 MiB; a console notice when no completed turn is found in that tail.
15
+ - #520 (PR #522): the hub-built review brief in every review request, `hub_review` coverage with a mode-following gate, and `ahub review brief`.
16
+ - #481 S10 (PR #523): plan review and CI scopes, the premature-review gate, identical-tree CI reuse with reporter jobs for the required check names, and the cost report.
17
+ - #450 / hub task #223 (PR #524, found by this release's document review): `ahub claude --as <id>` asks the hub to start a headless reviewer (`ahub start`, named by #506, never existed), `ahub stop` stops it, and stop replies name `ahub <kind> --as <id>` for every instance.
18
+ - Still open (unchanged): live native clients, installed managed-Pi #418 AC8 (#142), #438 AC7, the native console settings leg (#439 AC5), a real upgrade with reattach (#463), a real upgrade with a managed terminal and cancelled rows (#478), the live advise cycle of #481 AC9, the installed #493 D3 leg, and the live two-instance run (#450 I4, #138).
19
+ - New open legs:
20
+ - A live headless review with a real Claude account: fresh session, read-only tools, the `Read` deny rules for private paths, and the verdict recorded as `fresh` (#223).
21
+ - A live long session over 32 MiB going idle after a Stop (#517).
22
+ - Deferred to backlog: #230 (S10 P3s: fail-closed reuse decision, one repository-wide queue, ghost thread authors, advise races).
23
+
24
+ ## Reviews
25
+
26
+ | PR | Final head | Review | CI |
27
+ | --- | --- | --- | --- |
28
+ | #504 (#502) | b26ca1ea | codex, approved | exact head, success |
29
+ | #503 (#481 S1) | 5b22c841 | codex, approved | exact head, success |
30
+ | #505 (#450 I3) | 091689ac | codex: three rounds, then a merge-delta approval | exact head, success |
31
+ | #518 (#481 S9) | 1d2a9ac8 | planner via OCR delegation (Kimi out of quota, read-only Claude subagent): round 1 one P2 (redo blocked by WIP), round 2 approved | exact head, success |
32
+ | #506 (#223) | e305a17e | codex: four rounds (privacy, authority, lifecycle and process-group findings), then rebase-delta approval | exact head, success |
33
+ | #521 (#517) | 7ae00959 | codex: round 1 one P2 (newline-less cut tail), round 2 approved; bot P1/P2 fixed, delta approved | exact head, success |
34
+ | #522 (#520) | c35222f6 | codex: three rounds of findings (task escalated once by the hub's rejection rule; the person directed the planner to finish it), then approvals of the rebase and CI-fix deltas | exact head, success |
35
+ | #524 (#223 start/stop) | 9408ebde | codex: approved, plus a delta approval after the bot's P2 (offline reply command); codex also ran a real CLI/daemon fixture for start, refusal and stop | exact head, success |
36
+ | #523 (#481 S10) | 65ae2705 | planner via OCR delegation (read-only Claude subagent): round 1 P1 (advise PII done) and P2 (reuse missing required names), round 2 approved | exact head, success; a real identical-tree reuse run (39168948253) reported the required names and the PR merged on them |
37
+
38
+ ## Document review
39
+
40
+ Ten documents were stale against 03209040, and the agent-notes README became stale through `daemon.md`. Two fresh-context reviewers read them against the eight PRs above; the planner applied the corrections.
41
+
42
+ | Document | Result | Checked claims and correction |
43
+ | --- | --- | --- |
44
+ | `README.md` | corrected | Status 0.12.36; the Jcode entry sentence now says the command writes the running hub's plugin bundle (#502); the verification link and the open live legs (#223, #517, #523 added). |
45
+ | `docs/quickstart.md` | corrected | `v0.12.36` install. "Upgrading to 0.12.36": restart Claude sessions, the review brief and `coverage` (#520), WIP admission in every mode with `tasks.wip_limits` (#481 S9), the enforce-only gates (S1 acceptance, plan review, coverage, premature review), the #502 entry refresh, instances and #517. |
46
+ | `docs/operations.md` | corrected | Version and upgrade commands 0.12.36; the review brief and coverage in the two-agent review section; #517 in the busy-session section; WIP in every mode; the S1, S9 and S10 commands in the SDLC section; the #502 bundle path in the Jcode section. The headless reviewer's start and stop came with #524. `tasks.wip_limits` corrected to apply live (settings.ts, config-apply.ts and the per-admission read in daemon.ts), after the release review. |
47
+ | `docs/security.md` | corrected | Instance start-mode limits per kind (#505, #506); a new paragraph on review-only delivery and the headless reviewer's flags, read-only tools, `Read` deny rules and verdict fence (#223); the brief's privacy and merge-base rules, metadata-only GitHub reads, and the unchanged CI permissions (#520, #523). |
48
+ | `docs/agent-notes/adapters.md` | corrected | `reviewerVariant` joined the restricted-field list; rules for TUI launchers writing the hub's bundle (#502) and for `ClaudePrintPeer`'s authority and cleanup (#223). |
49
+ | `docs/agent-notes/budget.md` | corrected | Per-peer Claude context and session files through `claudeStateFile`; usage stays one shared file (#505). |
50
+ | `docs/agent-notes/bus.md` | corrected | `relevant` may return a discard reason; review-only delivery kept at send and at delivery (#223). |
51
+ | `docs/agent-notes/daemon.md` | corrected | Per-instance launch file name; instance transcript evidence; `claudeStateFile` and `ownTerminalRow`; channel extras never hub-started and `requireActiveInstance`; Stop verification only through the tail reader (#517). |
52
+ | `docs/agent-notes/tasks.md` | corrected | Scope adds `src/hub/review-brief.ts`; rules for `reviewAuthority` in `valid()`, the coverage gate's pins and merge-base reads, owner refusal of `routing.reviewOnly`, and the untouched-return exception. |
53
+ | `docs/agent-notes/tests.md` | corrected | The `seeded guards` job also passes on a verified identical-tree reuse (#523); headless-reviewer tests never run the real `claude`. |
54
+
55
+ | `docs/agent-notes/README.md` | no change | Stale only because `daemon.md`, a tracked path, changed; its console exact-row background still matches `daemon.md`. |
56
+
57
+ `AGENTS.md` lists `src/hub/review-brief.ts` under tasks and `src/hub/usage.ts` under daemon.
58
+
59
+ ## Checks
60
+
61
+ - Each merged PR's exact-head CI passed (table above). The release branch merges main `6e39b616` cleanly; the bundle is rebuilt with the pinned Bun 1.4.2 and is fresh; `tsc` is clean.
62
+ - `node scripts/check-docs.mjs --require-fresh` runs after the restamp and before the tag.
63
+
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "documents": {
4
4
  "README.md": {
5
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
5
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
6
6
  "paths": [
7
7
  "package.json",
8
8
  "src/",
@@ -11,14 +11,14 @@
11
11
  ]
12
12
  },
13
13
  "docs/security.md": {
14
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
14
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
15
15
  "paths": [
16
16
  "src/",
17
17
  "templates/"
18
18
  ]
19
19
  },
20
20
  "docs/operations.md": {
21
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
21
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
22
22
  "paths": [
23
23
  "package.json",
24
24
  "src/",
@@ -35,7 +35,7 @@
35
35
  ]
36
36
  },
37
37
  "docs/quickstart.md": {
38
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
38
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
39
39
  "paths": [
40
40
  "package.json",
41
41
  "src/",
@@ -43,7 +43,7 @@
43
43
  ]
44
44
  },
45
45
  "docs/agent-notes/adapters.md": {
46
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
46
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
47
47
  "paths": [
48
48
  "src/adapters/",
49
49
  "src/pi/",
@@ -76,7 +76,7 @@
76
76
  ]
77
77
  },
78
78
  "docs/agent-notes/budget.md": {
79
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
79
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
80
80
  "paths": [
81
81
  "src/hub/budget.ts",
82
82
  "src/cli/statusline-tee.ts",
@@ -88,11 +88,12 @@
88
88
  "src/adapters/definitions/native-quota.ts",
89
89
  "src/adapters/definitions/native-context.ts",
90
90
  "src/adapters/registry.ts",
91
- "src/hub/instance-budget.ts"
91
+ "src/hub/instance-budget.ts",
92
+ "src/hub/claude-state.ts"
92
93
  ]
93
94
  },
94
95
  "docs/agent-notes/bus.md": {
95
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
96
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
96
97
  "paths": [
97
98
  "src/hub/bus.ts",
98
99
  "src/hub/envelope.ts",
@@ -106,7 +107,7 @@
106
107
  ]
107
108
  },
108
109
  "docs/agent-notes/daemon.md": {
109
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
110
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
110
111
  "paths": [
111
112
  "src/hub/daemon.ts",
112
113
  "src/hub/control-client.ts",
@@ -151,7 +152,9 @@
151
152
  "src/adapters/definitions/native-cli-*.ts",
152
153
  "src/hub/instances.ts",
153
154
  "src/hub/instance-config.ts",
154
- "src/hub/instance-execution.ts"
155
+ "src/hub/instance-execution.ts",
156
+ "src/hub/usage.ts",
157
+ "src/hub/claude-state.ts"
155
158
  ]
156
159
  },
157
160
  "docs/agent-notes/local-worker.md": {
@@ -176,7 +179,7 @@
176
179
  ]
177
180
  },
178
181
  "docs/agent-notes/tasks.md": {
179
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
182
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
180
183
  "paths": [
181
184
  "src/hub/tasks.ts",
182
185
  "src/hub/board.ts",
@@ -192,11 +195,12 @@
192
195
  "src/hub/daemon.ts",
193
196
  "src/hub/settled-roles.ts",
194
197
  "src/adapters/definitions/builtin-metadata.ts",
195
- "src/hub/bus.ts"
198
+ "src/hub/bus.ts",
199
+ "src/hub/review-brief.ts"
196
200
  ]
197
201
  },
198
202
  "docs/agent-notes/tests.md": {
199
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
203
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
200
204
  "paths": [
201
205
  "test/",
202
206
  "scripts/check.sh",
@@ -215,7 +219,7 @@
215
219
  ]
216
220
  },
217
221
  "docs/agent-notes/README.md": {
218
- "verifiedAgainst": "03209040585a57c7c0a1f2b81f6be814df88267c",
222
+ "verifiedAgainst": "24b1637b6d6a964bd53708b3330ff442afe63f4e",
219
223
  "paths": [
220
224
  "src/cli/console-state.ts",
221
225
  "src/cli/attention.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staix/agent-hub",
3
- "version": "0.12.35",
3
+ "version": "0.12.36",
4
4
  "description": "Native multi-agent hub: Claude Code, Codex, Kimi Code, Pi and local inference as peers in one project",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-hub",
3
- "version": "0.12.35",
3
+ "version": "0.12.36",
4
4
  "description": "Channel between Claude Code and the agent-hub daemon: peer messages from Codex, Kimi and the local worker arrive as channel events; hub_send replies.",
5
5
  "author": {
6
6
  "name": "Young Joon Lee",