@staix/agent-hub 0.26.0 → 0.28.0
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 +30 -0
- package/README.md +13 -4
- package/docs/agent-notes/adapters.md +4 -2
- package/docs/agent-notes/bus.md +4 -4
- package/docs/agent-notes/daemon.md +8 -4
- package/docs/agent-notes/tasks.md +7 -2
- package/docs/agent-notes/tests.md +6 -5
- package/docs/design/adapters.md +76 -0
- package/docs/design/agent-hub-architecture.md +67 -0
- package/docs/design/agent-hub.md +52 -0
- package/docs/design/bus.md +48 -0
- package/docs/design/task-board.md +86 -0
- package/docs/dogfood.md +19 -2
- package/docs/operations.md +337 -15
- package/docs/profiles.md +2 -0
- package/docs/quickstart.md +15 -3
- package/docs/sdlc.md +4 -4
- package/docs/security.md +9 -4
- package/docs/smoke.md +2 -0
- package/docs/specs/2026-09-19-agent-hub-design.md +3 -1
- package/docs/specs/2026-11-01-research-campaigns-design.md +12 -1
- package/docs/verification/2026-10-31-codex-0166-reviewer-isolation.md +2 -0
- package/docs/verification/2026-11-01-0.27.0.md +49 -0
- package/docs/verification/2026-11-02-0.28.0.md +54 -0
- package/docs/verification/2026-11-02-autonomy-t4.md +39 -0
- package/docs/verification/2026-11-02-codex-0166-reviewer-tool-call.md +53 -0
- package/docs/verification/2026-11-02-control-write-after.json +139 -0
- package/docs/verification/2026-11-02-control-write-baseline.json +127 -0
- package/docs/verification/2026-11-02-control-write-guarded.json +127 -0
- package/docs/verification/2026-11-02-control-write-outcomes.md +65 -0
- package/docs/verification/2026-11-02-orca-1.4.245-cli-contract.md +51 -0
- package/docs/verified.json +13 -13
- package/package.json +2 -2
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +344 -116
- package/src/adapters/claude-channel.ts +12 -2
- package/src/adapters/compat.ts +1 -1
- package/src/adapters/definitions/native-cli-claude-setup.ts +31 -9
- package/src/adapters/definitions/native-cli-entry-jcode.ts +33 -0
- package/src/adapters/definitions/native-cli-entry-qwen.ts +2 -2
- package/src/adapters/jcode.ts +37 -4
- package/src/adapters/qwen-dual.ts +3 -2
- package/src/cli/agents.ts +4 -2
- package/src/cli/bench.ts +4 -2
- package/src/cli/board-read.ts +25 -0
- package/src/cli/claude-homes.ts +2 -2
- package/src/cli/console-state.ts +8 -3
- package/src/cli/help.ts +8 -6
- package/src/cli/identity.ts +14 -6
- package/src/cli/init-prompt.ts +179 -0
- package/src/cli/init-settings.ts +229 -0
- package/src/cli/init.ts +102 -9
- package/src/cli/launch.ts +3 -1
- package/src/cli/main.ts +112 -36
- package/src/cli/output.ts +14 -0
- package/src/cli/setup-homes.ts +18 -3
- package/src/cli/specs.ts +150 -0
- package/src/cli/study-output.ts +56 -0
- package/src/cli/study.ts +26 -3
- package/src/cli/terminal-recovery.ts +35 -11
- package/src/hub/action-policy.ts +5 -3
- package/src/hub/board.ts +56 -3
- package/src/hub/bus.ts +54 -7
- package/src/hub/child-process.ts +6 -4
- package/src/hub/config-apply.ts +4 -1
- package/src/hub/config-edit.ts +1 -1
- package/src/hub/config-tier.ts +1 -0
- package/src/hub/control-client.ts +28 -4
- package/src/hub/cost-governance.ts +22 -6
- package/src/hub/crash.ts +20 -0
- package/src/hub/daemon.ts +324 -64
- package/src/hub/delivery-hints.ts +6 -3
- package/src/hub/delivery-journal.ts +14 -3
- package/src/hub/events.ts +2 -1
- package/src/hub/hub-tools.ts +15 -9
- package/src/hub/no-writes.ts +1 -1
- package/src/hub/peers.ts +1 -1
- package/src/hub/project-runtime-state.ts +38 -13
- package/src/hub/review-brief.ts +18 -0
- package/src/hub/routing.ts +7 -3
- package/src/hub/sdlc-release-authorization.ts +11 -5
- package/src/hub/session-identity.ts +1 -1
- package/src/hub/settings.ts +2 -0
- package/src/hub/specs-config.ts +43 -0
- package/src/hub/specs-task.ts +108 -0
- package/src/hub/specs.ts +1008 -0
- package/src/hub/task-list-page.ts +75 -0
- package/src/hub/task-sweep.ts +10 -1
- package/src/hub/tasks.ts +448 -40
- package/src/hub/terminal-open.ts +10 -5
- package/src/hub/tool-request.ts +131 -0
- package/src/ui/office-model.ts +17 -1
- package/src/ui/office-space.ts +1 -1
- package/templates/config.json +1 -0
- package/templates/presets/confirmation-matrix.json +5 -5
- package/templates/profiles/dev.json +1 -0
- package/templates/profiles/general.json +1 -0
- package/templates/profiles/research.json +1 -0
- package/templates/profiles/writing.json +1 -0
- package/templates/release-guard.block.md +2 -1
- package/templates/specs.block.md +5 -0
package/docs/operations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Operations guide
|
|
2
2
|
|
|
3
|
-
This guide describes ahub 0.
|
|
3
|
+
This guide describes ahub 0.28.0 and control protocols 16 through 17. 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
|
|
@@ -355,6 +355,24 @@ lineages require a person; unrelated new messages retain the one-retry option.
|
|
|
355
355
|
|
|
356
356
|
The local worker and headless ACP peers, including Jcode, receive tools only inside a delivered turn. A hold prevents that turn, so these delivery-only transports do not offer recipient retry; their held hints ask the person to resolve the row. Ordinary messages stay queued. This restriction follows the current transport, not the vendor name: Kimi TUI remains pull-only and can request its one retry.
|
|
357
357
|
|
|
358
|
+
For an active session, `hub_delivery_resolve { delivery_id, revision, action, reason }`
|
|
359
|
+
settles only its own `needs_review` row, including while busy (#1079). Get the
|
|
360
|
+
observed revision from the bounded held-row metadata returned with `hub_inbox`.
|
|
361
|
+
Use `completed` after handling the delivery, or `discard` when it should not be
|
|
362
|
+
acted on, with a nonempty reason. The journal records the recipient actor and
|
|
363
|
+
reason. Another peer's row, a stale revision, remote-room disposition, active
|
|
364
|
+
`dispatching`/`accepted` rows, a paused or held peer, recovery, shutdown or storage
|
|
365
|
+
holds, and a reason that is private or sensitive all refuse. A row that carries an
|
|
366
|
+
invocation stays person-only (`ahub queue show <id>`, then `ahub queue resolve
|
|
367
|
+
<id>`), because the invocation may still be running. This never retries a message, changes a task
|
|
368
|
+
role or cancels the native turn; recipient retry keeps its existing one-use rules.
|
|
369
|
+
|
|
370
|
+
An explicit `hub_inbox` read can return newly queued messages behind a held row
|
|
371
|
+
and name the retained hold. It does not return the held originals, settle them
|
|
372
|
+
or release automatic delivery. Recovery, pause, lifecycle and storage fences
|
|
373
|
+
still apply. A delivery-only peer with no active turn still needs the person to
|
|
374
|
+
resolve its hold.
|
|
375
|
+
|
|
358
376
|
Every console resolution needs a reason. Queue `discard` removes queued originals or
|
|
359
377
|
settles a needs_review receipt; it never cancels a task or native turn.
|
|
360
378
|
|
|
@@ -384,11 +402,18 @@ behavior is unchanged. `ahub queue resolve ... [--revision N]` uses the supplied
|
|
|
384
402
|
revision instead of a fresh show. A `queued` delivery was never handed to its peer, so it can be discarded while the peer is busy (a pull-only TUI is busy most of
|
|
385
403
|
the time); `dispatching` and `accepted` deliveries stay refused, and `retry` keeps its rules. A refused resolution names its cause (`active delivery`, `peer busy`,
|
|
386
404
|
`stale revision`, `unknown delivery`, `already resolved`, `queued delivery is already scheduled`, `recipient queue is full`, `delivery journal unavailable`), never one
|
|
387
|
-
generic sentence (#713).
|
|
388
|
-
|
|
389
|
-
`
|
|
390
|
-
|
|
391
|
-
|
|
405
|
+
generic sentence (#713). A failed row that a resolution already settled (for
|
|
406
|
+
example the parent of a retry, whose redelivery is a separate row) is refused as
|
|
407
|
+
`already resolved`, never `stale revision`. `ahub queue show` on a failed row says
|
|
408
|
+
that nothing is left to do, or, if the row is unsettled, prints the `ahub queue
|
|
409
|
+
resolve <id> --action discard|completed` command (#1098).
|
|
410
|
+
|
|
411
|
+
`ahub queue discard --peer <id> --reason <text> [--state queued|needs_review|failed] [--yes] [--json]` clears one peer's backlog and is for the person or the configured conductor (any other agent identity is
|
|
412
|
+
refused, and a remote `peer@label` queue is the person's only). Without `--yes` it only says how many deliveries it would discard; with `--yes` it discards each delivery of that peer through the
|
|
413
|
+
same resolution as `queue resolve --action discard`, each recorded with the reason, and prints `discarded N of M` with the causes of any it could not discard. With no `--state` it takes the peer's queued rows and its
|
|
414
|
+
failed rows that no resolution has settled yet (#1096); `needs_review` rows need an explicit `--state needs_review`, and `--state` names exactly one kind. A failed row ran nothing, so it can be discarded while its peer is busy.
|
|
415
|
+
The new request form needs the `queue_discard_states` hub feature: against an older hub the CLI sends nothing for `failed` or for the default and says to upgrade, because that hub would discard queued rows instead.
|
|
416
|
+
`ahub queue list` hides rows a resolution already settled (for example the parent of a retry), prints how many on stderr, and `--all` shows them. Only the
|
|
392
417
|
named peer's queue is read, so other peers are untouched; it is refused while recovery or shutdown holds queue mutations. In the console Queue panel, `D` on a row opens
|
|
393
418
|
the same command for that row's peer, asks for a reason, then a `y` that names the count. No task is cancelled and no native turn is stopped.
|
|
394
419
|
|
|
@@ -973,7 +998,48 @@ ahub up
|
|
|
973
998
|
```
|
|
974
999
|
|
|
975
1000
|
`ahub init` writes the project configuration and managed instruction blocks.
|
|
976
|
-
Run it after an upgrade when those blocks need refreshing.
|
|
1001
|
+
Run it after an upgrade when those blocks need refreshing.
|
|
1002
|
+
|
|
1003
|
+
Settings flags (#1100) set the main project settings without a file edit.
|
|
1004
|
+
`--agents <a,b,...|none>` (`start.agents`) and `--autonomy inherit|off` (whether a
|
|
1005
|
+
new project inherits the machine autonomy preset) go to the untracked
|
|
1006
|
+
`config.local.json`. `--sdlc off|advise|enforce` sets `mode` in `sdlc.toml` (`off`
|
|
1007
|
+
writes no file on a new project). `--coordination advisory|turn-free`,
|
|
1008
|
+
`--memory`/`--no-memory`, `--snapshots`/`--no-snapshots` and `--pi`/`--no-pi` set
|
|
1009
|
+
their keys in `config.json`. On an existing project only a flag you give changes
|
|
1010
|
+
anything: `--dry-run` shows each change as `old -> new` (`--dry-run --json` adds a
|
|
1011
|
+
`settings` array), and a value equal to the current one is a no-op. An invalid
|
|
1012
|
+
value, or a flag given twice with different values, is refused with the allowed
|
|
1013
|
+
values, and nothing is written. Executables, secrets, models, providers, instances
|
|
1014
|
+
and permissions have no flags; they stay file edits.
|
|
1015
|
+
|
|
1016
|
+
A person at a terminal who runs `ahub init` on a new project with no flag that
|
|
1017
|
+
sets anything and no `--yes` is asked each setting in turn (#1065 T2): profile,
|
|
1018
|
+
the agents `ahub up` starts, design specs and their review mode, SDLC mode,
|
|
1019
|
+
coordination, shared memory, snapshots, the Pi peer, the machine autonomy
|
|
1020
|
+
preset, the release guard, and shadow history (asked in a folder with no Git
|
|
1021
|
+
work tree, and kept for an existing shadow repository, never in a Git
|
|
1022
|
+
repository). Each question is one line, the label, the choices and the default in
|
|
1023
|
+
brackets. Enter keeps the default and sets nothing; an answer is an explicit
|
|
1024
|
+
choice, exactly as the equivalent flag is, so the files written are the files
|
|
1025
|
+
the same flags write. A wrong answer asks again and is never guessed, and three
|
|
1026
|
+
wrong answers refuse the prompt. The plan follows, in the words `--dry-run`
|
|
1027
|
+
prints (including the machine autonomy preset a new project inherits, unless
|
|
1028
|
+
the answer was `off`), and `Write this? [y/N]` decides: N, an empty answer, Ctrl-C and Ctrl-D
|
|
1029
|
+
write nothing. Only the console role at a terminal (stdin and stdout) is asked:
|
|
1030
|
+
an agent identity is refused before `init` runs, a `--live-test` delegation, a
|
|
1031
|
+
pipe and `--dry-run` are never asked, and `--yes` takes the defaults. A flag of
|
|
1032
|
+
any kind (`--agents`, `--coordination`, `--profile`, `--shadow` and the rest)
|
|
1033
|
+
means the person has chosen, so nothing is asked and the flags apply alone. An
|
|
1034
|
+
existing project is never asked. The questions are built from the init settings
|
|
1035
|
+
table (`INIT_SETTINGS`), so a setting added there is asked without another
|
|
1036
|
+
change, and `test/init-prompt.test.ts` fails when the two disagree. The default
|
|
1037
|
+
in each bracket is read from where the writer gets it (`templates/config.json`,
|
|
1038
|
+
the loader's own defaults), and that test reads every one back through the
|
|
1039
|
+
loaders after a flagless `ahub init`, so a changed default cannot leave the
|
|
1040
|
+
prompt showing one value while Enter writes another. `--dry-run` and the
|
|
1041
|
+
prompt's plan take the machine-autonomy row from the same helper
|
|
1042
|
+
(`autonomyInheritanceChange`). `ahub setup`
|
|
977
1043
|
installs or updates the Claude plugin and a project-neutral PreToolUse hook in each
|
|
978
1044
|
Claude configuration home in use (see "Machine autonomy and Claude homes"), and
|
|
979
1045
|
registers the acon console plugin (see "acon console plugin"). Keep `ahub console` open when a local worker
|
|
@@ -1021,6 +1087,26 @@ the sandbox either. `git add`, `commit`, `stash` and `checkout` work, and
|
|
|
1021
1087
|
signs with a key under `~/.ssh` or `~/.gnupg` fails, because the sandbox cannot
|
|
1022
1088
|
read those directories. Run a refused command yourself, in a terminal.
|
|
1023
1089
|
|
|
1090
|
+
A task can declare what it needs (#1081): `hub_task_propose {needs_network: true}` or `{needs_worktree: true}`, and
|
|
1091
|
+
`ahub task propose --needs-network` or `--needs-worktree`. Only an explicit `true` sets either, and the hub never
|
|
1092
|
+
infers a need from the title. A declared need keeps the task away from a peer that cannot meet it: automatic
|
|
1093
|
+
routing, a reservation, `ahub task assign` and `hub_task_accept` all refuse it before any write, and
|
|
1094
|
+
`ahub route explain <id>` prints the cause for that peer. It is offered to a peer that can meet the need.
|
|
1095
|
+
|
|
1096
|
+
- `needs_network` is for work that fetches from a package registry, runs `git fetch` or `git push`, or calls an API.
|
|
1097
|
+
A hub-sandboxed peer (Pi, the local worker) has none while `local.bash_network` is off: `no network: local.bash_network
|
|
1098
|
+
is off ...`.
|
|
1099
|
+
- `needs_worktree` is for work that must run in its own git worktree on a task branch (the repository rule). A
|
|
1100
|
+
hub-sandboxed peer cannot create one, because `git worktree add` writes under the git common directory and runs
|
|
1101
|
+
outside the sandbox by design (#270): `no worktree: git worktree add runs outside the sandbox; ...`. A refused
|
|
1102
|
+
accept creates nothing, so no empty branch ref is left behind (the Pi accepts of #621 and #565 left two). Having
|
|
1103
|
+
the hub create the worktree and add it to a sandboxed peer's writable roots would move the sandbox write
|
|
1104
|
+
boundary (a commit writes under `.git/worktrees` and `.git/objects`), so it is the separate spec issue #1115.
|
|
1105
|
+
|
|
1106
|
+
A peer whose capability the hub cannot tell is never refused on this ground, and work that declares no need is
|
|
1107
|
+
routed as before. The flags are a person's or a planner's statement about the work, so an unflagged task can still
|
|
1108
|
+
reach a peer that cannot do it.
|
|
1109
|
+
|
|
1024
1110
|
Network is off unless `local.bash_network` says otherwise. With `true` it goes
|
|
1025
1111
|
only through the hub's egress proxy on a loopback port (0.11): commands get
|
|
1026
1112
|
`HTTPS_PROXY` and the other proxy variables, the proxy opens HTTPS (`CONNECT`,
|
|
@@ -1098,7 +1184,7 @@ assignment skips it until a delivery completes; inspect `ahub route explain` for
|
|
|
1098
1184
|
reason. A task owned by a peer whose task delivery exhausts retries is escalated with
|
|
1099
1185
|
that delivery's error, and the console is notified.
|
|
1100
1186
|
|
|
1101
|
-
A delivery in `needs_review` holds later deliveries to that peer. The console announces
|
|
1187
|
+
A delivery in `needs_review` holds automatic later deliveries to that peer; an explicit `hub_inbox` read may read new queued work behind it without releasing or replaying the hold (#1079). The console announces
|
|
1102
1188
|
the hold once, and status, task assignment and route explanations name its delivery id.
|
|
1103
1189
|
Inspect it with `ahub queue show <id>` and explicitly choose `completed`, `retry` or
|
|
1104
1190
|
`discard` through `ahub queue resolve`. Reassignment or approval of its task never
|
|
@@ -1124,6 +1210,41 @@ Pi 0.86 assistant usage is forwarded at `message_end`, including tool-loop messa
|
|
|
1124
1210
|
and recorded before settlement. If a model supplies no usable count, `ahub report`
|
|
1125
1211
|
says `tokens not reported`; the hub does not estimate usage from text length.
|
|
1126
1212
|
|
|
1213
|
+
## Control write outcomes and safe retries (#1078)
|
|
1214
|
+
|
|
1215
|
+
A daemon advertising `tool_write_idempotency` accepts a top-level control
|
|
1216
|
+
`requestId` for `hub_task_propose` and `hub_review`. This key is independent of
|
|
1217
|
+
transport `rid` and MCP JSON-RPC IDs. The proposal and review MCP tools expose optional `request_id`:
|
|
1218
|
+
omit it for a new call; after an unknown outcome, reuse the echoed key with the
|
|
1219
|
+
same arguments. The channel removes this transport argument before task
|
|
1220
|
+
validation. A new JSON-RPC ID does not change an explicitly supplied retry key. In-process tool calls (the local worker and Pi) refuse `request_id`: replay keys need the control-protocol transport.
|
|
1221
|
+
|
|
1222
|
+
Read `hub_task_list` for an uncertain proposal, `hub_task_show` for an uncertain
|
|
1223
|
+
verdict, or `ahub queue show <delivery-id>` (person/conductor) for a delivery.
|
|
1224
|
+
Call again only if the task, verdict or completion is absent. For a proposal or
|
|
1225
|
+
review retry, copy the returned `request_id`; do not invent a fresh key. An
|
|
1226
|
+
in-flight retry joins the original execution. A retained result is the receipt
|
|
1227
|
+
of that call, rather than a fresh statement of the task's current state.
|
|
1228
|
+
|
|
1229
|
+
`outcome: unknown` means a sent call may already have applied, including after a
|
|
1230
|
+
timeout, cancellation or lost connection. `outcome: refused` means this attempt
|
|
1231
|
+
did not run (for example an invalid key, insufficient authority or full actor
|
|
1232
|
+
window); it does not undo an earlier attempt. Known task permission/validation
|
|
1233
|
+
errors retain their specific error. Explicit retries are refused before sending
|
|
1234
|
+
to older daemons that do not advertise the feature.
|
|
1235
|
+
|
|
1236
|
+
Each authenticated actor has its own 512-entry, 15-minute replay window across
|
|
1237
|
+
its operations and launch generations. One actor filling that window does not
|
|
1238
|
+
block another. Replies are capped at 64 KiB and cached overlap metadata checks
|
|
1239
|
+
up to 64 current task references. Expired/foreign-instance IDs refuse without
|
|
1240
|
+
applying again; restart recovery uses board reads. `delivery_complete` uses the
|
|
1241
|
+
existing journal idempotence keyed by delivery ID and the live socket/generation,
|
|
1242
|
+
so settlement consumes no replay-window capacity. `hub_delivery_done` takes only
|
|
1243
|
+
its delivery ID and generation; it has no request key argument.
|
|
1244
|
+
|
|
1245
|
+
The latency receipt and its synthetic-only scope are in
|
|
1246
|
+
[control-write verification](verification/2026-11-02-control-write-outcomes.md).
|
|
1247
|
+
|
|
1127
1248
|
## A two-agent task and review
|
|
1128
1249
|
|
|
1129
1250
|
Choose an owner explicitly, then inspect the reviewer selected by the project
|
|
@@ -1307,6 +1428,18 @@ take it.
|
|
|
1307
1428
|
for. Dependencies are fixed when a task is proposed and can only name tasks that
|
|
1308
1429
|
already exist, so they cannot form a cycle.
|
|
1309
1430
|
|
|
1431
|
+
`hub_task_list` pages (#1083), because a 628-task board was 2.4 MB and over every agent tool-output limit.
|
|
1432
|
+
An agent's reply is `{tasks, total, next?}`: newest updated first (ties by id, descending), at most `limit`
|
|
1433
|
+
rows (default 50, 1 to 200), each compact (`id`, `state`, `owner`, `reviewer`, `title`). Pass `next` back as
|
|
1434
|
+
`cursor` for the following page; the cursor is the last row's `updated.id`, so a task that changes between
|
|
1435
|
+
calls neither repeats nor skips an older row, and the last page has no `next`. `ids` (1 to 200 distinct task
|
|
1436
|
+
numbers) returns the full public row of exactly those tasks, in the order given, and cannot be combined with
|
|
1437
|
+
`limit` or `cursor`; `detail: true` returns full rows for a page. `state`, `ready` and `release` filter before
|
|
1438
|
+
paging. PII tasks stay `[pii]` stubs in every form. Every refusal names its cause and what to pass instead.
|
|
1439
|
+
The person's console keeps the full bare array unless it names `limit`, `cursor`, `ids` or `detail`, so
|
|
1440
|
+
`ahub board`, `ahub tasks` and their `--json` output are unchanged. A peer that read the whole board as a
|
|
1441
|
+
bare array (the benchmark runner did) reads `tasks` instead, or asks for its task by `ids`.
|
|
1442
|
+
|
|
1310
1443
|
An owner named for a task that waits (`owner` with `after`, `--owner` with
|
|
1311
1444
|
`--after`) is its reserved owner: the task still waits, and when it is ready
|
|
1312
1445
|
routing offers it to that peer first, not to the first idle peer of the class.
|
|
@@ -1488,6 +1621,7 @@ ahub study approve rc-0123456789ab 2 # person only: create the unit task
|
|
|
1488
1621
|
ahub study show [rc-0123456789ab] # list campaigns (50 per page, --after continues) or one projection
|
|
1489
1622
|
ahub study close rc-0123456789ab 2 --reason "answered"
|
|
1490
1623
|
ahub study approve-protocol <64-hex hash> # person only: approve one exact experiment protocol
|
|
1624
|
+
ahub study experiments --campaign rc-0123456789ab [--after 50] # read the recorded attempts (also --attempt ra-... or --plan <hash> --baseline ra-... --variant ra-...)
|
|
1491
1625
|
```
|
|
1492
1626
|
|
|
1493
1627
|
- **Contract.** The JSON names the question, scope, exclusions, registered source ids, 1 to 32 units
|
|
@@ -1518,8 +1652,33 @@ ahub study approve-protocol <64-hex hash> # person only: approve one exact ex
|
|
|
1518
1652
|
- **Experiments.** Protocols, comparison plans and attempts are stored with their provenance (`declared`,
|
|
1519
1653
|
`host-observed` from a check receipt or a hub-hashed deliverable), and `ahub study approve-protocol` binds an
|
|
1520
1654
|
approval to one exact protocol hash and its evaluator; a changed protocol needs its own approval. The hub
|
|
1521
|
-
never ranks results.
|
|
1522
|
-
|
|
1655
|
+
never ranks results. The current in-progress owner of a bound unit task records inert data through
|
|
1656
|
+
`hub_experiment_record`: `kind` is `protocol`, `plan`, `attempt`, `event` or `receipt`, using the existing
|
|
1657
|
+
protocol/attempt/event/plan envelope or `{ kind: "receipt", receipt, signature }` for a signed runner receipt.
|
|
1658
|
+
The person may relay a signed receipt through the authenticated console connection; this does not grant
|
|
1659
|
+
agents person authority or allow a person to bypass the current task/source/campaign checks. Every PII turn
|
|
1660
|
+
refuses the tool. It returns only record metadata (kind, ids/hashes, sequence and receipt id as applicable),
|
|
1661
|
+
and neither starts an experiment nor signs or verifies a receipt in the relay. Existing host evidence and
|
|
1662
|
+
signature verification remain inside `Tasks`. Read records with `ahub study experiments` or
|
|
1663
|
+
`hub_experiment_show` (see Experiment readback below).
|
|
1664
|
+
- **Experiment readback (#602, #932 T3).** `ahub study experiments --campaign <id>` lists a campaign's attempts
|
|
1665
|
+
(50 rows a page, `--after <cursor>` continues), `--attempt <ra-id>` shows one, and `--plan <hash> --baseline
|
|
1666
|
+
<ra-id> --variant <ra-id>` shows one comparison under a recorded plan. `hub_experiment_show` takes the same three
|
|
1667
|
+
forms and is a read for every local peer. It runs no command and reads no file; it renders what
|
|
1668
|
+
`Tasks.experimentShow` already returns. Every value says where it came from: `declared` (the agent's own word),
|
|
1669
|
+
`host-observed` (a check receipt or a hub-hashed deliverable), `runner-attested` (a signature-verified runner
|
|
1670
|
+
receipt) or `person-attested`. A declared value is never shown as observed, a metric or output the hub could not
|
|
1671
|
+
read is `unknown`, sealing is `declared` and `isolation unverified` unless a runner receipt supplies the
|
|
1672
|
+
evidence, and failed, cancelled and unknown attempts stay in the counts at the top. A repeat is never an
|
|
1673
|
+
independent reproduction, and a comparison whose fixed inputs, evaluator, split or metric units differ, or that
|
|
1674
|
+
changes an undeclared factor, reads `no: <field> differs` and is shown, never ranked. A private campaign, task or
|
|
1675
|
+
source shows ids, counts and states only. **Optional rerun checklist** (written for a person, never run by the
|
|
1676
|
+
hub): a person who wants stronger evidence reruns the protocol themselves, then attaches it through the existing
|
|
1677
|
+
paths and no new one: a check on the task (`hub_check_start`, #513 and the remote runner #793) makes the end
|
|
1678
|
+
event's exit status `host-observed`; an output file named in an `output` event is hashed by the hub (#509) and
|
|
1679
|
+
stays `unknown` when it is missing or denied; a registered runner's signed receipt (#1050) is the only source of
|
|
1680
|
+
`runner-attested` sealing and isolation. Without one of these the experiment is reported as declared and
|
|
1681
|
+
unverified, which is not the same as wrong.
|
|
1523
1682
|
- **Privacy.** A campaign whose parent task is PII, or that names a private source, is private: every view keeps
|
|
1524
1683
|
ids, counts, states and provenance and stubs its text as `[pii]`. Study tool arguments and results are kept out
|
|
1525
1684
|
of hub-managed memory capture.
|
|
@@ -2036,6 +2195,16 @@ A newly initialized `ahub init` project inherits a trusted machine opt-in and sa
|
|
|
2036
2195
|
|
|
2037
2196
|
`ahub setup` selects the explicit `CLAUDE_CONFIG_DIR`, otherwise an existing default Claude home (or the not-yet-created default when no other home is selected), plus distinct homes proven in use by live registered Claude launcher records. It does not scan arbitrary profile directories. Each native plugin command receives that home's environment. One confirmation covers plugin setup and a project-neutral PreToolUse hook while preserving unrelated hooks and statusLine settings. The profile fallback requires the inherited hub state and peer identity and does nothing for a managed launch that already has its session hook, preventing duplicate delivery. Installing a hook proves configuration, not live enforcement.
|
|
2038
2197
|
|
|
2198
|
+
Setup manages only the user-scope `agent-hub@agent-hub` plugin row (`claude
|
|
2199
|
+
plugin install|uninstall ... --scope user`). A project- or local-scope row of that
|
|
2200
|
+
plugin is kept and named in a notice (`... plugin row preserved ...; setup never
|
|
2201
|
+
removes non-user scopes`). While such a row exists, setup is blocked rather than
|
|
2202
|
+
removing an agent-hub marketplace that points at another source (#1073). The
|
|
2203
|
+
semver check on installed plugin versions applies only to agent-hub rows, so
|
|
2204
|
+
another plugin recorded with a git SHA no longer fails the inventory (#1074). When
|
|
2205
|
+
a Claude home step fails, setup still records the `start.agents` answer before it
|
|
2206
|
+
reports the failure.
|
|
2207
|
+
|
|
2039
2208
|
`ahub autonomy status [--json]` includes the machine default and each discovered Claude home's plugin/hook state. Missing, unsafe, stale, unavailable or incomplete evidence is explicit; a missing selected home is reported without starting a native inventory command that could create it. The native Orca zero-prompt receipt remains T4.
|
|
2040
2209
|
|
|
2041
2210
|
|
|
@@ -2463,6 +2632,100 @@ Rules:
|
|
|
2463
2632
|
- Person only: an agent shell or a hub tool is refused (`ahub settings edit` is a console command in the identity gate, and the three control requests answer only the console role). Recovery or shutdown holds every edit.
|
|
2464
2633
|
- The hub must run this release: an older hub answers `unknown message` and the command says to upgrade and restart it.
|
|
2465
2634
|
|
|
2635
|
+
## Design spec inspection
|
|
2636
|
+
|
|
2637
|
+
`ahub specs list` discovers Markdown specs whose flat frontmatter names an `id`
|
|
2638
|
+
and `type`. `ahub specs covers <file...>` finds their path scopes.
|
|
2639
|
+
`ahub specs check` validates graph links, types and stamps without a daemon;
|
|
2640
|
+
it prints nothing and exits 0 when there are no specs or stamped documents.
|
|
2641
|
+
`--json` returns structured reports, and `--require-fresh` also fails on stale
|
|
2642
|
+
documents. `--base <ref>` reports changed paths whose covering spec stayed
|
|
2643
|
+
unchanged without making that report an error.
|
|
2644
|
+
|
|
2645
|
+
The `specs` config block defaults to
|
|
2646
|
+
`{ "enabled": true, "review": "report", "roots": [], "stamps_file": "" }`.
|
|
2647
|
+
Roots are repository-relative directories; an empty list scans the repository.
|
|
2648
|
+
The optional stamps file uses the schema of `docs/verified.json` for other
|
|
2649
|
+
documents. A scan stops at 2,000 Markdown files and 8 KiB of frontmatter per
|
|
2650
|
+
file; a truncated report names `specs.roots` as the way to narrow the scan.
|
|
2651
|
+
Symlinked files are skipped. Freshness counts commits touching covered paths
|
|
2652
|
+
since the stamp and detects uncommitted changes without running Git filters
|
|
2653
|
+
or external diffs. These commands never refresh a stamp.
|
|
2654
|
+
|
|
2655
|
+
The Switches settings `specs.enabled` and `specs.review` are machine-local
|
|
2656
|
+
settings, and the specs config fields are tier 2 structural settings. Setting
|
|
2657
|
+
`specs.enabled` to false suppresses this machine's notices and status summary,
|
|
2658
|
+
leaving the shared config unchanged. Explicit CLI and `hub_specs` inspection
|
|
2659
|
+
still work when notices are disabled.
|
|
2660
|
+
|
|
2661
|
+
`ahub init --specs` (the default) and `--no-specs` set the shared key
|
|
2662
|
+
`specs.enabled` and add or remove the `AGENT_HUB_SPECS` instruction block in
|
|
2663
|
+
`AGENTS.md` (the text is `templates/specs.block.md`). `--spec-review
|
|
2664
|
+
off|report|require` sets `specs.review`. Both are rows of the init settings
|
|
2665
|
+
table: on an existing project an explicit flag shows as one old -> new row in
|
|
2666
|
+
`--dry-run`, a flag equal to the current value is a no-op, and a plain `ahub
|
|
2667
|
+
init` follows the project's `specs.enabled` (on unless the project set it to false):
|
|
2668
|
+
it adds or refreshes the block when specs are on and removes it when they are off. Text outside
|
|
2669
|
+
the markers is never touched. A block with only one of its two markers is
|
|
2670
|
+
refused, naming the cause, and nothing is written.
|
|
2671
|
+
|
|
2672
|
+
`ahub specs stamp <id-or-document...> [--yes]` is a person's record that they
|
|
2673
|
+
reviewed a spec or a stamped document against HEAD. It is person only: an agent
|
|
2674
|
+
identity is refused before the command runs (it is a console command, and
|
|
2675
|
+
`--live-test` delegation refuses it too), and a run with no terminal is refused
|
|
2676
|
+
even with `--yes`. It shows `old -> new` per document, asks, and then changes
|
|
2677
|
+
only the spec's `verified-against` line (adding it before the closing `---` when
|
|
2678
|
+
absent) or the document's `verifiedAgainst` value in the stamps file, keeping
|
|
2679
|
+
every other byte, the line endings, a byte order mark and the file mode. The new
|
|
2680
|
+
stamp is the full HEAD SHA. It is refused, writing nothing for any target, while
|
|
2681
|
+
a document's covered paths have uncommitted changes, when the document has no
|
|
2682
|
+
paths, when a document's frontmatter cannot take a stamp, or when a name matches
|
|
2683
|
+
no or several documents; all refusals are listed together, and a document that
|
|
2684
|
+
cannot be stamped is refused before the question is asked. The answer may take
|
|
2685
|
+
minutes, so after it HEAD, each covered path's state and every target file's
|
|
2686
|
+
bytes are checked again, and any change refuses the whole run: what you approved
|
|
2687
|
+
is what is written. Removing the instruction block with `--no-specs` takes out
|
|
2688
|
+
only the block and one separating blank line, so the whitespace of the text
|
|
2689
|
+
around it is kept. Stamping changes a working-tree file: review the diff and commit it.
|
|
2690
|
+
Agents never edit `verified-against`. `docs/verified.json` is still restamped
|
|
2691
|
+
only in a release PR (AGENTS.md "Verified stamps").
|
|
2692
|
+
|
|
2693
|
+
`scripts/check-docs.mjs` stays a self-contained Node script, because the release
|
|
2694
|
+
workflow runs it on Node without Bun or an install and `src/hub/specs.ts` is
|
|
2695
|
+
TypeScript that depends on repository packages. `test/check-docs-parity.test.ts`
|
|
2696
|
+
holds it to the same state, commit count and dirty flag as the shared engine on
|
|
2697
|
+
the same stamps.
|
|
2698
|
+
|
|
2699
|
+
Task proposal and acceptance replies name the specs covering the task's refs
|
|
2700
|
+
paths. At completion the hub reads spec metadata from the submitted commit,
|
|
2701
|
+
compares the host-verified changed-file inventory with those scopes, and adds
|
|
2702
|
+
`spec not updated: <id>` and `spec errors: <n>` to the result and review brief.
|
|
2703
|
+
Dirty spec edits in another checkout do not satisfy this check. `report` records
|
|
2704
|
+
the report; `off` suppresses task notices. Under `require`, unchanged covering
|
|
2705
|
+
specs must be updated or named in `spec_ack`, for example
|
|
2706
|
+
`[{ "id": "bus", "reason": "Only an internal allocation changed; the contract is unchanged." }]`.
|
|
2707
|
+
Acknowledgements are screened, recorded at the exact head, and shown to the
|
|
2708
|
+
reviewer. A new head invalidates the old report. Unknown or truncated coverage
|
|
2709
|
+
cannot satisfy `require`; a refusal names the next step. A call accepts up to
|
|
2710
|
+
20 acknowledgements; larger changes can update the specs or split the task.
|
|
2711
|
+
Tasks without a submitted commit or with no changed files have no coverage
|
|
2712
|
+
obligation. Existing spec errors are reported on tasks touching covered paths
|
|
2713
|
+
or spec documents. A privacy change during a check suppresses its spec report
|
|
2714
|
+
without discarding the check result. If an applicable review policy changes
|
|
2715
|
+
to `require` while that check runs, the pass is retained and the owner is
|
|
2716
|
+
asked to refile completion under the current policy.
|
|
2717
|
+
|
|
2718
|
+
`hub_specs` offers read-only `check` and `covers` actions with at most 20 report
|
|
2719
|
+
items. These explicit reads and status inspect the daemon checkout; task notices
|
|
2720
|
+
inspect the owner's execution root and completion reports inspect its submitted
|
|
2721
|
+
commit. Immutable Markdown blobs are read in bounded batches and parsed results
|
|
2722
|
+
are cached by object id across submitted heads. PII tasks and private turns do not publish spec paths through task
|
|
2723
|
+
notices. Completion snapshots skip Git symlinks and cap each committed spec
|
|
2724
|
+
body at 4 MiB; an incomplete read stays unknown. Status shows a specs count,
|
|
2725
|
+
error count and stale count only when specs or stamped documents exist, with
|
|
2726
|
+
one hint when the specs instruction block is missing. Empty projects stay
|
|
2727
|
+
silent.
|
|
2728
|
+
|
|
2466
2729
|
## Start modes: TUI by default, headless as opt-in
|
|
2467
2730
|
|
|
2468
2731
|
A peer that has a TUI the hub attaches to starts in it by default (issue #269).
|
|
@@ -2476,6 +2739,19 @@ A peer that has a TUI the hub attaches to starts in it by default (issue #269).
|
|
|
2476
2739
|
| jcode (optional) | `tui` on the hub-owned ACP session (`ahub jcode`) | `ahub jcode --mode headless`, or `peers.jcode.start_mode: headless` |
|
|
2477
2740
|
| local | headless (hub-native) | not applicable |
|
|
2478
2741
|
|
|
2742
|
+
Daemon-owned peer launches, native version-helper probes and process-table helpers drop
|
|
2743
|
+
every inherited `ORCA_*` variable. They pass `CLAUDE_CONFIG_DIR` and `CODEX_HOME` through
|
|
2744
|
+
unchanged; Claude uses the former and Codex the latter, while other peers ignore
|
|
2745
|
+
selectors they do not own. The hub does not choose a different account,
|
|
2746
|
+
synthesize a home, or copy native credentials. A person-started native process
|
|
2747
|
+
launched from `ahub claude`, `ahub codex`, `ahub kimi` or another native launcher
|
|
2748
|
+
keeps its pane's `ORCA_*` context while its own peer markers replace inherited
|
|
2749
|
+
agent identity. Manager and person console wrappers keep their existing
|
|
2750
|
+
environment, routing and recovery rules. Adapter-owned fresh homes take
|
|
2751
|
+
precedence; Pi's fixed environment carries `CODEX_HOME` but not
|
|
2752
|
+
`CLAUDE_CONFIG_DIR`, and the local worker's fixed shell environment carries
|
|
2753
|
+
neither.
|
|
2754
|
+
|
|
2479
2755
|
- **You type the command:** `ahub pi` opens Pi's TUI in that terminal.
|
|
2480
2756
|
`--headless` and the start mode setting are the two ways to ask for the
|
|
2481
2757
|
background peer. `ahub settings set peers.pi.start_mode headless` writes the
|
|
@@ -2494,7 +2770,14 @@ A peer that has a TUI the hub attaches to starts in it by default (issue #269).
|
|
|
2494
2770
|
`{command}` is quoted for a POSIX shell; `{title}` and `{cwd}` are raw,
|
|
2495
2771
|
so give each an argv element of its own.
|
|
2496
2772
|
2. Orca, when the hub runs in an Orca worktree or an earlier `ahub <peer>`
|
|
2497
|
-
launch of this project recorded one (the path recovery uses).
|
|
2773
|
+
launch of this project recorded one (the path recovery uses). The terminal opens in the
|
|
2774
|
+
Orca worktree whose root is exactly this project's root, found with `orca
|
|
2775
|
+
worktree list` (#1105); it never uses the worktree of whichever terminal
|
|
2776
|
+
started the hub, which is another project's after `ahub --project`, a
|
|
2777
|
+
dashboard manager start or an upgrade. The start is refused, naming the cause
|
|
2778
|
+
and `terminal.open` as the alternative, when Orca cannot list its worktrees,
|
|
2779
|
+
has no worktree with this root, has more than one, or cut its list off at 500
|
|
2780
|
+
rows first.
|
|
2498
2781
|
- **No provider:** the start is refused with the command to run by hand. It is
|
|
2499
2782
|
never downgraded to headless. `ahub settings` lists each start mode, and the
|
|
2500
2783
|
dashboard's Start control says which mode a start will use and where its
|
|
@@ -2894,6 +3177,13 @@ the history entry reads `by: hub` with that planner and the reason
|
|
|
2894
3177
|
is paused for recovery pulls nothing, also when the setting is turned off or recovery begins while a pull is already waiting on its screening: that pull writes nothing, and a recovery waits for pulls in flight. A committed `config.json` cannot turn it on: like
|
|
2895
3178
|
the other machine-local policies it is ignored there with a log line.
|
|
2896
3179
|
|
|
3180
|
+
A backlog or unowned proposed card whose `plannedStart` is still in the future is
|
|
3181
|
+
not started automatically (#1092). Until that time the hub sends no
|
|
3182
|
+
`backlog_ready` line, makes no auto-pull, makes no ready-queue or queue-pressure
|
|
3183
|
+
owner offer, and the task sweep reports no stall. Planner grooming lists the card
|
|
3184
|
+
as `scheduled`. The card becomes eligible at the planned start itself. A planner's
|
|
3185
|
+
explicit pull or a person's assignment is unchanged.
|
|
3186
|
+
|
|
2897
3187
|
## Resetting a project's hub
|
|
2898
3188
|
|
|
2899
3189
|
`ahub reset` returns a project's hub to a clean state. Without `--yes` it is a
|
|
@@ -3100,7 +3390,7 @@ version is older than the selected running daemon; it installs nothing.
|
|
|
3100
3390
|
| Runtime | Control protocol window | Legacy status field |
|
|
3101
3391
|
| --- | --- | --- |
|
|
3102
3392
|
| 0.12.20 through 0.25.0 | 16 only | `protocol: 16` |
|
|
3103
|
-
| 0.26.0 | 16 through 17 | `protocol: 16`, `protocolMin: 16`, `protocolMax: 17` |
|
|
3393
|
+
| 0.26.0 through 0.28.0 | 16 through 17 | `protocol: 16`, `protocolMin: 16`, `protocolMax: 17` |
|
|
3104
3394
|
|
|
3105
3395
|
New clients choose the highest common protocol. The runtime supports N-1, so the
|
|
3106
3396
|
published protocol-16 client and channel plugin remain usable; unrelated feature
|
|
@@ -3705,6 +3995,20 @@ crash of one is not reported this way.
|
|
|
3705
3995
|
- Codex's app-server died with the hub; run `ahub codex` again. Claude Code's
|
|
3706
3996
|
plugin reconnects by itself while that session is open.
|
|
3707
3997
|
|
|
3998
|
+
The report in `ahub status` shows only what still stands (#1082), worked out when
|
|
3999
|
+
status is asked and not frozen at startup. A line that asks something of a peer
|
|
4000
|
+
(`run ahub codex again`, `reconnects by itself`, a Pi that is still down) goes as
|
|
4001
|
+
soon as that peer is attached again, whoever attached it. The headline's count of
|
|
4002
|
+
deliveries still in `needs_review` counts only the ones this crash left, read
|
|
4003
|
+
live, so it equals what `ahub queue list` shows for them and falls as each is
|
|
4004
|
+
resolved. At zero the count and its pointer to the queue are gone and the headline
|
|
4005
|
+
(`the previous hub run stopped without shutting down`) stays as the record that a
|
|
4006
|
+
crash was found. Lines that say what recovery found or did (`kimi resumed`,
|
|
4007
|
+
`pi not resumed`, `pi.auto_start started a fresh session`) are history and stay for
|
|
4008
|
+
the run. The hub log keeps every line as it was written. A row that becomes
|
|
4009
|
+
`needs_review` later in the run is in `ahub queue list` and is not part of this
|
|
4010
|
+
count.
|
|
4011
|
+
|
|
3708
4012
|
## Evidence and limits
|
|
3709
4013
|
|
|
3710
4014
|
The 0.6.4 release has real measurements in [the smoke checklist](smoke.md):
|
|
@@ -4055,7 +4359,7 @@ has appeared for `AHUB_CHECK_QUIET_S` seconds (300 by default, set to 300 in CI)
|
|
|
4055
4359
|
slow suite that is still passing tests is never cut. `scripts/progress-tee.sh` passes bun's
|
|
4056
4360
|
output through unchanged and appends one byte to a progress file for each of those lines;
|
|
4057
4361
|
the watchdog polls that file's size. On a stop it prints where the run is and the process
|
|
4058
|
-
table below it first. `AHUB_CHECK_HANG_S` (
|
|
4362
|
+
table below it first. `AHUB_CHECK_HANG_S` (2250 by default, sized in #1086 from two measured full runs on dgx02 of 1483 s and 1487 s of test time, 1.5 times the longer; it was 960) is only the backstop for a run
|
|
4059
4363
|
that keeps printing results while hung; hosted CI sets 1500 on Linux inside a 35-minute
|
|
4060
4364
|
job limit (#378, #593, #752, task 516). The macOS leg runs as four shards (#548): `AHUB_CHECK_SHARD=i/n`
|
|
4061
4365
|
makes `scripts/check.sh` run slice `i` of the full suite through `bun test --shard=i/n --timings=scripts/test-timings.json`, which puts
|
|
@@ -4383,6 +4687,16 @@ Use `ahub roster add jcode`, then `ahub jcode [--model <alias>] [--provider-prof
|
|
|
4383
4687
|
|
|
4384
4688
|
The native TUI opens only after Jcode has saved the selected session. On 0.98.1, `session/new` does not save it; the first real hub turn does. The launcher prints `jcode's TUI opens after its first hub turn; send it work, or Ctrl-C` once and waits for the same owned launch's saved session. Send Jcode work from the hub, or press Ctrl-C to end only the wait. No artificial prompt is sent. A console `peer_start` uses a terminal provider to run the same launcher, even while ACP is running; a conductor or dashboard start of an attached Jcode answers `already` and opens nothing (#559). Without a provider, run its displayed command in your own terminal. Options with no terminal need that manual path.
|
|
4385
4689
|
|
|
4690
|
+
A refused TUI launch names its cause and the next step (#1093): Jcode was
|
|
4691
|
+
restarted during the launch, its owned server is not running, its private socket
|
|
4692
|
+
was replaced, no session has been reported yet, the saved session failed the hub's
|
|
4693
|
+
safety check, the hub is busy stopping or recovering, Jcode is not running under
|
|
4694
|
+
this hub, or the project MCP entry is stale. The daemon logs only the cause code,
|
|
4695
|
+
never a path or id. After a crash or controlled recovery a Jcode whose start mode
|
|
4696
|
+
is `tui` runs headless. Until a TUI launch is served, `ahub status` and the
|
|
4697
|
+
launcher say `jcode is running headless after recovery; run ahub stop jcode, then
|
|
4698
|
+
ahub jcode to get its TUI back`.
|
|
4699
|
+
|
|
4386
4700
|
`ahub jcode --dry-run` stays pure and redacted. A person's `--print-command` can show the actual top-level native argv and closed native environment for an already-saved running session; it starts nothing, and like the launch it names a `--model`, `--provider-profile` or `--session-id` that differs from the running session (#574). The private socket/session tuple is not returned to hub tools or status. Native saved-session evidence is read-only and capped at 32 MiB; unsafe, mismatched or larger evidence refuses the TUI launch.
|
|
4387
4701
|
|
|
4388
4702
|
A busy jcode takes an `important` message into its running turn (#572): the hub sends it as a soft interrupt through jcode's own private server socket, which jcode injects at its next tool boundary, so the message no longer waits for the turn to end. The hub never cancels a turn to deliver. Headless Kimi and Qwen have no such path: an `important` message waits, and `ahub status` and the console show `important messages waiting on a busy ACP peer for N min` once it has waited past `budget.stale_min`, so you can decide to stop the peer.
|
|
@@ -4664,6 +4978,14 @@ admission reads, and the split changes no admission decision. An older hub shows
|
|
|
4664
4978
|
acceptance and self-claim in every lifecycle mode, so 0 refuses new acceptances; a
|
|
4665
4979
|
current owner's redo of sent-back work keeps its slot (#481 S9).
|
|
4666
4980
|
|
|
4981
|
+
A refusal at the limit separates what the owner carries from what it was only offered (#1080):
|
|
4982
|
+
`planner WIP capacity for codex: limit 2; open tasks #621, #624 (accepted #621; offered, not yet accepted #624); <next step>`.
|
|
4983
|
+
An `urgent` task (priority 0, or the `urgent` signal) that is the owner's own offer may take back the
|
|
4984
|
+
newest offers the owner has not accepted, only as many as it needs, when that is all that keeps it at the
|
|
4985
|
+
limit. The hub returns each one ownerless to To Do (history `unassigned`, by the hub, naming the urgent
|
|
4986
|
+
task; a planner-pulled offer also loses the reservation that counted toward the owner's WIP), withdraws its offer, and tells the planners and the console. After the displacement the hub checks that the owner is under its limit and refuses the accept with the cause and a next step if not. It never takes back accepted work,
|
|
4987
|
+
another urgent offer, a person-pinned offer or an offer with work evidence, and a refusal changes nothing.
|
|
4988
|
+
|
|
4667
4989
|
Pending unowned, unstarted pull can be undone at its latest owned revision via
|
|
4668
4990
|
`hub_backlog_undo` or the existing planning undo control, restoring its earlier
|
|
4669
4991
|
reservation. An ordinary return to Backlog also restores the pre-pull reservation unless a later explicit reservation edit superseded it. Normal release routing offers work only while that reserved peer
|
|
@@ -5047,7 +5369,7 @@ A reviewer has a review scope (#852): `full` (reads the code, runs the affected
|
|
|
5047
5369
|
|
|
5048
5370
|
Start them with `ahub claude --as claude-review`, `ahub codex --as codex-review` and `ahub kimi --as kimi-review`; stop with `ahub stop <id>`. For the Claude and Codex reviewers the command asks the running hub to start the reviewer and returns: nothing runs in that terminal, it takes no launch arguments, and `--print-command` or `--dry-run` prints a hub-start note instead of a launch (#720). Fresh Claude and Codex variants share the project checkout; the Kimi variant runs in a clean temporary working directory and reviews only the screened brief and host facts. All fresh variants refuse a custom worktree or permission mode. Codex and Kimi require `review_mode: "fresh"`; without it, an existing headless instance with the reviewer role keeps its native app-server/ACP behavior, worktree and permission options and does not join this pool. Claude retains its task 223 automatic headless-reviewer declaration. The agy reviewer slot remains automatically unavailable (`agy is an implementer peer (#485)`). A failed or unsupported fresh start never downgrades to a native continuing session. Ordinary implementer instances retain their own adapters. The default logical pool order is Claude, Codex, Kimi. Only configured kinds with at least one declared reviewer count as slots, including declared ones that are offline, paused, quota-limited or failing, so availability never renumbers them; configured kinds with no declaration are listed after the walk as `no declared reviewer`. `review.rerotate` defaults to false. Pool selection starts at PR number modulo the number of declared kind slots, or task id when there is no PR, then skips the implementer's family and unavailable candidates. Delta review prefers the preceding eligible independent family in a fresh child. A preceding same-family fallback does not outrank a newly available independent family. `ahub route explain` shows the same pure walk.
|
|
5049
5371
|
|
|
5050
|
-
Codex requires a verified `codex-cli` (0.146.0, 0.163.0 or 0.
|
|
5372
|
+
Codex requires a verified `codex-cli` (0.146.0, 0.163.0, 0.164.0 or 0.166.0) or one the person trusts on this machine, and a passing bounded runtime receipt before its model child starts. 0.146.0 and 0.163.0 passed the [2026-10-22 model-free production admission](verification/2026-10-22-codex-reviewer-isolation.md) and 0.164.0 the [2026-10-24 one](verification/2026-10-24-codex-0164-reviewer-isolation.md); 0.166.0 passed the [2026-10-31 model-free procedure](verification/2026-10-31-codex-0166-reviewer-isolation.md). Its [first authorized model review](verification/2026-10-31-codex-0166-reviewer-tool-call.md) missed a marker hidden by the fixture's accepted plan, so that admission was reverted. After a committed model-free envelope regression and a fixture correction, the separately authorized [2026-11-02 single model review](verification/2026-11-02-codex-0166-reviewer-tool-call.md) persisted one approved verdict with the required marker and exact head; 0.166.0 is now verified. A refusal names the installed and verified versions. Either set `codex_bin` to a verified executable, or run `ahub agents trust codex-review <version>`: trust lifts only the version pin, and every proof below still runs before each child (#691). Each launch approves exactly `hub_review` and `hub_task_show` per tool (`approval_mode = "approve"`), never through a server-wide default: without it Codex 0.164.0 listed the tools but refused the call, so reviews ended with no verdict (#783). A model-free receipt proves the inventory, not that a verdict reaches the hub; a [model-backed 0.164.0 run](verification/2026-10-25-codex-0164-reviewer-tool-call.md) recorded one verdict through that path. The producer checks native binary/config stability, configured MCP inventory with only the two hub tools, effective Apps/plugins/hooks disablement, an explicit empty legacy `notify` command and a named filesystem profile. Apps needs separate feature readback because configured inventory omits runtime connectors. Web search is requested disabled; its effective turn mode is not read back and managed requirements can select Cached (see the verification ceiling). Each launch proves public-read, exact/glob/symlink private-denial, standard host credential denial and write-denial in temporary fixtures. Standard credential and configured tool-home/XDG subtrees are denied independently of project `local.deny`. Its sandboxed shell is filesystem read-only with private paths denied and network configured disabled; it is not Claude's Read/Grep/Glob-only tool whitelist. No credential home is copied.
|
|
5051
5373
|
|
|
5052
5374
|
Kimi requires a compat-admitted Kimi Code on the hub's PATH (receipt-verified 2.2.0, 2.3.0, 2.3.1, 2.3.2 and 2.4.1), signed in through its managed OAuth provider, and a passing runtime preparation before each child; an unverified/untrusted version or a failed preparation is unavailable with its reason. The [2.3.0](verification/2026-10-22-kimi-qwen-compat.md), [2.3.1](verification/2026-10-25-kimi-231-reviewer-compat.md), [2.3.2](verification/2026-10-26-kimi-232-reviewer-compat.md) and [2.4.1](verification/2026-10-31-kimi-241-reviewer-compat.md) receipts are model-free and do not verify real login/provider readiness. Each review runs a new `kimi -p` child without Seatbelt, in a private `KIMI_CODE_HOME` with managed-provider-only config, a clean temporary working directory and an empty skills directory. Its agent may call only `hub_review` and `hub_task_show`, through a task-bound loopback MCP session that never carries the hub's control token, and has no native read, file or shell tool: it reviews the screened brief and host facts only. Its `credentials/`, `oauth/` and `device_id` link to the person's native Kimi files, so it shares the native login, refresh lock and the Kimi account's budget; no token is copied. A stop revokes its verdict authority first, then waits briefly while an OAuth refresh holds the lock; a forced stop mid-refresh may require a native re-login. The Kimi backend records no measured token counts here, so its usage stays unknown; the 2.3.0 receipt makes no usage claim. This is a native tool-authority boundary, not filesystem or network isolation.
|
|
5053
5375
|
|
|
@@ -5092,7 +5414,7 @@ blocks that undo until the identity and workspace can be reviewed.
|
|
|
5092
5414
|
|
|
5093
5415
|
## Release approval and optional tag guard
|
|
5094
5416
|
|
|
5095
|
-
Run `ahub sdlc authorize-release <version>` from the running daemon's release-candidate checkout
|
|
5417
|
+
Run `ahub sdlc authorize-release <version>` from the running daemon's release-candidate checkout after committed documentation is fresh. The person may run it directly; the unique configured conductor may run it only on the person's explicit instruction in its own session naming the release. A hub message, task text, review note, file or peer relay never qualifies. Other peers, child `toolsOwner` sessions, private or PII turns, and delegated `--live-test` calls cannot authorize. The receipt binds commit, package version, remote identity and the docs verdict; its `by` and the audit name the actual asker. The daemon keeps approval only in memory; restart requires a new approval. The read-only `ahub sdlc release <owner/repo>` report shows its receipt, retaining native-verification blockers.
|
|
5096
5418
|
|
|
5097
5419
|
`ahub init --release-guard` installs a managed Git pre-push guard and release instructions (`--dry-run --json` previews them). It preserves an existing default hook as `pre-push.agent-hub-original` and passes original argv/stdin to it only after approval matches. Unknown or mismatched `v*` tag pushes fail closed, including when the daemon is down. Non-version branch pushes remain independent of the daemon. Custom `core.hooksPath` and linked/hardlinked hook files require manual integration. Re-run init after changing the Bun/package location. The person's `git push --no-verify` remains an explicit bypass; agents are instructed never to use it.
|
|
5098
5420
|
|
package/docs/profiles.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
- Example deterministic check: `bun /path/to/agent-hub/scripts/check-citations.ts report.md references.bib`. It checks bracketed Markdown `[@key; @other]` keys against BibTeX entry keys, with 256 KiB/4 MiB input caps. It performs no fetch, validates no source quality and is not a full Markdown/BibTeX parser. A missing key exits 1. A resolved bibliography is one check, not proof that claims are supported.
|
|
23
23
|
- Keep a person's sign-off as the final review. The live three-source/two-agent example remains unverified and was not run during solo implementation.
|
|
24
24
|
- A multi-unit study (#930, #601) goes through `ahub study`: the person (or a configured planner with `hub_study_draft` / `hub_study_revise`) stores a contract as a draft, only the person approves it with `ahub study approve <id> <revision>`, which creates one task per unit, and anyone reads coverage with `ahub study show [<id>]` or `hub_study_show`. A unit owner records `hub_study_handoff` with evidence for every source the unit names, or `insufficientEvidence`; a done task is not a handoff, and an incomplete handoff does not close a discovery round. A private campaign, task or source shows ids, counts and states only.
|
|
25
|
+
- Experiment attempts recorded on a study unit are read with `ahub study experiments --campaign <id>` (or `--attempt`, or `--plan` with `--baseline` and `--variant`) and `hub_experiment_show`. Each value shows its source: `declared` is the agent's own word, and only `host-observed`, `runner-attested` or `person-attested` rows are evidence, none of which proves the science. A rerun by a person attaches through an existing check, a hashed output file or a registered runner's signed receipt, as the checklist in `docs/operations.md` ("Experiment readback") says; without one the experiment stays declared and its sealing unverified. The synthetic CPU-only fixture is `test/research-experiments-fixture.test.ts`; no account, GPU or native model has run an experiment here.
|
|
25
26
|
- The deterministic three-source, two-peer example (`test/study-daemon.test.ts`, "three-source, two-peer example"): one contract names sources S0, S1 and S2 and two discovery units, `alpha` (S0 and S1, owned by codex) and `beta` (S2, an independent check, owned by kimi). After `ahub study approve` both units read `none` and `0/2 covered`, `0/1 covered`. A handoff for S0 only moves `alpha` to `incomplete` with `1/2 covered`. A handoff for both S0 and S1, and one for S2, make both `complete` and the discovery round complete. Another peer's handoff for `alpha` is refused. This runs with fake peers: it shows the hub's rules, not that a native model follows the guidance.
|
|
26
27
|
|
|
27
28
|
# General project example
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
# Project profile overrides
|
|
54
55
|
|
|
55
56
|
- Acceptance criteria are profile-independent (#507b): a task's recorded criteria checklist (docs/sdlc.md, Acceptance-criteria checklist) is listed in every profile's review request, ahead of the profile's `review_checklist` lines, and an unmet item that starts with a criterion id names it; a profile only changes the wording of its checklist, never the criteria or their ids.
|
|
57
|
+
- Every shipped profile's `review_checklist` carries one error-message item (#1095): the reviewer names each new or changed error, refusal or failure message that lacks its cause or its next step. Because `review_checklist` replaces as a unit, a project that sets its own `profile_overrides.review_checklist`, and a pack (whose rubric lines become that override), does not get the item unless it adds one. The shipped lists are what a project without an override sees.
|
|
56
58
|
- Recurring unmet criteria become a candidate, never a change (#514a): when reviews name the same criterion id unmet on at least 3 tasks of one profile and class within 30 days, and those tasks make up at least 2 separate pieces of work (tasks sharing a PR or a branch count once), the hub files one backlog card with the `profile_overrides.review_checklist` line to consider. The line is text, and nothing applies it on its own. By hand: `profile_overrides` is not machine-local, so you choose the shared `.agenthub/config.json` (every checkout) or `config.local.json` (this machine), and add the line to your current checklist because `review_checklist` replaces as a unit. With the command (#514b): `ahub learn list` shows the open cards, `ahub learn accept <id>` adds that one line to your current checklist in `.agenthub/config.local.json` (this machine only, never the shared or any tracked file) through the settings writer, closes the card, and says it applies after a restart; `ahub settings undo` puts the previous file back; `ahub learn reject <id>` only closes the card. The line is rebuilt from the key line of the card and the board's own evidence, never parsed from the card text. Person only: an agent shell and the configured conductor are refused. PII tasks and evidence-only verdicts never count.
|
|
57
59
|
- `profile_overrides` in shared/local config selects project data over the chosen shipped profile. `classes`, `role_text` and `catalog_roles` maps merge by key across layers; `plan_keys`, `agents`, `example_checks` and `review_checklist` replace as units. A local `profile` selects the active base for both init and native contracts.
|
|
58
60
|
- Classes may add or remap profile aliases to existing base classes. Existing base names keep their meanings; class maps are bounded to 32 override entries. Task storage and route explanations preserve the alias, including a dev custom alias, while routing/budgets/checks use its base. Other tasks under custom dev data retain the selected profile semantics too, so document sections do not become whole-path overlaps. Unmodified dev rows retain their old shape.
|
package/docs/quickstart.md
CHANGED
|
@@ -17,7 +17,7 @@ ahub setup # installs the channel plugin and a pr
|
|
|
17
17
|
Or use the matching GitHub release:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
bun add -g github:STAIxBWLB/agent-hub#v0.
|
|
20
|
+
bun add -g github:STAIxBWLB/agent-hub#v0.28.0
|
|
21
21
|
ahub setup
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -31,6 +31,16 @@ move a running project to a newer release later, run `ahub upgrade` in a
|
|
|
31
31
|
terminal in that project: it reviews the plan with you, applies it and follows
|
|
32
32
|
it; other projects keep their version.
|
|
33
33
|
|
|
34
|
+
## Upgrading to 0.28.0
|
|
35
|
+
|
|
36
|
+
`ahub init` now takes flags for the main project settings (#1100, #1107): `--agents <a,b,...|none>`, `--sdlc off|advise|enforce`, `--coordination advisory|turn-free`, `--memory`/`--no-memory`, `--snapshots`/`--no-snapshots`, `--pi`/`--no-pi`, `--specs`/`--no-specs`, `--spec-review off|report|require` and, for a new project only, `--autonomy inherit|off`. On an existing project only a flag you give changes anything, `--dry-run` shows each change as old -> new, and an invalid value is refused with the allowed values. Run at a terminal on a new project with none of these flags and no `--yes`, `ahub init` asks each setting with its default in brackets and shows the plan before it writes anything; `--yes` takes the defaults, and a pipe, a peer or `--dry-run` is never asked (#1110). Design specs are new and on by default (#1097, #1102, #1107). A design spec is a Markdown file with `id` and `type` frontmatter. `ahub specs list|check|covers` reads the specs and checks their links and freshness without a daemon, agents get the read-only `hub_specs`, and `ahub status` adds a specs line when the project has specs. `ahub specs stamp` is your own record, made at a terminal, that you reviewed a spec against HEAD (see [design spec inspection](operations.md#design-spec-inspection)). The next `ahub init` in an existing project adds an `AGENT_HUB_SPECS` block to `AGENTS.md` unless the project set `specs.enabled` to false; `ahub init --no-specs` turns specs off and removes the block.
|
|
37
|
+
|
|
38
|
+
Agents now read the task board in pages: `hub_task_list` returns 50 compact rows by default with a `next` cursor, and `ids` or `detail: true` give full rows (#1083); `ahub board` from your terminal is unchanged. A task can declare `needs_network` or `needs_worktree` (`ahub task propose --needs-network|--needs-worktree`), and such work is no longer offered to a peer that cannot meet the need, such as a sandboxed Pi or local worker (#1081). An urgent task can take back offers its owner never accepted when they are all that fill its WIP limit (#1080). When the reply to a `hub_task_propose` or `hub_review` is lost, the call reports `outcome: unknown` with a `request_id` to reuse, so a retry does not file a duplicate (#1078). A busy agent can settle its own `needs_review` delivery with `hub_delivery_resolve`, and `hub_inbox` reads new messages queued behind a held one (#1079). `ahub queue discard --peer <id>` without `--state` now also clears the peer's unsettled failed deliveries, `--state failed` names failed deliveries alone, and `ahub queue list` hides rows a resolution already settled unless `--all` (#1103). Crash-recovery notices in `ahub status` clear once their condition is gone (#1082), and a start refused during a recovery hold says why and what to run (#1104). A backlog card with a planned start is not offered before that date (#1092). Agents the hub starts no longer inherit the Orca pane's routing (#1094), and their Orca terminals open in the project root's worktree (#1105). A Jcode session that recovery restarted headless gets its TUI back with `ahub stop jcode`, then `ahub jcode` (#1093). `ahub setup` keeps plugin rows it did not install (#1073, #1074). The reviewer checklist in the shipped profiles now asks that error messages state the cause and the next step; a profile override or a pack replaces that checklist and does not get the new item (#1109). Codex 0.166.0 is now a verified reviewer version (#1071), and the hub exact-pins `@staix/agent-mem` 0.19.0, which shares its index and hook records with 0.18.0 (#1072). As for 0.27.0, update the global CLI and the plugin yourself afterwards with `bun add -g @staix/agent-hub@0.28.0`, then `ahub setup`, and restart Claude sessions so they load the 0.28.0 plugin, which adds `hub_specs` and `hub_delivery_resolve`.
|
|
39
|
+
|
|
40
|
+
## Upgrading to 0.27.0
|
|
41
|
+
|
|
42
|
+
Nothing changes until you use something new. Release consent can now come from your explicit instruction to the conductor: say in its own session which release to ship (for example "release 0.27.0"), and the configured conductor runs `ahub sdlc authorize-release <version>` for you, under the same admission as `sdlc merge`; you can still run it yourself. The approval keeps every binding it had (exact commit, version, origin and fresh docs; a restart revokes it), its record names who ran it, and a hub message, task text, review note, file or another peer's relay never counts as the instruction (#1063, #1066). Research experiments gain a read and a write: `ahub study experiments` and `hub_experiment_show` read a campaign's attempts, one attempt or one comparison (#602), and an owner records protocols, plans, attempts, events and receipts with `hub_experiment_record`, refused during a private turn (#615). Concurrent starts of one project no longer fail on a `runtime.json` replaced while it was being read (#616). As for 0.26.0, update the global CLI and the plugin yourself afterwards: `bun add -g @staix/agent-hub@0.27.0`, then `ahub setup`.
|
|
43
|
+
|
|
34
44
|
## Upgrading to 0.26.0
|
|
35
45
|
|
|
36
46
|
`ahub upgrade` now upgrades one project: the one in the current directory, or the one `--project <path|id>` names; other projects keep their running version (#1039, #1045). From a 0.25.0 CLI, run it in the project directory, since 0.25.0 refuses `--project` for upgrade; it hands over to the 0.26.0 coordinator as before. It no longer updates the global CLI or the shared Claude plugin: run `bun add -g @staix/agent-hub@0.26.0` and then `ahub setup` yourself, and `ahub doctor` warns while either is older than a running daemon. The daemon speaks control protocol 17 and still accepts 16, so a 0.25.0 plugin keeps connecting. Each project keeps its verified runtime across stop and start; start it with a 0.26.0 or later CLI, because an older CLI ignores that record (#1052). A daemon refuses a `hub.db` in a newer format and names the version it needs. `ahub up` now also starts `claude` and `codex` (see [First session](#first-session)): `ahub setup` asks once which agents (`--agents <a,b>`, `none` for no agent), `ahub settings set start.agents <a,b>` changes one project, and `ahub up --no-agents` skips them for one run; a restart, recovery or upgrade relaunch starts none (#1046). An owner can re-file `hub_task_done` on an approved, unmerged task with a new head, which sends it back to review, and a reviewer can withdraw an approval with `changes_requested` (#1049). Signed external runner receipts for research attempts are opt-in: the person registers a runner under `research.runners` in untracked `.agenthub/config.local.json` (#1050). Restart Claude sessions so they load the 0.26.0 plugin.
|
|
@@ -153,7 +163,7 @@ The restarted Claude planner gets the release-train tools (`hub_release_new`, `h
|
|
|
153
163
|
|
|
154
164
|
Jcode must be 0.98.0 or later, below 1.0.0; 0.94.0 is no longer accepted, so `ahub doctor` fails its Jcode row for an older install and the peer does not start (#529). Every owned jcode process runs with `JCODE_NO_TELEMETRY=1`.
|
|
155
165
|
|
|
156
|
-
Since 0.12.37 the hub opens a split memory home through its shards (#534); the current exact `@staix/agent-mem` pin is 0.
|
|
166
|
+
Since 0.12.37 the hub opens a split memory home through its shards (#534); the current exact `@staix/agent-mem` pin is 0.19.0. Before anyone runs `amem migrate --shards` on a memory home, every hub using that home must run 0.12.37 or later: an older hub does not see the split and keeps writing the old layout. `ahub memory profile-check` is split-aware and compares each hub with its own project's shard (#536). See [memory profiles and rollout](memory.md#selected-memory-profile).
|
|
157
167
|
|
|
158
168
|
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:
|
|
159
169
|
|
|
@@ -177,6 +187,8 @@ ahub console # use in another terminal if up used --no-console; Tab opens
|
|
|
177
187
|
ahub kimi # Kimi in its own pull-only TUI; --mode headless for the hub-driven peer
|
|
178
188
|
```
|
|
179
189
|
|
|
190
|
+
On a new project at a terminal, `ahub init` first asks each main setting (profile, agents, specs, SDLC mode, coordination, memory, snapshots and the rest) with its default in brackets. Enter keeps a default, and nothing is written until you answer y to the plan. `ahub init --yes` takes every default without asking.
|
|
191
|
+
|
|
180
192
|
`ahub up` also starts a default set of agents, `claude` and `codex` unless you choose others, each in a terminal the hub opens (`terminal.open`, or Orca). It prints one line per agent, and an agent it cannot open is named with the command to run yourself (`ahub claude`, `ahub codex`). Choose the set once with `ahub setup --agents kimi,codex` (or answer the question in `ahub setup`), change one project with `ahub settings set start.agents <a,b>`, and skip it for a run with `ahub up --no-agents`. Without a terminal provider nothing is opened and the hub keeps running; start them by hand:
|
|
181
193
|
|
|
182
194
|
```bash
|
|
@@ -226,7 +238,7 @@ More: `ahub help`. How it is built and why: [`docs/specs/2026-09-19-agent-hub-de
|
|
|
226
238
|
|
|
227
239
|
## Shared memory
|
|
228
240
|
|
|
229
|
-
The hub exact-pins the first-party `@staix/agent-mem` 0.
|
|
241
|
+
The hub exact-pins the first-party `@staix/agent-mem` 0.19.0 core, including deterministic capture; no claude-mem worker is needed. Existing shared-v1 memory remains the default; upgrading does not migrate it. Managed agents use screened `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` tools, or propose a correction with `hub_memory_correct`; only a person accepts candidates through the supported `amem review` path. Since agent-mem 0.7.0, `amem review` also accepts candidates on a selected generation.
|
|
230
242
|
|
|
231
243
|
Before any real generation migration, upgrade every hub sharing that memory home to 0.12.30 or later and check its authenticated binding with `ahub memory profile-check` in each custom registry. Ready bindings prove compatibility, not an atomic live cutover: quiesce consumers and close their handles before migrating, then reopen through the supported session-preserving lifecycle. Invalid or changed profiles disable native memory without falling back to legacy writes; the bus and board continue. See [memory operations](operations.md#hub-memory) for the remaining rollout gates.
|
|
232
244
|
|