@staix/agent-hub 0.12.41 → 0.12.43
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 +26 -0
- package/README.md +7 -4
- package/docs/agent-notes/adapters.md +4 -2
- package/docs/agent-notes/bus.md +2 -0
- package/docs/agent-notes/daemon.md +7 -2
- package/docs/agent-notes/tasks.md +1 -0
- package/docs/agent-notes/tests.md +4 -2
- package/docs/operations.md +98 -24
- package/docs/quickstart.md +11 -3
- package/docs/sdlc.md +1 -1
- package/docs/security.md +3 -3
- package/docs/smoke.md +1 -1
- package/docs/specs/2026-09-19-agent-hub-design.md +51 -9
- package/docs/verification/2026-10-20-0.12.42.md +48 -0
- package/docs/verification/2026-10-21-0.12.43.md +50 -0
- package/docs/verification/2026-10-21-agy-1.4.3-t0.md +65 -0
- package/docs/verification/2026-10-21-pii-screen.md +14 -0
- package/docs/verified.json +13 -13
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +79 -29
- package/src/adapters/agy/entry.ts +11 -1
- package/src/adapters/agy/hooks.ts +7 -2
- package/src/adapters/pi.ts +46 -16
- package/src/cli/completion.ts +173 -0
- package/src/cli/console-state.ts +107 -20
- package/src/cli/console.ts +9 -6
- package/src/cli/help.ts +3 -2
- package/src/cli/identity.ts +2 -2
- package/src/cli/main.js +5 -1
- package/src/cli/main.ts +6 -0
- package/src/cli/terminal-recovery.ts +18 -9
- package/src/hub/daemon.ts +138 -33
- package/src/hub/hub-tools.ts +1 -1
- package/src/hub/main-checkout.ts +2 -2
- package/src/hub/manager.ts +10 -2
- package/src/hub/settings.ts +1 -1
- package/src/hub/snapshots.ts +252 -17
- package/src/hub/tasks.ts +16 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
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
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
- Incoming HEAD moves during open turns no longer produce false concurrent-edit warnings or attributed undo paths; bounded per-worktree reflog evidence distinguishes them from peer commits and sequencer replay changes, which stay attributed unless ambiguous. Rebase/pull --rebase start checkout is incoming; uncommitted edits carried through autostash or checkout -m are never excluded. Real concurrent change sets publish at most one notice per affected task; snapshot Git work shares a 250 ms burst budget and records unknown boundaries on exhaustion. Status reuses a checkout-branch probe only within the current synchronous burst. Pi terminal reconciliation uses the bounded existing owner monitor instead of spawning `ps` on every read; effect admission and teardown still verify fresh process identity (#576).
|
|
8
|
+
|
|
9
|
+
## 0.12.43
|
|
10
|
+
|
|
11
|
+
A busy daemon no longer stalls on git HEAD movement under open turns (#576); upgrade restore, task assignment and the agy peer get fixes, `ahub completion` arrives, and the verification gate changes for contributors (#609, #610).
|
|
12
|
+
|
|
13
|
+
- The daemon stays responsive when the checkout's HEAD moves (fast-forward, checkout, worktree merge) while turns are open: snapshot and diff Git calls in one burst share a 250 ms budget and an exhausted budget records unknown evidence, concurrent-edit notices go out once per affected task instead of once per task pair, and HEAD moves are classified from the worktree's HEAD reflog so an incoming checkout, merge or fast-forward is not attributed to a peer while the peer's own commit, amend, rebase replay or cherry-pick still is; ambiguous history stays unknown and paths still dirty at turn end are always kept. On a scratch burst `status` went from 21.3 s to 0.27 s and false conflicts from 144 to 0 (#576).
|
|
14
|
+
- An upgrade or restart no longer blocks on a restored Claude session whose launch record or terminal identity appears a few seconds after its terminal reads idle: the mapping is re-read until the restore deadline, and only a positive contradiction or the deadline blocks (#599).
|
|
15
|
+
- `hub_task_assign` and `ahub task assign` refuse with the routing reason (offline, not attached, excluded, plan review missing ...) instead of returning the unchanged task, and a proposal whose named owner could not take it says why in its result (#601).
|
|
16
|
+
- `ahub completion zsh|bash|fish` prints a completion script; candidates come from the help entries through the hidden `ahub __complete`, so they cannot drift from `ahub help` (#603).
|
|
17
|
+
- agy: native file reads are recorded as peer facts, for agy 1.4.2's `view_file` and 1.4.3's `read_file`, with a line range counted as a partial read (#555). agy 1.4.3 stays unverified (T0 re-run, #267); in its TUI the hub tools appear from the second turn (#607).
|
|
18
|
+
- The console's Peers tab shows each peer's planner WIP against its limit, and `w` edits the limit through the existing settings flow, for declared instances too; the Tasks tab toggles a ranked backlog view (`b`) and adds, pulls, plans, reserves, returns and cancels backlog work from the row, each action bound to the row's id and revision and confirmed with `y` (#532).
|
|
19
|
+
- A manager open that loses the race to another manager stops the process it spawned (#584).
|
|
20
|
+
- Contributors: CI runs per pull request (`check-pr-<number>`, a newer pending run replaces the older) instead of one repository-wide queue; `scripts/check.sh --changed` runs only the tests a change touches, and the gate pins its test environment (`GIT_CONFIG_GLOBAL=/dev/null`, no `NO_COLOR`, `TERM=xterm-256color`, temp root under the OS per-user temp dir); the full gate is CI's (#609, #610). Two timing-dependent tests were fixed (#617, #618). The live PII screen calibration is recorded with the served model id (#198).
|
|
21
|
+
|
|
22
|
+
## 0.12.42
|
|
23
|
+
|
|
24
|
+
`ahub agy` starts again after the Antigravity CLI updated itself (#589); the rest is contributor tooling (#591, #593, #595).
|
|
25
|
+
|
|
26
|
+
- `ahub agy` accepts the Antigravity CLI 1.4.x line instead of exactly 1.4.2: 1.4.2, the T0-verified version, launches as before, another 1.4.x patch launches with one stderr warning naming its version, and any other version is still refused before a hub connection or plugin write. agy updates itself, and 0.12.41 refused 1.4.3 (#589).
|
|
27
|
+
- `scripts/build.mjs` builds the plugin bundle with the Bun named in `.bun-version`: when the running Bun differs it re-runs itself once through `bun x bun@<pinned>`. A self-updated local Bun made the bundle check call a clean `main` stale and its remedy rebuild with the wrong Bun (#591).
|
|
28
|
+
- The test gate's whole-suite watchdog cut off passing runs: hosted CI now gives macOS 1260 s and Linux 1080 s inside a 25-minute job, and the local default is 960 s; the 20 s per-test timeout is unchanged (#593).
|
|
29
|
+
- `test/terminal-recovery.test.ts` no longer records an ambient `CLAUDE_CONFIG_DIR` from the shell running the tests (#595).
|
|
30
|
+
|
|
5
31
|
## 0.12.41
|
|
6
32
|
|
|
7
33
|
A one-fix release for a 0.12.40 regression.
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Codex, Kimi Code, Pi and a hub-owned local worker (Qwen Code, Jcode and Antigrav
|
|
|
5
5
|
optional) share a message bus and a task board per project and one memory on the
|
|
6
6
|
machine, each attached through its own native interface.
|
|
7
7
|
|
|
8
|
-
Status: 0.12.
|
|
8
|
+
Status: 0.12.43, 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
|
|
@@ -42,7 +42,8 @@ project. Site: [agent-hub.staix.net](https://agent-hub.staix.net).
|
|
|
42
42
|
running sessions across versions. Settings reload without a restart where their
|
|
43
43
|
apply class allows; guarded values wait for a person's confirmed
|
|
44
44
|
`ahub settings reload` in a terminal. The console supports revision-checked task
|
|
45
|
-
assignment/unassignment
|
|
45
|
+
assignment/unassignment, delivery-queue resolution, per-peer planner WIP limits
|
|
46
|
+
and backlog management from the Tasks tab. Peers with independent
|
|
46
47
|
tool turns can request one uncertain redelivery; the delivery-only local worker
|
|
47
48
|
and headless ACP peers leave held deliveries for the person to resolve.
|
|
48
49
|
|
|
@@ -85,14 +86,16 @@ Since 0.12.39 `ahub jcode` opens Jcode's native TUI on the hub-owned ACP session
|
|
|
85
86
|
default (#464); `--mode headless` or `ahub settings set peers.jcode.start_mode headless`
|
|
86
87
|
keeps headless startup. On 0.12.39 the TUI launcher stopped after the first hub turn;
|
|
87
88
|
0.12.40 opens it again (#564). On 0.12.40 `ahub codex` in a recorded Orca terminal
|
|
88
|
-
failed with `invalid remote address`; 0.12.41 starts it again (#586).
|
|
89
|
+
failed with `invalid remote address`; 0.12.41 starts it again (#586). Since 0.12.42
|
|
90
|
+
`ahub agy` accepts the Antigravity CLI 1.4.x line (1.4.2 verified; other patches warn),
|
|
91
|
+
because agy updates itself and 0.12.41 refused 1.4.3 (#589). Since 0.12.43 agy's native reads are recorded as peer facts on 1.4.2 and 1.4.3 (#555); 1.4.3 stays unverified, and in its TUI the hub tools appear from the second turn (#267).
|
|
89
92
|
Cancellation needs a daemon advertising `task_cancel`; controlled downgrades
|
|
90
93
|
refuse while cancelled rows exist. Live-test delegated CLI commands need a daemon
|
|
91
94
|
advertising `cli_audit_delegated` and refuse with an upgrade remedy otherwise
|
|
92
95
|
(#410). For local/Pi implementation, opt in to an available
|
|
93
96
|
`checks.runner = "container"`; issue-backed owners also need authenticated
|
|
94
97
|
spec access. PII work and designated reviewers retain their separate exemptions.
|
|
95
|
-
See [release verification](docs/verification/2026-10-
|
|
98
|
+
See [release verification](docs/verification/2026-10-21-0.12.43.md) for the live legs
|
|
96
99
|
still open, including #418 AC8, #438 AC7, the native console settings leg (#439 AC5),
|
|
97
100
|
real upgrades with reattach (#463) and with a managed terminal and cancelled tasks
|
|
98
101
|
(#478), a live headless Claude review (#223), a Claude session over 32 MiB (#517), a
|
|
@@ -70,7 +70,9 @@ Scope: the Codex, ACP and Pi adapters and the Pi extension (turn `generation` an
|
|
|
70
70
|
- Report reviewer failures (`onUnavailable`: `start_failed`, `quota`, `no_verdict`) only after the child's group is confirmed gone and only while its generation is current: a person's stop owns its hold and never reroutes. `quota` comes only from the backend's structured `failure(event)`, never from vendor text. An NDJSON frame over 256 KiB or more than 4 MiB of output aborts the review as `needs_review`.
|
|
71
71
|
- Codex reviewer isolation (`src/adapters/codex-review-isolation.ts`): accept only the pinned `codex-cli` version; prove model-free that Apps, plugins and hooks are disabled (`features list`), ambient MCP servers are replaced by disabled stubs, and the hub server alone is enabled with exactly `hub_review` and `hub_task_show`; run the native sandbox fixture probe before every launch; hash the binary once and fence binary and config files by metadata. Credential denies come only from the bounded `HOST_CREDENTIAL_PATHS` and `HOST_CREDENTIAL_ENV` lists, denied at the lexical and canonical path; refuse glob syntax or a root inside the checkout. A root that is dangling or unreadable refuses too; the reason names only its path class (`~/.docker`, `$DOCKER_CONFIG`), never a path or contents. Never pass the control token in a reviewer child's argv, env or MCP config: keep the hub state dir in its `privatePaths`.
|
|
72
72
|
|
|
73
|
-
- Antigravity P1 (`src/adapters/agy/`): keep it optional, cloud, off roster by default, implementer/verifier only and pull-only. Until per-mode native prompt behavior is verified, reject hub permission/unattended mappings, headless starts and resume selectors; do not infer a quota source. The launcher refuses extra instances, any `agy --version`
|
|
73
|
+
- Antigravity P1 (`src/adapters/agy/`): keep it optional, cloud, off roster by default, implementer/verifier only and pull-only. Until per-mode native prompt behavior is verified, reject hub permission/unattended mappings, headless starts and resume selectors; do not infer a quota source. The launcher refuses extra instances, any `agy --version` outside the 1.4.x line (1.4.2 is T0-verified; other 1.4.x patches launch with a stderr warning, #589), and a hub without the `native_hook_launch` feature.
|
|
74
74
|
- Only the person's `ahub agy` launcher manages `.agents/plugins/agent-hub/{plugin.json,mcp_config.json,hooks.json}`. Refuse linked/foreign entries before any write; cleanup only the matching launch. Never write project-level `.agents/hooks.json` or personal Gemini settings. The plugin MCP server is named `agent-hub_agent-hub` by the pinned native client.
|
|
75
|
-
- Managed native facts use the definition's typed `NativeFactsPort` and the daemon's ephemeral `native_hook_launch` authority. Bind every observation to the daemon, launch, native session, project and current socket generation. Stop requires `fullyIdle`, normal termination and a fresh validated completion row; a missing readback keeps the peer busy. Native fact acknowledgement accepts only SDK ephemeral-message rows in the exact session transcript path.
|
|
75
|
+
- Managed native facts use the definition's typed `NativeFactsPort` and the daemon's ephemeral `native_hook_launch` authority. Bind every observation to the daemon, launch, native session, project and current socket generation. Stop requires `fullyIdle`, normal termination and a fresh validated completion row; a missing readback keeps the peer busy. Native fact acknowledgement accepts only SDK ephemeral-message rows in the exact session transcript path. `decodeAgyHook` classifies as `Read` only the observed native read (`view_file` `AbsolutePath`, or 1.4.3 `read_file` `Path`); a `StartLine`/`EndLine` range becomes `offset`/`limit`, so a partial read never counts as a whole-file view. Unobserved edits get no scoped grant or effect attribution. The daemon records Pre/PostToolUse through `Facts.preTool`/`postTool` and offers nothing on them (#555).
|
|
76
76
|
- `terminalOwner(launchId)` (`src/hub/peers.ts`, #482) answers only for the adapter's current native TUI owner bound to that launch (Codex: the claimed link with that `launchId`, both sockets open; the launcher sends the id as the upgrade's bearer token through `--remote-auth-token-env`, because `codex --remote` refuses any path or query (#586); Pi: a started, verified TUI owner on its requested session); a start acknowledgement is never ownership. A Codex link that is not the claimed one or has a closed socket never adopts a thread.
|
|
77
|
+
|
|
78
|
+
- Pi terminal ownership reads only the existing monitor's current pid/signature/session/file/token observation, expiring after 1 s; unknown verification withdraws proof. Keep fresh shared process-signature checks at tool/effect admission and teardown, and never revive terminal proof across detach, offline, stop or a changed owner/session (#576).
|
package/docs/agent-notes/bus.md
CHANGED
|
@@ -35,3 +35,5 @@ Scope: delivery, digests and condensation, reply addressing, priority and limits
|
|
|
35
35
|
|
|
36
36
|
- `relevant` may return a string: the envelope is dropped with that string as its journal discard reason. Read relevance only through `irrelevance()`.
|
|
37
37
|
- 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).
|
|
38
|
+
|
|
39
|
+
- Concurrent-edit fan-out is linear in affected tasks: retain each notice's own-task stale/owner fence, but never persist the same change-set notice once for every task pair. Preserve per-task-pair research evidence separately (#576).
|
|
@@ -11,7 +11,7 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
11
11
|
- 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).
|
|
12
12
|
- `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.
|
|
13
13
|
- Settings (#269): the dashboard's `setting`, `setting_undo`, `setting_preview` and `setting_reload` actions and the console-role `settings_get|set|undo|preview|reload` requests go through `settingsSet`, `settingsUndo`, `settingsPreview` (`settingsUndoPreview` for `undo: true`) and `reloadConfig` (`src/hub/daemon.ts`) and the registry in `src/hub/settings.ts`. A new editable setting is a registry entry, never a new write path; a key that chooses what the hub runs or where secrets or task text go joins `NEVER_EDITABLE` instead. Writes go only to `.agenthub/config.local.json` and `.agenthub/routing.local.toml` through `store()`: the loader's own validation first, temp file and rename, never a file git tracks. Authority comes from the dashboard session (`DashboardSession`, `src/hub/ui.ts`) or the console role, never from the request body; `ui_action` from the manager is an ordinary session. Never return a setting's value in an event or notice except through `recordSetting`.
|
|
14
|
-
- Live reload (#439): `reloadConfig` is the only publication path. Settings writes and undo, `ahub settings reload`, the dashboard reload and the debounced watcher of the four `CONFIG_SOURCE_FILES` (`src/hub/config-reload.ts`) all reach it; `prepareConfiguration` validates the complete candidate before anything is published, and recovery or shutdown holds it. A write or undo passes its own key as `scope` and publishes only that path, and `acknowledgeConfiguration` records only the accepted paths, so other edits stay pending. Every changed key, inside the registry or not, is decided by `authorizeConfigLeaf` (`src/hub/config-apply.ts`): a refused key keeps its accepted value and is reported by name while the others apply, `roster.*` applies only through its own scoped roster write, and a change of the settled planner or conductor holders (`roleHolders` over `resolveSettledRoles`) is guarded even when a role list shrinks. Outside a named write, only the console's `settings_reload` (authority `terminal`) adopts guarded file edits, by sending back the `confirmation` token bound to the candidate `fingerprint` and `configRevision`; changed bytes or accepted state refuse it, and a watcher, dashboard or settings session never confirms. An undo that names `key` and `undoDigest` writes only while `pendingUndoIdentity` still matches both. A `restart` key (`configApply`) keeps its running value and is listed in `pendingRestart`; reload notices and events carry key names and reasons, never values. The console Settings panel arms a write only from a preview reply that matches its open edit's token, key and value
|
|
14
|
+
- Live reload (#439): `reloadConfig` is the only publication path. Settings writes and undo, `ahub settings reload`, the dashboard reload and the debounced watcher of the four `CONFIG_SOURCE_FILES` (`src/hub/config-reload.ts`) all reach it; `prepareConfiguration` validates the complete candidate before anything is published, and recovery or shutdown holds it. A write or undo passes its own key as `scope` and publishes only that path, and `acknowledgeConfiguration` records only the accepted paths, so other edits stay pending. Every changed key, inside the registry or not, is decided by `authorizeConfigLeaf` (`src/hub/config-apply.ts`): a refused key keeps its accepted value and is reported by name while the others apply, `roster.*` applies only through its own scoped roster write, and a change of the settled planner or conductor holders (`roleHolders` over `resolveSettledRoles`) is guarded even when a role list shrinks. Outside a named write, only the console's `settings_reload` (authority `terminal`) adopts guarded file edits, by sending back the `confirmation` token bound to the candidate `fingerprint` and `configRevision`; changed bytes or accepted state refuse it, and a watcher, dashboard or settings session never confirms. An undo that names `key` and `undoDigest` writes only while `pendingUndoIdentity` still matches both. A `restart` key (`configApply`) keeps its running value and is listed in `pendingRestart`; reload notices and events carry key names and reasons, never values. The console settings editor (the Settings panel, or the Peers panel's `w` WIP shortcut, which opens only an existing `tasks.wip_limits.<peer>` row for a rostered peer listed in status `taskWip`) stays bound to the panel that opened it (`SettingsEdit.panel`) and arms a write only from a preview reply that matches that panel and its open edit's token, key and value; pasted text never confirms. Console Tasks backlog actions (`p`, `a`, `e`, `R`, `c`) only prefill person CLI commands (`backlog pull-ready|plan|return`, `task cancel`) with the row's immutable id and its planning or flow revision; `validateLockedRow` rechecks the row's state and revision at Enter and again at `y`, and no console path writes the board directly (#532).
|
|
15
15
|
- Retained configuration (#544): a key the reload refused, or a file edit outside a scoped write that still differs from the accepted value, is listed in `retainedConfig` (key and sanitized reason only, never a value) in status, `status.json`, the settings view and the console snapshot until a reload accepts or reverts it (`retainedConfigAfterReload`). A config leaf that selects a peer's native launch belongs in that definition's `cli.launchConfigKeys`: the `start` and `peer_start` replies then carry `retainedLaunchConfig` (the running values), the launcher starts with them and prints `retainedLaunchWarning` before its start request.
|
|
16
16
|
- `pet` is console-local presentation (#483): validate it only through `validatePetConfig`, which both `loadConfig` and the reload schema call, and keep it applied live with no authority (`authorizeConfigLeaf`).
|
|
17
17
|
- Start modes (#269): every start the hub makes itself goes through `hubStart` (`src/hub/daemon.ts`): the dashboard's `start_peer`, the console-role `peer_start`, the conductor's `start` hook and `pi.auto_start`. It takes the mode from `startMode(peer)` and nothing else; never add a caller-chosen mode, flag or command to it, and never fall back to headless when a terminal cannot be opened (refuse with the manual command). The words a terminal runs are assembled there from `process.execPath`, the CLI entry, the project root and `startWords(peer)`. The only continuity exception is a validated Pi bookmark on `pi.auto_start`: append its recorded session file (or its session id when no file was recorded), backend and model; never pass both session selectors or accept caller-written replacements. Recovery and `startPeer` callers that pass a recorded mode keep it. A launcher with no `--mode` takes the daemon's accepted start mode from `status.json` `startModes` (`readControl`) before the file's value. A TUI start of an `owned-acp` peer (Jcode) from the console's `peer_start` opens its terminal even while the ACP owner is online: that terminal is a frontend on the owner. The conductor and the dashboard answer `already` for an attached one (#559). The real terminal providers are wired only in `src/hub/lifecycle.ts` (`DaemonOptions.terminal`): a daemon built without them, as in every test, opens nothing; a test injects a recording provider and never the real one.
|
|
@@ -36,7 +36,7 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
36
36
|
- 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.
|
|
37
37
|
- 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".
|
|
38
38
|
- A target that stopped after it started is restarted only through `recordRestart` (`src/cli/upgrade.ts`), recorded before the new one starts and at most once per project per resume: each done or waiting `restored:<peer>` binding becomes `retired:<peer>`, whose terminal is closed (`closedRetired:<peer>`) or found absent before that peer is relaunched, and is never revalidated against the new instance. Keep repaired-session provenance across every target restart, disabling automatic fresh/zero-turn replacement. A person may explicitly accept loss of a repaired Codex/Claude conversation only on typed positive missing transcript/rollout evidence and a disposal-time recheck; refuse live-test repaired overrides after read-only receipt classification and before runner/lock or coordinator mutation, fail closed on unclassifiable scope, and repeat in core before lock and after under-claim read, preserving ordinary #408 delegation; record the one-use grant and freshOverride evidence, and consume the grant on exact attachment. Pi stays excluded: positively missing accepted Pi files get stop-and-archive plus the normal project-scoped ahub pi command; bookmark retirement never falls back fresh in the same start. Clear the repair fence only for a done or waiting binding retired from that target; an uncertain creation without a durable binding keeps its fence. Launcher evidence is read for every instance in `restarts`, and a session attached without an id is unknown, never gone (#225).
|
|
39
|
-
- After a managed terminal is created, persist its binding before waiting up to `RECONNECT_WAIT_MS` for authenticated attachment to the expected target instance, operation and conversation (#414). Resume waits on the saved binding without creating another terminal. Count only attached, non-offline session ids; when the chosen terminal has no current launch record, a confirmed-ended row for another handle or an id-less attachment retains the bounded wait after older-launcher checks. A late current record must match the saved terminal; unknown or live replacement evidence still blocks. Timeout keeps the receipt blocked and records only terminal/hub metadata; a last native connect attempt that was never recorded is unknown, never inferred from terminal readiness or offline state. Final identity and preservation verification stays strict.
|
|
39
|
+
- After a managed terminal is created, persist its binding before waiting up to `RECONNECT_WAIT_MS` for authenticated attachment to the expected target instance, operation and conversation (#414). Resume waits on the saved binding without creating another terminal. Count only attached, non-offline session ids; when the chosen terminal has no current launch record, a confirmed-ended row for another handle or an id-less attachment retains the bounded wait after older-launcher checks. A late current record must match the saved terminal; unknown or live replacement evidence still blocks. Timeout keeps the receipt blocked and records only terminal/hub metadata; a last native connect attempt that was never recorded is unknown, never inferred from terminal readiness or offline state. Final identity and preservation verification stays strict. `createTerminal` re-reads the launch record and Orca binding of an idle replacement every `MAP_POLL_MS` until it maps to the original peer and session, a known identity or session contradicts it, or the deadline passes; only then does it report `ambiguous-create`. Missing identity alone is never a mapping (#599).
|
|
40
40
|
- An operation receipt stays `schema: 1`. Only `abandoned()` writes 2, on an operation with a recorded `disposition` whose coordinator predates #215: in the same write as the disposition, or, for a disposition 0.12.20 recorded at 1, by the next command that holds the runner claim. `validateReceipt` accepts 2 only with a disposition (#227). Never write 2 on an operation that can still be resumed.
|
|
41
41
|
- Four checks read another release's source text for an exact line: `coordinatorCurrent` (`export async function disposeRecovery` in `src/cli/upgrade.ts`), `targetReadsWaivers` (`export function readRecoveryWaivers` in `src/hub/restart.ts`), `coordinatorRestarts` (`export function recordRestart` in `src/cli/upgrade.ts`) and `supportsAction` (`export async function reattachRecovery` in `src/cli/upgrade.ts`). Renaming, moving or un-exporting one makes this release read as an older one: keep those lines until a capability list replaces the checks. The reattach CLI dispatch must use the same `supportsAction` check as its printed command; never redirect a fallback command back to a coordinator without that action. Recovery also reads a target's literal `OPTIONAL_PEERS` (`src/hub/peer-catalog.ts`, through `legacyTargetSupport`) and `START_MODE_PEERS` (`src/hub/start-mode.ts`, through `legacyHeadlessArgv`), declared in `src/adapters/definitions/native-recovery.ts`; keep both literal declarations until a published capability replaces them.
|
|
42
42
|
- Publish terminal ownership only after the current native owner is proven through `terminal_owner` (#482); capture and start acknowledgement are pending evidence only. Preserve unrelated and invalid rows, scope current evidence to project/instance/peer, and recheck the same native generation after asynchronous Orca reads. Keep Claude's hook record pre-spawn. Compatibility and retention ceilings are described in Operations, controlled recovery.
|
|
@@ -53,6 +53,7 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
53
53
|
- 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.
|
|
54
54
|
- Every `new Database(` under `src/` is followed at once by its own `PRAGMA busy_timeout` from a named `*_BUSY_TIMEOUT_MS` constant (`HUB_DB_BUSY_TIMEOUT_MS` in `src/hub/db-timeout.ts` for `hub.db`), and nothing sets `busy_timeout` again later: `test/db-busy-timeout.test.ts` reads the source and fails on any other opening idiom, so a new one extends that guard first (#303).
|
|
55
55
|
- The manager forwards a dashboard `start_peer` with the terminal provider cap (`MAX_COMMAND_MS`) plus 5 s and reports a missed deadline as `unconfirmed`, never as a failure; it recognises the deadline by the exact text `ControlClient.request` resolves with, so change the two together. The hub's terminal reopen guard and the dashboard's retry hold share `PEER_START_RETRY_MS` (`src/hub/start-mode.ts`): never give either its own number (#298).
|
|
56
|
+
- `openManager` keeps only the manager that answered `/open`: when the answering pid is not the process this open spawned, it stops its own spawn with SIGTERM, so a losing concurrent open never leaves an unowned manager (#584).
|
|
56
57
|
|
|
57
58
|
- Use the registry's `KNOWN_PEERS` (`src/adapters/registry.ts`) for the native catalog (the `src/hub/peer-catalog.ts` literal is a cross-release probe only) and `rosterAllows` for participation. Change live membership only at the authorized roster settings write or undo, applying exactly that key. Keep external ids and projects without roster settings compatible with the existing admission and lazy status rules. Fence starts and attachment before detaching or stopping a removed runtime; retain its queue, uncertain deliveries and independent pauses. Refuse removal of the conductor holder and require explicit confirmation and `--now` for an active turn.
|
|
58
59
|
|
|
@@ -76,3 +77,7 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
76
77
|
- 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).
|
|
77
78
|
- 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.
|
|
78
79
|
- Verify a native Claude Stop and its start baseline only through `readClaudeTranscriptCompletion` (4 MiB backwards chunks, at most 64 MiB plus one boundary byte; incomplete or out-of-bound rows are unavailable), never the size-capped `readClaudeTranscriptUsage`; an `unavailable` refusal leaves the peer busy and notifies once per turn start (#517).
|
|
80
|
+
|
|
81
|
+
- Classify HEAD moves with bounded, append-fenced per-worktree reflog evidence. Exclude only incoming checkout/merge/pull/proven-fast-forward reset paths; preserve commit/amend/cherry-pick and sequencer replay changes; classify rebase/pull --rebase start checkout as incoming, with overlapping replay paths unknown. Never exclude paths still dirty against end HEAD (autostash/checkout -m included). Unreadable or ambiguous movement/capture evidence is unknown, never an exclusion. Compute a concurrent change set once and publish no more than one conditional notice per affected task. Keep per-task-pair research events. Cache only raw checkout-branch probes within one synchronous burst, and reapply current privacy screening on every status rendering (#576).
|
|
82
|
+
|
|
83
|
+
- Share one monotonic 250 ms snapshot Git budget until the next event-loop I/O turn. Repository/HEAD probes, capture and end diffs consume the same remaining deadline; exhaustion or unreadable diff evidence records unknown trees and no attribution/undo, with one diagnostic per burst. Never substitute a stale baseline or apply a late result (#576).
|
|
@@ -9,6 +9,7 @@ Scope: the task flow, assignment, the state machine and the hub's MCP tools. Rea
|
|
|
9
9
|
- Role withdrawal matches the task id, role kind and owner-request header. Owner acceptance evidence must be that peer's accepted entry after the latest ownership event, never another owner's state or an earlier assignment span. Withdraw unread requests without inventing delivery evidence. Find them with `bus.pendingEnvelopes(peer)`, which includes recovery-deferred notices, never the snapshot's queues (#478). Preserve the original former-owner stop notice after a superseding escalation, while suppressing stale success/decision tails.
|
|
10
10
|
- Capacity declines (#531): `hub_task_decline` takes an optional `capacity: true`, recorded as `capacity: true` on the `declined` history entry. `excluded()` skips such an entry, and `Tasks.decline` passes the decliner as `exclude` to that move's own reroute only, so a later reroute or planner pull may offer the task to it again from its reservation. Never infer a capacity decline from the note text, and never treat a row without the field as one: older rows are refusals. `plannerRefusal` (peer ids and counts only, never task text) names why `pullPlanned` found no owner, and `planBacklog` refuses a reservation for a peer `excluded()` returns. `assign()` stays pure, so `route explain` reads the same `excluded()` and `plannerFull` inputs as assignment.
|
|
11
11
|
- `assign()` never defaults to the task's current owner, or a decline can only come back to the decliner. A reservation (#207) is the same risk: the reserved owner goes first only through `blocked()`, and a decline or an escalation for reason `rejections` or `manual` records the owner it left in the history entry's `from`, which `excluded()` reads, so no later reroute hands the task back through its reservation.
|
|
12
|
+
- A named owner that `assign()` refuses is never a silent no-op (#601): `assignTo` passes `refuseNamed` so `assignOwner` throws with the routing refusal reason before any write (pre-effect for tool callers, a plain `Error` for the console), and a proposal's unmet named owner is reported in the propose result through `namedOwnerNote`, read from the stall the proposal recorded. The task stays where it was; never deliver to an offline peer to make the name stick.
|
|
12
13
|
- The state machine allows `in_progress -> approved` only for classes without a reviewer; `review()` checks `in_review` itself.
|
|
13
14
|
- Treat `cancelled` as closed through `isClosedTaskState`, but keep dependency release restricted to approval. Cancellation goes through `Tasks.cancel`, preserves the row and roles, clears its reservation/cohort, sends revision-bound stop notices and writes no outcome memory; never map it to approval or cancel a native turn or worktree. Planner cancellation stays limited to its own historically unaccepted proposed/backlog work; accepted work remains person-only.
|
|
14
15
|
- Capture `TaskOffer.pullOnly` and the exact offer envelope id at publication. Keep unread-offer attention independent of attachment and restart until acceptance, decline, supersession or `offerRead` evidence; never replace that evidence with a generic inbox timestamp or completion state.
|
|
@@ -12,17 +12,19 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
|
|
|
12
12
|
- `ahub upgrade` without `--to` asks the registry (`npm view`) and hands a target newer than the CLI to `bun x` (#272): a test that reaches either puts a fake `npm` first on `PATH` and a recording stand-in for `process.execPath`, as `test/upgrade-cli.test.ts` does. The interactive screens are tested through a scripted `ScreenIO`; a CLI test that needs them marks `process.stdin` and `process.stdout` as terminals in a wrapper script.
|
|
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
|
+
- A test of turn or notice behavior that is not about the snapshot budget yields an I/O turn (`await new Promise(r => setImmediate(r))`) between captures: captures in one synchronous burst share the 250 ms budget and may correctly record unknown evidence. A wait on concurrent-edit evidence correlates the expected turn ids and paths (#617).
|
|
15
16
|
- 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
17
|
- 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
18
|
|
|
19
|
+
- `scripts/check.sh` pins the test environment (#610): `GIT_CONFIG_GLOBAL=/dev/null`, `NO_COLOR` unset, `TERM=xterm-256color`, temp root under the OS per-user temp dir, agent markers cleared. A test that needs a person's git config or color settings sets them itself. `--changed` selects tests with `scripts/changed-tests.mjs`: changed tests (nested suites included) plus every test that names a changed file directly; docs need none; any other changed file no test names, and any gate, package or shared-fixture change, runs everything.
|
|
18
20
|
- `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
|
-
- The whole-suite watchdog is `AHUB_CHECK_HANG_S` (default in `scripts/check.sh`, hosted values for both OSes 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. The check job's `timeout-minutes` must leave room above that value for setup: raise them together.
|
|
21
|
+
- The whole-suite watchdog is `AHUB_CHECK_HANG_S` (default in `scripts/check.sh`, hosted values for both OSes in `.github/workflows/check.yml`; #378 and #593, macOS CI hit it while tests still passed; currently 960 s local, 1080 s Linux, 1260 s macOS): 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. The check job's `timeout-minutes` must leave room above that value for setup: raise them together.
|
|
20
22
|
- A seed's named test must run on Linux, where the seeded job runs: a darwin-only test reports no result there and fails the job (#382). Cover a macOS-only protection with its regression test instead.
|
|
21
23
|
|
|
22
24
|
- 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
25
|
- 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
26
|
- `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
27
|
|
|
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.
|
|
28
|
+
- Keep the CI admission lock around the whole controller workflow, not just its decision job, in its per-PR (`check-pr-<number>`, `queue: single`: a newer pending run replaces the older) or main (`check-main`, `queue: max`) group, never with `cancel-in-progress: true` beside `queue: max` (GitHub refuses it) (#609); two groups admitting one tree at once is an accepted duplicate run, never a reason to fail closed on another tree. 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
29
|
|
|
28
30
|
- Headless-reviewer tests run `test/fakes/fake-claude-print.ts` through `command` or a PATH stand-in, and fresh Codex reviewer tests run `test/fakes/fake-codex-reviewer.ts` through `codex_bin`; a test that reaches the daemon's reviewer start must never run the real `claude` or `codex`. The fake's sandbox markers test host admission only, never native isolation. Fresh Kimi reviewer tests set and restore `KIMI_CODE_HOME` to a fixture native home (the backend links that home's `credentials/`, `oauth/` and `device_id`, else the person's `~/.kimi-code`) and run `test/fakes/fake-kimi-reviewer.ts` through `command` or a PATH stand-in, never the real `kimi`. agy tests put a fake `agy` first on PATH and set `HOME` to a temp dir before any transcript readback (`readAgyTranscript` reads `$HOME/.gemini`).
|
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.43 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
|
|
@@ -93,6 +93,27 @@ cyan, arguments and descriptions the terminal's default foreground. It has no
|
|
|
93
93
|
not `dumb` and `NO_COLOR` is empty or absent. Pipes and redirects get plain text
|
|
94
94
|
without escape sequences, laid out for 80 columns.
|
|
95
95
|
|
|
96
|
+
### Shell completion
|
|
97
|
+
|
|
98
|
+
`ahub completion zsh|bash|fish` prints a completion script; it never installs
|
|
99
|
+
files or edits shell configuration. On each Tab the script runs
|
|
100
|
+
`ahub __complete`, which answers from the help entries above (commands,
|
|
101
|
+
subcommands, options, their listed values and file names for path arguments)
|
|
102
|
+
without loading the rest of the CLI or contacting a hub, so completion always
|
|
103
|
+
matches the installed `ahub`. Agent shells may print the script too.
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
# zsh: any directory on fpath works; this one needs no .zshrc change with oh-my-zsh
|
|
107
|
+
ahub completion zsh > ~/.oh-my-zsh/custom/completions/_ahub && rm -f ~/.zcompdump* && exec zsh
|
|
108
|
+
# bash
|
|
109
|
+
ahub completion bash > ~/.local/share/bash-completion/completions/ahub
|
|
110
|
+
# fish
|
|
111
|
+
ahub completion fish > ~/.config/fish/completions/ahub.fish
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Upgrading ahub needs no regeneration. To remove it, delete that file and start
|
|
115
|
+
a new shell.
|
|
116
|
+
|
|
96
117
|
## Operator console and panels
|
|
97
118
|
|
|
98
119
|
`ahub console` combines the existing tail stream with peer, quota, approval-age
|
|
@@ -121,7 +142,7 @@ without color. The Approvals tab counts pending requests and the Queue tab
|
|
|
121
142
|
counts `needs_review` deliveries, in the attention and failure tones.
|
|
122
143
|
|
|
123
144
|
The console attention companion (#280) shows waiting, blocked, review, working,
|
|
124
|
-
idle or asleep with separate action/watch counts. `n` selects the exact approval,
|
|
145
|
+
idle or asleep with separate action/watch counts. Outside the Tasks table, `n` selects the exact approval,
|
|
125
146
|
held queue or review row, or prints applicable guidance; it never answers a
|
|
126
147
|
request or runs a command. Editing, choices and confirmation retain their controls.
|
|
127
148
|
`P` cycles the five built-in characters and off for the current console.
|
|
@@ -145,7 +166,8 @@ chunk can only edit the command line, but a read that holds nothing but arrow or
|
|
|
145
166
|
Home/End sequences is that many key presses, so a held key repeats its move. Home
|
|
146
167
|
or `<` jumps to a panel's first row and End or `>` to its last; the Events tab
|
|
147
168
|
follows new events while the last row is selected and stays on a row you moved to.
|
|
148
|
-
`w` opens the dashboard
|
|
169
|
+
`w` opens the dashboard outside the Peers tab; in Peers it edits the selected
|
|
170
|
+
peer's WIP limit. `o` opens the pet window; `:ui --all` and `:pet --window --close`
|
|
149
171
|
work on the command line too. In the Peers tab the planner's row reads `(planner)`, and
|
|
150
172
|
`l` then `y` makes the selected peer the planner (`ahub settings set planner <peer>`). In the Events
|
|
151
173
|
tab a row's header line is tokenized and coloured exactly as the same event in
|
|
@@ -160,14 +182,54 @@ meter keeps a fixed column at the right edge.
|
|
|
160
182
|
|
|
161
183
|
| Panel | Columns |
|
|
162
184
|
|---|---|
|
|
163
|
-
| Peers | PEER STATE MODE LINK Q ! REVIEW PAUSE QUOTA MODEL |
|
|
185
|
+
| Peers | PEER STATE MODE LINK Q ! WIP REVIEW PAUSE QUOTA MODEL |
|
|
164
186
|
| Approvals | ID PEER LEFT TITLE |
|
|
165
187
|
| Tasks | ID STATE OWNER REVIEWER CLASS AGE TITLE STAGE |
|
|
188
|
+
| Tasks, backlog view (`b`) | ID PRI RESERVED DEPS CLASS AGE TITLE |
|
|
166
189
|
| Queue | ID PEER STATE REV AGE |
|
|
167
190
|
| Settings | GROUP KEY VALUE SOURCE APPLIES |
|
|
168
191
|
|
|
192
|
+
In Tasks, `b` toggles open work and backlog. The backlog heading counts its rows;
|
|
193
|
+
rows sort by rank, then id. PRI shows priority/rank, RESERVED the reserved peer,
|
|
194
|
+
and DEPS either `ready` or the unapproved dependency ids. Titles use the public
|
|
195
|
+
board projection, so PII work remains `[pii]`. Narrow layouts keep ID, RESERVED
|
|
196
|
+
and TITLE before the other columns.
|
|
197
|
+
|
|
198
|
+
On a backlog row, `p` prefills `backlog pull-ready <id> <planningRevision> <reason>`,
|
|
199
|
+
`a` prefills `backlog plan` with a reservation JSON object, and `e` prefills the
|
|
200
|
+
same command with priority, rank and deps. Edit the JSON and supply a reason;
|
|
201
|
+
`c` uses the existing revision-bound `task cancel` command. Once pulled into open
|
|
202
|
+
work, `a` uses the usual task assignment flow. In either Tasks view, `n` prefills
|
|
203
|
+
`backlog add implement `; edit the class and title, or use
|
|
204
|
+
`:task propose --backlog` with paths/deps flags. On proposed or in-progress open
|
|
205
|
+
work, `R` prefills `backlog return <id>` for an ownerless proposal, or the
|
|
206
|
+
planning-revision-and-reason form for accepted, untouched work. The hub refuses
|
|
207
|
+
returns with execution, branch or commit evidence; its refusal appears as a notice.
|
|
208
|
+
|
|
209
|
+
These actions run the existing person CLI commands, after explicit confirmation;
|
|
210
|
+
Esc sends nothing. Row-prefilled ids and revisions cannot be edited, and stale
|
|
211
|
+
row revisions require a reload. `:backlog list` reads without confirmation;
|
|
212
|
+
backlog mutations (including pull, pull-ready, return, plan, split and undo)
|
|
213
|
+
confirm first. The console adds no write path or planner authority.
|
|
214
|
+
|
|
169
215
|
The MODE column appears only when at least one peer has a non-`ask` mode.
|
|
170
|
-
|
|
216
|
+
Peers' WIP column shows planner work in progress as `wip/limit` from `taskWip`,
|
|
217
|
+
including `0/2`; a peer without an entry reads `-`. At or above the limit, the
|
|
218
|
+
cell uses the attention tone. At narrow widths WIP gives way before PEER, STATE
|
|
219
|
+
and QUOTA, whether or not MODE is present.
|
|
220
|
+
|
|
221
|
+
In Peers, select a row and press `w` to edit `tasks.wip_limits.<peer>`, prefilled
|
|
222
|
+
with its current limit. The editor stays on Peers and uses the existing Settings
|
|
223
|
+
value, daemon preview, nonempty reason and `y` confirmation flow; Esc cancels without writing. The
|
|
224
|
+
setting definition supplies the bounds (currently 0..32), risk label (`raises`)
|
|
225
|
+
and `applies: live`; the shortcut adds no configuration write path. The Peers
|
|
226
|
+
hint reads `w WIP limit` and shortens to `w WIP` at narrow widths, alongside
|
|
227
|
+
`m permission mode` shortening to `m mode`. Without a `taskWip` entry, `w` shows
|
|
228
|
+
a notice and opens no edit. Press `6`, then `u` to preview and confirm the usual
|
|
229
|
+
Settings undo. These controls remain person-only, and `ahub settings` retains
|
|
230
|
+
its agent-shell refusal.
|
|
231
|
+
|
|
232
|
+
Other zero counters and unknown values read `-`. Durations read `45s`, `12m`, `3h05m`
|
|
171
233
|
or `2d03h`; quota resets and budget pauses read `in 2h13m`, and a pause by the
|
|
172
234
|
console user reads `user`. When a peer's status carries #205's optional
|
|
173
235
|
`toolsOnly` field (a Claude session attached without channel pushes), LINK reads
|
|
@@ -899,7 +961,12 @@ later. Your own `ahub task assign` is not blocked by those exclusions, and it
|
|
|
899
961
|
drops the agent's reservation. The PII constraint and capability limits
|
|
900
962
|
still apply, so a PII task goes to `local` or nobody whoever was reserved.
|
|
901
963
|
`ahub task assign` on a task that waits changes its reserved owner instead of
|
|
902
|
-
handing it over.
|
|
964
|
+
handing it over. On a task that does not wait, an assignment whose named owner cannot take
|
|
965
|
+
the task now (offline or not attached, excluded, a capability or PII limit, or
|
|
966
|
+
an enforce-mode SDLC gap) is refused with the reason and the task is unchanged;
|
|
967
|
+
assign again once the peer is attached (#601). When a proposal names an owner,
|
|
968
|
+
a self-claim included, and that owner did not get the task, the proposal's
|
|
969
|
+
result says why and names `hub_task_assign`. `ahub route explain <id>` names the reserved owner; once the
|
|
903
970
|
task is ready it also says whether routing would honor the reservation now, and
|
|
904
971
|
why not.
|
|
905
972
|
|
|
@@ -1080,6 +1147,7 @@ ahub undo <turn> --yes --context # Codex's latest turn: also drop it from Codex
|
|
|
1080
1147
|
Nothing is restored then. It plans again right before restoring and stops if
|
|
1081
1148
|
anything moved meanwhile. A turn that is already undone says so.
|
|
1082
1149
|
- A file the turn created is deleted; a file it deleted comes back.
|
|
1150
|
+
- When HEAD moves during a turn, the hub reads the appended HEAD reflog (bounded to 64 moves and 128 KiB). The turn's own commits, amends, cherry-picks and rebase picks still count as its changes. Files brought in by a pull, merge, rebase start, branch checkout or fast-forward reset are left out, unless they are still dirty at the turn's end. An unreadable or ambiguous reflog, a rewinding reset, or a file touched by both kinds of move makes the turn's files unknown (#576).
|
|
1083
1151
|
- `--context` asks Codex (`thread/revert`) to drop the turn, and every later one,
|
|
1084
1152
|
from its thread's saved history before the files are restored; Codex receives
|
|
1085
1153
|
nothing while that runs. It changes no file itself, works only on Codex's
|
|
@@ -1093,7 +1161,11 @@ ahub undo <turn> --yes --context # Codex's latest turn: also drop it from Codex
|
|
|
1093
1161
|
snapshotted by later turns like any other file. Keep PII files in an ignored
|
|
1094
1162
|
directory.
|
|
1095
1163
|
- A turn the hub stopped in the middle of shows the state `no end snapshot` and
|
|
1096
|
-
cannot be undone.
|
|
1164
|
+
cannot be undone. So does a turn whose boundary evidence is unknown: snapshot
|
|
1165
|
+
Git calls made in one callback burst share a 250 ms budget, and a capture that
|
|
1166
|
+
runs past it, fails, or sees HEAD move while it is taken is unknown, never a
|
|
1167
|
+
stale baseline (hub.log says `snapshot unavailable` once per burst). A turn
|
|
1168
|
+
whose diff or HEAD-move evidence cannot be read is unknown as well (#576).
|
|
1097
1169
|
- Claude's turns are not recorded: its channel shows the hub no turn boundary.
|
|
1098
1170
|
Claude Code's own checkpoints cover its edits, though not its shell commands.
|
|
1099
1171
|
- The snapshots are unreferenced objects in the repository's own object store, so
|
|
@@ -2044,21 +2116,21 @@ section is what they run.
|
|
|
2044
2116
|
|
|
2045
2117
|
Upgrade running projects with the target release's own coordinator. It accepts
|
|
2046
2118
|
a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
|
|
2047
|
-
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.
|
|
2119
|
+
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.43), and only
|
|
2048
2120
|
a target on its own protocol, so the target's coordinator fits every supported
|
|
2049
2121
|
source and carries every recovery fix released up to it. Protocol 8 and older
|
|
2050
2122
|
(0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
|
|
2051
2123
|
project directory, without replacing the global CLI first:
|
|
2052
2124
|
|
|
2053
2125
|
```bash
|
|
2054
|
-
bunx --package @staix/agent-hub@0.12.
|
|
2055
|
-
bunx --package @staix/agent-hub@0.12.
|
|
2126
|
+
bunx --package @staix/agent-hub@0.12.43 ahub upgrade --to 0.12.43 --dry-run
|
|
2127
|
+
bunx --package @staix/agent-hub@0.12.43 ahub upgrade --to 0.12.43 --yes
|
|
2056
2128
|
```
|
|
2057
2129
|
|
|
2058
2130
|
| Running now | Coordinator to use |
|
|
2059
2131
|
| --- | --- |
|
|
2060
2132
|
| 0.6.x (protocol 9) | the target's, through `bunx` as above |
|
|
2061
|
-
| 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.
|
|
2133
|
+
| 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.43 (protocol 16) | the target's, through `bunx` as above |
|
|
2062
2134
|
| any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
|
|
2063
2135
|
| 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
|
|
2064
2136
|
|
|
@@ -2090,14 +2162,14 @@ projects first:
|
|
|
2090
2162
|
|
|
2091
2163
|
```bash
|
|
2092
2164
|
ahub restart --dry-run
|
|
2093
|
-
ahub upgrade --to 0.12.
|
|
2165
|
+
ahub upgrade --to 0.12.43 --dry-run
|
|
2094
2166
|
```
|
|
2095
2167
|
|
|
2096
2168
|
Apply only after reviewing the plan:
|
|
2097
2169
|
|
|
2098
2170
|
```bash
|
|
2099
2171
|
ahub restart --yes
|
|
2100
|
-
ahub upgrade --to 0.12.
|
|
2172
|
+
ahub upgrade --to 0.12.43 --yes
|
|
2101
2173
|
ahub recovery status [<operation-id>]
|
|
2102
2174
|
ahub recovery resume [<operation-id>]
|
|
2103
2175
|
ahub recovery abort [<operation-id>]
|
|
@@ -2174,7 +2246,7 @@ A lost commit or start reply is reconciled against the actual daemon identity,
|
|
|
2174
2246
|
package digest, terminal binding, and phase receipt. An uncertain terminal
|
|
2175
2247
|
creation is never repeated blindly. Recovery retains the exact-pinned first-party memory package with the preserved runtime, includes its identity and bytes in the digest, and refuses missing, symlinked or changed retained dependencies instead of resolving a mutable ancestor/global installation. It does not copy the full dependency tree.
|
|
2176
2248
|
|
|
2177
|
-
After creating a managed terminal, the coordinator saves its exact handle, incarnation and worktree before waiting up to 600 seconds (10 minutes) for authenticated attachment to the expected target hub and conversation. A pending or failed creation receipt also waits when the current target has a verified live launcher; its saved binding retains the pending/failed origin across interruption. An idle terminal alone is not attachment proof. Without a current launch record, a confirmed-ended row for another terminal and an attached session still reporting no id keep the chosen terminal waiting within the same bound; a late matching record continues that wait. Live replacement and unreadable records still block. Only non-offline session ids count, and older-instance launchers are checked before declaring a launch gone. Timeout retains the binding and diagnostic receipt; resume waits on that same binding rather than opening a duplicate.
|
|
2249
|
+
After creating a managed terminal, the coordinator saves its exact handle, incarnation and worktree before waiting up to 600 seconds (10 minutes) for authenticated attachment to the expected target hub and conversation. A pending or failed creation receipt also waits when the current target has a verified live launcher; its saved binding retains the pending/failed origin across interruption. An idle terminal alone is not attachment proof: after idle, the coordinator re-reads the launch record and Orca's identity every second within the same bound, until the terminal maps to the expected session or contradicts it (#599). Without a current launch record, a confirmed-ended row for another terminal and an attached session still reporting no id keep the chosen terminal waiting within the same bound; a late matching record continues that wait. Live replacement and unreadable records still block. Only non-offline session ids count, and older-instance launchers are checked before declaring a launch gone. Timeout retains the binding and diagnostic receipt; resume waits on that same binding rather than opening a duplicate.
|
|
2178
2250
|
|
|
2179
2251
|
The wait checks the selected launcher's signed identity on each poll. When that exact launcher exits and the target confirms no session or other live launcher, a pending-origin wait (including a new terminal) records failure and offers the failed-restoration choices, including fresh-session for Codex or Claude. A failed-origin wait returns to its existing retry path. A replacement terminal, missing or unreadable launcher identity, unreadable target or different attached conversation blocks without treating unknown as gone. Success clears the waiting origin and preserves exact terminal/session revalidation. A launcher from an older target instance still blocks without another terminal. The 10-minute limit matches terminal creation readiness; terminal idle can precede native resume and MCP handshake completion. The zero-turn Claude exception still applies only when no original transcript exists. If Claude shows its development-channel confirmation screen, confirm it in
|
|
2180
2252
|
the captured terminal, then run `ahub recovery resume <operation-id>`; resume must not open a duplicate terminal.
|
|
@@ -2484,9 +2556,11 @@ next actions").
|
|
|
2484
2556
|
gone. One that dies before recording itself leaves no record to read, and
|
|
2485
2557
|
what happens next depends on whether Orca reports the bare login shell it
|
|
2486
2558
|
returned to as TUI-idle, which is not verified. If it does, the coordinator
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2559
|
+
re-reads the terminal's mapping every second (#599) and stops at once only when
|
|
2560
|
+
Orca names another peer or session; otherwise it stops with "original session
|
|
2561
|
+
restoration needs manual verification" (the terminal cannot be mapped to the
|
|
2562
|
+
session) when the 10-minute wait ends. If it does not, it stops with the same
|
|
2563
|
+
error after the 10-minute wait. Either way the receipt stays
|
|
2490
2564
|
`pending`; close that terminal in Orca (or wait, if the session may still
|
|
2491
2565
|
attach), then `resume`: with no live launcher and no attached session it
|
|
2492
2566
|
records `restored:<peer>` `failed` and lists the failed-restoration choices.
|
|
@@ -2944,10 +3018,10 @@ PR or push check with the identical Git tree and all three successful jobs. An a
|
|
|
2944
3018
|
unreadable result runs the main gate again and refuses release. A manual
|
|
2945
3019
|
`prepare_bundle` dispatch builds reviewable plugin assets without publishing;
|
|
2946
3020
|
it is never accepted as full-gate evidence. A `timing_runs=20` dispatch runs only the daemon, PII screen and ACP
|
|
2947
|
-
test files twenty times on macOS, in its own concurrency group; it does not replace the full gate.
|
|
3021
|
+
test files twenty times on macOS, in its own concurrency group; it does not replace the full gate. Each PR has its own CI concurrency group, so PRs run side by side; within a PR a newer pending run replaces the older pending one and an admitted run is never cancelled; main pushes and dispatches keep queueing every run. Two groups admitting the same tree at once may run it twice, never a false green (#609). `scripts/check.sh --changed [<base>]` runs every non-test step but only the affected test files, and the full suite when it cannot tell; the full gate stays CI's (#610).
|
|
2948
3022
|
`scripts/check.sh` stops a suite still running after `AHUB_CHECK_HANG_S` seconds
|
|
2949
|
-
(
|
|
2950
|
-
limit (#378).
|
|
3023
|
+
(960 by default); hosted CI sets 1080 on Linux and 1260 on macOS inside a 25-minute
|
|
3024
|
+
job limit (#378, #593).
|
|
2951
3025
|
The gate holds `<git common dir>/ahub-heavy.lock` across every worktree of a
|
|
2952
3026
|
repository. A second gate waits up to `AHUB_CHECK_LOCK_WAIT_S` (1800 seconds by
|
|
2953
3027
|
default; 0 fails immediately) and names the holder. A holder whose PID is gone
|
|
@@ -3235,11 +3309,11 @@ Native policy is unmanaged and has NO hub sandbox; no permission_modes.jcode or
|
|
|
3235
3309
|
|
|
3236
3310
|
## Optional Antigravity (agy) peer
|
|
3237
3311
|
|
|
3238
|
-
Antigravity is optional and off roster by default. Use `ahub roster add agy`, then run `ahub agy` in a terminal: it runs the Antigravity CLI
|
|
3312
|
+
Antigravity is optional and off roster by default. Use `ahub roster add agy`, then run `ahub agy` in a terminal: it runs the Antigravity CLI as a fresh pull-only TUI in that terminal. It accepts the 1.4.x line: 1.4.2 is the verified version, any other 1.4.x launches with a stderr warning (agy updates itself), and other versions are refused (#589). The running hub must advertise `native_hook_launch`; an older hub refuses before any write with an upgrade-or-restart remedy. Only the person's launcher starts it: conductor starts are refused, there is no controlled restore or resume, and extra agy instances are unavailable. Headless/print, resume (`--conversation`, `--continue`, `--new`), `--mode`, `--dangerously-skip-permissions` and `--unattended` are refused until their native mapping is verified; `--print-command` previews without writing.
|
|
3239
3313
|
|
|
3240
3314
|
The launcher writes exactly `plugin.json`, `mcp_config.json` and `hooks.json` in `.agents/plugins/agent-hub/`, refusing linked or foreign entries before any write, and removes only its own matching files when the TUI ends. It never writes project-level `.agents/hooks.json` or the person's `~/.gemini` settings. Run `ahub init` afterwards to ignore the untracked plugin directory; a tracked plugin is written with a warning. The native model sees the hub tools under the server name `agent-hub_agent-hub`.
|
|
3241
3315
|
|
|
3242
|
-
Like Kimi's TUI, agy is pull-only: it reads `hub_inbox` and shares results with `hub_send`, messages do not interrupt it, and automatic routing never picks it. Its roles are capped at implementer and verifier; a plan or review assignment and PII work are refused. Native permissions are unmanaged, with no hub sandbox, hub permission mode, quota source or session resume. Plugin hooks bound to that launch carry the hub's turn facts and report each completed native turn. The live TUI/account leg is unverified ([T0 receipt](verification/2026-10-19-agy-p1-t0.md)).
|
|
3316
|
+
Like Kimi's TUI, agy is pull-only: it reads `hub_inbox` and shares results with `hub_send`, messages do not interrupt it, and automatic routing never picks it. Its roles are capped at implementer and verifier; a plan or review assignment and PII work are refused. Native permissions are unmanaged, with no hub sandbox, hub permission mode, quota source or session resume. Plugin hooks bound to that launch carry the hub's turn facts and report each completed native turn. A native read is recorded as a peer `Read` fact: `view_file` (`AbsolutePath`) in 1.4.2 and `read_file` (`Path`) in 1.4.3; a `StartLine`/`EndLine` range counts as a partial read, never a whole-file view (#555). The live TUI/account leg is unverified ([T0 receipt](verification/2026-10-19-agy-p1-t0.md)). The 1.4.3 T0 re-run keeps 1.4.3 unverified: its `call_mcp_tool` schema and native tool names changed, and the TUI attaches the hub tools only from the second model turn ([1.4.3 receipt](verification/2026-10-21-agy-1.4.3-t0.md), #607).
|
|
3243
3317
|
|
|
3244
3318
|
# Headless ACP watch (#286)
|
|
3245
3319
|
|
|
@@ -3416,7 +3490,7 @@ unapproved dependencies, frozen scope and overriding person P0 order/reservation
|
|
|
3416
3490
|
The person uses `ahub backlog pull-ready <id> <revision> <reason>` or Pull within
|
|
3417
3491
|
WIP on a card. Explicit manual pull/assignment retain their existing authority.
|
|
3418
3492
|
|
|
3419
|
-
Capacity defaults to one per peer. `ahub settings set tasks.wip_limits.codex 2`
|
|
3493
|
+
Capacity defaults to one per peer. Each declared instance has its own `tasks.wip_limits.<instance>` key. `ahub settings set tasks.wip_limits.codex 2`
|
|
3420
3494
|
uses the existing machine-local registry path; integers 0..32 apply live (the next
|
|
3421
3495
|
admission reads the current value), with 0 disabling planner admission for that
|
|
3422
3496
|
peer. Status and the agent legend count
|
|
@@ -3498,7 +3572,7 @@ recovery action can be shown. The output never resumes, aborts or disposes a run
|
|
|
3498
3572
|
Person-reviewed tasks contribute review actions; an offline peer holding
|
|
3499
3573
|
unfinished work contributes one watch item with its lowest task id. The console
|
|
3500
3574
|
receives those structural facts through its existing authenticated status reply.
|
|
3501
|
-
`n` selects an exact visible review task, or prints the task/review guidance if
|
|
3575
|
+
Outside the Tasks table, `n` selects an exact visible review task, or prints the task/review guidance if
|
|
3502
3576
|
that row is unavailable. Offline guidance names status/task reads and an explicit
|
|
3503
3577
|
assignment command. No command is executed by navigation. There is no extra
|
|
3504
3578
|
console poll, timer or task-list request for stream mode.
|
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.43
|
|
21
21
|
ahub setup
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -30,13 +30,21 @@ 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.43
|
|
34
|
+
|
|
35
|
+
A busy hub no longer stalls when the checkout's HEAD moves under open turns: snapshot Git work in one burst shares a 250 ms budget, and incoming checkouts, merges and fast-forwards are told apart from a peer's own commits through the HEAD reflog, so they no longer raise false concurrent-edit warnings (#576). `ahub task assign` and `hub_task_assign` now refuse with the reason when the named peer cannot take the task (#601). `ahub completion zsh|bash|fish` prints a shell completion script (#603). The console's Peers tab shows each peer's planner WIP, and `w` edits its limit (#532). agy native file reads are recorded as peer facts on 1.4.2 and 1.4.3 (#555); 1.4.3 stays unverified, and in its TUI the hub tools appear from the second turn (#267, #607). Coming from 0.12.41 or older, the notes below apply too.
|
|
36
|
+
|
|
37
|
+
## Upgrading to 0.12.42
|
|
38
|
+
|
|
39
|
+
0.12.42 lets `ahub agy` start again after the Antigravity CLI updated itself to 1.4.3: the launcher accepts the 1.4.x line, launching 1.4.2 (the verified version) silently and another 1.4.x patch with a warning (#589). The rest of the release is contributor tooling (#591, #593, #595). Coming from 0.12.40 or older, the notes below apply too.
|
|
40
|
+
|
|
33
41
|
## Upgrading to 0.12.41
|
|
34
42
|
|
|
35
43
|
0.12.41 fixes one 0.12.40 regression: `ahub codex` in a recorded Orca terminal stopped at `invalid remote address`, because the launcher put the terminal launch id into the `--remote` URL, which Codex accepts only as `ws://host:port`. The id now travels as the upgrade's bearer token (#586). Coming from 0.12.39 or older, the 0.12.40 notes below apply too.
|
|
36
44
|
|
|
37
45
|
## Upgrading to 0.12.40
|
|
38
46
|
|
|
39
|
-
Restart Claude sessions after upgrading: each keeps the plugin server it started with until restarted, so a restart loads the 0.12.
|
|
47
|
+
Restart Claude sessions after upgrading: each keeps the plugin server it started with until restarted, so a restart loads the 0.12.43 plugin. That plugin asks Claude Code to list the hub tools again when a hub reconnect changes them (#490), and one from an older `ahub claude` launch is refused and stops reconnecting instead of reclaiming the peer (#551).
|
|
40
48
|
|
|
41
49
|
`ahub jcode` opens its TUI again; on 0.12.39 it stopped after the first hub turn (#564). A busy Jcode now takes an `important` message into its running turn (#572), and `ahub doctor` lists the extra MCP servers the hub-owned Jcode loads from its config files. See [Jcode operations](operations.md#optional-jcode-peer).
|
|
42
50
|
|
|
@@ -58,7 +66,7 @@ Upgrading from 0.12.37 or earlier, the 0.12.38 notes below also apply.
|
|
|
58
66
|
|
|
59
67
|
The 0.12.38 plugin reports a reply stopped by the hop cap as not delivered instead of as sent (#546); the restart above loads it.
|
|
60
68
|
|
|
61
|
-
Antigravity (`agy`) can join as an optional pull-only implementer (#485). It is off roster by default: install the Antigravity CLI 1.4.2, run `ahub roster add agy`, then run `ahub agy` in a terminal. Its native permissions are unmanaged and it has no hub sandbox. See [Antigravity operations](operations.md#optional-antigravity-agy-peer).
|
|
69
|
+
Antigravity (`agy`) can join as an optional pull-only implementer (#485). It is off roster by default: install the Antigravity CLI 1.4.x (1.4.2 verified; other 1.4.x patches launch with a warning; on 1.4.3 the hub tools appear from the second TUI turn), run `ahub roster add agy`, then run `ahub agy` in a terminal. Its native permissions are unmanaged and it has no hub sandbox. See [Antigravity operations](operations.md#optional-antigravity-agy-peer).
|
|
62
70
|
|
|
63
71
|
Reviews can rotate across fresh Claude, Codex and Kimi reviewer sessions (#519, #533). Declare headless reviewer-only instances in `.agenthub/config.local.json`; Codex and Kimi join only with `review_mode: "fresh"`. Codex also needs an installed Codex 0.146.0 (select it with `codex_bin` when PATH resolves another version), and Kimi needs Kimi Code 2.2.0 on PATH, signed in with its own OAuth login. A headless reviewer instance without `review_mode` keeps its native behavior and stays out of the pool. agy is not a reviewer: naming it in `review.pool` shows an unavailable skip in `ahub route explain`, never a review. Once a train is active or frozen, or `review.pool` is set or fresh reviewer instances are declared, `ahub upgrade` refuses a target release without that support, so an older release cannot take the project over. See [fresh reviewer pool](operations.md#fresh-reviewer-pool-519).
|
|
64
72
|
|
package/docs/sdlc.md
CHANGED
|
@@ -229,7 +229,7 @@ The planner can provide scope with `hub_plan_review`; the person can run `ahub s
|
|
|
229
229
|
|
|
230
230
|
A review request is premature if its task head does not match the PR head, configured required checks are not green, or a pending bot thread is unanswered. A resolved thread is settled; an unresolved one needs a user reply after its last bot comment. The hub reads identity, timestamps, authorship type and resolution only, never comment bodies. Without explicit required checks the native floor is both OS checks plus `seeded guards`. Advise reports the gap; enforce refuses before the requesting done/cohort writes. A private turn may finish its own PII task in advise with a generic unknown-readiness notice and no remote metadata read; the private-turn refusal for ordinary work remains. Delayed checks revalidate before completing. Background roster/quota role changes remain fact, but enforce holds a new review envelope without an admission readback; refresh it through a manual reviewer assignment after CI and replies are ready. The brief and verdict coverage belong to #520, separate from this admission.
|
|
231
231
|
|
|
232
|
-
CI controllers are serialized
|
|
232
|
+
CI controllers are serialized per pull request (`check-pr-<number>`) and for main pushes and dispatches (`check-main`), for the entire workflow and without canceling an admitted controller (#609). Within a PR `queue: single` lets a newer pending run replace the older pending one; main keeps `queue: max`, which preserves up to 100 waiting controllers ([GitHub concurrency documentation](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency)). Different PRs run side by side: a repository-wide lock serialized every PR (17-18 min alone, 40-54 min with 4-5 PRs in flight on 2026-10-20). Two groups admitting the same tree at the same instant can run it twice; that duplicate costs one run and never a false green. Required job names and read-only token permissions are unchanged. Before PR or push gates, `scripts/ci-reuse.mjs` reuses successful full proof for the identical Git tree, including its workflow. On reuse the two OS matrix jobs still expand and report their exact required names, while the seeded aggregate reports its exact name. They run only a `Reuse verified identical-tree full gate` marker step naming the original proof; full setup and gates are skipped. Skipped jobs and successful reuse-reporting jobs never count as fresh full proof. A running identical-tree gate refuses duplicate admission; unknown active coverage refuses safely. Metadata reads are bounded to 100 recent successes/active runs and 240 calls within 60 seconds. Pending serialized controllers are not admitted gates. Run focused tests locally and one full gate at the final head; a known flake warrants only one rerun of its failed job with recorded evidence.
|
|
233
233
|
|
|
234
234
|
`hub_sdlc_costs` and the person's `ahub sdlc costs [owner/repo]` report linked merged PRs without changing the board. A review round is a board done-to-verdict handoff, not each reviewer in a multi-reviewer round. An observed handoff still counts when its declared scope was none. The report counts distinct check-workflow run ids, extra attempts (`run_attempt - 1`), full re-reviews, delta rounds and summed review intervals, with GitHub review counts alongside them. Unspecified scope and unavailable evidence stay unknown/incomplete. Only current public links are projected; a private counterpart withholds the whole PR. Up to 16 linked PR reads share 20 seconds; each PR covers at most 100 commits, reviews and recent check-workflow runs, and the pure aggregator bounds 500 tasks, 200 PRs and 10,000 history entries. Truncation is explicit. S10 exposes pure band-breach proposal data; S7 owns rolling baselines, band configuration, automatic scheduling and board-card creation.
|
|
235
235
|
|