@staix/agent-hub 0.12.34 → 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.
- package/CHANGELOG.md +27 -0
- package/README.md +8 -6
- package/docs/agent-notes/adapters.md +6 -1
- package/docs/agent-notes/budget.md +4 -2
- package/docs/agent-notes/bus.md +5 -1
- package/docs/agent-notes/daemon.md +11 -3
- package/docs/agent-notes/local-worker.md +1 -1
- package/docs/agent-notes/tasks.md +15 -2
- package/docs/agent-notes/tests.md +5 -1
- package/docs/gsd-collaboration-analysis.md +5 -1
- package/docs/operations.md +97 -19
- package/docs/quickstart.md +8 -4
- package/docs/sdlc.md +100 -34
- package/docs/security.md +7 -3
- package/docs/specs/2026-09-19-agent-hub-design.md +237 -7
- package/docs/verification/2026-10-18-0.12.35.md +49 -0
- package/docs/verification/2026-10-18-493-claude-busy-channel.md +91 -0
- package/docs/verification/2026-10-19-0.12.36.md +63 -0
- package/docs/verified.json +26 -17
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +15781 -14850
- package/src/adapters/acp.ts +3 -1
- package/src/adapters/claude-channel.ts +59 -29
- package/src/adapters/claude-print.ts +230 -0
- package/src/adapters/codex-appserver.ts +1 -1
- package/src/adapters/definitions/builtin-metadata.ts +17 -1
- package/src/adapters/definitions/native-cli-entry-claude.ts +17 -3
- package/src/adapters/definitions/native-cli-entry-codex.ts +13 -5
- package/src/adapters/definitions/native-cli-entry-jcode.ts +6 -2
- package/src/adapters/definitions/native-cli-entry-kimi.ts +18 -12
- package/src/adapters/definitions/native-cli-entry-local.ts +3 -2
- package/src/adapters/definitions/native-cli-entry-pi.ts +8 -6
- package/src/adapters/definitions/native-cli-entry-qwen.ts +3 -2
- package/src/adapters/definitions/native-cli-entry-types.ts +3 -0
- package/src/adapters/definitions/native-factories.ts +7 -0
- package/src/adapters/definitions/native-recovery.ts +2 -2
- package/src/adapters/definitions/qwen-native.ts +2 -2
- package/src/adapters/local-worker.ts +3 -2
- package/src/adapters/pi.ts +3 -1
- package/src/adapters/registry-types.ts +11 -2
- package/src/adapters/registry.ts +36 -8
- package/src/cli/help.ts +5 -0
- package/src/cli/identity.ts +5 -4
- package/src/cli/launch.ts +45 -7
- package/src/cli/main.ts +136 -29
- package/src/cli/preview.ts +16 -5
- package/src/cli/recovery-guidance.ts +39 -22
- package/src/cli/reset.ts +4 -2
- package/src/cli/statusline-tee.ts +5 -2
- package/src/cli/terminal-recovery.ts +73 -16
- package/src/cli/upgrade-restore-state.ts +16 -7
- package/src/cli/upgrade-runtime.ts +83 -52
- package/src/cli/upgrade.ts +43 -27
- package/src/hub/board.ts +29 -7
- package/src/hub/budget.ts +55 -3
- package/src/hub/bus.ts +12 -6
- package/src/hub/claude-state.ts +37 -0
- package/src/hub/conductor.ts +16 -10
- package/src/hub/config-apply.ts +13 -2
- package/src/hub/config-reload.ts +11 -1
- package/src/hub/config-trust.ts +1 -1
- package/src/hub/control-client.ts +1 -1
- package/src/hub/cost-governance.ts +76 -0
- package/src/hub/crash.ts +14 -5
- package/src/hub/daemon.ts +473 -194
- package/src/hub/execution-budget.ts +3 -3
- package/src/hub/hub-tools.ts +36 -6
- package/src/hub/instance-budget.ts +73 -0
- package/src/hub/instance-config.ts +47 -0
- package/src/hub/instance-execution.ts +50 -0
- package/src/hub/instances.ts +114 -0
- package/src/hub/lifecycle-schema.ts +7 -3
- package/src/hub/permission-mode.ts +7 -7
- package/src/hub/review-brief.ts +175 -0
- package/src/hub/roster.ts +7 -6
- package/src/hub/routing.ts +97 -18
- package/src/hub/sdlc-queue.ts +2 -2
- package/src/hub/sdlc.ts +286 -39
- package/src/hub/settings.ts +34 -6
- package/src/hub/snapshots.ts +40 -9
- package/src/hub/start-mode.ts +7 -4
- package/src/hub/status-roster.ts +18 -0
- package/src/hub/task-sweep.ts +143 -0
- package/src/hub/tasks.ts +595 -47
- package/src/hub/text-projection.ts +7 -3
- package/src/hub/usage.ts +57 -20
- package/src/hub/workflow.ts +30 -52
- package/src/pi/launch.ts +4 -3
- package/src/ui/index.html +1 -1
- package/templates/AGENTS.block.md +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
Issue and pull request numbers in the entries for 0.7.7 and earlier refer to the previous repository, archived on 2026-09-30 when this repository's history was rewritten; the one exception is the open smoke-check issue, formerly #12, which moved here as #1. Numbers in newer entries refer to this repository.
|
|
4
4
|
|
|
5
|
+
## 0.12.36
|
|
6
|
+
|
|
7
|
+
Reviews get their own reviewers and a hub-built brief: a headless Claude reviewer runs a fresh session per review (#450, #223), every review request carries a review brief with a coverage gate (#520), and a second Claude session can join as a reviewer or planner (#450 I3). The planner reviews plans before work starts, WIP admission applies in every lifecycle mode, a person accepts a task's spec issue (#481 S1, S9), and review and CI costs are governed, with identical-tree CI reuse (#481 S10). A Claude session with a transcript over 32 MiB no longer stays busy forever (#517). Restart Claude sessions after upgrading: each keeps the plugin server it started with.
|
|
8
|
+
|
|
9
|
+
- Planner cost governance records review/CI scope on plans and receipts, gates premature reviews by current CI and bot replies, reuses identical-tree full CI and reports bounded merged-PR review/CI costs without board writes (#481 S10).
|
|
10
|
+
- A Claude session whose transcript grew past 32 MiB no longer stays busy forever: turn completion is read from the transcript's last 4 MiB, and a Stop refused because no completed turn is found in that tail now says so on the console, once per turn, instead of only in hub.log (#517).
|
|
11
|
+
- Every review request now carries a review brief built by the hub (no `ocr` CLI): the commit's reviewable files, the excluded ones with reasons (`linguist-generated`, lockfiles, binaries), the rules from `REVIEW.md` and `ahub-review-rules` attributes per file (both read at the merge base, so a change cannot loosen its own review), and a cross-check list. `hub_review` takes `coverage`, and in `enforce` an approval that leaves a reviewable path unaccounted is refused. `ahub review brief <id>` prints it (#520).
|
|
12
|
+
- Planner grooming reports repository-scoped dependencies, overlaps, WIP and capability/issue blockers without changing the board. Plan-review receipts bind the planner, planning revision and metadata-only issue edit evidence; enforce requires a current receipt before offering or accepting build work, advise reports gaps and off does not gate (#481 S9).
|
|
13
|
+
- WIP admission now applies in every lifecycle mode. Planner/person actions can return accepted but untouched work with history and planning retained; work evidence still refuses return, and ordinary accepted-work cancellation/unassignment remains person-only (#481 S9).
|
|
14
|
+
- `ahub jcode` no longer leaves a project MCP entry the daemon rejects as stale when the CLI on PATH and the running hub come from different installs: the hub reports its plugin bundle in `status`, and the Jcode and Kimi TUI launchers write that path (#502).
|
|
15
|
+
- A person accepts a task's spec issue with `ahub sdlc accept <task> --issue <n>`, bound to the issue's body edit time (identity and edit times only, no body). In enforce, build work starts only from a current acceptance: a body edit after acceptance asks for re-acceptance, while comments do not; advise only notifies (#481 S1).
|
|
16
|
+
- Declare a second Claude session as a reviewer or planner (`"claude-review": { "kind": "claude", "roles": ["reviewer"] }` in untracked `.agenthub/config.local.json`) and start it from your terminal with `ahub claude --as claude-review`. It joins as its own channel peer with its own launch, session, context and recovery records; the hub never starts it, and it takes no implementer role or worktree (#450 I3).
|
|
17
|
+
- Run a headless Claude reviewer the hub starts per review (`"claude-review": { "kind": "claude", "roles": ["reviewer"], "start_mode": "headless" }`, then `ahub claude --as claude-review`, which asks the hub to start it): each review request gets a new read-only `claude -p` session that sees the review facts and a bounded diff, never the builder's summary or agent chat. Review requests route to a declared reviewer-only instance first, a fallback to the planner is noted on the task, and each verdict records `reviewContext: fresh | continuing` (#450, hub task #223).
|
|
18
|
+
|
|
19
|
+
## 0.12.35
|
|
20
|
+
|
|
21
|
+
A Claude session started with `ahub claude` gets its hub messages while it is busy (#493), `ahub jcode` starts again (#484), a kind can run several headless instances (#450 I2), and an enabled lifecycle follows the AI-Native SDLC Playbook with gsd-lite retired (#481 S0+S8). Restart Claude sessions after upgrading: each keeps the plugin server it started with.
|
|
22
|
+
|
|
23
|
+
- Let an attached channel session read the daemon queue with `hub_inbox` while busy, using the existing pull, holds and journal completion; tool results carry fresh queued and important counts in every MCP mode, and a zero clears a stale hint (#493).
|
|
24
|
+
- Steer important messages into a busy channel session's running turn instead of waiting for the turn to end; ordinary messages still wait (#493). Mid-turn reading was verified on Claude Code 2.1.302.
|
|
25
|
+
- Session instructions, tool texts and the AGENTS block forbid `[FYI]` for actionable messages (PR ready, done, submitted, ruling needed, blocker, changed contract or path) (#493).
|
|
26
|
+
- `ahub jcode` no longer refuses every start as off roster, and the `ahub kimi --mode tui` off-roster check works: `status` now carries each supported peer's roster membership, and a hub without it is reported as unknown with a remedy (#484).
|
|
27
|
+
- Declare extra headless peer instances (`<kind>-<name>`, for example a second Codex or Kimi reviewer) in untracked `.agenthub/config.local.json` and start them with `ahub <kind> --as <id>`. Extra implementers run in their own registered worktree, routing balances a kind across its instances, and quota pauses are shared per account (#450 I2).
|
|
28
|
+
- An enabled lifecycle (`mode` advise or enforce) defaults to the playbook stages intent, spec, plan, build, test, review, merge, release and maintain, and status and the dashboard name the playbook stage. Stored `implement`/`verify` receipts read as `build`/`test`. Off keeps its seven stages, receipts, tool schema, export and output unchanged (#481 S0).
|
|
29
|
+
- gsd-lite is retired into the acceptance-criteria checklist (`criteria`, part of the Compliance pass), which counts once recorded in an enabled lifecycle; checklist task import is removed. Until 0.13.0, `workflow = "gsd-lite"` and the `phase` gate load with a warning in `hub.log` and the `phase` receipt name is still accepted; from 0.13.0 all three are refused with a field-level reason (#481 S8).
|
|
30
|
+
- The protected-segment grant test checks every segment through the production grant decision and no longer grows with the set, ending its Ubuntu CI timeout (#219 task, #485 follow-up).
|
|
31
|
+
|
|
5
32
|
## 0.12.34
|
|
6
33
|
|
|
7
34
|
Built-in native policy now lives behind the adapter registry (#451 A2). Native behaviour is unchanged except the disclosed Codex watchdog fence below; the core keeps no vendor tables, and a guard refuses new ones. The changes_requested threshold that moves a task to another peer is now the setting `tasks.escalate_after`, with a default of three instead of the old fixed two (#488). Antigravity, Gemini CLI and Grok project configuration directories are protected like other agent configuration (#485). Live native clients, the #418 AC8 managed-Pi leg (#142) and #438 AC7 remain unverified by this release preparation. Installation and the person's restart require separate receipts.
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Codex, Kimi Code, Pi and a hub-owned local worker (Qwen Code and Jcode optional)
|
|
|
5
5
|
share a message bus and a task board per project and one memory on the machine,
|
|
6
6
|
each attached through its own native interface.
|
|
7
7
|
|
|
8
|
-
Status: 0.12.
|
|
8
|
+
Status: 0.12.36, control protocol 16. Bun + TypeScript, one loopback daemon per
|
|
9
9
|
project. Site: [agent-hub.staix.net](https://agent-hub.staix.net).
|
|
10
10
|
|
|
11
11
|
## What it does today
|
|
@@ -77,16 +77,18 @@ cd <your project> && ahub init && ahub up
|
|
|
77
77
|
|
|
78
78
|
After upgrading from 0.12.30 or earlier, run `ahub jcode --mode headless` once in each
|
|
79
79
|
project that uses Jcode to refresh its owned MCP entry before conductor or dashboard
|
|
80
|
-
starts of Jcode. The entry's format is unchanged in 0.12.
|
|
81
|
-
reports the entry missing or stale is fixed by the same command.
|
|
80
|
+
starts of Jcode. The entry's format is unchanged in 0.12.36; a daemon start that still
|
|
81
|
+
reports the entry missing or stale is fixed by the same command, which since 0.12.36
|
|
82
|
+
writes the running hub's own plugin bundle (#502).
|
|
82
83
|
Cancellation needs a daemon advertising `task_cancel`; controlled downgrades
|
|
83
84
|
refuse while cancelled rows exist. For local/Pi implementation, opt in to an
|
|
84
85
|
available `checks.runner = "container"`; issue-backed owners also need authenticated
|
|
85
86
|
spec access. PII work and designated reviewers retain their separate exemptions.
|
|
86
|
-
See [release verification](docs/verification/2026-10-
|
|
87
|
+
See [release verification](docs/verification/2026-10-19-0.12.36.md) for the live legs
|
|
87
88
|
still open, including #418 AC8, #438 AC7, the native console settings leg (#439 AC5),
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
real upgrades with reattach (#463) and with a managed terminal and cancelled tasks
|
|
90
|
+
(#478), a live headless Claude review (#223), and a Claude session over 32 MiB
|
|
91
|
+
(#517).
|
|
90
92
|
|
|
91
93
|
Before migrating a memory home with `amem`, upgrade every hub using that home to
|
|
92
94
|
0.12.30 or later, check `ahub memory profile-check`, then quiesce and close all memory
|
|
@@ -49,5 +49,10 @@ Scope: the Codex, ACP and Pi adapters and the Pi extension (turn `generation` an
|
|
|
49
49
|
- Pi TUI hub prompts (#379; an idle snapshot ACK arriving before a personal start inserted a hub prompt into the person's turn): attribute a start, end or settle to a hub turn only by the command's `promptId`, which lasts until the logical `agent_settled`; treat any other start while a hub prompt is pending or running as personal activity that detaches Pi. Settle `failed_safe` only on a `prompt_not_started` refusal bound to the verified owner, session, command id and generation; everything else stays `needs_review`. Refuse roster return without `fencedPrompt`.
|
|
50
50
|
|
|
51
51
|
- Adapter registry (#451): kind-specific policy lives in that peer's `AdapterDefinition` under `src/adapters/definitions/` (runtime definitions `NATIVE_BUILTIN_DEFINITIONS_WITHOUT_QWEN` in `builtin-metadata.ts` plus `qwen.ts`; the daemon constructs every native driver through `start.create` and `DAEMON_PORTS`; `BUILTIN_DEFINITIONS_WITHOUT_QWEN` is the frozen A1 export, read by no runtime consumer). Outside `src/adapters/`, read a semantic field of `definitionOf(id)`: never a raw peer-id comparison, a resolved kind (`kindOf`, `definitionOf(...).kind`) or a constant alias compared with a native name, a vendor-keyed object, a peer-name array, or a closed-list import from `peer-catalog.ts`, `start-mode.ts` or `permission-mode.ts`; the guard resolves aliases and import/re-export bindings. `test/registry-guard.baseline.json` is `[]` and stays empty: a new site moves into a definition, never into the baseline. The only exceptions are the cross-release literals `KNOWN_PEERS` (5), `OPTIONAL_PEERS` (2) and `START_MODE_PEERS` (3), pinned separately in `test/registry-guard.test.ts`. `LaunchContext.nativeCommand` carries only validated config argv (or its redacted preview), never model input; a definition's `permission.grants` text is what `permissionGrant` shows, ahead of the built-in wording. Keep native mode-id maps in `definitions/*-native.ts`, free of registry factories (`test/adapter-import-order.test.ts`).
|
|
52
|
-
- Registry load runs `assertDaemonEngine` and `assertNativeCapabilityScope` before publication. A definition that is not a fixed builtin (object identity in `fixedBuiltinDefinitions`, never a kind name) may not declare `start.acpCommand`, `attach.admission`, `budget.resetSoftTokensOnResume`, `session.crashIdentity`, a `pi-rpc` daemon port or `
|
|
52
|
+
- Registry load runs `assertDaemonEngine` and `assertNativeCapabilityScope` before publication. A definition that is not a fixed builtin (object identity in `fixedBuiltinDefinitions`, never a kind name) may not declare `start.acpCommand`, `attach.admission`, `budget.resetSoftTokensOnResume`, `session.crashIdentity`, a `pi-rpc` daemon port, `routing` or `reviewerVariant`. Only `definitionOf(id, instances)` picks a kind's `reviewerVariant`, for a declared extra whose own `start_mode` is `"headless"`. A new field that depends on fixed-builtin assumptions or host-global native state joins that list (`test/adapter-capability-scope.test.ts`). `trust.onPrem` admits PII work (rule: `tasks.md`).
|
|
53
53
|
- `validatePiSession` (`src/pi/session.ts`) throws `PiSessionUnresumable` only on positive evidence (ENOENT, a file outside the managed session directory, an unparsable or mismatched header) and `PiSessionBookmarkMismatch` only when a valid header names another session id; every other read failure is rethrown unchanged, because the daemon retires a Pi continuity bookmark only on those two classes (#463). `PiPeer` rethrows a mismatch with the neutral header-id message and never claims a bookmark exists (`test/pi-session-validation.test.ts`).
|
|
54
|
+
|
|
55
|
+
- Spawn with `peerChildEnv(<instance id>)`, not the kind name. An ACP `kind` comes only from the host declaration, never from the id suffix or agent text.
|
|
56
|
+
|
|
57
|
+
- TUI launchers (Kimi, Jcode) write the plugin bundle the hub reports in `status` into their MCP entry, and the CLI's own copy only when the hub reports none (#502). Only the Jcode start path checks the entry against the daemon's own `SERVER_JS` (`jcodeMcpReady`); Kimi TUI admission does not compare it.
|
|
58
|
+
- `ClaudePrintPeer` (#223) clears `reviewing` at the leader's exit and first in `kill()`. A stop or watchdog settles `needs_review` at once, before the kill; `completed`, `idle` and `offline` come only after the whole process group is confirmed gone, and a failed cleanup keeps the child handle and stays `busy`. The daemon's `reviewAuthority` compares `reviewToken`: never widen it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Budget, pause and handoff
|
|
2
2
|
|
|
3
|
-
Scope: quota and native context readings, checkpoints, pause, handoff and resume, and the status line tee. Read before editing `src/hub/budget.ts`, `src/hub/context-window.ts`, `src/cli/statusline-tee.ts`, `src/adapters/definitions/native-quota.ts`, `src/adapters/definitions/native-context.ts`, `src/hub/bus.ts`, `src/hub/delivery-journal.ts
|
|
3
|
+
Scope: quota and native context readings, checkpoints, pause, handoff and resume, and the status line tee. Read before editing `src/hub/budget.ts`, `src/hub/context-window.ts`, `src/cli/statusline-tee.ts`, `src/adapters/definitions/native-quota.ts`, `src/adapters/definitions/native-context.ts`, `src/hub/bus.ts`, `src/hub/delivery-journal.ts`, `src/hub/restart.ts` (pause persistence) or the per-account fanout in `src/hub/instance-budget.ts`.
|
|
4
4
|
|
|
5
5
|
- Budget: checkpoint first, pause second (a paused peer receives nothing). A handoff that fails is left unmarked so the next tick or hub run retries it; never record it as done.
|
|
6
6
|
- A handoff needs somebody to hand over to: `canHandOff` is false right after a restart, when no peer is attached yet, and the handoff waits for a later tick instead of stripping tasks of their owner.
|
|
@@ -11,10 +11,12 @@ Scope: quota and native context readings, checkpoints, pause, handoff and resume
|
|
|
11
11
|
|
|
12
12
|
- Keep native context occupancy (`src/hub/context-window.ts`, readers in `src/adapters/definitions/native-context.ts`) separate from quota accounting; never use Codex's accumulated `total` as occupancy or estimate Pi counters.
|
|
13
13
|
- Context checkpoint completion requires its request id and the current attached peer/native session. Invalidate its transport generation synchronously at a new peer claim, before asynchronous recall or attachment. Never pause, reassign or replace a session on context pressure. Refuse private-turn, PII-pattern and all associated open PII-task summaries (owner or reviewer, including in_review, with the current routing policy; use `isClosedTaskState` to exclude approved and cancelled work) before local persistence or cloud memory; never broadcast checkpoint text.
|
|
14
|
-
- Invalid/stale context readings expose unknown and do not rearm a crossing. Latch a crossing only after its event is accepted; reconsider paused/recovery-held crossings after release with fresh current-session readings. Tee context fields contain finite numeric values or null only, bound to daemon instance, launcher and native session.
|
|
14
|
+
- Invalid/stale context readings expose unknown and do not rearm a crossing. Latch a crossing only after its event is accepted; reconsider paused/recovery-held crossings after release with fresh current-session readings. Tee context fields contain finite numeric values or null only, bound to daemon instance, launcher and native session. Context and session go to the per-peer file `claudeStateFile(base, peer)` (the builtin keeps the unsuffixed name); `claude-usage.json` stays one shared file per account.
|
|
15
15
|
|
|
16
16
|
- A provider hard refusal ends a reading override and supersedes a soft evaluation still awaiting its checkpoint; never let the obsolete checkpoint overwrite that pause. An ACP provider quota refusal reports a hard budget reading and confirms the live pause before the adapter requeues work, so the pause fences retries and the existing relay handles assignments. Use the observed window length for an unknown reset; repeated quota refusals while paused do not consume poison-envelope retries.
|
|
17
17
|
- Kimi's ACP `{used, size}` occupancy is a context reading (`acpContext`, source `acp_usage_update`) bound to the adapter's own session id: never a `tokens` event or a budget window, and an invalid shape reports unknown, not the previous value. A gate crossing sends a checkpoint request only to definitions with `budget.checkpoint` (Claude and Codex); an ACP peer gets the event and the notice (#285).
|
|
18
18
|
- A quota resume notice replaces the peer's unread resume notices: carry their moves into the new one (`refs.budgetResumeMoves`, or the whole text of a notice that has none), publish it, and only then withdraw the ones it replaces, so a failed publish keeps them (#306).
|
|
19
19
|
- Quota handoff context reads `QUOTA_HANDOFF_PLATFORMS` (`src/adapters/registry.ts`, each definition's `hooks.recallPlatform`: claude, codex, kimi, qwen, jcode). It is independent of `hooks.recallInjected`: a handoff platform never joins the injected-platform exclusion in recall (`test/adapter-handoff-platforms.test.ts`).
|
|
20
20
|
- `Budget.report` skips `user`, `hub` and a registered kind with no `budget` block or with `budget.quotaExempt` (only local); an external id keeps quota accounting. `budget.instrumented` (execution budget) never exempts quota.
|
|
21
|
+
|
|
22
|
+
- Key quota readings, pause records, overrides, checkpoints and handoffs by the canonical account (`hooks.account`, idempotent); telemetry keeps the reporter id and native context occupancy stays per instance. `instanceBudgetHooks` fans pause, resume, checkpoint and handoff out to every member, and `canHandOff` excludes the paused account's siblings. Startup normalization merges old alias pause rows without dropping a row or marking an unfinished handoff done. A manual pause stays per member.
|
package/docs/agent-notes/bus.md
CHANGED
|
@@ -8,13 +8,14 @@ Scope: delivery, digests and condensation, reply addressing, priority and limits
|
|
|
8
8
|
- Apply reloaded `batch_max`, `batch_ms` and `queue_cap` only through `Bus.configureScheduling` (#439): it validates the values and changes later batching and admission only. Never re-arm an existing batch deadline, trim or reorder queued work, or touch prefaces, pauses, recovery holds or in-flight delivery from it.
|
|
9
9
|
- A failed digest is retried one envelope at a time, so a poison envelope cannot take its neighbours down with it.
|
|
10
10
|
- An `important` envelope being steered is not in the queue while the steer is in flight; queue it first and an idle transition delivers it twice.
|
|
11
|
+
- `WsPeer.steer` exists only for a push channel session: set at attach, cleared on detach, roster detach and a pull-only attach, and it refuses anything but important work in the current busy turn (#493).
|
|
11
12
|
- `replyParent()` decides what a reply answers (highest hop, never the `hub` preface). Use it for deliveries and steers alike, or the hop cap can be reset.
|
|
12
13
|
- What a peer is handed (`out`) and what it stands for (`originals`) differ once a delivery is condensed: the bus keeps both, registers `out` so `reply_to` resolves, puts the originals back on a `failed_safe` receipt and holds any other failure (a thrown `deliver`, a later `onFailed`, a `needs_review` receipt) as `needs_review` with its originals, for `ahub queue resolve`, and counts no attempt when the peer merely got busy while the delivery was prepared. A delivery with an `important` envelope is never condensed.
|
|
13
14
|
- A condensed digest is sent by `digest`, not `hub`: `replyParent()` skips only the hub's `presence` item, and a reply to a digest must keep the highest hop of what it replaced. On a `failed_safe` delivery or a `retry` resolution the bus puts back the originals, never the digest.
|
|
14
15
|
- Limits admit what is sent: the envelope `newEnvelope` builds (a reply inherits its parent's sender, `digest` resolves to the originals, `capPriority` applies), never the raw `to` and priority. Admit first and build later, and implicit replies all count as broadcasts.
|
|
15
16
|
- A reply is addressed, never broadcast. An adapter that answers a delivery passes `to: replyAudience(envs)`; anything else with an `inReplyTo` inherits that envelope's sender. Leaving `to` empty fans the message out to every peer.
|
|
16
17
|
- `digest` is not a peer: addressing a reply at the envelopes the peer was handed sends it nowhere once a delivery was condensed. The bus resolves `digest` back through `lastDelivery.originals`; anything else that reads a reply's `to` has to do the same.
|
|
17
|
-
- A pull-only peer (a Claude session without channel pushes or Kimi in its own TUI) is never drained; `Bus.pull` hands it what one push would take. Drain and pull share `held()` (recovery, an uncertain delivery, any pause, the lifecycle `deliveryHeld` fence) and `remember()` (so `reply_to` resolves), and a drain rechecks `deliverable()` after condensing because such a session can take the peer meanwhile. A pull is journaled `completed` in the same transaction as the bus snapshot, never `accepted`; a failed one puts back only that peer's queue and preface and never reloads the snapshot.
|
|
18
|
+
- A pull-only peer (a Claude session without channel pushes or Kimi in its own TUI) is never drained; `Bus.pull` hands it what one push would take. An attached channel session may also pull its own queue through `hub_inbox` while busy (#493); the same holds and journal completion apply. Drain and pull share `held()` (recovery, an uncertain delivery, any pause, the lifecycle `deliveryHeld` fence) and `remember()` (so `reply_to` resolves), and a drain rechecks `deliverable()` after condensing because such a session can take the peer meanwhile. A pull is journaled `completed` in the same transaction as the bus snapshot, never `accepted`; a failed one puts back only that peer's queue and preface and never reloads the snapshot.
|
|
18
19
|
- Record exact task-offer reads only through `DeliveryJournal.completeDelivered` on an active-fenced adapter completion, correlated reply or actual pull, atomically with completion. Capture original offers before terminal pruning and record their ids, never condensed ids; accepted receipts, generic transitions, operator/hub dispositions and restored completed rows are not read evidence.
|
|
19
20
|
- The `onImportantQueued` nudge for a pull-only peer (#398) is advisory: it never dequeues, steers, journals or settles, and a throw from it never stops an enqueue.
|
|
20
21
|
- Merge recall and restored prefaces through `mergePrefaces`/`uniqueMemoryLines`; preserve distinct context and new notes, deduplicate memory identities, and keep colliding short prefixes distinct. Use `recallDisplayText`/`recallMemoryLines` before display caps: suppress only matching automatic approval outcomes, retain nonempty rejection details, preserve id headers and complete-word excerpts, and keep token trimming at line boundaries. Keep these changes display-only.
|
|
@@ -30,3 +31,6 @@ Scope: delivery, digests and condensation, reply addressing, priority and limits
|
|
|
30
31
|
- A hub-native peer (Pi, the local worker) does not get to call its own message `important`: `capPriority` caps it unless the delivery it answers held an `important` envelope addressed to it. Check the delivery, not `replyParent`, which ties on hop and takes the later item. Do not bypass it by setting `priority` in the adapter.
|
|
31
32
|
|
|
32
33
|
- Routing never chooses a pull-only owner or reviewer automatically. Pass live pull-only ids and role-specific explicit naming to the pure assign function; an automatic singleton is not named. Only a honored persisted owner reservation, explicit owner nomination/claim, or authorized reviewer nomination bypasses that eligibility refusal, never roster, PII, pause or capability guards.
|
|
34
|
+
|
|
35
|
+
- `relevant` may return a string: the envelope is dropped with that string as its journal discard reason. Read relevance only through `irrelevance()`.
|
|
36
|
+
- A review-only instance (a declared extra whose roles are exactly `reviewer`) receives only person messages, hub `review` items and hub `task` items addressed to it. Keep `reviewOnlyItem` in both `silence` (at send) and `relevant` (at delivery) (#223).
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
- Console attention navigation selects a delivery only by an exact visible row id. A missing id or row prints read-only guidance; never select by peer or fall back to the first Queue row.
|
|
7
7
|
|
|
8
|
-
Scope: the operator console, control WS and its protocol, state files, the dashboard listener and settings, the Claude channel's reconnect, `ahub setup`, git snapshots, upgrade and recovery. Read before editing `src/adapters/definitions/native-recovery*.ts`, `src/adapters/definitions/native-policy-aux.ts`, `src/adapters/definitions/native-config-*.ts`, `src/adapters/definitions/native-cli-*.ts`, `src/cli/console.ts`, `src/cli/console-state.ts`, `src/cli/attention.ts`, `src/ui/needs.ts`, `src/hub/daemon.ts`, `src/hub/ui.ts`, `src/hub/settings.ts`, `src/hub/control-client.ts`, `src/adapters/claude-channel.ts`, `src/hub/restart.ts`, `src/hub/recovery-store.ts`, `src/hub/snapshots.ts`, `src/hub/manager.ts`, `src/hub/lifecycle.ts`, `src/hub/crash.ts`, `src/hub/start-mode.ts`, `src/hub/terminal-open.ts`, `src/hub/recovery-error.ts`, `src/hub/db-timeout.ts`, `src/hub/config-reload.ts`, `src/hub/config-apply.ts`, `src/hub/recovery-continuity.ts`, `src/cli/recovery-presentation-options.ts`, `src/cli/setup.ts`, `src/cli/upgrade*.ts`, `src/cli/terminal-recovery.ts`, `src/cli/recovery-package.ts
|
|
8
|
+
Scope: the operator console, control WS and its protocol, state files, the dashboard listener and settings, the Claude channel's reconnect, `ahub setup`, git snapshots, upgrade and recovery. Read before editing `src/adapters/definitions/native-recovery*.ts`, `src/adapters/definitions/native-policy-aux.ts`, `src/adapters/definitions/native-config-*.ts`, `src/adapters/definitions/native-cli-*.ts`, `src/cli/console.ts`, `src/cli/console-state.ts`, `src/cli/attention.ts`, `src/ui/needs.ts`, `src/hub/daemon.ts`, `src/hub/ui.ts`, `src/hub/settings.ts`, `src/hub/control-client.ts`, `src/adapters/claude-channel.ts`, `src/hub/restart.ts`, `src/hub/recovery-store.ts`, `src/hub/snapshots.ts`, `src/hub/manager.ts`, `src/hub/lifecycle.ts`, `src/hub/crash.ts`, `src/hub/start-mode.ts`, `src/hub/terminal-open.ts`, `src/hub/recovery-error.ts`, `src/hub/db-timeout.ts`, `src/hub/config-reload.ts`, `src/hub/config-apply.ts`, `src/hub/recovery-continuity.ts`, `src/cli/recovery-presentation-options.ts`, `src/cli/setup.ts`, `src/cli/upgrade*.ts`, `src/cli/terminal-recovery.ts`, `src/cli/recovery-package.ts`, `src/cli/facts-hook.ts` or the instance modules (`src/hub/instances.ts`, `src/hub/instance-config.ts`, `src/hub/instance-execution.ts`), or before adding a native peer.
|
|
9
9
|
|
|
10
10
|
- The plugin bundle is installed apart from the daemon. Breaking a control WS message contract bumps `PROTOCOL` in `control-client.ts`; a new request answered as unknown or an optional field preserves it, as does additive optional public task metadata in `ui_snapshot` that older clients ignore (such as `deps` in #246).
|
|
11
11
|
- `peer_stop` is console-only and stops only a hub-owned headless ACP, Pi or local runtime through its adapter. Refuse native-terminal peers and recovery-held mutations; serialize with starts and permission changes, and refuse a recovery `prepare` while a stop runs. An admitted stop holds delivery through `BusOptions.deliveryHeld` before any teardown await (never a console pause that resume can undo, or a global recovery hold that blocks unrelated peers) and withdraws the peer's pending approvals before the adapter stops. A requested stop holds an in-flight delivery as `needs_review` with an ids-only stop reason, suppresses restart/escalation, and never resolves that delivery automatically.
|
|
@@ -24,7 +24,7 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
24
24
|
- Defer hub notices only for an authenticated recovery `prepare` or `commit` whose target features include `recovery_deferred_hub`, or for a restored daemon. Otherwise `setRecoveryHold(true)` moves the deferred notices into queues before commit records expected integrity, and a bare `fenceRecovery` defers nothing. Abort and lease expiry release the bus hold before clearing the operation; if that release fails, keep the operation and let expiry retry on its 1 s timer (#478).
|
|
25
25
|
- Resume a prepared `commitSent` source that is unavailable or database-busy inside the existing bounded shutdown poll; never re-send commit, re-prepare or close terminals again on that path. Require confirmed `stopped` before target startup, refuse a replacement instance, and retain the prepared receipt on timeout.
|
|
26
26
|
- Keep restoration receipts explicitly tagged as pending, waiting with origin/binding, done with binding, or failed. Project waiting origins as `waiting:pending` and `waiting:failed`; preserve the chosen binding and origin across interruption instead of inferring completion from an object.
|
|
27
|
-
- A zero-turn Claude session has no transcript, so it can never be resumed: every identity gate that compares session ids (restore, coordinator verify, daemon readiness) must tolerate a fresh session while the transcript is absent and stay strict the moment one exists. The commit snapshot records `sessionPersisted` for the restored daemon, and snapshots too old to have it are re-derived from disk. Never treat "session id changed" as proof of a lost conversation without checking the transcript first. A post-restore detachment repair (#463) is bound to its last accepted session even when its transcript is absent; never use the zero-turn exception to replace that recorded conversation.
|
|
27
|
+
- A zero-turn Claude session has no transcript, so it can never be resumed: every identity gate that compares session ids (restore, coordinator verify, daemon readiness) must tolerate a fresh session while the transcript is absent and stay strict the moment one exists. An instance's transcript counts as missing only on positive ENOENT/ENOTDIR of its own reported path (`transcriptPersisted`, `pathEvidence`); with no reported path or another lstat error, treat it as persisted. The commit snapshot records `sessionPersisted` for the restored daemon, and snapshots too old to have it are re-derived from disk. Never treat "session id changed" as proof of a lost conversation without checking the transcript first. A post-restore detachment repair (#463) is bound to its last accepted session even when its transcript is absent; never use the zero-turn exception to replace that recorded conversation.
|
|
28
28
|
- The terminal-recovery launcher signature is the shared pinned `processSignature` (`src/pi/process-signature.ts`): a record written by one CLI invocation must compare equal when a later invocation re-reads the live launcher under another TZ/LC_ALL (#177). In-process `process.env` mutation does not reach Bun.spawnSync's default child environment, so cross-environment regressions are tested with real subprocesses. A row written by 0.12.12 or older carries the unpinned signature, which `launcherState` also compares (#228). A launch-record row that fails validation is unknown for the peer it may belong to and is written back unchanged, never filtered out (#228).
|
|
29
29
|
- Judge every recorded owner pid (hub manifest, registry claim, recovery runner, manager owner, launcher record) with `processLiveness` in `src/pi/process-signature.ts`, never a bare `process.kill(pid, 0)`: after a reboot a recorded pid can belong to another process, even one we may not signal, and the bare probe wedged recovery and `ahub up` (#226). A writer records `processSignature(process.pid)` beside its pid; a registry claim stores it as `<instance id> <signature>` because an older daemon's claim rewrites the pid but not that column. Records without a signature keep the bare-pid answer; unknown is never gone.
|
|
30
30
|
- A restored daemon accepts a changed native session id (Kimi and local aside: they restart as fresh workers) in two ways only: the #64 rule for a Claude session that never persisted a transcript, and the operation-fenced `recovery-waivers.json`, which the coordinator writes wherever it accepts a session other than the planned one: a reconnect-only Claude (#206), an operator-chosen fresh session, the plan's `freshStart` of a Codex thread the hub saw start with no turn, or a zero-turn Claude it accepted (#215). Never waive on any other evidence. Re-preparation after an expired lease keeps every effect receipt, and `restored:<peer>` = `failed` never counts as restored. Judge a restoration launcher by its `terminal-recovery.json` record and process signature (and a `terminal_handle_stale` answer), never by the terminal's exit; an unreadable record is unknown, never "none".
|
|
@@ -39,7 +39,7 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
39
39
|
- Recovery judges the registry claim as it is now (`inspectRecovery` re-reads `registeredProjects()`), never the plan's frozen copy; a registry that cannot be read is not inspected, never stopped (#226).
|
|
40
40
|
- `inspectRecovery` catches only `RecoveryDeferredHubError` from `readRestartSnapshot`: keep the stopped state and return the static `snapshotError` blocker without a `snapshot` binding. Never echo rejected content, repair the snapshot or offer resume from it (#478).
|
|
41
41
|
- The managed Claude hook (`src/cli/facts-hook.ts`) may only add `permissionDecision: "allow"` on `PreToolUse`, and for `ask-when-needed` only what `projectFileTool` accepts: a hub that is down, slow or refuses decides nothing. The daemon puts `permission` in a `facts` reply only for the hook of this instance's recorded `ahub claude` launch (the same `launchId`, not `--unattended`), and a permission-only hook (`hookPurpose`) never drives busy state (#242).
|
|
42
|
-
- `ahub claude` (`src/cli/launch.ts`, #270) publishes `claude-launch.json` for every launch against a running hub, atomically and without a lock: hooks, permission status, session observation and recovery read its `launchId`, so never make it wait for native-proof state. The native child's pid and signature go only into the private `claude-native-<binding hash>.json`, keyed by the exact launch record, written once under `claude-launch.lock` and removed at that child's own exit; never put them in `claude-launch.json`, where a late callback of an earlier launch could replace a newer record. Crash cleanup of a previous launch's settings file (`cleanupStaleClaudeSettings`) needs the launcher gone by `processLiveness` and that native proof, and for a `direct-child` proof the native pid absent from an available `processTable`: a direct child may exec in place, so its signature certifies nothing. A script or interpreter gets no proof and keeps its settings file.
|
|
42
|
+
- `ahub claude` (`src/cli/launch.ts`, #270) publishes `claude-launch.json` (`claude-launch.<id>.json` for an `--as` instance) for every launch against a running hub, atomically and without a lock: hooks, permission status, session observation and recovery read its `launchId`, so never make it wait for native-proof state. The native child's pid and signature go only into the private `claude-native-<binding hash>.json`, keyed by the exact launch record, written once under `claude-launch.lock` and removed at that child's own exit; never put them in `claude-launch.json`, where a late callback of an earlier launch could replace a newer record. Crash cleanup of a previous launch's settings file (`cleanupStaleClaudeSettings`) needs the launcher gone by `processLiveness` and that native proof, and for a `direct-child` proof the native pid absent from an available `processTable`: a direct child may exec in place, so its signature certifies nothing. A script or interpreter gets no proof and keeps its settings file.
|
|
43
43
|
|
|
44
44
|
- Keep SQLite recovery contention in the existing blocked receipt as retryable `database_busy`, retaining bounded throw-site frames and the ordinary `ok: false` rid reply. Use a neutral control error; the receipt's next actions name resume or the partway disposition. Clear a superseded failure on abort, disposal, fresh-session choice or a refused resume of a disposition. After a commit request, treat busy inspection as unconfirmed and keep polling only inside the existing shutdown bound.
|
|
45
45
|
- Recovery inspection uses its existing 30 s control cap for the first status read and consumes a structured busy reply without a second status probe; ordinary lifecycle probes keep their default. Treat `busy_timeout` as a ceiling for eligible waits, not a guarantee that every write waits: a WAL snapshot conflict may fail immediately. Account for synchronous 3 s hub-database waits and serial timer callbacks when choosing a timeout; several waits may consume the 30 s control margin. Never multiply the busy wait through retries or infer stopped from a shorter probe's timeout.
|
|
@@ -57,3 +57,11 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
57
57
|
- Observe memory counters only through the machine-local candidate sidecar. Bind delivered counters to a positive journal acknowledgement and the original render context; skip private envelopes and current PII tasks/turns. Leave missing telemetry unknown, and never pass candidates or counters to evidence consumers. Require memory_correct for correction proposals, refuse PII turns, and keep project/identity authority server-side.
|
|
58
58
|
|
|
59
59
|
- Keep full memory home, generation ID, selector revision and malformed-row totals in authenticated person status/CLI receipts, never disk status.json or agent CLI output; low-privilege receipts use a generation prefix and omit home, selector revision and malformed-row totals. Emit typed unbound disabled/unavailable receipts with no profile when no memory handle opened; profile-check may treat an authenticated same-home generation-capable unbound daemon as memory-quiesced, never a stale bound handle. Scope profile-check readiness to its named registry inventory; old, unknown or unreadable receipts refuse readiness, and other custom registries need separate checks.
|
|
60
|
+
|
|
61
|
+
- Bind instance declarations once at startup through the daemon-local `definitionOf` closure and the `extraIds` catalogs; never publish them to the global registry or take them from a request. `instances` is restart-class, and its settings rows come only from `projectSettings(declarations)`.
|
|
62
|
+
- Every start resolves `resolveInstanceExecutionCwd` and passes that `executionCwd` as adapter cwd, sandbox, grant and Pi session root; set `executionOwners` only for the adapter actually started. Extra-instance native state is per instance, while its MCP binding keeps the canonical hub state dir.
|
|
63
|
+
- Recovery: record an extra Codex launch row only after the start reply supplies `executionCwd`; keep `projectRoot`, `executionCwd` and `terminalRoot` separate and never bind an extra by kind metadata. Abort and archive validate receipts without current declarations; restore, fresh and reattach require them; refuse before effects when `peer_instances` is missing. Extra-instance turns write `turn_workspaces` in the `turns` transaction and leave the legacy snapshot fields unknown; undo requires the same trusted declaration and validated root.
|
|
64
|
+
|
|
65
|
+
- Name every Claude per-peer state file through `claudeStateFile` (`src/hub/claude-state.ts`) with that peer's id, never a hard-coded builtin name; pick a peer's `terminal-recovery.json` row only through `ownTerminalRow`. `sessionPointers` in `src/cli/reset.ts` must match any new per-peer pointer (#450 I3).
|
|
66
|
+
- A declared Claude channel extra is never hub-started: keep it out of `STARTABLE_PEERS`, instance start modes and `RESERVED_IDS`. A launcher admits `--as <id>` only when the running daemon's status `activeInstances` lists it (`requireActiveInstance`), never from the config on disk.
|
|
67
|
+
- Verify a native Claude Stop and its start baseline only through `readClaudeTranscriptCompletion` (bounded tail), never the size-capped `readClaudeTranscriptUsage`; an `unavailable` refusal leaves the peer busy and notifies once per turn start (#517).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Local worker and sandbox
|
|
2
2
|
|
|
3
|
-
Scope: the hub-native local worker, its tools, path guard, denylist and seatbelt sandbox. Read before editing `src/adapters/local-worker.ts`, `src/local/`, `src/memory/capture.ts` or `src/hub/facts.ts` (both read the denylist), `src/hub/git.ts`,
|
|
3
|
+
Scope: the hub-native local worker, its tools, path guard, denylist and seatbelt sandbox. Read before editing `src/adapters/local-worker.ts`, `src/local/`, `src/memory/capture.ts` or `src/hub/facts.ts` (both read the denylist), `src/hub/git.ts`, the grant filter in `src/hub/permission-mode.ts`, or the sandbox root in `src/hub/instance-execution.ts`.
|
|
4
4
|
|
|
5
5
|
- Nothing the local worker executes may run outside `sandboxedExec`; a new tool that spawns a process goes through it, and a tool that touches a path goes through `guardPath`.
|
|
6
6
|
- The sandbox denies home reads by default (toolchain dirs, the project and its real git dir excepted) and all network, loopback included: claude-mem and the Codex app-server listen on loopback without auth. Tests that bind a local port therefore fail when the worker runs them, also with `local.bash_network: true` (the egress proxy keeps loopback closed, and the proxy variables send a test's plain-HTTP `fetch` to the proxy, which refuses it); that is the intended trade-off, and `"direct"` is the switch until 0.13.0 removes it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Task board and hub tools
|
|
2
2
|
|
|
3
|
-
Scope: the task flow, assignment, the state machine and the hub's MCP tools. Read before editing `src/hub/tasks.ts`, `src/hub/board.ts`, `src/hub/routing.ts`, `src/hub/task-sweep.ts`, `src/hub/settled-roles.ts`, `src/hub/conductor.ts`, `src/hub/supervision.ts`, `src/hub/tool-refusal.ts` or `src/hub/
|
|
3
|
+
Scope: the task flow, assignment, the state machine and the hub's MCP tools. Read before editing `src/hub/tasks.ts`, `src/hub/board.ts`, `src/hub/routing.ts`, `src/hub/task-sweep.ts`, `src/hub/settled-roles.ts`, `src/hub/conductor.ts`, `src/hub/supervision.ts`, `src/hub/tool-refusal.ts`, `src/hub/hub-tools.ts` or `src/hub/review-brief.ts`.
|
|
4
4
|
|
|
5
5
|
- Tool callers are models: MCP `inputSchema` is not enforced on the way in. Normalize at the boundary (`cleanRefs`) before anything reaches the board, and never throw after a board write: a publish or notify that follows a `review()` or `done()` board write goes through the one `releaseNotice` guard, which turns a failed publish into a console notice, drops a failed notify and never retries (#231, #243). An assignment's delivery once its board write is saved (#276, #297): the move is fact, the failed publish is not retried in place (the journal's own recovery covers a storage error, and a retry may duplicate a publish that actually left), and a person looks for a queued or needs_review delivery with `ahub queue list --peer <owner>` (then `ahub queue show <id>`, or the accepted entry in `ahub task show <id>` if the journal is down) before re-sending with `ahub task assign <id> <owner>`. The distinction is made once, in `assignOwner`: a failure after the write prints the one console notice from `undeliveredNotice` right there, once, and throws `AssignmentUndeliveredError` carrying the saved task; callers (`review()`'s repeated rejection, `escalate` and its callers, the ready offer, both relays, the idle sweep, rescreen) decide control flow by the type and print nothing more, and `propose`, `assignTo` and `decline` additionally let the error reach the caller in its turn, which is a person or peer that can act. Two exceptions get no notice, by construction: a row superseded meanwhile, meaning a later history entry that moves or settles the task (another assignment, an unassign, the owner's accept, done, approval, close), while entries that do neither (the hub's quiet bookkeeping: answers, reviewer changes, idle sweeps, check results) leave the assignment undelivered and the notice stands, so the original error goes to the caller as before only on supersession; and a claim's own accepted write and "claimed by" line stay outside the delivery rule (a claim is its own hand-over; its overlap and routing announcements to earlier owners are deliveries and share the wrapper, so a failure there does read as one). A failure before the write stays a plain `Error` (#254), a failed write leaves the ready offer unconsumed (#231), and the notices before the write (waits, no-owner, the reserved-owner line) go through `releaseNotice` too, so those pre-write notices cannot fail their caller.
|
|
6
6
|
- Post-await assignment publication is fenced by current role authority: supersession returns the current task without a saved-delivery notice; reviewer-only changes refresh current metadata and do not suppress a valid owner delivery. A replacement notice goes only to a role that actually received the request, not to an unread-only queue.
|
|
@@ -22,7 +22,7 @@ Scope: the task flow, assignment, the state machine and the hub's MCP tools. Rea
|
|
|
22
22
|
|
|
23
23
|
- Pass off-roster ids as data into `assign()` so its trace and every owner/reviewer choice share the membership filter. Refuse a manual off-roster assignment before a board write, including a reservation. Use `reassignForRoster` through the existing assignment delivery path on removal, including in-review ownership while keeping its review state; keep the old owner or reviewer when no eligible replacement exists and emit the guarded public-title notice. Preserve budget-relay behavior when sharing that implementation.
|
|
24
24
|
|
|
25
|
-
-
|
|
25
|
+
- Criteria checklists (`criteria`, retired alias `phase`) are written only through Tasks.recordLifecycle by that task's reviewer/person, after the PII screen. Refuse a checklist task list before any write; never change dependencies, accepted owners or reservations from a checklist. Keep verified checklist claims separate from externally read CI, and bind them to the current reviewed head. Screen `checklistOf(next)`, never `next.criteria` alone: off stores a phase write under `phase`. Plain off (no retired `workflow`) keeps the #257 receipt bytes, the schema-1 export and the `phase` tool schema; advertise `criteria` only when daemon status carries `lifecycleCriteria`. Export only derived sanitized board/config projections.
|
|
26
26
|
|
|
27
27
|
- A planner patch that names `reserved` at all, the same value included, is refused while `hasPersonReservation` holds; planner pull and grooming both ask it (#378: a same-value write laundered a person's reservation).
|
|
28
28
|
- `done()` gates the SDLC transition once: pass `gated` to `complete()` when nothing was awaited since, and after any awaited gate readback refuse if another done already moved the task, in every mode (#382: advise recorded overlapping dones).
|
|
@@ -35,3 +35,16 @@ Scope: the task flow, assignment, the state machine and the hub's MCP tools. Rea
|
|
|
35
35
|
- Keep candidate production in Tasks: screen review/correction payloads and current task/turn privacy before CandidateStore writes; recheck after asynchronous screening. Never make candidate failures roll back a saved review, or let a peer accept a candidate. Keep candidate tool arguments/results out of capture.
|
|
36
36
|
|
|
37
37
|
- Feed the same current spec/test capability map into every `assign()` path, explicit nomination and reservation. Apply these capability refusals only to non-PII owner admission, preserving reviewer and on-prem PII routing exemptions; refuse a missing required capability before a manual owner assignment write. Bind spec/check authority and result delivery to the current task, owner, peer generation and privacy policy.
|
|
38
|
+
|
|
39
|
+
- Resolve any id that may be an extra instance with `definitionOf`/`kindOf`/`familyOf(id, this.d.instances?.())`; a bare `definitionOf(id)` answers builtins only. Only a kind's routing preference expands to its instances; manual ids, reservations and nominations stay exact. Reviewer independence compares families: take the own family only when no other is eligible, record it through `assignmentNote` (`sameFamilyFallback=true`), explicit nominations included; persist the `instance`/`family` refusal codes as `policy`.
|
|
40
|
+
- Admit a declared extra as owner of `implement`, `bulk_edit` or `test` work only with the current implementer role and `ownerIsolation[id] === true`, the daemon's proof that the live adapter started in `executionRoots[id]` outside the canonical cwd. Never derive it from the declaration's `worktree`, its roles or a reload.
|
|
41
|
+
|
|
42
|
+
- Spec acceptance (#481 S1) is written only by `Tasks.acceptSpec` for the person; never accept it from a tool or a receipt. The daemon uses `Tasks.acceptReviewed` to bind spec and plan readbacks to one task snapshot before `Tasks.accept`; retain its synchronous missing-spec and plan-admission refusals. Apply WIP and plan admission before `done` implicitly accepts proposed work and before cohort writes. Never read or store an issue body: identity and edit times only.
|
|
43
|
+
|
|
44
|
+
- Preserve planner-reviewed cost keys when an accept replaces only file-list intent; explicit enforce scope drift needs a new planner receipt. New enforce plan-review receipts require typed review/CI scopes; keep legacy missing scope unspecified until its planning revision invalidates it. Run premature-review admission before done/cohort writes, recheck state and actor authority after every await, and keep admission separate from the review brief. Scope is cost metadata, never a permission or reviewer bypass.
|
|
45
|
+
- Cost reports recheck planner/private-turn authority and current linked privacy before each underlying external read and final projection. Do not emit a stale/relinked observation as a complete zero-cost row. S7 owns band configuration and automatic proposal writes.
|
|
46
|
+
|
|
47
|
+
- `Tasks.review` captures `reviewAuthority` once and rechecks it in `valid()` after every await, right before each write; a headless reviewer's verdict holds only while the same child runs for that task. Never cache the answer (#223).
|
|
48
|
+
- The review coverage gate (#520) pins `refs.commit` and the sdlc receipt and rechecks them in `valid()`; an unavailable brief is never an empty one (enforce refuses, advise notes). Read brief attributes and rules at the merge base (`--attr-source`, `check-attr --source`, `git show <base>:`), never from the head or the checkout.
|
|
49
|
+
- A `routing.reviewOnly` definition is refused as owner inside `assign()`'s eligibility check, for every class, nomination and reservation; keep it there, not at call sites.
|
|
50
|
+
- `Board.update`'s untouched-return exception is the only way owned or accepted work returns to backlog: keep every condition (exact event, owner and reviewer null, state, `expectedFlowRevision`, non-empty note, no work evidence) and reach it only through `Tasks.returnUntouchedToBacklog` (#481 S9).
|
|
@@ -13,7 +13,7 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
|
|
|
13
13
|
- Cross-process fixtures wait for the consuming client to process its handshake (the channel connected diagnostic), not merely the daemon's attached/idle state. Deadline-routing fixtures hold and release responses at the fallback decision; do not place a fixed sleep between deadline fractions and assume scheduler headroom (#287). Receipt-order fixtures use the normal watchdog for ordinary I/O, trigger expiry after observed native acceptance, and await a consumed transport barrier before asserting on late results.
|
|
14
14
|
- A bounded polling wait must assert its condition after the last attempt, or document why giving up is intentional. Append-only event histories wait for a correlated closing event, not removal of the opening event. Before changing a slow wait, identify the unreached state and repair its cause (#296).
|
|
15
15
|
- A request that a test expects a stop or shutdown to cut gets its rejection handler where the request is created, never after the awaited teardown: a late `catch` races the reset and the run fails on an unhandled rejection.
|
|
16
|
-
- Run `bun scripts/seeded-check.ts` before reporting the seeded-guard gate complete. Keep the `scripts/seeds.json` cases sequential; require the same named test green before its seeded assertion fails. Seed rot, survivors, setup/compiler failures, timeout/watchdog termination and process leaks fail the gate. Never run the full seed runner from a unit test or mutate the source checkout; inspect preserved failed fixtures before removing them. CI runs it as four sequential Linux shards (`--shard i/4`) beside the ordinary check, separately from `scripts/check.sh`; the required `seeded guards` job passes only when every shard passed. Keep that job name: branch protection and `scripts/ci-gates.mjs` read it (#457).
|
|
16
|
+
- Run `bun scripts/seeded-check.ts` before reporting the seeded-guard gate complete. Keep the `scripts/seeds.json` cases sequential; require the same named test green before its seeded assertion fails. Seed rot, survivors, setup/compiler failures, timeout/watchdog termination and process leaks fail the gate. Never run the full seed runner from a unit test or mutate the source checkout; inspect preserved failed fixtures before removing them. CI runs it as four sequential Linux shards (`--shard i/4`) beside the ordinary check, separately from `scripts/check.sh`; the required `seeded guards` job passes only when every shard passed, or when the decision job reused a verified identical-tree full gate (`admission == 'reuse'`). Keep that job name: branch protection and `scripts/ci-gates.mjs` read it (#457).
|
|
17
17
|
|
|
18
18
|
- `scripts/check.sh` holds the repo's heavy-job slot (`<git common dir>/ahub-heavy.lock`, #398) for the whole run, so a test never runs the real gate; `test/check-lock.test.ts` runs a copy in a scratch repo.
|
|
19
19
|
- The whole-suite watchdog is `AHUB_CHECK_HANG_S` (default in `scripts/check.sh`, hosted macOS value in `.github/workflows/check.yml`; #378, macOS CI hit it while tests still passed): raise it only when the suite was still progressing at the cutoff, never for a hung test, and keep the per-test 20 s timeout.
|
|
@@ -22,3 +22,7 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
|
|
|
22
22
|
- Keep CI's Bun version sourced from `.bun-version` through the pinned setup-bun action; update the version file rather than adding per-job version literals.
|
|
23
23
|
- Release verification requires both OS checks and the aggregate `seeded guards` success for an identical tree, a tag matching `package.json` on `origin/main`, and fresh ancestor-bound documentation stamps. Preserve the separate npm OIDC publish job and GitHub Release write job; neither job gets the other's credential authority.
|
|
24
24
|
- `test/conformance/` runs real adapters against fake transports. Record a case that does not apply as an explicit unsupported outcome, never synthetic success, and never change native production behavior to satisfy a generic case.
|
|
25
|
+
|
|
26
|
+
- Keep the CI admission lock around the whole controller workflow, not just its decision job. Preserve successful identical-tree full proof and required job names; a skipped job, pending controller or unavailable active inventory is never a successful full gate. CI reuse tests use fixed metadata fixtures and never dispatch real duplicate workflows.
|
|
27
|
+
|
|
28
|
+
- Headless-reviewer tests run `test/fakes/fake-claude-print.ts` through `command` or a PATH stand-in; a test that reaches the daemon's reviewer start must never run the real `claude`.
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
# GSD-shaped collaboration in agent-hub (#252)
|
|
1
|
+
# Retired: GSD-shaped collaboration in agent-hub (#252)
|
|
2
|
+
|
|
3
|
+
Retired on 2026-10-18 by #481. The AI-Native SDLC Playbook is the lifecycle standard. Only the head-bound acceptance-criteria checklist remains, under the Compliance pass; phase task import is removed. The text below preserves the historical analysis and unrun measurement plan, not current configuration instructions. Current behavior and the migration window are in [SDLC](sdlc.md#acceptance-criteria-checklist).
|
|
4
|
+
|
|
5
|
+
## Historical analysis
|
|
2
6
|
|
|
3
7
|
Source review: 2026-10-11, agent-hub 5647038. Recommendation: preserve the default flow; offer a bounded gsd-lite checklist/dependency presentation through #257's opt-in lifecycle. Defer a bidirectional GSD artifact bridge until it has a separately reviewed import contract and measured value.
|
|
4
8
|
|
package/docs/operations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Operations guide
|
|
2
2
|
|
|
3
|
-
This guide describes ahub 0.12.
|
|
3
|
+
This guide describes ahub 0.12.36 and control protocol 16. Live verification
|
|
4
4
|
results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
|
|
5
5
|
|
|
6
6
|
## Agent-operated live verification
|
|
@@ -802,7 +802,13 @@ includes), read the check result, and list what is
|
|
|
802
802
|
unmet (`hub_review` takes `unmet`, `ahub review ... --unmet <item>`). A reviewer
|
|
803
803
|
that missed the request, and the owner, read the done summary and check result
|
|
804
804
|
with `hub_task_show {id}`: the task's public view with its history, as the
|
|
805
|
-
conductor sees it, and only a stub for a PII task. Other peers are refused.
|
|
805
|
+
conductor sees it, and only a stub for a PII task. Other peers are refused. Each
|
|
806
|
+
request also carries the hub's review brief for the task's commit: reviewable and
|
|
807
|
+
excluded files with reasons, the `REVIEW.md` and `ahub-review-rules` rules read at
|
|
808
|
+
the merge base, and a cross-check list; `ahub review brief <id>` prints it.
|
|
809
|
+
`hub_review` takes `coverage {reviewed, skipped}`: in enforce an approval that leaves
|
|
810
|
+
a reviewable path unaccounted is refused, and advise notes the gap in the verdict
|
|
811
|
+
(#520). The hub
|
|
806
812
|
records how each review turned out, per implementer, reviewer and class:
|
|
807
813
|
approved; caught (changes were requested and the owner's redo was approved);
|
|
808
814
|
contradicted (within a week, work on the same file or symbol failed its check
|
|
@@ -1777,6 +1783,16 @@ but cannot show pushes, so it attaches tools-only (protocol 16, issue #205):
|
|
|
1777
1783
|
started while an `ahub claude` session holds the peer stands by and attaches
|
|
1778
1784
|
only after that session leaves.
|
|
1779
1785
|
|
|
1786
|
+
### Claude channel sessions while busy (#493)
|
|
1787
|
+
|
|
1788
|
+
A Claude session started with `ahub claude` receives pushes when it is idle. While it is busy:
|
|
1789
|
+
|
|
1790
|
+
- Every hub tool result carries fresh counts, `(N queued hub message(s), M important hub message(s) waiting: call hub_inbox before starting long local work)`, when important work waits. A zero count clears an earlier hint.
|
|
1791
|
+
- `hub_inbox` reads the daemon queue (and any local failed-push buffer) in a channel session too. A read is one `completed` delivery, like a tools-only read; holds refuse it the same way.
|
|
1792
|
+
- An important message is pushed into the running turn (steered) instead of waiting for the turn to end. Mid-turn reading was verified on Claude Code 2.1.302; an older client that drops it leaves the delivery `accepted` until a person resolves it. Ordinary messages still wait for the idle push or `hub_inbox`.
|
|
1793
|
+
- Do not use `[FYI]` for PR ready, done, submitted, ruling-needed, blocker or changed-contract messages: they need action. `hub_task_done` and `hub_review` already notify their recipients.
|
|
1794
|
+
- Turn completion is read from the transcript's last 4 MiB, whatever its size. When no completed turn is found there, the console says once per turn that the peer stays busy and its messages wait in its queue (#517).
|
|
1795
|
+
|
|
1780
1796
|
## Graceful shutdown
|
|
1781
1797
|
|
|
1782
1798
|
Before stopping, let active turns and approvals settle when possible:
|
|
@@ -1962,21 +1978,21 @@ section is what they run.
|
|
|
1962
1978
|
|
|
1963
1979
|
Upgrade running projects with the target release's own coordinator. It accepts
|
|
1964
1980
|
a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
|
|
1965
|
-
11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.
|
|
1981
|
+
11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.36), and only
|
|
1966
1982
|
a target on its own protocol, so the target's coordinator fits every supported
|
|
1967
1983
|
source and carries every recovery fix released up to it. Protocol 8 and older
|
|
1968
1984
|
(0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
|
|
1969
1985
|
project directory, without replacing the global CLI first:
|
|
1970
1986
|
|
|
1971
1987
|
```bash
|
|
1972
|
-
bunx --package @staix/agent-hub@0.12.
|
|
1973
|
-
bunx --package @staix/agent-hub@0.12.
|
|
1988
|
+
bunx --package @staix/agent-hub@0.12.36 ahub upgrade --to 0.12.36 --dry-run
|
|
1989
|
+
bunx --package @staix/agent-hub@0.12.36 ahub upgrade --to 0.12.36 --yes
|
|
1974
1990
|
```
|
|
1975
1991
|
|
|
1976
1992
|
| Running now | Coordinator to use |
|
|
1977
1993
|
| --- | --- |
|
|
1978
1994
|
| 0.6.x (protocol 9) | the target's, through `bunx` as above |
|
|
1979
|
-
| 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.
|
|
1995
|
+
| 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.36 (protocol 16) | the target's, through `bunx` as above |
|
|
1980
1996
|
| any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
|
|
1981
1997
|
| 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
|
|
1982
1998
|
|
|
@@ -2008,14 +2024,14 @@ projects first:
|
|
|
2008
2024
|
|
|
2009
2025
|
```bash
|
|
2010
2026
|
ahub restart --dry-run
|
|
2011
|
-
ahub upgrade --to 0.12.
|
|
2027
|
+
ahub upgrade --to 0.12.36 --dry-run
|
|
2012
2028
|
```
|
|
2013
2029
|
|
|
2014
2030
|
Apply only after reviewing the plan:
|
|
2015
2031
|
|
|
2016
2032
|
```bash
|
|
2017
2033
|
ahub restart --yes
|
|
2018
|
-
ahub upgrade --to 0.12.
|
|
2034
|
+
ahub upgrade --to 0.12.36 --yes
|
|
2019
2035
|
ahub recovery status [<operation-id>]
|
|
2020
2036
|
ahub recovery resume [<operation-id>]
|
|
2021
2037
|
ahub recovery abort [<operation-id>]
|
|
@@ -3047,7 +3063,7 @@ that the file is untracked; a dropped value is reported by the settings result.
|
|
|
3047
3063
|
|
|
3048
3064
|
## SDLC artifact receipts and gates
|
|
3049
3065
|
|
|
3050
|
-
The
|
|
3066
|
+
The playbook lifecycle (#257, #481) is off without `.agenthub/sdlc.toml`. When enabled its stages are intent, spec, plan, build, test, review, merge, release and maintain, grouped as Plan, Design, Build, Test, Deploy and Maintain. Advise shows blockers; enforce checks implemented head-bound review and approval gates. Stored implement/verify receipts read as build/test; new enabled receipts use canonical ids. See [the SDLC contract](sdlc.md) for gates, required check names, local receipts, console-only readbacks and the S0-S8 delivery table. A person accepts a spec issue with `ahub sdlc accept <task> --issue <n>` (S1). The planner records plan reviews with review and CI scope (`hub_plan_review`, `ahub sdlc plan-review`) and grooms with `ahub backlog groom`; `ahub backlog return <task> <revision> <reason>` returns accepted, untouched work (S9). `ahub sdlc costs [owner/repo]` reports review rounds and CI runs of merged PRs without writing the board (S10). S2-S7, S11 and a full live advise/release cycle remain pending. Owners/reviewers record bounded identities through `hub_sdlc_record`; these grant no additional authority. Off output, receipt and schema shapes stay unchanged.
|
|
3051
3067
|
## Optional Qwen Code peer
|
|
3052
3068
|
|
|
3053
3069
|
Select Qwen per project with `ahub roster add qwen`; it defaults off and is absent
|
|
@@ -3075,7 +3091,7 @@ Qwen controlled recovery and automatic crash resume load the recorded conversati
|
|
|
3075
3091
|
|
|
3076
3092
|
## Optional Jcode peer
|
|
3077
3093
|
|
|
3078
|
-
Use ahub roster add jcode, then ahub jcode --mode headless [--model <alias>] [--provider-profile <name>]. The person launcher configures only agent-hub-jcode in .jcode/mcp.json; run ahub init afterwards to ignore the untracked machine-path file. Conductor/dashboard starts read that entry without editing it. Preview starts nothing, and ahub stop jcode stops only the owned private daemon/ACP groups. jcode_cmd, jcode_home and jcode_provider_profile are machine-local and never editable from settings.
|
|
3094
|
+
Use ahub roster add jcode, then ahub jcode --mode headless [--model <alias>] [--provider-profile <name>]. The launcher reads roster membership from the hub's status reply; a hub older than 0.12.35 does not send it, so the launcher stops with an upgrade-or-restart remedy and starts nothing (#484). The person launcher configures only agent-hub-jcode in .jcode/mcp.json; run ahub init afterwards to ignore the untracked machine-path file. It writes the plugin bundle the running hub reports in `status`, so a CLI from another install no longer leaves a stale entry; `ahub kimi` does the same for Kimi's TUI entry (#502). Conductor/dashboard starts read that entry without editing it. Preview starts nothing, and ahub stop jcode stops only the owned private daemon/ACP groups. jcode_cmd, jcode_home and jcode_provider_profile are machine-local and never editable from settings.
|
|
3079
3095
|
|
|
3080
3096
|
After upgrading to the recipient-retry release, a Jcode project MCP entry written before `AGENTHUB_DELIVERY_ONLY` was added is intentionally stale. Once per project, the person runs `ahub jcode --mode headless` before using conductor/dashboard starts. The launcher rewrites only the owned entry with the delivery-only marker, preserving foreign entries and refusing collisions; recovery relaunches already use this CLI path. Readiness checks never rewrite the file, and an explicit false marker or any other drift remains refused. Until that rewrite, daemon starts keep their actionable stale-entry refusal rather than advertising a retry tool Jcode cannot use.
|
|
3081
3097
|
|
|
@@ -3090,11 +3106,12 @@ Native policy is unmanaged and has NO hub sandbox; no permission_modes.jcode or
|
|
|
3090
3106
|
- Protocol stays 16; a same-protocol older daemon answers the new request as unknown, which the CLI reports. No automatic pane opening is included in this slice.
|
|
3091
3107
|
- Native T0 limits: [ACP watch verification](verification/2026-10-11-acp-watch-t0.md).
|
|
3092
3108
|
|
|
3093
|
-
#
|
|
3109
|
+
# Acceptance-criteria checklist (#481)
|
|
3094
3110
|
|
|
3095
|
-
-
|
|
3096
|
-
-
|
|
3097
|
-
- `
|
|
3111
|
+
- The task reviewer/person records a head-bound `criteria` receipt with criterion ids matching the issue's AC ids, required/result fields and hashed evidence refs. This checklist belongs to the Compliance review pass. Use `ahub sdlc record <id> '<receipt JSON>'`; [schema and example](sdlc.md#acceptance-criteria-checklist).
|
|
3112
|
+
- Advise shows incomplete/stale checklist blockers; enforce checks them at approval. The `criteria` gate does not need a workflow selector. Dependencies stay with `ahub task propose --after`; checklist task import is removed.
|
|
3113
|
+
- `status <id>`, `explain <id>` and `export <id>` use the same current board/config projection. Export keeps sanitized state and source hashes, with no external text, extra authority or verification claim.
|
|
3114
|
+
- Migration from the retired workflow and its compatibility window (until hub 0.13.0) are described in [Retired workflow compatibility](sdlc.md#retired-workflow-compatibility-252-481-s8). Stored checklist task lists are ignored with a visible note; they never change board dependencies.
|
|
3098
3115
|
|
|
3099
3116
|
# Catalog session guidance (#295)
|
|
3100
3117
|
|
|
@@ -3257,10 +3274,12 @@ The person uses `ahub backlog pull-ready <id> <revision> <reason>` or Pull withi
|
|
|
3257
3274
|
WIP on a card. Explicit manual pull/assignment retain their existing authority.
|
|
3258
3275
|
|
|
3259
3276
|
Capacity defaults to one per peer. `ahub settings set tasks.wip_limits.codex 2`
|
|
3260
|
-
uses the existing machine-local registry path; integers 0..32 apply
|
|
3261
|
-
with 0 disabling planner admission for that
|
|
3262
|
-
|
|
3263
|
-
owned unfinished work plus unowned planner-pull reservations.
|
|
3277
|
+
uses the existing machine-local registry path; integers 0..32 apply live (the next
|
|
3278
|
+
admission reads the current value), with 0 disabling planner admission for that
|
|
3279
|
+
peer. Status and the agent legend count
|
|
3280
|
+
owned unfinished work plus unowned planner-pull reservations. The same limit gates
|
|
3281
|
+
acceptance and self-claim in every lifecycle mode, so 0 refuses new acceptances; a
|
|
3282
|
+
current owner's redo of sent-back work keeps its slot (#481 S9).
|
|
3264
3283
|
|
|
3265
3284
|
Pending unowned, unstarted pull can be undone at its latest owned revision via
|
|
3266
3285
|
`hub_backlog_undo` or the existing planning undo control, restoring its earlier
|
|
@@ -3420,7 +3439,7 @@ reference markers remain protected. Split-part plan schemas follow the selected
|
|
|
3420
3439
|
project profile. Terminal tables preserve the visible read for stages and use
|
|
3421
3440
|
a fresh peer status read on the same authenticated connection.
|
|
3422
3441
|
|
|
3423
|
-
Integer WIP editors
|
|
3442
|
+
Integer WIP editors save a value, including zero and inheritance; it applies at the next admission. GitHub intake accepts dot-prefixed repository names within the existing bounded owner/repository identity. Split undo also refuses children referenced by another task's persisted phase checklist.
|
|
3424
3443
|
|
|
3425
3444
|
Declining rework returns changes_requested to To Do before rerouting. When a planner-pulled task has no eligible destination capacity, it remains ownerless in To Do and is retried after capacity clears, preserving the declined-owner exclusion.
|
|
3426
3445
|
|
|
@@ -3491,3 +3510,62 @@ Native transparency/floating and the bridge were verified in the macOS spike.
|
|
|
3491
3510
|
Real keystrokes, dragging and persistence, Spaces, message delivery and body
|
|
3492
3511
|
click need the manual PR checklist before merge; automated fixtures do not
|
|
3493
3512
|
establish those native results.
|
|
3513
|
+
|
|
3514
|
+
## Additional headless peer instances
|
|
3515
|
+
|
|
3516
|
+
Declare extra instances only in an untracked `.agenthub/config.local.json`, then
|
|
3517
|
+
restart the hub. For example, a reviewer can use:
|
|
3518
|
+
|
|
3519
|
+
```json
|
|
3520
|
+
{
|
|
3521
|
+
"instances": {
|
|
3522
|
+
"codex-review": { "kind": "codex", "roles": ["reviewer"] },
|
|
3523
|
+
"kimi-review": { "kind": "kimi", "roles": ["reviewer"] }
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
```
|
|
3527
|
+
|
|
3528
|
+
Start them with `ahub codex --as codex-review` and
|
|
3529
|
+
`ahub kimi --as kimi-review`. Codex keeps its native TUI and its own hub-owned
|
|
3530
|
+
app-server proxy; extra Kimi, Qwen, Pi and local instances use headless starts.
|
|
3531
|
+
Extra Jcode instances are unavailable. An extra Claude instance is a reviewer or
|
|
3532
|
+
planner you start yourself: declare it with `roles` only (for example
|
|
3533
|
+
`"claude-review": { "kind": "claude", "roles": ["reviewer"] }`, no `start_mode` or
|
|
3534
|
+
`worktree`) and run `ahub claude --as claude-review` in a terminal. It keeps its own
|
|
3535
|
+
`claude-*.claude-review.json` state files.
|
|
3536
|
+
|
|
3537
|
+
A headless Claude reviewer is run by the hub instead (#223): declare
|
|
3538
|
+
`"claude-review": { "kind": "claude", "roles": ["reviewer"], "start_mode": "headless" }`
|
|
3539
|
+
and start it with `ahub claude --as claude-review`, which asks the running hub to start it (nothing runs in that terminal); `ahub stop claude-review` stops it. It holds no process while idle; each
|
|
3540
|
+
review request runs one new `claude -p` session (never resumed) that may only read
|
|
3541
|
+
the checkout and call `hub_review` and `hub_task_show`, with no user settings,
|
|
3542
|
+
hooks or plugins. It gets the review facts and a bounded diff of the head, never
|
|
3543
|
+
the builder's summary or agent chat, and the board records its verdicts as
|
|
3544
|
+
`reviewContext: fresh`. Review requests go to it first; while it is not started,
|
|
3545
|
+
the planner reviews and the task's assignment note says `reviewer=planner (fallback)`.
|
|
3546
|
+
A missing
|
|
3547
|
+
`peer_instances` feature on an old daemon or upgrade target requires a supporting
|
|
3548
|
+
version before launching or restoring extras.
|
|
3549
|
+
|
|
3550
|
+
An additional implementer must have an existing registered Git worktree and
|
|
3551
|
+
attached branch at `.worktrees/<instance-id>`, named explicitly by `worktree` in
|
|
3552
|
+
its declaration. The hub validates it and does not create it in this phase.
|
|
3553
|
+
Reviewer instances may share the checkout, or name their own validated worktree.
|
|
3554
|
+
The execution directory is separate from the canonical hub project. An Orca
|
|
3555
|
+
terminal may belong to either that canonical project or the instance's execution
|
|
3556
|
+
worktree; recovery preserves its exact recorded grouping and live launcher.
|
|
3557
|
+
Changing or removing the declaration invalidates its saved extra-instance
|
|
3558
|
+
binding. Do not infer ownership from a native-kind label alone.
|
|
3559
|
+
|
|
3560
|
+
A routing preference for a kind chooses among its instances using current load
|
|
3561
|
+
and WIP. A manual instance id remains exact. Reviewers from the same kind share
|
|
3562
|
+
a family; the board records a same-family fallback when no other eligible family
|
|
3563
|
+
exists. Native context is per conversation, while quota windows and quota pauses
|
|
3564
|
+
are shared by kind/account. A quota reset does not lift a manual pause.
|
|
3565
|
+
|
|
3566
|
+
Facts and turn snapshots follow the instance's execution checkout. Use a CLI
|
|
3567
|
+
that supports instances to undo those turns: older readers see their snapshot
|
|
3568
|
+
fields as unknown and cannot restore them into the main checkout. The supporting
|
|
3569
|
+
CLI checks the saved workspace against the current declaration again before any
|
|
3570
|
+
context change or file restoration. Removing the declaration intentionally
|
|
3571
|
+
blocks that undo until the identity and workspace can be reviewed.
|
package/docs/quickstart.md
CHANGED
|
@@ -17,7 +17,7 @@ ahub setup # installs the Claude Code channel plu
|
|
|
17
17
|
Or use the matching GitHub release:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
bun add -g github:STAIxBWLB/agent-hub#v0.12.
|
|
20
|
+
bun add -g github:STAIxBWLB/agent-hub#v0.12.36
|
|
21
21
|
ahub setup
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -30,11 +30,15 @@ and upgrade or crash recovery, see the [operations guide](operations.md). To
|
|
|
30
30
|
move running projects to a newer release later, run `ahub upgrade` in a
|
|
31
31
|
terminal: it reviews the plan with you, applies it and follows it.
|
|
32
32
|
|
|
33
|
-
## Upgrading to 0.12.
|
|
33
|
+
## Upgrading to 0.12.36
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Restart Claude sessions after upgrading: each keeps the plugin server it started with, and `hub_review` now takes `coverage`. Every review request for a non-private task with a commit carries a review brief the hub builds from that commit: reviewable files, excluded ones (`linguist-generated` in `.gitattributes`, lockfiles, binaries) and rules from `REVIEW.md` or an `ahub-review-rules` attribute, read at the merge base. `ahub review brief <id>` prints it (#520).
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
WIP admission now applies in every lifecycle mode, `off` included: an owner at its WIP limit (default one open task per peer) cannot accept or claim another task, while a redo of its own sent-back work keeps its slot. Raise it with `ahub settings set tasks.wip_limits.<peer> N` (applies at the next admission); a limit of 0 refuses every new acceptance for that peer (#481 S9).
|
|
38
|
+
|
|
39
|
+
Only in `enforce`: build work needs the person's `ahub sdlc accept <task> --issue <n>` and a current plan review (`hub_plan_review`, or `ahub sdlc plan-review`); an approval must account for every reviewable path of the brief; and a review request waits for the PR head, green required checks and answered bot threads. `advise` reports the same gaps; `off` adds none (#481, #520).
|
|
40
|
+
|
|
41
|
+
If the daemon refused a Jcode or Kimi TUI entry as stale because the CLI on PATH and the running hub came from different installs, run `ahub jcode --mode headless` or `ahub kimi` again (#502). For a second Claude session as reviewer or planner, or a headless Claude reviewer, see [instances](operations.md#additional-headless-peer-instances). A Claude session whose transcript passed 32 MiB no longer stays busy after its turns end (#517).
|
|
38
42
|
|
|
39
43
|
From 0.12.30 or earlier, existing Jcode project MCP entries need one refresh before conductor or dashboard starts. Once per project, the person runs:
|
|
40
44
|
|