@staix/agent-hub 0.12.31 → 0.12.32

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 (73) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +13 -7
  3. package/docs/agent-notes/adapters.md +7 -4
  4. package/docs/agent-notes/bus.md +1 -0
  5. package/docs/agent-notes/daemon.md +10 -7
  6. package/docs/agent-notes/local-worker.md +1 -1
  7. package/docs/agent-notes/tasks.md +3 -2
  8. package/docs/agent-notes/tests.md +1 -0
  9. package/docs/cooperbench.md +1 -1
  10. package/docs/gsd-collaboration-analysis.md +1 -1
  11. package/docs/memory.md +1 -1
  12. package/docs/operations.md +114 -22
  13. package/docs/quickstart.md +10 -6
  14. package/docs/security.md +12 -8
  15. package/docs/smoke.md +34 -0
  16. package/docs/specs/2026-09-19-agent-hub-design.md +204 -0
  17. package/docs/specs/2026-09-20-upgrade-recovery-design.md +191 -0
  18. package/docs/verification/2026-10-18-0.12.32.md +54 -0
  19. package/docs/verified.json +20 -15
  20. package/package.json +2 -2
  21. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  22. package/plugins/agent-hub/server.js +1296 -26
  23. package/src/adapters/acp.ts +5 -6
  24. package/src/adapters/definitions/builtin-metadata.ts +121 -0
  25. package/src/adapters/definitions/kimi-native.ts +4 -0
  26. package/src/adapters/definitions/qwen-native.ts +24 -0
  27. package/src/adapters/definitions/qwen.ts +71 -0
  28. package/src/adapters/pi.ts +6 -2
  29. package/src/adapters/registry-types.ts +174 -0
  30. package/src/adapters/registry.ts +36 -0
  31. package/src/cli/console-state.ts +74 -5
  32. package/src/cli/console.ts +35 -2
  33. package/src/cli/help.ts +3 -1
  34. package/src/cli/identity.ts +13 -3
  35. package/src/cli/launch.ts +1 -6
  36. package/src/cli/main.ts +200 -39
  37. package/src/cli/output.ts +2 -0
  38. package/src/cli/preview.ts +8 -5
  39. package/src/cli/recovery-guidance.ts +137 -0
  40. package/src/cli/recovery-presentation-options.ts +8 -0
  41. package/src/cli/recovery-session-file.ts +18 -0
  42. package/src/cli/terminal-recovery.ts +48 -0
  43. package/src/cli/upgrade-interactive.ts +129 -75
  44. package/src/cli/upgrade-labels.ts +30 -0
  45. package/src/cli/upgrade-presentation-data.ts +41 -0
  46. package/src/cli/upgrade-presentation-flags.ts +31 -0
  47. package/src/cli/upgrade-presentation.ts +217 -0
  48. package/src/cli/upgrade-restore-state.ts +6 -2
  49. package/src/cli/upgrade-runtime.ts +345 -194
  50. package/src/cli/upgrade.ts +276 -25
  51. package/src/hub/bus.ts +11 -0
  52. package/src/hub/cohorts.ts +2 -2
  53. package/src/hub/config-apply.ts +242 -0
  54. package/src/hub/config-reload.ts +120 -0
  55. package/src/hub/config-trust.ts +11 -2
  56. package/src/hub/crash.ts +8 -6
  57. package/src/hub/daemon.ts +559 -170
  58. package/src/hub/events.ts +2 -2
  59. package/src/hub/manager.ts +1 -1
  60. package/src/hub/peer-catalog.ts +10 -13
  61. package/src/hub/peers.ts +12 -2
  62. package/src/hub/permission-mode.ts +5 -3
  63. package/src/hub/recovery-continuity.ts +152 -0
  64. package/src/hub/recovery-store.ts +10 -4
  65. package/src/hub/sdlc.ts +5 -1
  66. package/src/hub/settings.ts +50 -36
  67. package/src/hub/settled-roles.ts +35 -0
  68. package/src/hub/supervision.ts +3 -2
  69. package/src/hub/tasks.ts +28 -8
  70. package/src/hub/ui.ts +1 -1
  71. package/src/memory/brief.ts +6 -5
  72. package/src/pi/session.ts +23 -4
  73. package/src/ui/index.html +23 -7
@@ -1,6 +1,6 @@
1
1
  # Operations guide
2
2
 
3
- This guide describes ahub 0.12.31 and control protocol 16. Live verification
3
+ This guide describes ahub 0.12.32 and control protocol 16. Live verification
4
4
  results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
5
5
 
6
6
  ## Agent-operated live verification
@@ -120,7 +120,7 @@ sounds on an action-count transition from zero, at most once per minute, never
120
120
  for a message alone. Plain mode prints the line only when the action count changes.
121
121
  Messages addressed to `user` remain attention items until the next key. Drawing
122
122
  adds no timer, network request or writable settings path.
123
- Tabs change with the digits 1 to 5 or with Left and Right (wrapping at both
123
+ The operational tabs change with digits 1 to 5 or Left and Right (wrapping at both
124
124
  ends), never while a command is being edited or a choice is open; under a
125
125
  confirmation an arrow dismisses it like any key but y, without moving a tab. A pasted
126
126
  chunk can only edit the command line, but a read that holds nothing but arrow or
@@ -135,7 +135,7 @@ the stream; only the header is tab-flattened before tokenizing. Body lines retai
135
135
  the previous rendering and stay plain, as does command output; colour never changes
136
136
  what the panel's text says.
137
137
 
138
- Peers, Approvals, Tasks and Queue are tables with a header row. A column is as
138
+ Peers, Approvals, Tasks, Queue and Settings are tables with a header row. A column is as
139
139
  wide as its widest cell, up to a third of the terminal; the last column takes
140
140
  the rest and is cut with `...`. In Tasks, TITLE takes the rest and the STAGE
141
141
  meter keeps a fixed column at the right edge.
@@ -146,6 +146,7 @@ meter keeps a fixed column at the right edge.
146
146
  | Approvals | ID PEER LEFT TITLE |
147
147
  | Tasks | ID STATE OWNER REVIEWER CLASS AGE TITLE STAGE |
148
148
  | Queue | ID PEER STATE REV AGE |
149
+ | Settings | GROUP KEY VALUE SOURCE APPLIES |
149
150
 
150
151
  The MODE column appears only when at least one peer has a non-`ask` mode.
151
152
  Zero counters and unknown values read `-`. Durations read `45s`, `12m`, `3h05m`
@@ -1436,6 +1437,16 @@ override them.
1436
1437
 
1437
1438
  ## Settings from the dashboard and the terminal
1438
1439
 
1440
+ In `ahub console`, press `6` for Settings. Existing operational-tab arrow cycling
1441
+ is unchanged; from Settings, Left returns to Events and Right to Peers. Select a
1442
+ row and press `e` to edit: value, daemon preview, nonempty reason, then `y`. Press
1443
+ `u` to preview and confirm undo. Undo binds the key and exact undo-record digest;
1444
+ if another write replaces that record, preview again. For busy roster removal,
1445
+ the panel names `ahub roster remove <peer> --now`, which explicitly stops an owned
1446
+ runtime or detaches a native session during its active turn; the panel does not force it.
1447
+ Esc cancels, and pasted confirmation text cannot
1448
+ write. This panel uses the current authenticated daemon connection.
1449
+
1439
1450
  The dashboard's Settings section and `ahub settings` show and change the same
1440
1451
  closed list of settings (issue #269). Run them from a plain terminal:
1441
1452
 
@@ -1447,17 +1458,21 @@ ahub settings set routing.classes.implement.peers codex,kimi,pi
1447
1458
  ahub settings set permission_modes.kimi ask-when-needed
1448
1459
  ahub settings set research.enabled inherit # remove the machine-local value
1449
1460
  ahub settings undo # put back the file the last write changed
1461
+ ahub settings reload # validate and apply the complete four-file candidate
1450
1462
  ahub ui --settings # dashboard with a 15-minute settings session
1451
1463
  ```
1452
1464
 
1453
1465
  | Group | Keys | Stored in | Applies |
1454
1466
  | --- | --- | --- | --- |
1455
1467
  | Permissions | `permission.<peer>` (the mode now) | the running hub only | at once |
1456
- | Permissions | `permission_modes.<peer>` (the mode at hub start) | `config.local.json` | next hub start |
1468
+ | Permissions | `permission_modes.<peer>` (the default mode) | `config.local.json` | next peer start |
1457
1469
  | Start | `peers.pi.start_mode`, `peers.codex.start_mode`, `peers.kimi.start_mode` (`tui` or `headless`) | `config.local.json` | that peer's next start |
1458
- | Start | `pi.auto_start` | `config.local.json` | next hub start |
1470
+ | Start | `pi.auto_start` | `config.local.json` | next startup/recovery auto-start decision; never starts a peer merely on reload |
1459
1471
  | Routing | `routing.stay_switch`, `routing.classes.<class>.peers`, `.escalate_to`, `.route`, `.pi_backend` | `routing.local.toml` | at once |
1460
- | Switches | `research.enabled`, `approvals.notify`, `snapshots.enabled`, `coordination` | `config.local.json` | next hub start |
1472
+ | Switches | `research.enabled`, `approvals.notify`, `snapshots.enabled` | `config.local.json` | live, without disturbing an active turn |
1473
+ | Switches | `coordination` | `config.local.json` | newly created tasks only |
1474
+ | Switches | `task_sweep.enabled`, `.auto_reassign`, `.interval_s`, `.unaccepted_min`, `.idle_min`, `.review_min`, `.ready_min`, `.ladder_min` | `config.local.json` | live; reschedules the sweep timer |
1475
+ | Routing | `tasks.wip_limits.<peer>` | `config.local.json` | live |
1461
1476
  | Roles | `planner` (the one peer that plans) | `config.local.json` | at once |
1462
1477
 
1463
1478
  - Writes go only to `.agenthub/config.local.json` and `.agenthub/routing.local.toml`,
@@ -1470,8 +1485,28 @@ ahub ui --settings # dashboard with a 15-minute settings session
1470
1485
  file each value comes from. `--preview`, and the dashboard's Preview button,
1471
1486
  show `ahub route explain` for the open tasks before and after, or what a
1472
1487
  permission mode grants, and save nothing.
1473
- - A row shows the value in force, its source file, when it applies, and for a
1474
- value read at hub start what the next start will read (`Pending restart`).
1488
+ - A row shows running and file values, source and apply class (`live`, `next use`,
1489
+ or `restart`). Pending restart keys and reasons also appear in status, console
1490
+ and dashboard, including startup-only blocks outside the editable registry.
1491
+ - Settings writes and undo, the dashboard Reload configuration button and
1492
+ `ahub settings reload` use one complete validation/apply path. Debounced changes
1493
+ of config.json, config.local.json, routing.toml and routing.local.toml use it too,
1494
+ including atomic file replacement. Invalid candidates apply nothing and emit
1495
+ one bounded error notice. Valid but unauthorized keys retain their accepted value and are reported per key; other eligible changes still apply. Recovery/shutdown hold reloads.
1496
+ - Individual writes and undo publish only the named setting. Other file edits remain unapplied.
1497
+ - `ahub settings reload` lists guarded keys with complete before -> after values (including full argv) and any planner/conductor holder effect. It requires an interactive terminal and exact `y` within 30 seconds before adopting them. Oversized previews remain unapplied and must be split or reduced. Candidate bytes or accepted state changes invalidate that confirmation. Watchers and ordinary dashboard reloads never confirm a raise.
1498
+ - Privacy tightening (local PII constraints/screening, added PII patterns, nonholder role reductions and explicit capability-list narrowing) is automatic, including tracked files. A planner/conductor holder change is guarded even when a role list shrinks; deleting a restricted capability entry restores all capabilities and is guarded. Reload checks the actual files' Git provenance. Changed machine-local or raising
1499
+ values from tracked/unverifiable files are refused; an ordinary dashboard or
1500
+ watcher cannot adopt unrelated raising local edits. A settings session cannot
1501
+ adopt routing fields outside its editable registry. Existing confirmation and
1502
+ roster lifecycle fences remain; use the confirmed roster setting for membership.
1503
+ Pi relay model aliases (`pi.dgx_coding`, `pi.dgx_fast`) and `routing.pi` retain their running values until restart, because existing native sessions use the published relay catalogue and context contract. Routing policy changes apply to future decisions; local model/target changes apply at the next peer or sidecar creation.
1504
+
1505
+ - Runtime/client ownership still requires restart for memory handles and sync,
1506
+ gateway/MLX, runner/check commands, profile/tool contracts, converters, existing
1507
+ session privacy/sandbox policies, the terminal provider and benchmark environment.
1508
+ The exhaustive reasons are in the issue #439 spec amendment. A pending file value
1509
+ is not applied to the running consumer. Coordination creation pins last for the daemon lifetime; a restart re-pins retained rows to its startup mode.
1475
1510
  - `ahub settings undo` (the dashboard's "Undo last write") puts back the one
1476
1511
  previous version of the file the last write changed. It refuses when that
1477
1512
  file was edited since, and when it would put a stored never-ask back (set it
@@ -1484,10 +1519,11 @@ ahub ui --settings # dashboard with a 15-minute settings session
1484
1519
  `.agenthub/routing.local.toml`: run `ahub init` again, or add it. A
1485
1520
  `permission_modes` value is read only from a file git confirms nobody
1486
1521
  committed (config trust); where the hub will not read what was written, the
1487
- reply and the Settings row say so.
1522
+ reload refuses the guarded candidate and the Settings row identifies the file.
1488
1523
  - Authority: a dashboard opened with `ahub ui` reads settings, lowers a mode to
1489
- `ask`, turns `pi.auto_start` off, sets a start mode back to `tui` and changes
1490
- the Switches group. Everything
1524
+ `ask`, turns `pi.auto_start` off, sets a start mode back to `tui`, sets a WIP
1525
+ limit to 0, turns `task_sweep.enabled` or `.auto_reassign` off and changes
1526
+ the other Switches. Everything
1491
1527
  else needs `ahub ui --settings`, whose session may raise for 15 minutes, or
1492
1528
  `ahub settings` in a terminal. `never-ask` needs the peer id typed in the
1493
1529
  dashboard, or `--yes` in the terminal, and a stored never-ask default still
@@ -1913,21 +1949,21 @@ section is what they run.
1913
1949
 
1914
1950
  Upgrade running projects with the target release's own coordinator. It accepts
1915
1951
  a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
1916
- 11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.31), and only
1952
+ 11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.32), and only
1917
1953
  a target on its own protocol, so the target's coordinator fits every supported
1918
1954
  source and carries every recovery fix released up to it. Protocol 8 and older
1919
1955
  (0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
1920
1956
  project directory, without replacing the global CLI first:
1921
1957
 
1922
1958
  ```bash
1923
- bunx --package @staix/agent-hub@0.12.31 ahub upgrade --to 0.12.31 --dry-run
1924
- bunx --package @staix/agent-hub@0.12.31 ahub upgrade --to 0.12.31 --yes
1959
+ bunx --package @staix/agent-hub@0.12.32 ahub upgrade --to 0.12.32 --dry-run
1960
+ bunx --package @staix/agent-hub@0.12.32 ahub upgrade --to 0.12.32 --yes
1925
1961
  ```
1926
1962
 
1927
1963
  | Running now | Coordinator to use |
1928
1964
  | --- | --- |
1929
1965
  | 0.6.x (protocol 9) | the target's, through `bunx` as above |
1930
- | 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.31 (protocol 16) | the target's, through `bunx` as above |
1966
+ | 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.32 (protocol 16) | the target's, through `bunx` as above |
1931
1967
  | any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
1932
1968
  | 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
1933
1969
 
@@ -1959,17 +1995,18 @@ projects first:
1959
1995
 
1960
1996
  ```bash
1961
1997
  ahub restart --dry-run
1962
- ahub upgrade --to 0.12.31 --dry-run
1998
+ ahub upgrade --to 0.12.32 --dry-run
1963
1999
  ```
1964
2000
 
1965
2001
  Apply only after reviewing the plan:
1966
2002
 
1967
2003
  ```bash
1968
2004
  ahub restart --yes
1969
- ahub upgrade --to 0.12.31 --yes
2005
+ ahub upgrade --to 0.12.32 --yes
1970
2006
  ahub recovery status [<operation-id>]
1971
2007
  ahub recovery resume [<operation-id>]
1972
2008
  ahub recovery abort [<operation-id>]
2009
+ ahub recovery reattach <operation-id> codex|claude|pi
1973
2010
  ahub recovery dispose [<operation-id>] --fresh-session <peer> --reason <text>
1974
2011
  ahub recovery dispose [<operation-id>] --stop-and-archive --reason <text>
1975
2012
  ```
@@ -2070,6 +2107,16 @@ through a pipe, the JSON plan, the `ahub: blocker:` lines and the exit codes are
2070
2107
  unchanged. The screens add no way to change an operation: every choice runs one
2071
2108
  of the commands in this section for you, so that command's refusals decide.
2072
2109
 
2110
+ The screens use the console palette and `--color=auto|always|never`, with the
2111
+ same `NO_COLOR` and `TERM=dumb` precedence. Auto colours a suitable TTY; explicit
2112
+ always has the console's override behaviour. Raw JSON bypasses colour and width
2113
+ handling. Default and never preserve the existing pipe, dry-run, status and
2114
+ dispose output byte for byte. Presentation flags go after the command, for
2115
+ example `ahub recovery --color=never` or
2116
+ `ahub recovery status <operation-id> --json`. An explicit `--json` returns only
2117
+ the raw document, without a human suffix. `upgrade --json` reviews a JSON plan;
2118
+ `--yes` is still needed to apply it without the interactive review.
2119
+
2073
2120
  The plan screen lists each project with its hub version and, per attached peer,
2074
2121
  its state, how it runs (`TUI` in a terminal the plan bound to its session,
2075
2122
  `headless` as the hub's own process, `own` for a session the hub did not
@@ -2102,23 +2149,35 @@ plan shows the ended agents as offline.
2102
2149
 
2103
2150
  After apply the command stays attached and prints each step as the receipt
2104
2151
  records it, and while a source is being prepared, what it still waits for.
2152
+ Each reported step has a status mark and elapsed observation time. Resume lists
2153
+ only steps observed on that attempt and says `resuming from ...` once. Its stage
2154
+ step really runs again and is labelled `checking retained release`. Waits use
2155
+ the coordinator's actual recorded start and deadline, for example
2156
+ `[waiting] alpha: restoring Codex and Pi sessions (waiting 2m10s of 10m)`.
2157
+ Older receipts without timing metadata say `timing unknown`; updatedAt is never
2158
+ used as a substitute. Timing-only save failures log a warning and do not fail
2159
+ the operation. Stable waits print only on change and at most once per minute.
2160
+ Approval waits point to `ahub console`; native attachment waits point to the
2161
+ recorded launch and conversation. Korean text and
2162
+ long paths wrap to the measured width on plan, progress and menu screens.
2105
2163
  Enter opens the operation's screen while the runner works on. Ctrl+C leaves the
2106
2164
  command, at any prompt and while following, and never stops the runner: the
2107
- `left:` line names the command that comes back to the screen, with the
2108
- operation's own coordinator, because the installed `ahub` is the older release
2109
- until the upgrade ends. A Ctrl+C between `a` and the start of the operation
2165
+ `left:` line names `ahub recovery status <operation-id>`. Use `--verbose` for
2166
+ the internal command with the operation's retained coordinator, because the
2167
+ installed `ahub` may still be the older release until the upgrade ends. A Ctrl+C between `a` and the start of the operation
2110
2168
  starts nothing. A prompt for a reason that is answered with
2111
2169
  Ctrl+C or the end of input ends nothing.
2112
2170
 
2113
2171
  The operation's screen also opens first whenever an operation holds the lock,
2114
2172
  and for bare `ahub recovery`. It shows the phase and step, each project's phase
2115
- and effect receipts and the error, then the choices that `status` lists under
2173
+ and human outcome labels, then What happened / Why / What to do and the choices that `status` lists under
2116
2174
  `next` for the same receipt and live state:
2117
2175
 
2118
2176
  | Key | Runs | Offered when |
2119
2177
  | --- | --- | --- |
2120
2178
  | `r` | `recovery resume`, then follows | resume can get past what is live |
2121
2179
  | `c` | `recovery abort` | no runtime was stopped and no terminal effect or commit request is recorded |
2180
+ | `a` | `recovery reattach <id> <peer>` | the recorded detached session is eligible for reattachment |
2122
2181
  | `f` | `recovery dispose --fresh-session <peer>`, after a reason | a Codex or Claude restoration failed |
2123
2182
  | `e` | `recovery dispose --stop-and-archive`, after a confirmation and a reason | every unverified project reads as running, stopped or missing |
2124
2183
  | `x` | `e`, then the reset below | as `e` |
@@ -2128,6 +2187,26 @@ When more than one restoration failed, the second and later peers get
2128
2187
  `f-<peer>`. `s` refreshes the screen, `j` prints the receipt as JSON and `q`
2129
2188
  leaves the operation as it is.
2130
2189
 
2190
+ The marked recommendation is a read-only Enter default: refresh the plan, follow
2191
+ an active runner, read the receipt or refresh the operation. Apply, resume and
2192
+ reattach require their explicit keys; buffered Enter never starts them. Unknown failures recommend
2193
+ reading `j` before retrying effects. A wait whose runner cannot be verified is
2194
+ shown disabled with its reason, and cannot run a command. Stop, archive, reset
2195
+ and fresh-session choices carry a warning and name the consequence before the
2196
+ person confirms. Raw receipt keys and the original recorded error are available
2197
+ with `j` or `--verbose`. The four preservation failures name the actual failed
2198
+ queue, manual-pause, board or budget comparison; an older untyped cause remains
2199
+ unknown rather than being guessed from its text.
2200
+
2201
+ Completion and stop-and-archive use a human summary on a TTY. It separates the
2202
+ outcome, recorded plugin/global installation effects, remaining work and the
2203
+ per-peer session commands. An optional fresh read-only inspection names the
2204
+ current hub version; a failed reading says `runtime unknown`, never a guessed
2205
+ version from the plan. The summary performs no lifecycle action. Use `j` or
2206
+ `--json` for the full receipt; JSON is intentionally exempt from human wrapping.
2207
+ For a long command, copy the exact single-line value from `j` or the status JSON;
2208
+ the width-wrapped human preview is for reading.
2209
+
2131
2210
  While a runner is only waiting for its source to get quiet (step `prepare`, no
2132
2211
  effect recorded), `c` stops that runner and then aborts. It is offered only for
2133
2212
  a runner whose claim carries a process signature that still matches; a claim
@@ -2281,11 +2360,23 @@ next actions").
2281
2360
  unpinned signature too, so it counts as running when this command runs in
2282
2361
  the same time zone and locale as the launcher did. `resume` is refused while a stop-and-archive is partway. A lifecycle command refused by the lock names
2283
2362
  the operation's own `status` command, which lists what to do next.
2363
+ - `ahub recovery reattach <operation-id> codex|claude|pi` is person-only, including during live verification: an agent shell cannot delegate it. Name the operation and exactly one peer; session, backend, model and terminal overrides are not accepted. Use the exact operation-coordinator command printed by status or its blocked guidance. It repairs only that peer and leaves the operation blocked; run the offered `recovery resume` command to continue the remaining steps.
2364
+ The CLI delegates only when the retained coordinator supports reattach. An existing older coordinator without that action uses this release's implementation instead; a missing receipt, retained coordinator path or coordinator file prints inspection/recovery guidance and starts no session.
2365
+ A peer that attached and later went offline can be re-restored once when its saved terminal is positively orphaned or missing and no current or older operation launcher may still run. The recorded session id and Pi session file stay fixed; the new terminal binding is saved before waiting for authenticated attachment. A second detach blocks. An unreadable terminal, changed incarnation or worktree, disconnected-only evidence, truncated inventory or live/unknown launcher does not authorize another terminal.
2366
+ Recovery status names the saved Codex thread, Pi session file and Claude session, the terminal evidence, and the applicable reattach command. A different attached conversation remains a strict refusal.
2284
2367
  - `ahub recovery dispose <operation-id> --fresh-session <peer> --reason <text>`
2285
2368
  applies to a Codex or Claude peer whose restoration failed (Pi is refused: a
2286
2369
  restored hub resumes Pi's recorded session). It records the lost session or
2287
2370
  thread id (status shows it under `lostContinuity`) and resumes: the peer
2288
2371
  starts without its old conversation, and the rest is verified as usual.
2372
+ A session the operation already reattached keeps that repaired provenance
2373
+ across target restarts and is never replaced automatically. Its
2374
+ loss can be accepted only after the restoration reported the recorded Claude
2375
+ transcript or Codex rollout as positively missing, naming the checked path;
2376
+ dispose checks that path again before saving the choice and otherwise refuses
2377
+ with "recorded conversation is not positively missing". Under `--live-test`
2378
+ this repaired-session choice is refused even where an ordinary fresh session
2379
+ may be delegated.
2289
2380
  - `ahub recovery dispose <operation-id> --stop-and-archive --reason <text>`
2290
2381
  abandons the operation. It checks every project first and refuses while a
2291
2382
  hub is unreachable, starting, stopping or of another control protocol; `next`
@@ -2332,7 +2423,8 @@ next actions").
2332
2423
  again.
2333
2424
  Start a project whose target ran with that release's CLI (`bunx --package
2334
2425
  @staix/agent-hub@<version> ahub up`), since it may have changed the task
2335
- database. The global CLI was not promoted.
2426
+ database. The global CLI was not promoted. The archive summary distinguishes completed target startup and plugin installation from remaining global CLI installation, and prints recorded-session commands: `ahub codex resume <thread-id>`, `ahub pi --session-file <path>`, and the Claude reconnect command. On the next `ahub up`, `pi.auto_start` resumes the archived operation's recorded Pi session rather than choosing a fresh conversation. Unknown or conflicting archived identity refuses that automatic resume.
2427
+ That session is kept as a bookmark, `.agenthub/state/recovery-continuity.json`. When its session file can no longer be resumed or does not match it, the hub archives the bookmark and starts no fresh session in that start; the error names `ahub pi --mode <mode> --session-file <managed-file>` for choosing one. An invalid or unreadable bookmark, or session storage that cannot be verified, starts nothing, keeps the bookmark and prints the `mv -n` command that archives it after inspection. The bookmark is retired once Pi attaches with a different authenticated session.
2336
2428
  - Both choices are for a person in a terminal; an agent shell is refused, and
2337
2429
  the reason is kept in the operation's audit. Run each with the command
2338
2430
  `next` or the error prints: the operation's own coordinator, or the release
@@ -17,7 +17,7 @@ ahub setup # installs the Claude Code channel plu
17
17
  Or use the matching GitHub release:
18
18
 
19
19
  ```bash
20
- bun add -g github:STAIxBWLB/agent-hub#v0.12.31
20
+ bun add -g github:STAIxBWLB/agent-hub#v0.12.32
21
21
  ahub setup
22
22
  ```
23
23
 
@@ -30,9 +30,11 @@ and upgrade or crash recovery, see the [operations guide](operations.md). To
30
30
  move running projects to a newer release later, run `ahub upgrade` in a
31
31
  terminal: it reviews the plan with you, applies it and follows it.
32
32
 
33
- ## Upgrading to 0.12.31
33
+ ## Upgrading to 0.12.32
34
34
 
35
- Existing Jcode project MCP entries need one refresh before conductor or dashboard starts. Once per project, the person runs:
35
+ The upgrade runs with the target release's own coordinator. If the operation blocks because a restored Codex, Claude or Pi terminal disappeared, the person runs `ahub recovery reattach <operation-id> codex|claude|pi` to relaunch that peer with its recorded session (one relaunch per receipt), then `ahub recovery resume` to finish.
36
+
37
+ 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:
36
38
 
37
39
  ```bash
38
40
  ahub jcode --mode headless
@@ -83,6 +85,7 @@ or set `OMNIROUTE_API_KEY`. Name the model in `.agenthub/routing.toml` (`[local]
83
85
  | `ahub board` | who has what; `ahub task show <id>` for one task |
84
86
  | `ahub task cancel <id> --reason <text>` | close obsolete work without approving it or stopping a native turn |
85
87
  | `ahub settings set planner <peer>` | pin the planner; status reports whether it came from settings, roles or the automatic choice |
88
+ | `ahub settings reload` | apply edited config files without a restart; guarded values wait for your `y` in this terminal, and restart-only keys stay pending |
86
89
  | `ahub status` | peers, queues, pauses; `ahub budget` for quota windows |
87
90
  | `ahub memory profile-check` | a person's read-only check of running memory bindings in the current registry |
88
91
  | `ahub ask <question>` | what the board, shared memory and the log say, with the ids the answer rests on |
@@ -93,7 +96,7 @@ More: `ahub help`. How it is built and why: [`docs/specs/2026-09-19-agent-hub-de
93
96
 
94
97
  ## Shared memory
95
98
 
96
- The hub exact-pins the first-party `@staix/agent-mem` 0.3.0 core. 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. Generation candidate acceptance is still refused.
99
+ The hub exact-pins the first-party `@staix/agent-mem` 0.3.1 core. 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. Generation candidate acceptance is still refused.
97
100
 
98
101
  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.
99
102
 
@@ -110,8 +113,9 @@ contents: inspect them with `ahub tail`, then use `ahub permit <id> <option>` to
110
113
  allow. They can be denied on the page. PII task details remain available only via
111
114
  `ahub task show <id>` in the terminal. The page also starts a peer in its start
112
115
  mode (a TUI opens in a terminal when the hub has a terminal provider) and shows
113
- the settings; raising one needs `ahub ui --settings` or `ahub settings` in a
114
- terminal. See the operations guide, "Settings from the dashboard and the
116
+ the settings with a Reload configuration button; raising one needs `ahub ui --settings`
117
+ or `ahub settings` in a terminal, and guarded values from an edited file need
118
+ `ahub settings reload` there. See the operations guide, "Settings from the dashboard and the
115
119
  terminal" and "Start modes".
116
120
 
117
121
  `ahub ui --no-open` prints a one-time link instead of launching a browser. Open it
package/docs/security.md CHANGED
@@ -11,7 +11,7 @@ agent-hub connects agents that can each run commands. This page says what the hu
11
11
  - **Telemetry holds no bodies.** `.agenthub/state/events.jsonl` (issue #40) records envelope ids, routing and sizes, task ids and states, overlapping paths and token counts, and the task id (with a PII flag) that each usage and token record is attributed to. It never records a message body, a task title or detail, and marks private (PII) envelopes and tasks as such. It stays on the machine; `ahub export` only prints it. Two opt-in stores copy numbers from it into your home directory, shared by every project on the machine (directories mode 700, files 600): research records (issue #247, `research.enabled`) in `~/.agenthub/research/` hold per approved task the ids, states, counts, tokens, times and PII flag the events hold, a person's label from a closed list, and a hash in place of the project id; benchmark runs (issue #251) in `~/.agenthub/bench/` hold suite name and hash, arm label, the attached peers' ids, models and permission modes, task ids, outcomes, exit codes, counts, tokens and times, never suite text or a command's output.
12
12
  - **Snapshots stay in your repository.** Per-turn snapshots (issue #33) are git objects in the project's own object store, written through a temporary index; nothing is referenced, pushed or copied elsewhere, and `git gc` prunes them. They hold what the work tree held, including untracked files that are not ignored, so keep secrets in ignored files. They carry the repository's own permissions, and nothing caps their disk use but `git gc`. A turn of a peer holding an open PII task is not snapshotted; a PII file left in the project is snapshotted by later turns like any other file. `ahub undo` restores only files whose current content is exactly what the turn left.
13
13
  - **The edit hook reads, never decides.** `ahub check-path --hook` (issue #32) reads hub.db and returns context for Claude and a line for you; it sets no permission decision, so your permission rules stay in charge. It names other owners' task ids, titles and states, which then reach Claude's model; PII tasks are left out.
14
- - **The session record holds identities only.** `.agenthub/state/sessions.json` (issue #37, mode 600) keeps each attached peer's recovery metadata: launch options, session and thread ids, Pi's session file path. No message or task text; loss notices name deliveries by id, sender and public task title.
14
+ - **The session record holds identities only.** `.agenthub/state/sessions.json` (issue #37, mode 600) keeps each attached peer's recovery metadata: launch options, session and thread ids, Pi's session file path. No message or task text; loss notices name deliveries by id, sender and public task title. The Pi continuity bookmark that recovery keeps across stop and archive (`.agenthub/state/recovery-continuity.json`, mode 600, at most 16 KiB) holds identities only too: operation and project ids, the project root, and Pi's session id, session file, backend and model name; a bookmark that is not a private regular file, is larger than that or names another project or operation reads as invalid, which is kept distinct from no bookmark.
15
15
  - **Context checkpoints have a separate text record.** Native occupancy readings carry numeric metadata only. An optional context checkpoint persists its summary in `.agenthub/state/context-checkpoint-<peer>.json` with mode 0600 and attempts shared-memory storage when enabled. Completion requires the outstanding request id, current peer/native session and transport generation; new connection claims invalidate old requests. Private turns, every open PII task associated with the peer as owner or reviewer (including pending review), and PII-pattern summaries are refused before persistence or cloud memory. Its text is never broadcast, and context pressure does not pause, reassign or replace the session.
16
16
  - **The local worker is boxed in.** Paths are resolved through symlinks and must stay inside the project; a secrets denylist (`.env*`, keys, credential files, the hub's own state and the state archives `ahub reset --all` leaves) applies to its file tools, its git arguments and its memory capture alike; `.git` and `.agenthub` are not writable. Writes, edits, shell commands and mutating git wait for approval unless the operator's permission mode grants them (writes and edits inside the grant filter in `ask-when-needed`, all four in `never-ask`; see below), and the approver sees what will be written or run, with control characters escaped. Everything it executes runs under the macOS sandbox, attended or not. Since 0.10 the profile starts from deny default (issue #39): commands run and read only the system, toolchain and project directories (and the project's git dir and the selected developer dir; with network on, the public CA bundles); no writes outside the project, its git dir and a temp dir of its own (`TMPDIR`, made for each command and removed when it ends; issue #63); no `.git` name at any depth, closing the creation, rename, symlink and gitfile routes to a planted repository, no `config` or `hooks` directly under one nor below the discovered modules root of the project's own `.git` (a submodule's git directory, nested submodules included; every term is anchored below that root, so a directory named `refs`, `config` or `hooks` above the project neither disables the rule nor trips it; a `/refs/` or `/logs/` segment below it keeps refs named `config` or `hooks` writable, and leaves a submodule whose own path contains such a segment uncovered; a submodule whose path has `hooks` as a whole component (`tools/hooks` included) fares worse: the rule matches its whole git directory, so every write there is refused; the discovered git directories, the modules root and every component in between are also refused as targets, closing the rename, replace and symlink routes to the same files), no `commondir` at any depth below one, with every such name matched folded against the code points HFS+ ignores (the fold covers the security-relevant names; on a volume that folds names, folded spellings of the components between `.git` and a submodule's git directory are not matched — the 1024-byte SBPL literal cannot hold a folded path — the same residual the external git dir rules carry since #270), and no `.agenthub` anywhere in the project (in an external git dir the `config`/`hooks` rules cover only its own children and the hooks directory's contents, so refs named `config` or `hooks` still work); a nested repository in bare layout stays open — the directory is the git dir, with no `.git` name to anchor a rule on, and the hub never runs git there, whatever the project root is: its calls are all `-C <project root>` or `--no-index` on temp files, and none descends into a nested directory's git layout, so a planted hook fires only if a person or another tool runs git in that directory themselves; the rules are probed on HFS+, which folds the 16 code points the patterns tolerate, and on a case-sensitive APFS image, which folds nothing (a folded spelling is an inert new file there and the real names stay refused); the cost is that `git init`, `git clone` and `git worktree add` do not run inside the sandbox (add, commit, stash, checkout and gc still do), `git submodule update --init` does not either (its git directory's `config` write is refused), and neither do `git worktree remove`, `git worktree prune` of a stale record, `git clean -ffd` in a project with a nested repository, or `rm -rf` of a directory that holds a `.git` (refusing the unlink is what stops the rename-out route); no network, loopback included, unless `local.bash_network`; with it, only through the hub's egress proxy to the hosts in `local.network_allow` (issue #65), which refuses names that resolve to internal addresses (behind NAT64 with the well-known prefix, by the IPv4 address the answer carries; a network-specific prefix is not recognised), so claude-mem and the Codex app-server stay out of reach (`"direct"` opens everything, until 0.13.0). One channel stays open: `trustd`, which TLS clients need, can fetch a certificate's AIA or OCSP URL on a command's behalf, outside the proxy. The allow-default profile of 0.9 and earlier was removed in 0.12.0 (issue #83); a `local.sandbox` setting is ignored with a note. The shared temp dirs (the user's and `/private/tmp`) are closed. Without the sandbox there is no `bash` tool.
17
17
  - **Capabilities are enforced, not suggested.** `capabilities` (issue #39) is checked by the daemon where task operations and messages arrive, so a peer cannot get round it by phrasing. A peer can never answer a permission request: the control link takes `permit` from the console role only, and a message that quotes a permit command is just text. Both bind the hub's own tool paths: a vendor agent with its own shell in the project (Codex, Claude, Kimi) can read `.agenthub/state/control-token` and connect as the console, which only the local worker's and Pi's sandbox prevents.
@@ -23,7 +23,7 @@ agent-hub connects agents that can each run commands. This page says what the hu
23
23
 
24
24
  ## Native memory authority and profile selection
25
25
 
26
- The portable core is the exact-pinned first-party `@staix/agent-mem` 0.3.0 package; it does not replace the hub's caller identity, PII policy or task-write authority. Deny, hardened git, real paths and process identity are single-sourced in its Node-safe platform entry. Current project privacy is applied by the hub before promotion and again before model-facing reads. Standalone person reads are unscreened, and the standalone `--policy-free` acknowledgement grants no hub or peer authority.
26
+ The portable core is the exact-pinned first-party `@staix/agent-mem` 0.3.1 package; it does not replace the hub's caller identity, PII policy or task-write authority. Deny, hardened git, real paths and process identity are single-sourced in its Node-safe platform entry. Current project privacy is applied by the hub before promotion and again before model-facing reads. Standalone person reads are unscreened, and the standalone `--policy-free` acknowledgement grants no hub or peer authority.
27
27
 
28
28
  `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` take the project from the daemon, require `memory_read`, refuse private turns and validate UTF-8 input before logs or storage work. Complete records and graph metadata are screened before counts and truncation. Search is at most 20 lines/4 KiB (default 8); show accepts at most 8 ids and returns at most 8 KiB; graph is at most 120 nodes/240 edges/6 KiB (default 60 nodes), with no edge lacking an endpoint. Unknown, ambiguous and withheld ids share one neutral refusal. Arguments and results are excluded from hub-managed capture; this does not govern a vendor's independent transcript or memory hooks.
29
29
 
@@ -98,8 +98,11 @@ if that audit cannot be written, the command refuses. The current daemon emits
98
98
  `agent_cli` with `delegated: true` and `refused: false`. Allowed-class commands retain the peer identity and capability checks, including
99
99
  messages, proposals and reviews. Peer starts, pause and resume may delegate
100
100
  operational console authority; task assign/escalate under the flag refuse. `--as-user`, person task labels,
101
- person-authored planning/release/memory/goal writes, SDLC record, benchmark run
102
- and the pet composer are refused. No argument text is copied into this audit.
101
+ person-authored planning/release/memory/goal writes, SDLC record, benchmark run,
102
+ `ahub recovery reattach`, a `--fresh-session` dispose that would replace a repaired
103
+ session's conversation (or whose scope cannot be read), and the pet
104
+ composer are refused; presentation flags such as `--color` or `--verbose` before
105
+ the recovery action do not hide it from this check. No argument text is copied into this audit.
103
106
  Delegated dashboard restrictions are bound to its server-issued ticket/session:
104
107
  operational settings/start/stop controls remain, but message, proposal and
105
108
  workflow-history actions refuse even if the body tries to clear the restriction.
@@ -150,16 +153,17 @@ Please report vulnerabilities privately through GitHub's "Report a vulnerability
150
153
  - Every request must have the exact listener Host. Every data or action request, including the ticket exchange and snapshot polling, must be POST with the exact listener Origin and JSON content type. Foreign and missing origins, missing or expired sessions, oversized bodies and unknown actions are rejected. There is no CORS support. The only unauthenticated GET is the fixed, data-free HTML shell. No files or paths are served dynamically.
151
154
  - Responses are non-cacheable, cannot be framed, suppress referrers, and use a content security policy restricting scripts/styles to the shipped inline content and connections to this origin. Browser text is rendered with textContent, never interpreted as HTML.
152
155
  - The browser receives a bounded redacted event stream, peer states and queue counts, public task views, budget windows, pending approvals, the settings rows (closed values and ids, the file each comes from) and each startable peer's start plan (issue #269), benchmark run summaries (issue #251): the newest runs in `~/.agenthub/bench/`, whichever project on this machine ran them, by suite name, arm label, state, the task id in progress, counts, tokens and times, never suite text, and the office view's optional fields (issue #264): each peer's open turn (start time, attributed task id, attribution kind), a `checking` flag on tasks whose check is running, and warning `links` of overlapping, conflicting or cohort tasks (task and peer ids only, never paths, symbols or reasons; a PII task never joins a link, and a private or PII-attributed turn exposes no task id). Private envelope bodies and PII task text never cross this endpoint. Local-worker and Pi approval titles can contain PII, so their details remain terminal-only; the dashboard identifies the request and directs the operator to `ahub tail` before allowing it. Budget checkpoint summaries are also omitted.
153
- - The closed action list includes permission response, peer pause/resume, console message, task proposal/assignment and the settings actions below (set, undo, preview). Project-board actions add revision-fenced planning, Backlog pull/return/split/undo and release planning/state changes through Tasks; they do not tag, publish or write GitHub state. These use the existing daemon/task paths and budget pause rules. `start_peer` (issue #269) starts a peer from a closed list in the mode a person set, with a command the hub assembles: the request carries a peer id and nothing else. There is no generic control proxy, task-detail read, shell, file access, free-form configuration edit, budget override, launch of a caller-chosen command or daemon shutdown API.
156
+ - The closed action list includes permission response, peer pause/resume, console message, task proposal/assignment and the settings actions below (set, undo, preview, reload). Project-board actions add revision-fenced planning, Backlog pull/return/split/undo and release planning/state changes through Tasks; they do not tag, publish or write GitHub state. These use the existing daemon/task paths and budget pause rules. `start_peer` (issue #269) starts a peer from a closed list in the mode a person set, with a command the hub assembles: the request carries a peer id and nothing else. There is no generic control proxy, task-detail read, shell, file access, free-form configuration edit, budget override, launch of a caller-chosen command or daemon shutdown API.
154
157
  - The listener stops with the daemon. Expired sessions must be reopened with `ahub ui`; the page does not silently obtain new credentials.
155
158
 
156
159
  ## Dashboard settings and the settings session (issue #269)
157
160
 
158
161
  - Settings are a closed registry (`src/hub/settings.ts`). The dashboard and `ahub settings` can write only its keys, each checked against its own closed values, and only to `.agenthub/config.local.json` and `.agenthub/routing.local.toml`. A file git tracks is never written, so the shared `config.json` and `routing.toml` stay byte-identical; in a repository where git cannot answer, nothing is written either. Commands and binaries (`kimi_cmd`, `codex_bin`, `pi.cmd`, `checks`, `mlx`), credential files and gateway URLs (`omniroute`, `memory.worker_url`), the local worker's reach (`local.read_allow`, `local.bash_network`, `local.network_allow`), `bench.enabled` and `terminal` are refused by name from every surface: they choose what the hub runs or where secrets and task text go.
159
162
  - `routing.local.toml` holds `stay_switch` and, per class, `peers`, `escalate_to`, `route` (an id `routing.toml` defines) and `pi_backend`, and nothing else: targets, routes, signals and the PII constraint cannot be set through it. A write is read by the hub's own loader before it replaces the file (temp file and rename), and one previous version is kept for undo.
160
- - An ordinary dashboard session (`ahub ui`) reads settings, lowers a mode to `ask`, turns `pi.auto_start` off and changes the safe switches (`research.enabled`, `approvals.notify`, `snapshots.enabled`, `coordination`). Whatever can widen what agents do without asking needs a settings session: a non-ask mode now or at hub start, routing, starting Pi with the hub, removing a machine-local value, and undo. `ahub ui --settings` opens one: its ticket marks the session for 15 minutes, after which it is an ordinary session. `never-ask` also needs the peer's id typed as the confirmation, and a stored never-ask default still waits for the console's `y` at each hub start. An undo never puts never-ask back, and removing a machine-local value that uncovers a never-ask in the shared file needs the same confirmation. "Lowering to `ask`" means handing the decision back to the agent's own rules: for Codex that is the approval policy the person configured natively, which the hub does not judge.
163
+ - An ordinary dashboard session (`ahub ui`) reads settings, lowers a mode to `ask`, turns `pi.auto_start`, `task_sweep.enabled` or `task_sweep.auto_reassign` off, sets a start mode back to `tui` or a WIP limit to 0, and changes the safe switches (`research.enabled`, `approvals.notify`, `snapshots.enabled`, `coordination`). Whatever can widen what agents do without asking needs a settings session: a non-ask mode now or at hub start, routing, starting Pi with the hub, removing a machine-local value, and undo. `ahub ui --settings` opens one: its ticket marks the session for 15 minutes, after which it is an ordinary session. `never-ask` also needs the peer's id typed as the confirmation, and a stored never-ask default still waits for the console's `y` at each hub start. An undo never puts never-ask back, and removing a machine-local value that uncovers a never-ask in the shared file needs the same confirmation. "Lowering to `ask`" means handing the decision back to the agent's own rules: for Codex that is the approval policy the person configured natively, which the hub does not judge.
161
164
  - A settings session is as strong as the console for these settings and no stronger elsewhere. A mode change is the console's own request with the same refusals; tool approvals stay deny-only for Pi and local; there is still no shell, file, task-detail or launch-command API. `ahub ui --settings` and `ahub settings` pass the same identity gate as `ahub permission`, which is an operating policy, not authentication. The hostile-agent boundary above applies unchanged: an agent with an unrestricted shell as the same user can impersonate the console, and so can open a settings session.
162
165
  - Every change writes a `settings` event (the key, the value before and after, the source `dashboard` or `terminal`) and a line in `hub.log` and open consoles; opening a settings session is logged too. The unified dashboard (`ahub ui --all`) forwards settings actions as an ordinary session and opens no settings session.
166
+ - Configuration reload (issue #439). The daemon watches `config.json`, `config.local.json`, `routing.toml` and `routing.local.toml` and re-reads the complete candidate after a change, as the dashboard's Reload configuration and `ahub settings reload` do; an invalid candidate applies nothing. Each changed key is then authorized on its own against its file's actual git provenance. A privacy tightening (local-only PII, the model screen on, added PII patterns, narrower roles or capability lists, unless it moves the planner or conductor) and a safe registered setting apply from any file. Every other change, machine-local fields included, keeps its running value when its file is tracked or git cannot answer. From an untracked file such a guarded change is adopted only by `ahub settings reload` in an interactive terminal, after it lists each guarded key with its full before and after values and the person types `y` within 30 seconds; the confirmation is bound to the file contents and accepted state it was shown for. File watches and dashboard reloads, a settings session's included, never confirm, and no reload changes the roster: membership moves only through the roster setting. Keys whose consumers are bound at start (memory, the gateway and MLX, checks, the privacy and sandbox policy of existing sessions, the terminal provider and others) stay pending until a restart.
163
167
  - Start modes. A start the hub makes itself (the dashboard's Start control, `peer_start` from a console child, the conductor's `hub_peer_start`, `pi.auto_start`) takes the peer's start mode. Through settings only a settings session or the terminal can set it to headless; a config file can also set `peers.<id>.start_mode`, the shared one included (it is not a machine-local field: headless was the only form for Pi, Kimi and the local worker before this change, a hub-made headless Codex start is the app-server the hub already ran for it, and a start mode grants nothing a permission mode or a capability controls). For a TUI the hub opens a terminal running `<runtime> <its own entry point> --project <this project> <peer>` (and `--mode tui` for Pi): every word is the hub's own, the command line is those words each quoted for a POSIX shell, and no request field, tool argument or agent message is part of it. In a `terminal.open` template `{command}` is that quoted line and `{title}` and `{cwd}` are raw text for argv elements of their own; each placeholder is substituted once, so a project path that itself contains a placeholder, a quote or `$` stays one word. A provider's own error text goes to `hub.log`, not to the caller. The terminal comes from `terminal.open`, a machine-local command template that config trust refuses from a committed file and that no settings surface can write, or from Orca. The opened terminal's environment carries no agent marker, so `ahub` there has the console's identity. Without a provider the start is refused with the command to run by hand; it is never downgraded to headless. A conductor can start a peer but cannot choose its mode.
164
168
 
165
169
  ## Multi-project manager (protocol 7)
@@ -192,7 +196,7 @@ conductor holder is refused. Local and Pi scoped tools cannot write `.agenthub`.
192
196
  Claude, Codex and Kimi still follow their own file permissions and can edit a
193
197
  config file; such an edit changes participation only at the next hub start. A
194
198
  live settings write or undo applies its own roster key and does not adopt other
195
- file edits. External ids outside the known native catalog keep their prior
199
+ file edits, and a configuration reload refuses roster changes. External ids outside the known native catalog keep their prior
196
200
  admission rules.
197
201
 
198
202
  Kimi's pull-only TUI owns its tool approvals and session. The person's launcher
@@ -215,7 +219,7 @@ are in [the configuration inventory](verification/2026-10-11-agent-config-invent
215
219
  Instruction files `AGENTS.md`, `CLAUDE.md` and `QWEN.md` remain grantable by default.
216
220
  A person can set `scoped_grants.protect_instructions` to true to require approval
217
221
  for scoped writes and edits through original or resolved spellings. It applies
218
- live after a settings write or undo, never changes reads or never-ask, and cannot
222
+ live after a settings write, undo or reload (turning it off from an edited file needs the confirmed terminal reload), never changes reads or never-ask, and cannot
219
223
  be set through an agent, tools or conductor surface. Claude's daemon response
220
224
  withholds the scoped mode on these writes so an older hook grants nothing too.
221
225
 
package/docs/smoke.md CHANGED
@@ -1901,3 +1901,37 @@ The current source fixture at 6d311a51dccd41d3703079175cac65a487189b15 used the
1901
1901
  This supersedes earlier phone-fixture pending statements only for this source. The old 1bbced04 captures remain historical; no later byte-identity premise is used. Native planner/two-release, accounts, model ingestion and measured effects remain unverified.
1902
1902
 
1903
1903
  The later bounded release-audit preview text is verified by DOM tests, not by a refreshed phone capture. The6d311a51 PNGs remain evidence for their pinned source; see the later-audit note in the phone verification report.
1904
+
1905
+
1906
+ ## Settings reload and console fixture (#439, 2026-10-17)
1907
+
1908
+ Native real-terminal smoke is **UNVERIFIED**. The admitted remote install/test
1909
+ attempt exited 75 before running because Python pid 6672 (parent 6671) had no
1910
+ verified repository owner. No retry, process kill, user-hub settings change,
1911
+ installation or restart was performed. A scripted ConsoleTerminal is fixture
1912
+ evidence, not a native PTY or account result.
1913
+
1914
+ The implementation fixtures cover the following in disposable projects and temp
1915
+ memory homes:
1916
+
1917
+ - Console Settings tab, daemon preview, bounded reason, explicit y, undo, stale
1918
+ preview fencing and pasted-y refusal.
1919
+ - Dashboard reload/context, running/file values, pending restart reasons and
1920
+ stable drafts; older snapshots remain readable.
1921
+ - Real fixture daemon: live switches/WIP and undo, retained pause/queue/instance,
1922
+ actual sweep timer cancellation/rescheduling, atomic rename watcher, snapshot
1923
+ capture on a later turn and pending memory restart without opening a consumer.
1924
+ - Whole-candidate JSON/TOML/unknown-key refusal, one error notice, per-key retention
1925
+ of valid unauthorized edits, automatic privacy tightening, scoped write/undo,
1926
+ fingerprint-bound guarded reload confirmation and agent-role request refusals.
1927
+
1928
+ To complete the native leg, use a disposable project from a person terminal (or
1929
+ an explicitly authorized per-invocation delegation under docs/security.md).
1930
+ Open `ahub console`, select Settings with 6, edit a safe switch, inspect its
1931
+ preview, enter a reason, confirm y and verify running/file values. Preview and
1932
+ confirm undo; verify the restored value through `ahub settings get`. Paste y at
1933
+ confirmation and verify no write. Change a sweep interval and confirm the same
1934
+ hub instance stays running with its queue and pauses intact. Record the source
1935
+ head, terminal and daemon readbacks separately before claiming AC5 native smoke.
1936
+
1937
+ For the guarded CLI leg, edit a disposable untracked WIP limit, run `ahub settings reload`, inspect its complete before -> after preview, decline and verify the running limit is retained. Repeat and confirm y, then verify the same instance and queue/pause state. Record this separately from the scripted CLI fixture; the token proves freshness within console authority, and the CLI supplies the person-presence checks.