@staix/agent-hub 0.12.29 → 0.12.31

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 (95) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +92 -218
  3. package/docs/agent-notes/README.md +12 -0
  4. package/docs/agent-notes/adapters.md +3 -2
  5. package/docs/agent-notes/budget.md +1 -1
  6. package/docs/agent-notes/bus.md +7 -1
  7. package/docs/agent-notes/daemon.md +14 -1
  8. package/docs/agent-notes/local-worker.md +4 -2
  9. package/docs/agent-notes/tasks.md +14 -0
  10. package/docs/agent-notes/tests.md +6 -3
  11. package/docs/memory.md +70 -152
  12. package/docs/operations.md +317 -25
  13. package/docs/plans/2026-10-16-amem-failure-registry.md +101 -0
  14. package/docs/plans/2026-10-16-amem-p0-baseline.md +110 -0
  15. package/docs/plans/2026-10-16-amem-p2-read-tools.md +28 -0
  16. package/docs/plans/amem-cases.json +482 -0
  17. package/docs/quickstart.md +24 -2
  18. package/docs/security.md +42 -2
  19. package/docs/smoke.md +11 -0
  20. package/docs/specs/2026-09-19-agent-hub-design.md +142 -7
  21. package/docs/specs/2026-09-20-upgrade-recovery-design.md +84 -10
  22. package/docs/verification/2026-10-17-0.12.30.md +70 -0
  23. package/docs/verification/2026-10-17-0.12.31.md +71 -0
  24. package/docs/verification/2026-10-17-418-probes.md +21 -0
  25. package/docs/verified.json +13 -13
  26. package/package.json +5 -2
  27. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  28. package/plugins/agent-hub/server.js +129 -62
  29. package/src/adapters/claude-channel.ts +29 -11
  30. package/src/adapters/local-worker.ts +2 -2
  31. package/src/adapters/pi.ts +5 -0
  32. package/src/cli/attention.ts +5 -1
  33. package/src/cli/console-state.ts +145 -29
  34. package/src/cli/console.ts +40 -10
  35. package/src/cli/help.ts +3 -2
  36. package/src/cli/identity.ts +4 -3
  37. package/src/cli/jcode-mcp.ts +1 -1
  38. package/src/cli/main.js +2 -2
  39. package/src/cli/main.ts +43 -14
  40. package/src/cli/memory.ts +87 -187
  41. package/src/cli/output.ts +19 -2
  42. package/src/cli/recovery-package.ts +59 -10
  43. package/src/cli/upgrade-interactive.ts +2 -1
  44. package/src/cli/upgrade-restore-state.ts +133 -0
  45. package/src/cli/upgrade-runtime.ts +204 -63
  46. package/src/cli/upgrade.ts +57 -24
  47. package/src/hub/board.ts +83 -24
  48. package/src/hub/bus.ts +108 -38
  49. package/src/hub/check-runner.ts +514 -0
  50. package/src/hub/child-process.ts +1 -0
  51. package/src/hub/control-client.ts +5 -1
  52. package/src/hub/daemon.ts +529 -89
  53. package/src/hub/delivery-hints.ts +30 -0
  54. package/src/hub/delivery-journal.ts +185 -12
  55. package/src/hub/delivery-superseded.ts +52 -0
  56. package/src/hub/envelope.ts +31 -1
  57. package/src/hub/git.ts +2 -38
  58. package/src/hub/host-executable.ts +11 -0
  59. package/src/hub/hub-tools.ts +14 -2
  60. package/src/hub/manager.ts +1 -1
  61. package/src/hub/memory-candidates.ts +103 -0
  62. package/src/hub/memory-fail.ts +25 -0
  63. package/src/hub/memory-observations.ts +47 -0
  64. package/src/hub/memory-plan-guard.ts +33 -0
  65. package/src/hub/memory-policy.ts +42 -0
  66. package/src/hub/memory-profile-check.ts +170 -0
  67. package/src/hub/memory-profile.ts +192 -0
  68. package/src/hub/memory-staleness.ts +55 -0
  69. package/src/hub/path-policy.ts +8 -0
  70. package/src/hub/peer-catalog.ts +3 -0
  71. package/src/hub/project.ts +4 -37
  72. package/src/hub/read-tools.ts +127 -0
  73. package/src/hub/routing.ts +35 -16
  74. package/src/hub/settings.ts +2 -1
  75. package/src/hub/spec-read.ts +120 -0
  76. package/src/hub/supervision.ts +21 -6
  77. package/src/hub/task-sweep.ts +7 -6
  78. package/src/hub/tasks.ts +370 -71
  79. package/src/local/deny.ts +4 -17
  80. package/src/memory/brief.ts +8 -5
  81. package/src/memory/capture.ts +3 -1
  82. package/src/memory/recall.ts +50 -110
  83. package/src/pi/process-signature.ts +2 -42
  84. package/src/ui/index.html +12 -9
  85. package/src/ui/needs.ts +7 -5
  86. package/src/ui/office-model.ts +4 -1
  87. package/src/ui/task-board.ts +1 -1
  88. package/src/ui/task-progress.ts +6 -2
  89. package/templates/AGENTS.block.md +1 -1
  90. package/templates/profiles/general.json +1 -1
  91. package/templates/profiles/research.json +1 -1
  92. package/templates/profiles/writing.json +1 -1
  93. package/src/memory/import.ts +0 -90
  94. package/src/memory/store.ts +0 -805
  95. package/src/memory/sync.ts +0 -145
@@ -1,6 +1,6 @@
1
1
  # Operations guide
2
2
 
3
- This guide describes ahub 0.12.29 and control protocol 16. Live verification
3
+ This guide describes ahub 0.12.31 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
@@ -123,8 +123,13 @@ adds no timer, network request or writable settings path.
123
123
  Tabs change with the digits 1 to 5 or with 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
- chunk can only edit the command line, but a read that holds nothing but arrow
127
- sequences is that many key presses, so a held key repeats its tab move. In the Events
126
+ chunk can only edit the command line, but a read that holds nothing but arrow or
127
+ Home/End sequences is that many key presses, so a held key repeats its move. Home
128
+ or `<` jumps to a panel's first row and End or `>` to its last; the Events tab
129
+ follows new events while the last row is selected and stays on a row you moved to.
130
+ `w` opens the dashboard and `o` the pet window; `:ui --all` and `:pet --window --close`
131
+ work on the command line too. In the Peers tab the planner's row reads `(planner)`, and
132
+ `l` then `y` makes the selected peer the planner (`ahub settings set planner <peer>`). In the Events
128
133
  tab a row's header line is tokenized and coloured exactly as the same event in
129
134
  the stream; only the header is tab-flattened before tokenizing. Body lines retain
130
135
  the previous rendering and stay plain, as does command output; colour never changes
@@ -176,6 +181,68 @@ decisions and a never-ask permission mode require confirmation; delivery resolut
176
181
  status state counts and never fetches the board. Leaving restores
177
182
  the terminal and returning from panels replays the bounded stream buffer.
178
183
 
184
+ Tasks and Queue selections follow the selected id across refreshes. If that row
185
+ disappears, no replacement row inherits the action. Task actions also bind the
186
+ row's `flowRevision` (its history length); queue actions bind the delivery
187
+ revision. The id and revision in a row-started command cannot be edited. Peer,
188
+ reason and the final role/action remain editable, and the confirmation names the
189
+ validated result. An older hub without `flowRevision` refuses revision-bound task
190
+ row actions instead of silently running them unchecked.
191
+
192
+ In Tasks, `a` assigns the owner in ordinary open states and the reviewer in
193
+ `in_review`; a waiting task says when assignment is a reservation. `u` unassigns
194
+ the corresponding role, and `r` reviews only in `in_review`. In Queue, `r`
195
+ prefills `discard` for a queued row and `retry` for a needs_review row, with the
196
+ action still editable before confirmation. `completed` is never the default.
197
+ Status, console notices and `route explain` show every held row with its id, sender, kind and age. The hub completes rows made entirely of superseded hub workflow notices or presence items, recording an ids-only reason and the hub actor. Mixed messages, live task notices and unknown references remain held. A Claude session without channel support safely returns unseen pushes for `hub_inbox`; a thrown notification write remains uncertain.
198
+
199
+ Claude channel/pull sessions, Codex and Pi may call `hub_delivery_retry { delivery_id }` for their own
200
+ `needs_review` row once. Its tool results show held-row count, ids, senders,
201
+ kinds and age, never message bodies or task text (up to 32 rows/4 KiB, with an
202
+ explicit truncation notice). The redelivery starts with a fixed warning that
203
+ the earlier attempt is uncertain and its effects must be checked before acting.
204
+ The warning fits within the existing journal body limit. If needed, only the rendered copy is clipped at a Unicode character boundary and ends with an explicit cut marker; the original message is retained. Consumed-retry proof follows every coalesced original atomically with a successful checkpoint, surviving safe failure, stale removal, pruning and restart.
205
+
206
+ Any earlier explicit retry in the same recipient's lineage, including a person's
207
+ retry, leaves a later hold for the person. A busy peer's request only requeues
208
+ the originals; delivery waits for idle and retains all pauses and recovery holds.
209
+ Hub presence prefaces are mutable context, so they do not consume or inherit a
210
+ message's retry allowance and never receive the uncertain-retry warning.
211
+ The tool cannot complete or discard a row. If a recovery snapshot lacks retry
212
+ history, or older pruned retry records cannot be mapped, the affected message
213
+ lineages require a person; unrelated new messages retain the one-retry option.
214
+
215
+ 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.
216
+
217
+ Every console resolution needs a reason. Queue `discard` removes queued originals or
218
+ settles a needs_review receipt; it never cancels a task or native turn.
219
+
220
+ `ahub task unassign <id> [--role owner|reviewer] [--revision N]` is the terminal
221
+ equivalent. Owner removal is allowed in `proposed`, `in_progress` and
222
+ `changes_requested`, returns active work to `proposed`, and clears any owner
223
+ reservation. It is refused in `in_review`, `approved` and `backlog`. Reviewer
224
+ removal retains the state, including `in_review`, and refuses to remove the human
225
+ reviewer of PII work. No replacement is routed and no native process or external
226
+ effect is rolled back. A person-unassigned task stays out of automatic owner
227
+ offers across dependency release, planner-pull processing, release timers and
228
+ restarts until an explicit assignment or reservation. The later unassign also
229
+ fences planner undo, so undo and re-pull cannot restore the removed reservation.
230
+ Former queued assignment or review requests are withdrawn without resolving
231
+ uncertain deliveries, and the former agent loses current authority. A withdrawal
232
+ notice uses delivery evidence or that peer's own accept/self-claim after the
233
+ latest assignment; another owner's in-progress state or an earlier acceptance
234
+ does not count. Withdrawing an unread queue alone sends none. If a later person
235
+ assignment supersedes an escalation or offline relay, the stale success result
236
+ and decision note are suppressed, but the former owner is still told the current
237
+ owner and to stop working.
238
+
239
+ `ahub task assign <id> <peer> [--role owner|reviewer] [--revision N]` uses a
240
+ checked console operation when a revision is present. Without it, existing CLI
241
+ behavior is unchanged. `ahub queue resolve ... [--revision N]` uses the supplied
242
+ revision instead of a fresh show. Revision mismatches and superseded post-await
243
+ publications fail without a board or delivery side effect; a reviewer-only change
244
+ keeps a valid owner assignment but refreshes its reviewer content.
245
+
179
246
  The Tasks panel summarizes the whole public board with an approved/all fraction,
180
247
  a 20-cell ASCII bar and state counts. Proposed tasks with unapproved or missing
181
248
  `after` dependencies count as waiting; PII stubs count normally. Each task has a
@@ -388,9 +455,157 @@ The Stop hook acknowledgement is not a counted completion. The daemon checks the
388
455
  native transcript after the hook can return; missing or changed-session evidence
389
456
  stays unknown.
390
457
 
458
+ ## Pi with DGX and MLX
459
+
460
+ Pi is optional. Install Pi separately and set `pi.enabled` to `true` in
461
+ `.agenthub/config.json`. Set `pi.auto_start` to `true` to start it with the hub.
462
+ Pi starts in its TUI by default; `ahub pi --headless`, or the start mode
463
+ setting (`ahub settings set peers.pi.start_mode headless`), asks for the
464
+ background peer instead. The project uses its existing OmniRoute connection for DGX;
465
+ `pi.dgx_coding` and `pi.dgx_fast` select the gateway's configured model IDs.
466
+
467
+ ```bash
468
+ ahub models setup # prepare bounded Qwen3.5 4B MLX in an existing Ollama service
469
+ ahub models start # verify loopback Ollama/model readiness (no daemon spawn)
470
+ ahub models status
471
+ ahub pi --headless --backend auto
472
+ ahub say @pi "Read the project and summarize the next small implementation task"
473
+ ahub pi # its TUI in this terminal; an idle headless session moves into it
474
+ ```
475
+
476
+ The default routing template assigns implementation, bulk edits and tests to
477
+ DGX, and summaries/triage to MLX. Pi and the existing local worker take priority
478
+ before cloud peers; planning and final review stay with Claude/Codex. Existing
479
+ projects keep their routing file, so add `pi` to the relevant `peers` lists and
480
+ set `pi_backend = "dgx"` or `"mlx"` for each class. PII tasks remain local-worker
481
+ only. `--backend dgx` or `--backend mlx` explicitly pins a Pi session's backend.
482
+
483
+ Pi connects to an authenticated relay with model aliases `dgx/coding`,
484
+ `dgx/fast`, and `mlx/fast`; upstream gateway credentials stay in the hub.
485
+ Its managed tools use the existing path guards, shell sandbox and terminal
486
+ approval flow. Keep `ahub console` open to approve write/edit/shell operations:
487
+ a request nobody answers expires, and two in a row end Pi's turn.
488
+ Tool-call receipts survive daemon restart; an interrupted operation with an
489
+ unknown outcome must be reconciled before repeating it. Cancelling a Pi turn
490
+ does not automatically hand its task to a cloud peer.
491
+
492
+ For assigned, non-private work, `hub_task_spec` reads the named GitHub issues
493
+ through the hub's authenticated, bounded read path. `hub_check_start` runs an
494
+ exact Git ref's permitted tests or typecheck in the opt-in isolated container
495
+ runner (`checks.runner: "container"`); `hub_check_result` and `hub_check_cancel`
496
+ read or cancel that owned run. Missing spec/check capability refuses the
497
+ assignment early; it never grants host commands, credentials or broader sandbox
498
+ access. Receipts distinguish exact source/tree/lockfile, platform, exit and
499
+ uncertain or cancelled outcomes. See [bounded spec and check access](security.md#bounded-task-specs-and-isolated-checks-418)
500
+ for the authorization and resource bounds.
501
+
502
+ Retention bounds inactive valid check receipts to 200 records and the newest 20
503
+ full outputs, excluding active runs. Full output is also consumed by the owner
504
+ result read or expires after 24 hours.
505
+ Malformed or unreadable receipts are a retention exception: their receipt bytes,
506
+ output and staging stay for inspection, with ID-only warnings separate from
507
+ unknown container-owner warnings. Maintenance skips them while continuing valid
508
+ retention; it never deletes an unknown container. See the security contract for
509
+ the same-user parent-swap cleanup limitation. These source guarantees do not
510
+ establish the separate native macOS acceptance leg.
511
+
512
+ The `mlx/fast` alias now defaults to an externally managed Ollama MLX backend.
513
+ Install and start Ollama separately, with `OLLAMA_NO_CLOUD=1`,
514
+ `OLLAMA_NUM_PARALLEL=1`, `OLLAMA_MAX_LOADED_MODELS=1`, and a finite
515
+ `OLLAMA_KEEP_ALIVE` (five minutes is the tested setting). `models setup`
516
+ prepares `agenthub-fast-mlx:4b-8k` from `qwen3.5:4b-mlx`, with an 8K total
517
+ context and a 2K output cap. The relay budgets input separately at 6,000
518
+ estimated tokens and serializes local requests across project hubs.
519
+
520
+ `models status` distinguishes model availability from memory residency.
521
+ `models stop` refuses to unload an externally managed Ollama model: other
522
+ clients may be using it. Ollama owns idle eviction; stopping a hub never
523
+ kills Ollama. The OpenAI compatibility endpoint does not enforce a request
524
+ `keep_alive` field, so configure the server and verify its expiry readback.
525
+ The relay can fall back to DGX before streaming starts as before. See the
526
+ [Ollama migration procedure](#ollama-mlx-migration-issue-51)
527
+ for existing Python runtime/configuration cleanup and rollback.
528
+
529
+ A project has one managed Pi session owner. Mode changes require the agent to
530
+ settle and preserve the session file. Before the first generation, a live source
531
+ verified to be empty can instead retain its exact session ID without a file.
532
+ Missing history from a nonempty session blocks handover. Protocol 9 adds Pi
533
+ recovery metadata. Protocol 10, released in 0.7.0, adds durable delivery
534
+ receipts and conservative queue recovery; it is verified live (see the
535
+ [smoke checklist](smoke.md)).
536
+ Older protocol hubs still require their matching CLI and an attended bootstrap.
537
+
538
+ ## Local dashboard
539
+
540
+ With a running daemon, `ahub ui` opens a local dashboard for messages, peer states
541
+ and queues, the task board, budget windows, pending approvals and this machine's
542
+ benchmark runs. Use `ahub ui --no-open` to print a single-use link when the
543
+ browser cannot be opened.
544
+ Open the link within 60 seconds; the browser session lasts one hour.
545
+
546
+ The dashboard can send console messages, propose and assign tasks, pause or resume
547
+ peers, answer approvals, start a peer in its start mode and show the settings.
548
+ An ordinary session changes the safe switches and lowers a mode to `ask`; the
549
+ rest needs `ahub ui --settings` or `ahub settings` in a terminal. See
550
+ [Settings](#settings-from-the-dashboard-and-the-terminal) and
551
+ [Start modes](#start-modes-tui-by-default-headless-as-opt-in).
552
+ Budget pauses still require the terminal override.
553
+ Private envelopes and PII tasks stay redacted. Local-worker and Pi tool details and
554
+ allow decisions stay in `ahub tail` / `ahub permit`; the page can deny them.
555
+ No dashboard port is opened until requested. See [the session security model](security.md#local-dashboard-sessions-issue-6).
556
+
557
+ ## Multiple projects and worktrees
558
+
559
+ Version 0.4.0 adds one independent hub per repository or Git worktree.
560
+ Subdirectory commands resolve to that project; symlink aliases resolve to the same
561
+ hub. Explicit selection works from any directory:
562
+
563
+ ```bash
564
+ ahub --project /path/to/project-a init
565
+ ahub --project /path/to/project-b init
566
+ ahub --project /path/to/project-a up
567
+ ahub --project /path/to/project-b up
568
+ ahub projects
569
+ ahub status --all
570
+ ahub --project /path/to/project-a codex
571
+ ahub ui --all
572
+ ```
573
+
574
+ The unified dashboard lists registered roots and opens their boards, streams,
575
+ messages, approvals and budgets. It can start hubs and stop a selected hub after
576
+ confirmation. Its Start control opens a peer's TUI only through a terminal provider
577
+ (`terminal.open` or Orca); without one, launch Claude/Codex TUIs from a terminal. The manager stays available
578
+ when a project stops; `ahub ui --all --stop` stops only the manager. Existing
579
+ `ahub ui` still opens the current project's dashboard.
580
+
581
+ `ahub projects --json` returns machine-readable live status. Use a listed ID or a
582
+ path with `--project`; the selector must precede the command. `ahub projects remove
583
+ <id>` forgets a stopped registration without deleting project data. A moved root
584
+ gets a new registration. Missing roots remain visible until removed.
585
+
586
+ Runtime state stays in each project's `.agenthub/state/`. The machine registry is
587
+ `~/.agenthub/registry.db`; existing `ports.json` allocations are imported once.
588
+ `AGENTHUB_HOME` selects an isolated machine registry (also used by tests). An
589
+ inherited state directory from a different project cannot redirect a new CLI
590
+ invocation. Explicit custom state requires a matching project marker or the
591
+ initialization pair `AGENTHUB_PROJECT_DIR` / `AGENTHUB_STATE_DIR`.
592
+
593
+ Manager-started hubs use attended mode and project configuration, including
594
+ credential-file references. They do not inherit the launching project's gateway
595
+ URL/key overrides. Native memory remains shared according to claude-mem aliases;
596
+ worktrees recall their parent and composite identity. A shared-alias notice does
597
+ not mean that task boards or agent sessions are shared. Provider quota readings
598
+ may describe the same account and should not be added across projects.
599
+
600
+ Before upgrading an older hub, inspect the plan with the matching CLI.
601
+ Incompatible or unverified processes are shown explicitly and are never killed by
602
+ PID-name matching. See the operations guide and the
603
+ [multi-project specification](specs/2026-09-19-multi-project-design.md).
604
+
391
605
  ## Install and start
392
606
 
393
- Use Bun 1.3 or newer. Install the released package and install its Claude
607
+ Use Bun 1.4.2 or newer. Source checks and CI use the version pinned in
608
+ `.bun-version` (currently 1.4.2). Install the released package and install its Claude
394
609
  channel plugin:
395
610
 
396
611
  ```bash
@@ -472,8 +687,9 @@ does not list), needs its directory in `local.read_allow`, for example
472
687
  hub's tools: list a peer and it keeps only the capabilities named, from
473
688
  `propose` (`hub_task_propose`), `assign` (proposing with another peer as owner),
474
689
  `remember` (the `hub_remember` tool; the notes the hub itself keeps of done
475
- summaries and review verdicts are not gated) and `important` (`[IMPORTANT]`
476
- messages). For example `"capabilities": { "local": ["propose", "remember"] }`.
690
+ summaries and review verdicts are not gated), `memory_correct` (propose a local correction candidate for person review), `memory_read`
691
+ (`hub_memory_search`, `hub_memory_show`, `hub_memory_graph`) and `important`
692
+ (`[IMPORTANT]` messages). For example `"capabilities": { "local": ["propose", "remember"] }`.
477
693
  A peer that is not listed keeps all of them, a listed peer whose value is not a
478
694
  list gets none, and an unknown capability name grants nothing; `hub.log` says
479
695
  so for each, and logs every refusal (`capabilities:`). A refused tool call says
@@ -523,8 +739,7 @@ resolves an uncertain delivery automatically. The same rule holds on every path
523
739
  assigns a task (#297): once the move is saved on the board, a failed delivery prints
524
740
  exactly one console notice ("the move is saved... delivery is not confirmed"), printed
525
741
  where the error is thrown, and the caller (a peer in its turn, or the CLI) still gets
526
- its error. Two exceptions, by construction: a move superseded while the assignment was being prepared, meaning a later history entry that moves or settles the task (another assignment, an unassign, the owner's accept, done, approval, close; the hub's quiet bookkeeping such as a late check result or a reviewer change does not supersede), is
527
- the caller's error as before, with no notice naming either owner; and a claim is its own hand-over, so its
742
+ its error. Two exceptions, by construction: a move superseded while the assignment was being prepared, meaning a later history entry that moves or settles the task (another assignment, an unassign, the owner's accept, done, approval, close; the hub's quiet bookkeeping such as a late check result or a reviewer change does not supersede), returns the current task without a failed tool call and with no notice naming either owner; and a claim is its own hand-over, so its
528
743
  accepted write and line stay outside the delivery rule (its overlap and routing announcements to earlier
529
744
  owners are deliveries and share it). The repair is always
530
745
  to look for a queued or needs_review delivery with
@@ -735,7 +950,7 @@ ahub task label 12 reverted # a later verdict (ok, regressed, reverted, i
735
950
 
736
951
  ## Hub memory
737
952
 
738
- The hub keeps its own memory in `~/.agenthub/memory/` beside claude-mem ([how it works](memory.md)): notes saved
953
+ The hub opens the selected memory profile under `memoryHome()` (default `~/.agenthub/memory/`) beside claude-mem ([how it works](memory.md)): notes saved
739
954
  against an open task are short-term; when the task is approved its decisions, contracts and fails become long-term.
740
955
  Task briefs, session-start recall and `ahub ask` read it first, and the dashboard has a Memory section.
741
956
 
@@ -748,6 +963,20 @@ ahub memory forget 1a2b3c4d # a person's; also promote, demote, sup
748
963
 
749
964
  `"memory": { "native": false }` in `.agenthub/config.json` turns it off for a project.
750
965
 
966
+ The exact-pinned `@staix/agent-mem` 0.3.0 resolves `AMEM_HOME`, then `$AGENTHUB_HOME/memory`, then `~/.agenthub/memory`. An absent `M/profile.json` selects shared v1; an explicit generation selects `M/generations/G` with the package's readonly legacy bridge. All daemon memory consumers and the hub memory/goal CLI use that selected profile. Invalid metadata or a missing selected generation makes native memory unavailable while the bus and board continue; there is no fallback to legacy writes. Inspect the daemon's memory binding/availability before interpreting missing memory as an empty store.
967
+
968
+ The daemon checks its selector at hub operation entry and before candidate/counter writes. It does not hot-switch handles or provide an atomic fence against selection changes during an in-flight core call. Quiesce consumers and close their handles before migration or selection changes; reopen through the supported session-preserving lifecycle afterward. Candidate/counter storage remains `M/candidates.db`, independent of `G`; `amem review` on a generation is still refused. Every running hub using this home needs an authenticated receipt: a matching ready binding, or a generation-capable unbound receipt (`disabled` when native memory is off, `unavailable` when opening failed) proving it holds no memory handle. An unbound daemon and zero running hubs are quiesced for memory; a stale bound handle, unreadable registry or unknown runtime is not ready. Existing JSON memory/goal results remain unchanged; the additive binding receipt belongs to daemon status, profile-check and the decay object. This source integration does not authorize installing a new runtime, migrating real memory, restarting sessions or claiming real-machine sync/capture receipts. Migration/deactivation and their limits belong to [agent-mem](https://github.com/STAIxBWLB/agent-mem); see [the hub profile contract](memory.md#selected-memory-profile).
969
+
970
+ Run `ahub memory profile-check [--json]` from the person's terminal for the read-only preflight. It identifies live registry owners by signed process identity and authenticated daemon replies, then reports their loaded memory package and bound home/profile. The receipt names the current `AGENTHUB_HOME` registry scope; zero results establish no live daemon in that inventory, not system-wide process absence. Inventory and check separate custom registries too when they share `AMEM_HOME`. A missing or unreadable runtime receipt never counts as a different home or permission to migrate.
971
+
972
+ Before real migration, first upgrade every hub sharing the home to 0.12.30 or later. Obtain positive ready or unbound/quiesced receipts in every relevant registry; then quiesce consumers and close bound handles before changing the selector. A matching ready handle proves compatibility but is still an open handle. Verify synthetic cross-writes before the separately approved real migration, then reopen through the supported session-preserving lifecycle afterward. Merely installing this release does not authorize migration or provide live capture/device-sync evidence.
973
+
974
+ Managed agents read through `hub_memory_search`, `hub_memory_show` and `hub_memory_graph`, with the server's project identity, the `memory_read` capability and current privacy screening. They cannot supply another project; private turns are refused. The tools bound UTF-8 input/output, screen before counts and truncation, and exclude their arguments/results from hub-managed capture. `hub_memory_correct` has its own `memory_correct` capability and records a screened correction candidate, not a note change. See [the complete memory contract](memory.md) for caps and refusal semantics.
975
+
976
+ Review candidates and rendered/delivered/cited counters stay in machine-local `M/candidates.db`, outside sync, import, recall, briefs, ask and graph evidence. Public changes-requested reviews with unmet items may propose a fail candidate; missing cause/retry details stay unknown. Shared-v1 acceptance is a person's `amem review` action with its TTY/policy checks; selected generations still refuse that command. Read-time `(stale?)` hints and plan-fail advice never change stored rows or task authority. Structured fail notes are validated against 4000 UTF-8 bytes before screening or writes, with no silent truncation.
977
+
978
+ Recall presentation omits generated task-approval outcome notes and shows only nonempty reasons from generated changes-requested notes; an ordinary decision that merely resembles a header stays visible. Contracts and fails remain eligible. Capped recall lines preserve memory headers and end at word boundaries, and one delivery deduplicates ids across restored/current prefaces and shared note lines. Stored notes and brief evidence are unchanged; platform recall retains its budget split.
979
+
751
980
  Between your machines, through a private git remote, with long-term tasks that span them:
752
981
 
753
982
  ```bash
@@ -1229,6 +1458,7 @@ ahub ui --settings # dashboard with a 15-minute settings session
1229
1458
  | Start | `pi.auto_start` | `config.local.json` | next hub start |
1230
1459
  | Routing | `routing.stay_switch`, `routing.classes.<class>.peers`, `.escalate_to`, `.route`, `.pi_backend` | `routing.local.toml` | at once |
1231
1460
  | Switches | `research.enabled`, `approvals.notify`, `snapshots.enabled`, `coordination` | `config.local.json` | next hub start |
1461
+ | Roles | `planner` (the one peer that plans) | `config.local.json` | at once |
1232
1462
 
1233
1463
  - Writes go only to `.agenthub/config.local.json` and `.agenthub/routing.local.toml`,
1234
1464
  the machine-local files (`ahub init` ignores both in git). The shared
@@ -1322,8 +1552,10 @@ The configured `kimi_cmd` must be a single executable or end in exactly `acp`;
1322
1552
  the TUI uses the executable or drops that final word. Other wrappers are refused
1323
1553
  with the headless command rather than guessed.
1324
1554
 
1325
- The TUI is pull-only. Its model reads `hub_inbox` at the start of work and before
1326
- reporting, and shares results explicitly with `hub_send`. Status, the console and
1555
+ The TUI is pull-only. Its model reads `hub_inbox` at the start of work, between
1556
+ steps of longer work and before reporting, and shares results, and mid-work
1557
+ blockers or changed contracts, explicitly with `hub_send` addressed with `to`
1558
+ (progress-only notes `[FYI]`). Status, the console and
1327
1559
  the dashboard show `pull-only`, the waiting count and the last inbox read. Messages
1328
1560
  and important markers do not push or interrupt it. There is no hub busy state,
1329
1561
  watchdog, console approval, hub permission mode, context reading, automatic quota
@@ -1527,6 +1759,28 @@ so a restarted hub never launches beside a survivor. A hub whose project root
1527
1759
  or state directory was deleted stops itself within about 10 seconds; the
1528
1760
  dashboard manager does the same when its home directory vanishes.
1529
1761
 
1762
+ ## The planner (#455)
1763
+
1764
+ One peer plans: it proposes and splits tasks, grooms the backlog and gets the
1765
+ backlog and sweep notices. `ahub status` prints it with its source, the
1766
+ dashboard's Agents view shows a Planner badge, and the console marks its row.
1767
+
1768
+ - `setting`: `planner` in `.agenthub/config.json` or `config.local.json` (the
1769
+ machine's file wins). That peer is the only planner; every other peer loses
1770
+ the role. It is one of `claude`, `codex`, `kimi`, `qwen` or `jcode`: the
1771
+ hub-sandboxed `pi` and `local` never plan.
1772
+ - `roles`: with no `planner` key, the `roles` planners stand. That is `claude`
1773
+ by default.
1774
+ - `automatic`: when no rostered peer holds the role, the hub gives it to the
1775
+ first rostered peer of that list. It recomputes this at start and after
1776
+ each roster change, and writes nothing to disk.
1777
+
1778
+ Change it with `ahub settings set planner codex`, the dashboard Settings row
1779
+ (a settings session, `ahub ui --settings`) or `l` in the console. Planning
1780
+ authority and the backlog notices move at once. The new planner's role text
1781
+ updates at its next start. `ahub settings undo` puts the previous planner
1782
+ back. Agents cannot change it.
1783
+
1530
1784
  ## Resetting a project's hub
1531
1785
 
1532
1786
  `ahub reset` returns a project's hub to a clean state. Without `--yes` it is a
@@ -1659,21 +1913,21 @@ section is what they run.
1659
1913
 
1660
1914
  Upgrade running projects with the target release's own coordinator. It accepts
1661
1915
  a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
1662
- 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.29), and only
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
1663
1917
  a target on its own protocol, so the target's coordinator fits every supported
1664
1918
  source and carries every recovery fix released up to it. Protocol 8 and older
1665
1919
  (0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
1666
1920
  project directory, without replacing the global CLI first:
1667
1921
 
1668
1922
  ```bash
1669
- bunx --package @staix/agent-hub@0.12.29 ahub upgrade --to 0.12.29 --dry-run
1670
- bunx --package @staix/agent-hub@0.12.29 ahub upgrade --to 0.12.29 --yes
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
1671
1925
  ```
1672
1926
 
1673
1927
  | Running now | Coordinator to use |
1674
1928
  | --- | --- |
1675
1929
  | 0.6.x (protocol 9) | the target's, through `bunx` as above |
1676
- | 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.29 (protocol 16) | 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 |
1677
1931
  | any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
1678
1932
  | 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
1679
1933
 
@@ -1705,14 +1959,14 @@ projects first:
1705
1959
 
1706
1960
  ```bash
1707
1961
  ahub restart --dry-run
1708
- ahub upgrade --to 0.12.29 --dry-run
1962
+ ahub upgrade --to 0.12.31 --dry-run
1709
1963
  ```
1710
1964
 
1711
1965
  Apply only after reviewing the plan:
1712
1966
 
1713
1967
  ```bash
1714
1968
  ahub restart --yes
1715
- ahub upgrade --to 0.12.29 --yes
1969
+ ahub upgrade --to 0.12.31 --yes
1716
1970
  ahub recovery status [<operation-id>]
1717
1971
  ahub recovery resume [<operation-id>]
1718
1972
  ahub recovery abort [<operation-id>]
@@ -1777,7 +2031,11 @@ release. The global CLI is promoted last.
1777
2031
 
1778
2032
  A lost commit or start reply is reconciled against the actual daemon identity,
1779
2033
  package digest, terminal binding, and phase receipt. An uncertain terminal
1780
- creation is never repeated blindly. If Claude shows its development-channel confirmation screen, confirm it in
2034
+ creation is never repeated blindly. Recovery retains the exact-pinned first-party memory package with the preserved runtime, includes its identity and bytes in the digest, and refuses missing, symlinked or changed retained dependencies instead of resolving a mutable ancestor/global installation. It does not copy the full dependency tree.
2035
+
2036
+ After creating a managed terminal, the coordinator saves its exact handle, incarnation and worktree before waiting up to 600 seconds (10 minutes) for authenticated attachment to the expected target hub and conversation. A pending or failed creation receipt also waits when the current target has a verified live launcher; its saved binding retains the pending/failed origin across interruption. An idle terminal alone is not attachment proof. Without a current launch record, a confirmed-ended row for another terminal and an attached session still reporting no id keep the chosen terminal waiting within the same bound; a late matching record continues that wait. Live replacement and unreadable records still block. Only non-offline session ids count, and older-instance launchers are checked before declaring a launch gone. Timeout retains the binding and diagnostic receipt; resume waits on that same binding rather than opening a duplicate.
2037
+
2038
+ The wait checks the selected launcher's signed identity on each poll. When that exact launcher exits and the target confirms no session or other live launcher, a pending-origin wait (including a new terminal) records failure and offers the failed-restoration choices, including fresh-session for Codex or Claude. A failed-origin wait returns to its existing retry path. A replacement terminal, missing or unreadable launcher identity, unreadable target or different attached conversation blocks without treating unknown as gone. Success clears the waiting origin and preserves exact terminal/session revalidation. A launcher from an older target instance still blocks without another terminal. The 10-minute limit matches terminal creation readiness; terminal idle can precede native resume and MCP handshake completion. The zero-turn Claude exception still applies only when no original transcript exists. If Claude shows its development-channel confirmation screen, confirm it in
1781
2039
  the captured terminal, then run `ahub recovery resume <operation-id>`; resume must not open a duplicate terminal.
1782
2040
  Kimi and local sessions may start fresh with preserved routing and task context.
1783
2041
  A Claude session that never persisted a transcript (zero turns) also starts fresh:
@@ -1897,7 +2155,8 @@ or cancel and upgrade later.
1897
2155
  its phase, step and error; `runner`, which says whether a runner process holds
1898
2156
  the operation now (`running` with its pid, or `none`; `stale` marks a receipt
1899
2157
  that says running with no runner behind it); each project's phase and effect
1900
- receipts (`closed:<peer>`, `restored:<peer>` as `done`, `pending` or `failed`);
2158
+ receipts (`closed:<peer>` as `done` or `pending`; `restored:<peer>` as
2159
+ `pending`, `waiting:pending`, `waiting:failed`, `done` or `failed`);
1901
2160
  whether the shared plugin and the global CLI were installed; and `next`, the
1902
2161
  commands that apply now, read from every source the operation has not stopped
1903
2162
  yet (every error of `resume` ends with the same list). `resume` is left out
@@ -1907,7 +2166,11 @@ message text. `resume` does not
1907
2166
  start a second runner while one is alive. Every `next` entry and error names the
1908
2167
  operation's own coordinator, `bun <preserved source>/src/cli/main.js recovery
1909
2168
  ...`: in the middle of an upgrade the global `ahub` may still be the older
1910
- release, whose `recovery` lacks these commands. Copy that command line. When
2169
+ release, whose `recovery` lacks these commands. The published 0.12.30 CLI also
2170
+ mislabels tagged waiting receipts as done and can hide the fresh-session choice,
2171
+ even when its status command exists. Use the printed preserved-source
2172
+ coordinator for status, resume and disposition; do not decide from that older
2173
+ CLI's receipt display. Copy that command line. When
1911
2174
  an older coordinator started the operation, `dispose` is named from the running
1912
2175
  release, which has it. What
1913
2176
  each receipt allows, given what is live, is tabulated in the recovery spec
@@ -1945,6 +2208,11 @@ next actions").
1945
2208
  use its offered `ahub recovery resume <id>`. Resume rechecks the source and
1946
2209
  reconciles a commit that may already have been requested. A busy read while
1947
2210
  that committed source is stopping stays inside the existing shutdown wait.
2211
+ A resumed prepared receipt with `commitSent` also polls an unavailable source
2212
+ within the 30-second shutdown bound, including initial database contention,
2213
+ without sending another commit, re-preparing or closing terminals again. Only
2214
+ confirmed `stopped` permits target startup; a replacement instance refuses, and
2215
+ expiry retains the prepared receipt and the same operation for another resume.
1948
2216
  A stop-and-archive that meets contention instead says to retry that
1949
2217
  disposition; resume remains refused while abandonment is partway. Successful
1950
2218
  abort, fresh-session choice and disposal clear the earlier failure annotation.
@@ -2274,6 +2542,22 @@ the capability is absent. It never rewrites these settings. Explicit
2274
2542
  refused before any local startup. Re-enable MLX or explicitly migrate the
2275
2543
  recorded launch before recovery.
2276
2544
 
2545
+ ## Task stalls and cancellation
2546
+
2547
+ A ready task with an ineligible reservation, no eligible peer or a cancelled dependency shows an ids-only stall cause in status and the Tasks panel. The hub reports a cause once, repeating only when the cause changes or the task is re-planned. It directs ownerless advice to the designated planner's next bounded preface and the configured supervision stream, otherwise the person's attention list; it does not create an extra ordinary turn beside backlog batching. Configure the missing capability, assign another eligible peer, re-plan or cancel the task as appropriate; a reservation never bypasses routing guards.
2548
+
2549
+ An offer to a pull-only peer adds an advisory "open <peer>: task #N is waiting for it" attention item. It clears when that exact offer is accepted, declined, superseded or genuinely delivered and settled to the addressed peer. Another inbox read, an accepted-only receipt or a person's queue completion does not prove it was read. The attention item survives peer detach and daemon restart using the saved offer's pull-only flag; it does not alter delivery state.
2550
+
2551
+ The person can retain superseded work as closed history:
2552
+
2553
+ ```sh
2554
+ ahub task cancel <id> --reason <text> [--superseded-by <ref>] [--revision N]
2555
+ ```
2556
+
2557
+ The console also offers cancellation with the selected task's flow revision. Approved tasks cannot be cancelled. The planner's `hub_task_cancel` tool is limited to its own unaccepted backlog/proposed work; previously accepted work requires the person. Cancellation sends the former owner/reviewer a stop notice, releases overlap/reservation participation and keeps dependents blocked with a cancelled-dependency notice. It does not stop a native turn, delete a worktree or write an outcome memory note. Cancelled work is closed history, counted separately from approved work; it does not satisfy an approval dependency. A still-running private turn keeps its privacy fence after cancellation. Use the displayed revision to avoid acting on a task that changed while it was selected.
2558
+
2559
+ The daemon advertises `task_cancel`; a current CLI refuses cancellation against older daemons. Recovery retains verified target features beside its immutable root/digest, reuses them on resume and checks only sources not yet past commit; a legacy receipt without that evidence needs a target probe only before commit. Upgrade/restart refuses a target without this feature while cancelled rows exist and names their ids. No cancelled row is rewritten as approved. An old binary launched by hand remains unsupported: it can count cancelled work as open or fail to move it. Use a compatible coordinator instead. Live task cancellation and sweep enablement are separate post-release operations.
2560
+
2277
2561
  ## Task idle sweep
2278
2562
 
2279
2563
  The between-turn task sweep (#186) is disabled by default. Set `task_sweep` in
@@ -2287,6 +2571,7 @@ The between-turn task sweep (#186) is disabled by default. Set `task_sweep` in
2287
2571
  "unaccepted_min": 60,
2288
2572
  "idle_min": 120,
2289
2573
  "review_min": 120,
2574
+ "ready_min": 60,
2290
2575
  "ladder_min": 30,
2291
2576
  "auto_reassign": false
2292
2577
  }
@@ -2298,6 +2583,8 @@ at least 1; timeouts are bounded to the platform timer limit. Each threshold
2298
2583
  measures time since the last real task history event. A ladder record does not
2299
2584
  refresh that activity; a new event resets the ladder even at the same timestamp.
2300
2585
 
2586
+ Ready proposed tasks without an owner use `ready_min` and the `ready-unassigned` ladder; unresolved or cancelled dependencies do not become ready. A person's unassignment suppresses this automatic ladder until a later explicit assignment or reservation. Planner-pulled work keeps its reserved peer and current WIP/hold admission; an unavailable or full reservation never selects another worker.
2587
+
2301
2588
  The first overdue sweep sends the assigned owner or reviewer one normal task
2302
2589
  reminder. After `ladder_min`, the next sweep notifies the console and available
2303
2590
  planner-role peers. After another interval it reports a reassignment suggestion
@@ -2379,13 +2666,15 @@ registry directories and a scrubbed environment. The normal 20-second test timeo
2379
2666
  both legs. Successful fixtures are removed; a failed pair prints its preserved
2380
2667
  fixture location with test and leak evidence for inspection.
2381
2668
 
2382
- The required Linux CI job `seeded guards` follows the ordinary checks; it does not
2383
- repeat on macOS or run recursively inside `bun test`. The runner reports every
2669
+ CI runs the pairs as four Linux shards (`bun scripts/seeded-check.ts --shard i/4`,
2670
+ every fourth pair, still sequential within a shard) beside the ordinary checks; the
2671
+ required job `seeded guards` passes only when all four shards passed (#457). The pairs
2672
+ do not repeat on macOS or run recursively inside `bun test`. The runner reports every
2384
2673
  pair's elapsed seconds and the total runtime. A green ordinary check alone does
2385
2674
  not prove these pairs.
2386
2675
 
2387
- The full CI gate tests the PR head tree on Linux and macOS, followed by the
2388
- sequential seeded-guard job. Main and release jobs reuse only a successful full
2676
+ The full CI gate tests the PR head tree on Linux and macOS, with the seeded-guard
2677
+ shards running at the same time. Main and release jobs reuse only a successful full
2389
2678
  PR or push check with the identical Git tree and all three successful jobs. An absent or
2390
2679
  unreadable result runs the main gate again and refuses release. A manual
2391
2680
  `prepare_bundle` dispatch builds reviewable plugin assets without publishing;
@@ -2662,6 +2951,9 @@ Qwen controlled recovery and automatic crash resume load the recorded conversati
2662
2951
 
2663
2952
  Use ahub roster add jcode, then ahub jcode --mode headless [--model <alias>] [--provider-profile <name>]. The person launcher configures only agent-hub-jcode in .jcode/mcp.json; run ahub init afterwards to ignore the untracked machine-path file. Conductor/dashboard starts read that entry without editing it. Preview starts nothing, and ahub stop jcode stops only the owned private daemon/ACP groups. jcode_cmd, jcode_home and jcode_provider_profile are machine-local and never editable from settings.
2664
2953
 
2954
+ After upgrading to the recipient-retry release, a Jcode project MCP entry written before `AGENTHUB_DELIVERY_ONLY` was added is intentionally stale. Once per project, the person runs `ahub jcode --mode headless` before using conductor/dashboard starts. The launcher rewrites only the owned entry with the delivery-only marker, preserving foreign entries and refusing collisions; recovery relaunches already use this CLI path. Readiness checks never rewrite the file, and an explicit false marker or any other drift remains refused. Until that rewrite, daemon starts keep their actionable stale-entry refusal rather than advertising a retry tool Jcode cannot use.
2955
+
2956
+
2665
2957
  Native policy is unmanaged and has NO hub sandbox; no permission_modes.jcode or runtime mode mapping is invented. Quota and consumption remain unknown. Version 0.94.0 cannot prove native session/load identity, so attached Jcode blocks controlled recovery before effects and crash recovery asks for deliberate native reopening. A requested load without an echoed identity refuses; no fresh session is presented as restored. Provider/tool/native teardown receipts remain unverified in the pinned contract report.
2666
2958
 
2667
2959
  # Headless ACP watch (#286)
@@ -2790,7 +3082,7 @@ Create a phase with `ahub release new <name> <goal> <order>`, inspect `list` or
2790
3082
  `show`, and set planned start/cut/ship with `plan <name> <revision> <dates-json>`.
2791
3083
  `activate`, `freeze`, `ship` and `drop` need its current revision. Only a person
2792
3084
  freezes, ships, drops or edits frozen scope. Ship records the first ship time
2793
- only after every member is approved or moved out; it runs no tag or publish.
3085
+ only after every member is approved, cancelled or moved out; it runs no tag or publish.
2794
3086
  The dashboard shows phase progress, blocking dependencies, dates and remaining
2795
3087
  work. Actual task dates come from execution/review/approval history, never input.
2796
3088