@staix/agent-hub 0.27.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +11 -3
  3. package/docs/agent-notes/adapters.md +4 -2
  4. package/docs/agent-notes/bus.md +4 -4
  5. package/docs/agent-notes/daemon.md +7 -3
  6. package/docs/agent-notes/tasks.md +5 -0
  7. package/docs/agent-notes/tests.md +6 -5
  8. package/docs/design/adapters.md +76 -0
  9. package/docs/design/agent-hub-architecture.md +67 -0
  10. package/docs/design/agent-hub.md +52 -0
  11. package/docs/design/bus.md +48 -0
  12. package/docs/design/task-board.md +86 -0
  13. package/docs/dogfood.md +16 -1
  14. package/docs/operations.md +308 -12
  15. package/docs/profiles.md +1 -0
  16. package/docs/quickstart.md +11 -3
  17. package/docs/sdlc.md +1 -1
  18. package/docs/security.md +8 -3
  19. package/docs/smoke.md +2 -0
  20. package/docs/specs/2026-09-19-agent-hub-design.md +2 -0
  21. package/docs/verification/2026-10-31-codex-0166-reviewer-isolation.md +2 -0
  22. package/docs/verification/2026-11-02-0.28.0.md +54 -0
  23. package/docs/verification/2026-11-02-autonomy-t4.md +39 -0
  24. package/docs/verification/2026-11-02-codex-0166-reviewer-tool-call.md +53 -0
  25. package/docs/verification/2026-11-02-control-write-after.json +139 -0
  26. package/docs/verification/2026-11-02-control-write-baseline.json +127 -0
  27. package/docs/verification/2026-11-02-control-write-guarded.json +127 -0
  28. package/docs/verification/2026-11-02-control-write-outcomes.md +65 -0
  29. package/docs/verification/2026-11-02-orca-1.4.245-cli-contract.md +51 -0
  30. package/docs/verified.json +13 -13
  31. package/package.json +2 -2
  32. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  33. package/plugins/agent-hub/server.js +338 -112
  34. package/src/adapters/claude-channel.ts +12 -2
  35. package/src/adapters/compat.ts +1 -1
  36. package/src/adapters/definitions/native-cli-claude-setup.ts +31 -9
  37. package/src/adapters/definitions/native-cli-entry-jcode.ts +33 -0
  38. package/src/adapters/definitions/native-cli-entry-qwen.ts +2 -2
  39. package/src/adapters/jcode.ts +37 -4
  40. package/src/adapters/qwen-dual.ts +3 -2
  41. package/src/cli/agents.ts +4 -2
  42. package/src/cli/bench.ts +4 -2
  43. package/src/cli/board-read.ts +25 -0
  44. package/src/cli/claude-homes.ts +2 -2
  45. package/src/cli/console-state.ts +8 -3
  46. package/src/cli/help.ts +6 -5
  47. package/src/cli/identity.ts +9 -1
  48. package/src/cli/init-prompt.ts +179 -0
  49. package/src/cli/init-settings.ts +229 -0
  50. package/src/cli/init.ts +102 -9
  51. package/src/cli/launch.ts +3 -1
  52. package/src/cli/main.ts +106 -35
  53. package/src/cli/output.ts +14 -0
  54. package/src/cli/setup-homes.ts +18 -3
  55. package/src/cli/specs.ts +150 -0
  56. package/src/cli/terminal-recovery.ts +35 -11
  57. package/src/hub/board.ts +56 -3
  58. package/src/hub/bus.ts +54 -7
  59. package/src/hub/child-process.ts +6 -4
  60. package/src/hub/config-apply.ts +4 -1
  61. package/src/hub/config-edit.ts +1 -1
  62. package/src/hub/config-tier.ts +1 -0
  63. package/src/hub/control-client.ts +28 -4
  64. package/src/hub/cost-governance.ts +22 -6
  65. package/src/hub/crash.ts +20 -0
  66. package/src/hub/daemon.ts +304 -56
  67. package/src/hub/delivery-hints.ts +6 -3
  68. package/src/hub/delivery-journal.ts +14 -3
  69. package/src/hub/hub-tools.ts +10 -6
  70. package/src/hub/peers.ts +1 -1
  71. package/src/hub/review-brief.ts +18 -0
  72. package/src/hub/routing.ts +7 -3
  73. package/src/hub/settings.ts +2 -0
  74. package/src/hub/specs-config.ts +43 -0
  75. package/src/hub/specs-task.ts +108 -0
  76. package/src/hub/specs.ts +1008 -0
  77. package/src/hub/task-list-page.ts +75 -0
  78. package/src/hub/task-sweep.ts +10 -1
  79. package/src/hub/tasks.ts +448 -40
  80. package/src/hub/terminal-open.ts +10 -5
  81. package/src/hub/tool-request.ts +131 -0
  82. package/src/ui/office-model.ts +17 -1
  83. package/src/ui/office-space.ts +1 -1
  84. package/templates/config.json +1 -0
  85. package/templates/profiles/dev.json +1 -0
  86. package/templates/profiles/general.json +1 -0
  87. package/templates/profiles/research.json +1 -0
  88. package/templates/profiles/writing.json +1 -0
  89. package/templates/specs.block.md +5 -0
@@ -1,6 +1,6 @@
1
1
  # Operations guide
2
2
 
3
- This guide describes ahub 0.27.0 and control protocols 16 through 17. Live verification
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
- `ahub queue discard --peer <id> --reason <text> [--state queued|needs_review] [--yes] [--json]` clears one peer's backlog and is for the person or the configured conductor (any other agent identity is
390
- 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 queued (default) or `needs_review` delivery of that peer through the
391
- 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. Only the
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. `ahub setup`
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.
@@ -2062,6 +2195,16 @@ A newly initialized `ahub init` project inherits a trusted machine opt-in and sa
2062
2195
 
2063
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.
2064
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
+
2065
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.
2066
2209
 
2067
2210
 
@@ -2489,6 +2632,100 @@ Rules:
2489
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.
2490
2633
  - The hub must run this release: an older hub answers `unknown message` and the command says to upgrade and restart it.
2491
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
+
2492
2729
  ## Start modes: TUI by default, headless as opt-in
2493
2730
 
2494
2731
  A peer that has a TUI the hub attaches to starts in it by default (issue #269).
@@ -2502,6 +2739,19 @@ A peer that has a TUI the hub attaches to starts in it by default (issue #269).
2502
2739
  | jcode (optional) | `tui` on the hub-owned ACP session (`ahub jcode`) | `ahub jcode --mode headless`, or `peers.jcode.start_mode: headless` |
2503
2740
  | local | headless (hub-native) | not applicable |
2504
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
+
2505
2755
  - **You type the command:** `ahub pi` opens Pi's TUI in that terminal.
2506
2756
  `--headless` and the start mode setting are the two ways to ask for the
2507
2757
  background peer. `ahub settings set peers.pi.start_mode headless` writes the
@@ -2520,7 +2770,14 @@ A peer that has a TUI the hub attaches to starts in it by default (issue #269).
2520
2770
  `{command}` is quoted for a POSIX shell; `{title}` and `{cwd}` are raw,
2521
2771
  so give each an argv element of its own.
2522
2772
  2. Orca, when the hub runs in an Orca worktree or an earlier `ahub <peer>`
2523
- 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.
2524
2781
  - **No provider:** the start is refused with the command to run by hand. It is
2525
2782
  never downgraded to headless. `ahub settings` lists each start mode, and the
2526
2783
  dashboard's Start control says which mode a start will use and where its
@@ -2920,6 +3177,13 @@ the history entry reads `by: hub` with that planner and the reason
2920
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
2921
3178
  the other machine-local policies it is ignored there with a log line.
2922
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
+
2923
3187
  ## Resetting a project's hub
2924
3188
 
2925
3189
  `ahub reset` returns a project's hub to a clean state. Without `--yes` it is a
@@ -3126,7 +3390,7 @@ version is older than the selected running daemon; it installs nothing.
3126
3390
  | Runtime | Control protocol window | Legacy status field |
3127
3391
  | --- | --- | --- |
3128
3392
  | 0.12.20 through 0.25.0 | 16 only | `protocol: 16` |
3129
- | 0.26.0 through 0.27.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` |
3130
3394
 
3131
3395
  New clients choose the highest common protocol. The runtime supports N-1, so the
3132
3396
  published protocol-16 client and channel plugin remain usable; unrelated feature
@@ -3731,6 +3995,20 @@ crash of one is not reported this way.
3731
3995
  - Codex's app-server died with the hub; run `ahub codex` again. Claude Code's
3732
3996
  plugin reconnects by itself while that session is open.
3733
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
+
3734
4012
  ## Evidence and limits
3735
4013
 
3736
4014
  The 0.6.4 release has real measurements in [the smoke checklist](smoke.md):
@@ -4081,7 +4359,7 @@ has appeared for `AHUB_CHECK_QUIET_S` seconds (300 by default, set to 300 in CI)
4081
4359
  slow suite that is still passing tests is never cut. `scripts/progress-tee.sh` passes bun's
4082
4360
  output through unchanged and appends one byte to a progress file for each of those lines;
4083
4361
  the watchdog polls that file's size. On a stop it prints where the run is and the process
4084
- table below it first. `AHUB_CHECK_HANG_S` (960 by default) is only the backstop for a run
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
4085
4363
  that keeps printing results while hung; hosted CI sets 1500 on Linux inside a 35-minute
4086
4364
  job limit (#378, #593, #752, task 516). The macOS leg runs as four shards (#548): `AHUB_CHECK_SHARD=i/n`
4087
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
@@ -4409,6 +4687,16 @@ Use `ahub roster add jcode`, then `ahub jcode [--model <alias>] [--provider-prof
4409
4687
 
4410
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.
4411
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
+
4412
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.
4413
4701
 
4414
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.
@@ -4690,6 +4978,14 @@ admission reads, and the split changes no admission decision. An older hub shows
4690
4978
  acceptance and self-claim in every lifecycle mode, so 0 refuses new acceptances; a
4691
4979
  current owner's redo of sent-back work keeps its slot (#481 S9).
4692
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
+
4693
4989
  Pending unowned, unstarted pull can be undone at its latest owned revision via
4694
4990
  `hub_backlog_undo` or the existing planning undo control, restoring its earlier
4695
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
@@ -5073,7 +5369,7 @@ A reviewer has a review scope (#852): `full` (reads the code, runs the affected
5073
5369
 
5074
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.
5075
5371
 
5076
- Codex requires a verified `codex-cli` (0.146.0, 0.163.0 or 0.164.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), but its [one authorized model review](verification/2026-10-31-codex-0166-reviewer-tool-call.md) missed the required synthetic marker in the persisted verdict, so the version remains unverified and its proposed verified bump was reverted. 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.
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.
5077
5373
 
5078
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.
5079
5375
 
package/docs/profiles.md CHANGED
@@ -54,6 +54,7 @@
54
54
  # Project profile overrides
55
55
 
56
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.
57
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.
58
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.
59
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.
@@ -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.27.0
20
+ bun add -g github:STAIxBWLB/agent-hub#v0.28.0
21
21
  ahub setup
22
22
  ```
23
23
 
@@ -31,6 +31,12 @@ 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
+
34
40
  ## Upgrading to 0.27.0
35
41
 
36
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`.
@@ -157,7 +163,7 @@ The restarted Claude planner gets the release-train tools (`hub_release_new`, `h
157
163
 
158
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`.
159
165
 
160
- Since 0.12.37 the hub opens a split memory home through its shards (#534); the current exact `@staix/agent-mem` pin is 0.18.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).
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).
161
167
 
162
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:
163
169
 
@@ -181,6 +187,8 @@ ahub console # use in another terminal if up used --no-console; Tab opens
181
187
  ahub kimi # Kimi in its own pull-only TUI; --mode headless for the hub-driven peer
182
188
  ```
183
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
+
184
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:
185
193
 
186
194
  ```bash
@@ -230,7 +238,7 @@ More: `ahub help`. How it is built and why: [`docs/specs/2026-09-19-agent-hub-de
230
238
 
231
239
  ## Shared memory
232
240
 
233
- The hub exact-pins the first-party `@staix/agent-mem` 0.18.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.
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.
234
242
 
235
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.
236
244
 
package/docs/sdlc.md CHANGED
@@ -17,7 +17,7 @@ The built-in lifecycle follows the [AI-Native SDLC Playbook](https://claude.com/
17
17
  | plan | Build | planner/owner | plan, branch, existing predecessor gates | current planner review required at build admission; literal-path conformance gates approval in enforce | agent-executable |
18
18
  | build | Build | owner | PR identity/current head and local check on that head | entering review, when enabled | agent-executable |
19
19
  | test | Test | verifier/reviewer | required checks and local gate on the reviewed head | approval, when enabled; bug test integrity and the configuration-PR eval gate below | agent-executable |
20
- | review | Deploy | assigned reviewer | current head-bound verdict, no pending change request/open thread; AC checklist under Compliance | approval, when enabled; open Important findings block in enforce | agent-executable |
20
+ | review | Deploy | assigned reviewer | current head-bound verdict, no pending change request/open thread; AC checklist under Compliance; each new or changed error, refusal or failure message names its cause and next step (Bugs pass, #1095) | approval, when enabled; open Important findings block in enforce | agent-executable |
21
21
  | merge | Deploy | person | current-head readiness, ordered touching PRs | shown; the guarded merge below runs only when `auto_merge` is `on` (default off) | agent-executable where the project's AGENTS.md delegates it to the approving reviewer (this repository does, #784); the hub still shows the person as actor |
22
22
  | release | Deploy | person | merged commit, version/tag, docs freshness/live receipt checklist | person authorization and optional tag hook below | agent-evidence / person-verdict (consent) |
23
23
  | maintain | Maintain | person/planner | follow-up intent and operational evidence | shown; metrics and control bands from S7 (`ahub sdlc metrics`) | agent-executable |