@staix/agent-hub 0.29.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/README.md +15 -7
- package/docs/agent-notes/README.md +13 -0
- package/docs/agent-notes/adapters.md +7 -3
- package/docs/agent-notes/budget.md +1 -0
- package/docs/agent-notes/bus.md +10 -4
- package/docs/agent-notes/daemon.md +16 -8
- package/docs/agent-notes/local-worker.md +1 -0
- package/docs/agent-notes/tasks.md +10 -4
- package/docs/agent-notes/tests.md +8 -4
- package/docs/design/adapters.md +108 -0
- package/docs/design/agent-hub-architecture.md +58 -0
- package/docs/design/bus.md +147 -1
- package/docs/design/task-board.md +100 -0
- package/docs/dogfood.md +29 -8
- package/docs/events.md +3 -0
- package/docs/memory.md +17 -1
- package/docs/operations.md +410 -86
- package/docs/profiles.md +35 -0
- package/docs/quickstart.md +25 -5
- package/docs/sdlc.md +1 -1
- package/docs/security.md +182 -62
- package/docs/smoke.md +13 -2
- package/docs/specs/2026-09-19-agent-hub-design.md +84 -14
- package/docs/specs/2026-09-19-multi-project-design.md +7 -2
- package/docs/specs/2026-10-12-office-view-design.md +86 -3
- package/docs/verification/2026-11-03-0.30.0.md +54 -0
- package/docs/verification/2026-11-03-agy-1.4.12-launcher-nonce.md +42 -0
- package/docs/verification/2026-11-03-agy-1.4.12.md +90 -0
- package/docs/verification/2026-11-03-agy-tui-close.md +49 -0
- package/docs/verification/2026-11-03-grok-1.0.62-t0.md +150 -0
- package/docs/verification/2026-11-03-pi-150-compat.md +40 -0
- package/docs/verification/2026-11-03-pi-title-api.md +26 -0
- package/docs/verification/2026-11-03-qwen-0265-acp.md +55 -0
- package/docs/verification/2026-11-03-qwen-0265-dual-output.md +40 -0
- package/docs/verification/2026-11-04-1171-channel-client-evidence.md +31 -0
- package/docs/verification/2026-11-05-0.31.0.md +182 -0
- package/docs/verification/2026-11-05-claude-implementer-2.1.318.md +70 -0
- package/docs/verification/2026-11-05-hardcoded-values-classification-rules.md +257 -0
- package/docs/verification/2026-11-05-hardcoded-values-ratchet.md +55 -0
- package/docs/verification/2026-11-06-rooms-presence-cost.md +152 -0
- package/docs/verification/claude-shell-wrapper-native.py +1 -1
- package/docs/verification/dogfood/2026-11-03.md +3095 -0
- package/docs/verification/pi-150-model-free.ts +57 -0
- package/docs/verification/pi-150-native.mjs +21 -0
- package/docs/verification/pi-150-title-api.mjs +31 -0
- package/docs/verified.json +14 -14
- package/package.json +3 -4
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +4565 -3617
- package/src/adapters/acp.ts +5 -4
- package/src/adapters/channel-peer.ts +72 -3
- package/src/adapters/claude-channel-evidence.ts +52 -0
- package/src/adapters/claude-channel.ts +61 -18
- package/src/adapters/claude-implementer.ts +29 -7
- package/src/adapters/claude-print-child.ts +12 -2
- package/src/adapters/codex-appserver.ts +13 -12
- package/src/adapters/compat.ts +13 -13
- package/src/adapters/definitions/builtin-metadata.ts +13 -13
- package/src/adapters/definitions/qwen.ts +1 -0
- package/src/adapters/local-worker.ts +82 -23
- package/src/adapters/pi.ts +140 -16
- package/src/adapters/registry-types.ts +16 -0
- package/src/adapters/registry.ts +4 -0
- package/src/adapters/reviewer-print.ts +50 -11
- package/src/broker/server.ts +44 -13
- package/src/broker/store.ts +38 -8
- package/src/cli/answer-args.ts +50 -0
- package/src/cli/attention.ts +17 -2
- package/src/cli/autonomy.ts +66 -1
- package/src/cli/backlog-return-args.ts +37 -0
- package/src/cli/console-question.ts +110 -0
- package/src/cli/console-state.ts +82 -17
- package/src/cli/console.ts +54 -1
- package/src/cli/handoff-args.ts +15 -5
- package/src/cli/handoff-output.ts +15 -2
- package/src/cli/help.ts +10 -5
- package/src/cli/identity.ts +21 -4
- package/src/cli/main.ts +167 -16
- package/src/cli/memory.ts +107 -3
- package/src/cli/output.ts +29 -6
- package/src/cli/pet.ts +4 -4
- package/src/cli/results-args.ts +30 -0
- package/src/cli/runtime-version-warning.ts +50 -0
- package/src/cli/status-lines.ts +41 -1
- package/src/cli/tail-render.ts +1 -0
- package/src/cli/upgrade-interactive.ts +14 -2
- package/src/cli/worktree-tidy.ts +158 -0
- package/src/cli/worktrees-output.ts +43 -0
- package/src/hub/action-class.ts +9 -1
- package/src/hub/board.ts +396 -20
- package/src/hub/bus.ts +497 -57
- package/src/hub/completion-detail.ts +50 -0
- package/src/hub/completions-store.ts +168 -0
- package/src/hub/completions.ts +120 -0
- package/src/hub/conductor.ts +4 -3
- package/src/hub/config-apply.ts +8 -5
- package/src/hub/config-reload.ts +10 -1
- package/src/hub/control-client.ts +40 -4
- package/src/hub/daemon.ts +1795 -142
- package/src/hub/delivery-failure.ts +14 -0
- package/src/hub/delivery-hints.ts +14 -4
- package/src/hub/delivery-journal.ts +751 -42
- package/src/hub/delivery-superseded.ts +4 -1
- package/src/hub/dogfood-read.ts +62 -9
- package/src/hub/envelope.ts +3 -3
- package/src/hub/events.ts +6 -0
- package/src/hub/handoff.ts +145 -6
- package/src/hub/hub-tools.ts +66 -11
- package/src/hub/manager.ts +67 -3
- package/src/hub/memory-policy.ts +44 -1
- package/src/hub/memory-sync-policy.ts +109 -0
- package/src/hub/memory-sync-state.ts +145 -0
- package/src/hub/no-writes.ts +1 -1
- package/src/hub/operational-settings.ts +11 -2
- package/src/hub/operational-view.ts +12 -1
- package/src/hub/peer-doing.ts +33 -3
- package/src/hub/peers.ts +32 -2
- package/src/hub/planning.ts +6 -1
- package/src/hub/question-desk.ts +201 -0
- package/src/hub/question-detach.ts +6 -0
- package/src/hub/questions.ts +260 -0
- package/src/hub/research-evidence.ts +106 -0
- package/src/hub/restart.ts +14 -0
- package/src/hub/review-anchor.ts +181 -0
- package/src/hub/review-brief.ts +13 -0
- package/src/hub/review-comments.ts +115 -0
- package/src/hub/review-findings.ts +7 -2
- package/src/hub/review-material.ts +76 -0
- package/src/hub/routing.ts +3 -1
- package/src/hub/settings.ts +3 -0
- package/src/hub/task-sweep.ts +2 -0
- package/src/hub/tasks.ts +607 -71
- package/src/hub/ui.ts +2 -0
- package/src/hub/worktree-prs.ts +100 -0
- package/src/hub/worktree-shelf.ts +246 -0
- package/src/memory/capture.ts +5 -2
- package/src/pet/config.ts +25 -13
- package/src/pi/extension.ts +43 -3
- package/src/rooms/link.ts +209 -21
- package/src/rooms/remote-peer.ts +186 -19
- package/src/rooms/service.ts +338 -22
- package/src/rooms/store.ts +437 -65
- package/src/rooms/wire.ts +24 -6
- package/src/ui/index.html +271 -17
- package/src/ui/needs.ts +10 -4
- package/src/ui/office-model.ts +64 -8
- package/src/ui/office-space.ts +1 -0
- package/src/ui/plugin-questions.ts +56 -0
- package/src/ui/plugin-results.ts +81 -0
- package/src/ui/plugin.ts +219 -28
- package/src/pet/window.html +0 -114
- package/src/pet/window.jxa.js +0 -122
- package/src/pet/window.ts +0 -154
package/docs/operations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Operations guide
|
|
2
2
|
|
|
3
|
-
This guide describes ahub 0.
|
|
3
|
+
This guide describes ahub 0.31.0 and control protocols 16 through 17. Live verification
|
|
4
4
|
results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
|
|
5
5
|
|
|
6
6
|
## Agent-operated live verification
|
|
@@ -211,8 +211,7 @@ Home/End sequences is that many key presses, so a held key repeats its move. Hom
|
|
|
211
211
|
or `<` jumps to a panel's first row and End or `>` to its last; the Events tab
|
|
212
212
|
follows new events while the last row is selected and stays on a row you moved to.
|
|
213
213
|
`w` opens the dashboard outside the Peers tab; in Peers it edits the selected
|
|
214
|
-
peer's WIP limit. `
|
|
215
|
-
work on the command line too. In the Peers tab the planner's row reads `(planner)`, and
|
|
214
|
+
peer's WIP limit. `:ui --all` works on the command line too. In the Peers tab the planner's row reads `(planner)`, and
|
|
216
215
|
`l` then `y` makes the selected peer the planner (`ahub settings set planner <peer>`). In the Events
|
|
217
216
|
tab a row's header line is tokenized and coloured exactly as the same event in
|
|
218
217
|
the stream; only the header is tab-flattened before tokenizing. Body lines retain
|
|
@@ -278,6 +277,42 @@ dashboard's peer rows and the conductor's `hub_status` show the same value; it
|
|
|
278
277
|
lives in the daemon's memory only, never in `status.json`, a log, an event or
|
|
279
278
|
memory capture. Board WIP is unchanged.
|
|
280
279
|
|
|
280
|
+
Pi and the local worker can name an unnamed session with `hub_set_title`
|
|
281
|
+
(#1055). A normalized title is 1-80 characters; the first agent name is final.
|
|
282
|
+
The person replaces it with `ahub title <peer> <text...>`, or selects the peer
|
|
283
|
+
in the console and presses `t`. The rename input starts empty after the command
|
|
284
|
+
prefix, even when an unnamed label is visible. Other peers rename in their
|
|
285
|
+
native UI. No helper model is called, and task, branch and instance names are
|
|
286
|
+
independent. A private turn, an open PII owner/reviewer assignment, a sensitive
|
|
287
|
+
title or a failed metadata screen refuses the write.
|
|
288
|
+
|
|
289
|
+
Every refused title call includes its reason code plus a public cause and next
|
|
290
|
+
step. An unconfirmed write can have landed: check `ahub status` before retrying
|
|
291
|
+
when the error says it may have been applied. A person rename on an idle Pi
|
|
292
|
+
session that has never exchanged a message creates native title metadata but
|
|
293
|
+
may not create a session file yet. Recovery preserves that state by refusing
|
|
294
|
+
ID-only recreation; exchange one message or explicitly start a new session,
|
|
295
|
+
then retry recovery.
|
|
296
|
+
|
|
297
|
+
An unnamed session displays a muted label from the first acknowledged hub
|
|
298
|
+
delivery, at most 60 normalized characters. Queued or unaccepted messages do not
|
|
299
|
+
supply it. The console and configured conductor can see this incoming-message
|
|
300
|
+
label; other agent status readers see `unnamed`. Its source note distinguishes
|
|
301
|
+
the incoming message from text written by the recipient peer. The label is
|
|
302
|
+
computed only for live status and dashboard reads;
|
|
303
|
+
`status.json`, events, logs and memory receive no derived label. The daemon
|
|
304
|
+
stores only the peer's title-session ID and acknowledged delivery/envelope IDs
|
|
305
|
+
for native-session peers in `session-title-inputs.json`. The
|
|
306
|
+
[storage contract](design/adapters.md#session-title-slots) defines its bounds
|
|
307
|
+
and lifetime. Removed instances are pruned when their removal applies, and
|
|
308
|
+
Local bindings are discarded because the worker starts a new memory session.
|
|
309
|
+
After restart it recomputes the label only when
|
|
310
|
+
the same session and retained journal original match; a new session or pruned
|
|
311
|
+
original shows no inherited label. Pi's real name stays in Pi's native session;
|
|
312
|
+
the local worker's name lives only with that worker's in-memory session. The
|
|
313
|
+
native setter/readback probe is separate from the still-pending live restart
|
|
314
|
+
receipt tracked in #1143 and `docs/smoke.md`.
|
|
315
|
+
|
|
281
316
|
In Peers, select a row and press `w` to edit `tasks.wip_limits.<peer>`, prefilled
|
|
282
317
|
with its current limit. The editor stays on Peers and uses the existing Settings
|
|
283
318
|
value, daemon preview, nonempty reason and `y` confirmation flow; Esc cancels without writing. The
|
|
@@ -361,8 +396,11 @@ observed revision from the bounded held-row metadata returned with `hub_inbox`.
|
|
|
361
396
|
Use `completed` after handling the delivery, or `discard` when it should not be
|
|
362
397
|
acted on, with a nonempty reason. The journal records the recipient actor and
|
|
363
398
|
reason. Another peer's row, a stale revision, remote-room disposition, active
|
|
364
|
-
`dispatching
|
|
365
|
-
holds, and a reason that is private or sensitive
|
|
399
|
+
`dispatching` rows, a non-channel peer's `accepted` row, a paused or held peer,
|
|
400
|
+
recovery, shutdown or storage holds, and a reason that is private or sensitive
|
|
401
|
+
all refuse. An explicit push-channel session may also settle its own `accepted`
|
|
402
|
+
row as described under [accepted channel delivery settlement](#accepted-channel-delivery-settlement-1172).
|
|
403
|
+
A row that carries an
|
|
366
404
|
invocation stays person-only (`ahub queue show <id>`, then `ahub queue resolve
|
|
367
405
|
<id>`), because the invocation may still be running. This never retries a message, changes a task
|
|
368
406
|
role or cancels the native turn; recipient retry keeps its existing one-use rules.
|
|
@@ -453,7 +491,7 @@ OS color preference through CSS. Both inline scripts and the style retain CSP
|
|
|
453
491
|
hashes; there are no external chart/theme assets. Live theme/readability inspection
|
|
454
492
|
is tracked in `docs/smoke.md` and remains unverified until performed.
|
|
455
493
|
|
|
456
|
-
The dashboard Office section (#264, phase 1
|
|
494
|
+
The dashboard Office section (#264, phase 1) draws the same snapshot as a
|
|
457
495
|
static flat office: one desk per peer in a stable slot (claude, codex, kimi, pi,
|
|
458
496
|
local, then others by id; a peer going offline dims its desk and never moves
|
|
459
497
|
another), rooms for the board columns in a fixed order (To do, Work floor,
|
|
@@ -480,6 +518,16 @@ projection without animating; the settle rule and reduced motion apply
|
|
|
480
518
|
unchanged. The live browser look is tracked in `docs/smoke.md` and
|
|
481
519
|
remains unverified until performed.
|
|
482
520
|
|
|
521
|
+
Phase 5 (#1152) adds a Backlog room before To do: cards in rank, then
|
|
522
|
+
priority, then id order, at most 8 with "+N more" opening the backlog filter,
|
|
523
|
+
each with its reserved, pinned and waiting marks, and a count equal to the
|
|
524
|
+
board's backlog count. Up to three release docks (planning, active or frozen
|
|
525
|
+
releases, then "+N releases") show approved/scope and the cut date; activating
|
|
526
|
+
a dock sets the task list's release filter. Each planner-role desk carries the
|
|
527
|
+
number of unplanned backlog cards (no rank, no reservation), and the wall shows
|
|
528
|
+
that count when no planner desk is visible. All of it is read from the existing
|
|
529
|
+
snapshot; the design is `docs/specs/2026-10-12-office-view-design.md`.
|
|
530
|
+
|
|
483
531
|
Motion (phase 2): card moves between rooms and desks, message arcs between
|
|
484
532
|
desks (from the hub or the console they start at an anchor point), delivery
|
|
485
533
|
warning marks and the busy latch all follow the snapshot. Motion is CSS only:
|
|
@@ -713,8 +761,8 @@ setting (`ahub settings set peers.pi.start_mode headless`), asks for the
|
|
|
713
761
|
background peer instead. The project uses its existing OmniRoute connection for DGX;
|
|
714
762
|
`pi.dgx_coding` and `pi.dgx_fast` select the gateway's configured model IDs.
|
|
715
763
|
Every Pi start (headless, TUI, console or auto start) first runs the configured
|
|
716
|
-
`pi.cmd` with `--version` (#847). Pi 1.4.0
|
|
717
|
-
([model-free receipt](verification/2026-10-26-pi-140-compat.md)); another
|
|
764
|
+
`pi.cmd` with `--version` (#847). Pi 1.4.0 and 1.5.0 are verified
|
|
765
|
+
([1.4.0 model-free receipt](verification/2026-10-26-pi-140-compat.md), [1.5.0](verification/2026-11-03-pi-150-compat.md)); another
|
|
718
766
|
version, or one that cannot be read, is refused before Pi starts, unless the
|
|
719
767
|
person trusts that exact version with `ahub agents trust pi <version>`.
|
|
720
768
|
|
|
@@ -965,11 +1013,18 @@ plugin stale when the module changed after setup, so run `ahub setup` again afte
|
|
|
965
1013
|
- **Panels.** The plugin's panels are the dashboard's seven views, and the panel is the `ahub ui`
|
|
966
1014
|
page itself, following acon's theme. It reaches project hubs only through the manager's own
|
|
967
1015
|
listing and forwarding (`ahub ui --all`): registered project and instance ids, the manager's
|
|
968
|
-
closed action list and the seven view names. There is no new protocol
|
|
1016
|
+
closed action list and the seven view names. There is no new protocol. An answer, a result
|
|
1017
|
+
receipt or a review comment sent from acon goes through a manager port of its own (`answer`,
|
|
1018
|
+
`receipt`, `consoleControl`) that needs acon's verified person `meta`.
|
|
969
1019
|
- **Inbox.** acon's inbox lists each running project's pending approvals (Allow once / Deny,
|
|
970
|
-
answered with the hub's own `permit` and an option the request offers)
|
|
971
|
-
|
|
972
|
-
|
|
1020
|
+
answered with the hub's own `permit` and an option the request offers), open questions and unread
|
|
1021
|
+
results (see the Questions and Results sections), the settled-worktree alert and in-review
|
|
1022
|
+
tasks whose reviewer is you (Open board). A local-worker or Pi approval stays deny-only there, as on the
|
|
1023
|
+
dashboard: answer it with `ahub permit` after `ahub tail`. A reply holds at most 50 items, most
|
|
1024
|
+
urgent first (decisions, reviews, results, candidates, then alerts), and counts the rest (#1196).
|
|
1025
|
+
Running projects are asked at once, each within about 2 s; a project that misses that keeps the
|
|
1026
|
+
items it last returned unless an action has happened since. A poll within 1 s reuses the last
|
|
1027
|
+
reply, one within 10 s gets it at once while a refresh runs, and any action drops it.
|
|
973
1028
|
- **Confirmation.** `stop`, `permit`, `send`, the settings writes (`setting`, `setting_undo`,
|
|
974
1029
|
`setting_reload`, `config_edit_apply`), `start_peer`, `backlog_split` and the inbox's Allow once
|
|
975
1030
|
and Deny answer `needsConfirm` with a preview first; acon runs them after you confirm.
|
|
@@ -1209,6 +1264,10 @@ to look for a queued or needs_review delivery with
|
|
|
1209
1264
|
with `ahub task assign <id> <owner>`. Nothing resends automatically: a blind resend can
|
|
1210
1265
|
duplicate a delivery that actually left.
|
|
1211
1266
|
|
|
1267
|
+
#### Accepted channel delivery settlement (#1172)
|
|
1268
|
+
|
|
1269
|
+
An explicit Claude push-channel session can settle or discard its own accepted row with the shown revision and a public-safe reason, but an `accepted` receipt still means transport acceptance only. If the session sends neither native completion nor an explicit disposition within `bus.accepted_settle_ms`, the next maintenance sweep moves the row to `needs_review` with a fixed timeout cause; no replay occurs. The default is ten minutes (range 1,000-86,400,000 ms). A live `hub_inbox` result includes that session's own accepted and held row ids and revisions, including when the accepted delivery blocks pulling, so it can inspect the row and use `hub_delivery_resolve`. If held metadata cannot be read, the response carries a fixed unavailable sentinel; the plugin keeps any pulled messages and directs the session to `ahub queue list --peer <peer-id>`, without exposing the metadata error. Important, task and review timeouts publish one status notice to the configured conductor with only delivery id, peer id and revision when `conductor.feed` is on; `feed: off` remains the existing opt-out, and no conductor role is forced. The timeout row is excluded from task-state superseding and remains visible until a person or the explicit channel session records a disposition. Recovery refuses a target without `accepted_delivery_settlement` while such a timeout row is retained; projects without one remain compatible with older targets. The row transition is durable before notice publication; if the hub crashes or notice publication is refused by journal storage after the transition, the held row remains authoritative and visible and the host does not invent a replay path.
|
|
1270
|
+
|
|
1212
1271
|
Reviewer candidates follow `[classes.review].peers`, then attached peers with a
|
|
1213
1272
|
`reviewer` role in `roles`. The owner cannot review its own task. If none is available,
|
|
1214
1273
|
the assignment output and console notice say that `done` will approve without review
|
|
@@ -1745,9 +1804,10 @@ ahub study experiments --campaign rc-0123456789ab [--after 50] # read the reco
|
|
|
1745
1804
|
ids, counts, states and provenance and stubs its text as `[pii]`. Study tool arguments and results are kept out
|
|
1746
1805
|
of hub-managed memory capture.
|
|
1747
1806
|
- **Upgrades.** The daemon advertises `research_records`, `research_dispatch`, `research_dropped_offers`,
|
|
1748
|
-
`research_experiments`, `research_comparisons` and `
|
|
1749
|
-
`research_runners`, stored runner receipts or any `research.runners` block
|
|
1750
|
-
recovery onto a release without the
|
|
1807
|
+
`research_experiments`, `research_comparisons`, `research_runners` and `research_evidence` (#931). While the
|
|
1808
|
+
matching rows exist (for `research_runners`, stored runner receipts or any `research.runners` block; for
|
|
1809
|
+
`research_evidence`, stored claim evidence links), a restart, upgrade or recovery onto a release without the
|
|
1810
|
+
feature is refused.
|
|
1751
1811
|
|
|
1752
1812
|
## Hub memory
|
|
1753
1813
|
|
|
@@ -1764,7 +1824,7 @@ ahub memory forget 1a2b3c4d # a person's; also promote, demote, sup
|
|
|
1764
1824
|
|
|
1765
1825
|
`"memory": { "native": false }` in `.agenthub/config.json` turns it off for a project.
|
|
1766
1826
|
|
|
1767
|
-
The exact-pinned `@staix/agent-mem` 0.
|
|
1827
|
+
The exact-pinned `@staix/agent-mem` 0.20.1 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.
|
|
1768
1828
|
|
|
1769
1829
|
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`; since agent-mem 0.7.0 `amem review` also lists and accepts candidates on a selected generation. 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).
|
|
1770
1830
|
|
|
@@ -2241,7 +2301,7 @@ Run `ahub autonomy on` from a person's terminal. It previews the concrete settin
|
|
|
2241
2301
|
|
|
2242
2302
|
On a running hub, the on confirmation retains peer-specific consent under the machine hub home, outside the project and its execution roots, authenticated and bound to this project and the exact per-peer permission-mode values the person confirmed. A project-file marker or a forged state row cannot confirm never-ask. Missing or changed evidence keeps the ordinary per-peer console confirmation; changing one peer's mode invalidates that peer's consent. Start defaults and action-policy changes do not invalidate mode consent. Off and preset undo remove retained consent, so restoring a never-ask value with undo needs a new on confirmation, or a hub start under a trusted machine opt-in when the value exactly matches the preset plan, to retain it again. An agent shell, a delegated live-test command, a tools connection and the conductor cannot turn autonomy on or off. No hub tool exposes it.
|
|
2243
2303
|
|
|
2244
|
-
`ahub autonomy status`
|
|
2304
|
+
`ahub autonomy status` starts with a padded peer table of current effective modes and preset next-start defaults (`unmanaged` when no mode is requested). Guarded actions follow, grouped by identical class, verdict and reason, with the affected peers (or "all peers") and counts of classes and classes enforced for at least one peer. Shared unknowns are printed once with their peer lists; floor-shaped missing entries are not repeated. Machine-default and Claude-home notices are retained, and paths under the user's home appear with `~`. Reasons and unknowns keep their original text. `--json` returns the unchanged structured report; an older hub without structured peers keeps the legacy line output. Plugin, native policy, terminal provider and GitHub branch protection are reported as missing or unknown when no current evidence establishes them. Orca uses the existing registered worktree opener; a custom `terminal.open` template is preserved. A headless or CI invocation selects headless defaults where the kind supports them. With the hub stopped, status reads only the project configuration: effective modes and retained consent are reported unknown, and every floor class is not enforced.
|
|
2245
2305
|
|
|
2246
2306
|
A controlled restart or upgrade checks target feature `project_autonomy` while preset metadata or retained consent is active. A target without it is refused before the source is held or stopped; it could not read the new config metadata. Turn the preset off before selecting such a target.
|
|
2247
2307
|
|
|
@@ -2386,6 +2446,7 @@ A guarded file edit that the daemon keeps at its accepted value remains visible
|
|
|
2386
2446
|
| Routing | `routing.stay_switch`, `routing.classes.<class>.peers`, `.escalate_to`, `.route`, `.pi_backend` | `routing.local.toml` | at once |
|
|
2387
2447
|
| Switches | `research.enabled`, `approvals.notify`, `snapshots.enabled` | `config.local.json` | live, without disturbing an active turn |
|
|
2388
2448
|
| Switches | `coordination` | `config.local.json` | newly created tasks only |
|
|
2449
|
+
| Switches | `worktrees.quiet_days` (0-3650, default 7, 0 never shelves by quiet time), `worktrees.alert_over` (0-100000, default 10, 0 never alerts) ([worktree shelf](#the-worktree-shelf-1057)) | `config.local.json` | live |
|
|
2389
2450
|
| Switches | `task_sweep.enabled`, `.auto_reassign`, `.interval_s`, `.unaccepted_min`, `.idle_min`, `.review_min`, `.ready_min`, `.ladder_min`, `.no_writes_turns` | `config.local.json` | live; `.no_writes_turns` sets the turn threshold independently; other keys reschedule the sweep timer |
|
|
2390
2451
|
| Routing | `tasks.wip_limits.<peer>` | `config.local.json` | live |
|
|
2391
2452
|
| Routing | `tasks.escalate_after` (1-10, default 3: consecutive `changes_requested` before a task moves to the next `escalate_to` peer) | `config.local.json` | live; the next verdict uses it |
|
|
@@ -2404,6 +2465,7 @@ A guarded file edit that the daemon keeps at its accepted value remains visible
|
|
|
2404
2465
|
| Routing | `bus.pull_budget_bytes` (1-65536 bytes, default 65536) | `config.local.json` | live; next pull-only read, oldest first; the first oversized item still goes |
|
|
2405
2466
|
| Routing | `bus.notes_kept` (1-10 notes, default 10) | `config.local.json` | live; next shared-note or failed-preface merge; existing prefaces remain unchanged on reload |
|
|
2406
2467
|
| Routing | `bus.terminal_history_limit` (1-2048 rows, default 2048) | `config.local.json` | live; next normal terminal settlement; unresolved rows and retry ancestry stay protected |
|
|
2468
|
+
| Routing | `bus.accepted_settle_ms` (1000-86400000 ms, default 600000) | `config.local.json` | live; the next accepted-channel timeout sweep, approximately every five seconds |
|
|
2407
2469
|
| Routing | `recovery.reconnect_wait_s` (600-3600 seconds, default 600) | `config.local.json` | next use; the next managed-terminal attachment wait of an upgrade recovery reads it once, at its start |
|
|
2408
2470
|
| Routing | `recovery.unmanaged_reconnect_wait_s` (90-900 seconds, default 90) | `config.local.json` | next use; the next unmanaged Claude reconnect wait reads it once, at its start |
|
|
2409
2471
|
| Routing | `recovery.control_timeout_s` (30-300 seconds, default 30) | `config.local.json` | next use; the next control request of the recovery coordinator to a hub reads it |
|
|
@@ -2483,7 +2545,7 @@ The H0 operational items of `tasks.ts`, `routing.ts` and `task-sweep.ts` that st
|
|
|
2483
2545
|
|
|
2484
2546
|
#### Bus and delivery conversions (#489 H3)
|
|
2485
2547
|
|
|
2486
|
-
The five `bus.*` rows above use the H1 descriptor, schema, settings writer and live
|
|
2548
|
+
The five pre-existing #489 `bus.*` rows above use the H1 descriptor, schema, settings writer and live
|
|
2487
2549
|
reload path. Unset defaults equal `MAX_ATTEMPTS`, `DIGEST_MAX`, `PULL_BUDGET_BYTES`,
|
|
2488
2550
|
`NOTES_KEPT` and `TERMINAL_CAP`. Only `bus.max_attempts` may rise; the other four
|
|
2489
2551
|
can only tighten today's ceilings. A reload does not trim/reorder queues or
|
|
@@ -2491,6 +2553,8 @@ prefaces, reset attempts, re-arm batch deadlines, prune history, or change a pau
|
|
|
2491
2553
|
or in-flight delivery. Terminal history is a target: protected retry parents and the current mutation receipt may
|
|
2492
2554
|
keep the count above it. The settings add no conductor authority.
|
|
2493
2555
|
|
|
2556
|
+
`bus.accepted_settle_ms` (#1172) adds a timeout for explicit push-channel acceptance, rather than converting an existing constant. Its ten-minute default allows normal session initialization, compaction and handling while bounding a silently lost notification; the channel can confirm earlier, before a long task finishes. The setting is read at the next maintenance sweep. Expiry changes only the delivery journal to `needs_review` and never replays the message; native completion, task completion and task approval remain separate.
|
|
2557
|
+
|
|
2494
2558
|
The [H3 H0 ledger](verification/2026-10-30-bus-delivery-operational-settings.md)
|
|
2495
2559
|
lists all 59 unique inventory identities (5 converted and 54 excluded). The
|
|
2496
2560
|
persisted `SEEN_CAP`/dedupe contract and withdrawn cancellation evidence stay
|
|
@@ -3025,6 +3089,21 @@ The states are `queued`, `dispatching`, `accepted`, `completed`,
|
|
|
3025
3089
|
the native bridge received the delivery; it does not prove that the agent
|
|
3026
3090
|
executed it. Only native completion or a correlated reply can settle a receipt.
|
|
3027
3091
|
|
|
3092
|
+
Failed deliveries carry a public-safe `failureCause` from the fixed classes
|
|
3093
|
+
`peer offline`, `adapter refused`, `push error`, `turn aborted`, and `timeout`
|
|
3094
|
+
(#1178). `ahub queue show` and `ahub queue list --json` expose the class, never
|
|
3095
|
+
message text as the cause. Older rows without it have an unknown cause; the hub
|
|
3096
|
+
does not reconstruct one from their reason or body. This diagnostic does not
|
|
3097
|
+
change settlement: a possibly effected delivery remains `needs_review`, not a
|
|
3098
|
+
safe failure merely because its cause is known.
|
|
3099
|
+
|
|
3100
|
+
`ahub status` shows each peer's unresolved failed count above zero, with
|
|
3101
|
+
`ahub queue discard --peer <id> --state failed` as the next step. Inspect the
|
|
3102
|
+
rows first, then supply the discard command's reason and confirmation. A row
|
|
3103
|
+
already settled by an explicit resolution is excluded, including a failed
|
|
3104
|
+
parent left behind by `retry`; its linked attempt has its own state. Older hubs
|
|
3105
|
+
without this count and unavailable delivery storage do not imply a zero count.
|
|
3106
|
+
|
|
3028
3107
|
The console interface is:
|
|
3029
3108
|
|
|
3030
3109
|
```text
|
|
@@ -3094,12 +3173,47 @@ them while the hub was down does not keep the short list (#490). A status probe
|
|
|
3094
3173
|
that is unavailable right after a restart is retried, then the list is
|
|
3095
3174
|
announced anyway.
|
|
3096
3175
|
|
|
3176
|
+
### Hand a peer to a standby session (#1174)
|
|
3177
|
+
|
|
3178
|
+
`ahub status` lists live standby connections with their connection identity and
|
|
3179
|
+
reported PID when available. From the person's terminal, request a handover:
|
|
3180
|
+
|
|
3181
|
+
```sh
|
|
3182
|
+
ahub peer takeover claude
|
|
3183
|
+
```
|
|
3184
|
+
|
|
3185
|
+
The Peers panel in `ahub console` offers the same takeover action with `o`. An explicit
|
|
3186
|
+
console selection stays bound to the displayed standby id; the CLI's peer-only
|
|
3187
|
+
form chooses the oldest eligible live standby. The result reports that a claim
|
|
3188
|
+
was requested. Refresh status to confirm attachment. If no eligible standby
|
|
3189
|
+
remains, the command refuses without detaching the current owner.
|
|
3190
|
+
|
|
3191
|
+
Use `ahub peer takeover claude <standby-id>` to select the exact connection shown
|
|
3192
|
+
by status. If a request times out, inspect status before retrying; the handover
|
|
3193
|
+
may already have started.
|
|
3194
|
+
|
|
3195
|
+
This detaches the old hub connection, not its native process. The old plugin's
|
|
3196
|
+
next hub tool explains that the person detached it; it cannot reconnect and take
|
|
3197
|
+
the peer back. Unconfirmed deliveries follow their normal settlement rules, and
|
|
3198
|
+
takeover itself never marks them completed. A reported PID or connection UUID is
|
|
3199
|
+
not native session or permission evidence. Agent and delegated live-test writes
|
|
3200
|
+
are refused by the same person-only path.
|
|
3201
|
+
|
|
3202
|
+
A previous plugin may display a generic terminal-admission refusal after takeover;
|
|
3203
|
+
run `ahub setup` and restart that plugin for the specific person-detachment text.
|
|
3204
|
+
With an older daemon the plugin keeps the prior standby reconnect behavior, and
|
|
3205
|
+
an unsupported takeover request names the unavailable operation. No live account
|
|
3206
|
+
or native process handover is certified by the fixture tests.
|
|
3207
|
+
|
|
3097
3208
|
### Replaced or ended Claude sessions (#551)
|
|
3098
3209
|
|
|
3099
3210
|
A replaced session says it is standing by. Its reconnect requests cannot reclaim
|
|
3100
3211
|
an attached or claiming peer, even if its status-file read missed that holder. A
|
|
3101
3212
|
channel-capable session may still replace a pull-only holder once its claim has
|
|
3102
|
-
finished.
|
|
3213
|
+
finished. A session whose plugin does not opt in to standby (an older plugin, or
|
|
3214
|
+
tools mode) keeps the newest-hello behavior; an opted-in session started while
|
|
3215
|
+
another holds the peer stays a standby until the person runs `ahub peer takeover`
|
|
3216
|
+
or the holder leaves (#1174).
|
|
3103
3217
|
|
|
3104
3218
|
A plugin carrying an older launch id than this daemon's current per-peer Claude
|
|
3105
3219
|
launch is refused with close 4430. It stops reconnecting, and hub tools report that
|
|
@@ -3447,18 +3561,55 @@ are not active pruning references.
|
|
|
3447
3561
|
A scoped upgrade leaves the global CLI and shared Claude plugin unchanged.
|
|
3448
3562
|
Update the CLI separately with `bun add --global @staix/agent-hub@<version>`, then
|
|
3449
3563
|
run `ahub setup` for the plugin. `ahub doctor` reports either tool when its known
|
|
3450
|
-
version is older than the selected running daemon; it installs nothing.
|
|
3564
|
+
version is older than the selected running daemon; it installs nothing. After a
|
|
3565
|
+
completed or scheduled upgrade, `ahub upgrade` prints the same step when the CLI
|
|
3566
|
+
or the plugin is older than the daemon it installed (#1179). It prints nothing with
|
|
3567
|
+
`--json` or for `ahub restart`, and the advice never fails an upgrade.
|
|
3451
3568
|
|
|
3452
3569
|
| Runtime | Control protocol window | Legacy status field |
|
|
3453
3570
|
| --- | --- | --- |
|
|
3454
3571
|
| 0.12.20 through 0.25.0 | 16 only | `protocol: 16` |
|
|
3455
|
-
| 0.26.0 through 0.
|
|
3572
|
+
| 0.26.0 through 0.31.0 | 16 through 17 | `protocol: 16`, `protocolMin: 16`, `protocolMax: 17` |
|
|
3456
3573
|
|
|
3457
|
-
New clients choose the highest common protocol. The
|
|
3458
|
-
published protocol-16 client and channel plugin remain usable; unrelated feature
|
|
3574
|
+
New clients choose the highest common protocol. The protocol window remains 16
|
|
3575
|
+
through 17, so the published protocol-16 client and channel plugin remain usable; unrelated feature
|
|
3459
3576
|
capabilities still require their own labels. A disjoint window refuses with 4426.
|
|
3460
3577
|
The compatibility-floor `protocol` field remains readable by old clients.
|
|
3461
3578
|
|
|
3579
|
+
Release N-1 is counted in minor versions, separately from this protocol window
|
|
3580
|
+
(#1164, family contract entelecheia/ai-workspace#70). For 0.31.x, N-1 is 0.30.0,
|
|
3581
|
+
the latest published patch of 0.30.x (exact `@staix/agent-mem` 0.20.1, control
|
|
3582
|
+
protocol 17 with descriptor floor 16). Every patch on 0.31.x keeps that release
|
|
3583
|
+
baseline. A change that cannot retain it needs a new minor release. For 0.30.x
|
|
3584
|
+
the baseline was 0.29.0.
|
|
3585
|
+
|
|
3586
|
+
In the minor release PR, together with its `package.json` version bump, query
|
|
3587
|
+
the published versions of `@staix/agent-hub`,
|
|
3588
|
+
select the latest stable patch of the preceding minor line, and mechanically
|
|
3589
|
+
bump `test/fixtures/release-n-1/package.json` and its own `bun.lock`. Do not
|
|
3590
|
+
merge this bump before or separately from the minor version bump: the guard
|
|
3591
|
+
requires the fixture minor to be the package minor minus one. Update
|
|
3592
|
+
the corresponding release entry in `test/published-protocol-compat.test.ts`
|
|
3593
|
+
with the package version, exact amem dependency and protocol read from that
|
|
3594
|
+
published package. Generate the lock with the pinned Bun, then commit it. The gate installs it separately
|
|
3595
|
+
with `bun install --frozen-lockfile`; the compatibility test uses its unchanged
|
|
3596
|
+
published runtime, client and plugin in both directions. Keep the separate
|
|
3597
|
+
`test/fixtures/protocol-v16` fixture at 0.25.0 while protocol 16 is promised;
|
|
3598
|
+
the previous-minor fixture does not replace protocol-floor coverage.
|
|
3599
|
+
|
|
3600
|
+
Each new minor release's CHANGELOG entry states the selected N-1 version and the
|
|
3601
|
+
compatibility of each surface: wire/protocol, files and format floors, CLI,
|
|
3602
|
+
and MCP tools. State any capability or format ceiling explicitly. Patch release
|
|
3603
|
+
entries contain no new N-1 statement and inherit their minor line's baseline.
|
|
3604
|
+
`release-prepare` moves the Unreleased text mechanically; the release author
|
|
3605
|
+
adds this minor-only statement during preparation and checks the fixture bump
|
|
3606
|
+
in that release PR. Never amend a tagged release section. The 0.30.0 N-1
|
|
3607
|
+
record added by #1164 is an explicitly dated post-release note, published in the
|
|
3608
|
+
0.31.0 section; it was not part of the published 0.30.0 tag or tarball. Its MCP ceiling includes
|
|
3609
|
+
0.29.0 free-form `plan.sources` values: 0.30.0 requires registered source ids
|
|
3610
|
+
and rechecks existing stored plans even when accept sends no new plan.
|
|
3611
|
+
No compatibility statement grants release consent.
|
|
3612
|
+
|
|
3462
3613
|
Guard-aware runtimes read `hub.db` format metadata before startup effects and
|
|
3463
3614
|
before writable database opens. A newer incompatible format refuses with
|
|
3464
3615
|
`this project was opened by agent-hub X; use X or later`. The format counter
|
|
@@ -4725,7 +4876,7 @@ selected roster and existing capabilities; the TUI is always a person's start.
|
|
|
4725
4876
|
- If the hub cannot read the event file the peer is `detached`, shown as offline with a notice, never idle: Qwen itself keeps working, and the hub reattaches when the file is readable again.
|
|
4726
4877
|
- Restart: if the hub restarts while your Qwen keeps running, it reads on from its saved offset (no event twice, no launch). If Qwen is gone, `ahub qwen --mode tui` starts `qwen -r <session id>` on the same two files; the earlier submits are not replayed and the recorded answers are not shared again. Recovery never restores this terminal as a headless worker, and `ahub stop qwen` refuses: end Qwen in its own terminal.
|
|
4727
4878
|
|
|
4728
|
-
Receipt-verified native ACP identities are qwen-code 0.25.0 and 0.26.0 ([dated receipt](verification/2026-10-22-kimi-qwen-compat.md)), 0.26.1 ([0.26.1 receipt](verification/2026-10-26-qwen-0261-acp.md))
|
|
4879
|
+
Receipt-verified native ACP identities are qwen-code 0.25.0 and 0.26.0 ([dated receipt](verification/2026-10-22-kimi-qwen-compat.md)), 0.26.1 ([0.26.1 receipt](verification/2026-10-26-qwen-0261-acp.md)) 0.26.4 ([0.26.4 ACP receipt](verification/2026-10-31-qwen-0264-acp.md)) and 0.26.5 ([0.26.5 ACP receipt](verification/2026-11-03-qwen-0265-acp.md)). The separate [0.26.4](verification/2026-10-31-qwen-0264-dual-output.md) and [0.26.5](verification/2026-11-03-qwen-0265-dual-output.md) dual-output attempts did not establish their queued-turn criterion, so `qwen-dual` stays at 0.26.1. A CLI version label alone
|
|
4729
4880
|
is insufficient: startup verifies its native identity/version and advertised mode
|
|
4730
4881
|
ids before any prompt. The earlier local installation reported CLI 0.25.0 while
|
|
4731
4882
|
its package/ACP source said 0.24.1; that was not a ready identity. The 0.26.0 receipt
|
|
@@ -4776,7 +4927,7 @@ Native policy is unmanaged and has NO hub sandbox; no permission_modes.jcode or
|
|
|
4776
4927
|
|
|
4777
4928
|
## Optional Antigravity (agy) peer
|
|
4778
4929
|
|
|
4779
|
-
Antigravity is optional and off roster by default. Use `ahub roster add agy`, then run `ahub agy` in a terminal: it runs the Antigravity CLI as a fresh pull-only TUI in that terminal. It accepts the 1.4.x line: 1.4.2 and 1.4.
|
|
4930
|
+
Antigravity is optional and off roster by default. Use `ahub roster add agy`, then run `ahub agy` in a terminal: it runs the Antigravity CLI as a fresh pull-only TUI in that terminal. It accepts the 1.4.x line: 1.4.2, 1.4.7 and 1.4.12 are the verified versions ([1.4.7 receipt](verification/2026-10-26-agy-1.4.7.md), [1.4.12 launcher nonce receipt](verification/2026-11-03-agy-1.4.12-launcher-nonce.md)), any other 1.4.x launches with a stderr warning (agy updates itself; set `AGY_CLI_DISABLE_AUTO_UPDATE=1` for a live run, #1140), and other versions are refused (#589) unless the person trusts that exact version with `ahub agents trust agy <version>` (#691). The running hub must advertise `native_hook_launch`; an older hub refuses before any write with an upgrade-or-restart remedy. Only the person's launcher starts it: conductor starts are refused, there is no controlled restore or resume, and a declared agy extra instance is refused when the config loads (#625). Headless/print, resume (`--conversation`, `--continue`, `--new`), `--mode`, `--dangerously-skip-permissions` and `--unattended` are refused until their native mapping is verified; `--print-command` previews without writing.
|
|
4780
4931
|
|
|
4781
4932
|
The launcher writes exactly `plugin.json`, `mcp_config.json` and `hooks.json` in `.agents/plugins/agent-hub/`, refusing linked or foreign entries before any write, and removes only its own matching files when the TUI ends. It never writes project-level `.agents/hooks.json` or the person's `~/.gemini` settings. Run `ahub init` afterwards to ignore the untracked plugin directory; a tracked plugin is written with a warning. The native model sees the hub tools under the server name `agent-hub_agent-hub`.
|
|
4782
4933
|
|
|
@@ -4905,6 +5056,14 @@ A `schedules` entry in `.agenthub/config.local.json` takes either `every` (an in
|
|
|
4905
5056
|
- **Upgrades.** The daemon advertises `calendar_schedules`. While a schedule uses `cron` or `tz`, a restart, upgrade or recovery onto a release without it is refused, naming the reason.
|
|
4906
5057
|
- Out of scope: holiday and exchange calendars. A task whose first step finds a non-working day can end itself.
|
|
4907
5058
|
|
|
5059
|
+
## Registered sources and request drafts (#1144)
|
|
5060
|
+
|
|
5061
|
+
`ahub source add` registers a bounded file or URL snapshot, and `ahub source list` lists its `src:` registry ID. For profiles that support `plan.sources`, task proposal and acceptance validate each ID against this registry before changing the board or notifying peers. An unknown ID is refused with `ahub source list` as the next step. Source overlaps use the registry IDs; a private task's public plan remains withheld.
|
|
5062
|
+
|
|
5063
|
+
The dashboard's Plan sheet includes a read-only registered-source list with ID, kind, byte size, hash prefix and registration time. It receives only those allowlisted metadata fields through the existing snapshot, with no source content or origin paths.
|
|
5064
|
+
|
|
5065
|
+
Use Capture a request in the same sheet, or `ahub intake`, to stage natural-language work as held draft Backlog cards. Optional source IDs refer to the registered snapshots. The dashboard uses the same Tasks intake path and public task projection as the CLI; nothing is offered until a draft is approved. Inspect drafts in Backlog, then use `ahub intake approve` or `ahub intake discard` in a terminal. A delegated `--live-test` dashboard session cannot create intake drafts. If submission is unconfirmed, read Backlog before trying again to avoid a duplicate request.
|
|
5066
|
+
|
|
4908
5067
|
## Staging work in Backlog (#263)
|
|
4909
5068
|
|
|
4910
5069
|
Use `ahub task propose implement "Later work" --backlog --owner codex` to stage
|
|
@@ -5025,7 +5184,33 @@ reserved peer that cannot take it (offline, paused, excluded, at its WIP limit)
|
|
|
5025
5184
|
refuses the pull before any change, naming the peer and its reason; it is not
|
|
5026
5185
|
passed over to another peer. `ahub route explain` previews the same reserved-only
|
|
5027
5186
|
choice. An unreserved pull keeps reserving a slot as above. A reserved offer that
|
|
5028
|
-
was never started can return untouched
|
|
5187
|
+
was never started can return untouched. Omitting planning fields retains its
|
|
5188
|
+
reservation, so `tasks.auto_pull` can offer it again as soon as the slot is free.
|
|
5189
|
+
|
|
5190
|
+
To park untouched work in one operation, the planner's
|
|
5191
|
+
`hub_backlog_return_untouched` accepts optional `fields` containing only
|
|
5192
|
+
`reserved` (a peer ID or `null`). For example:
|
|
5193
|
+
|
|
5194
|
+
```json
|
|
5195
|
+
{"id":138,"revision":6,"reason":"wait for the person","fields":{"reserved":null}}
|
|
5196
|
+
```
|
|
5197
|
+
|
|
5198
|
+
The return, reservation change, planning revision and previous reservation are
|
|
5199
|
+
saved together before capacity notices or auto-pull run. Read the returned
|
|
5200
|
+
`planningRevision` for a later planning change. Without `fields`, the planning
|
|
5201
|
+
revision and reservation are retained. Reservation updates use the existing
|
|
5202
|
+
person/planner, roster, exclusion and capability checks; a planner cannot clear
|
|
5203
|
+
or replace a person's reservation. The ordinary `ahub backlog return` form keeps
|
|
5204
|
+
its existing reservation-preserving behavior.
|
|
5205
|
+
|
|
5206
|
+
The CLI has the same two edits (#1177): `ahub backlog return <task> <revision>
|
|
5207
|
+
<reason...> [--reserved <peer> | --unreserve]` sends `fields.reserved` as the peer
|
|
5208
|
+
(`--reserved kimi` or `--reserved=kimi`) or `null` (`--unreserve`) with the
|
|
5209
|
+
return, so the reservation moves or clears in the same operation and under the
|
|
5210
|
+
same checks. The flags may stand anywhere among the reason's words and are not
|
|
5211
|
+
part of the reason; at most one of them, and a malformed one is refused before
|
|
5212
|
+
anything is sent. With neither flag the command sends exactly what it always
|
|
5213
|
+
did and the reservation is kept.
|
|
5029
5214
|
|
|
5030
5215
|
Capacity defaults to one per peer. Each declared instance has its own `tasks.wip_limits.<instance>` key. `ahub settings set tasks.wip_limits.codex 2`
|
|
5031
5216
|
uses the existing machine-local registry path; integers 0..32 apply live (the next
|
|
@@ -5152,13 +5337,14 @@ built-ins and off for the current console only. `?` lists this under Pet, even
|
|
|
5152
5337
|
while drawing is off. The command prompt keeps its original row and width.
|
|
5153
5338
|
|
|
5154
5339
|
`pet.glyphs` selects auto/ascii/blocks; unsupported locales and dumb/linux
|
|
5155
|
-
terminals retain the ASCII floor. `pet.blink:false` is static. `pet
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5340
|
+
terminals retain the ASCII floor. `pet.blink:false` is static. Both `pet`
|
|
5341
|
+
(`false` or an option block) and its fields validate identically at startup and
|
|
5342
|
+
reload in `.agenthub/config.json` and `.agenthub/config.local.json`, apply live
|
|
5343
|
+
as console-local presentation on an open console's next refresh, and grant no
|
|
5344
|
+
authority (#483). Legacy `pet.palette` still validates blue, teal, violet or
|
|
5345
|
+
ochre (`a`/`b`/`c`/`d`) for configuration compatibility, but has no rendering
|
|
5346
|
+
effect after the window retirement. A legacy `pet.window` value is ignored with one notice; a
|
|
5347
|
+
window-only local block preserves inherited `pet:false`. Neither
|
|
5162
5348
|
choosing nor drawing a character changes authority, config files, task state or
|
|
5163
5349
|
polling. Explicit `ahub pet` and text status use the configured line face; prompt
|
|
5164
5350
|
tokens remain character-independent. Native glyph width and tmux are unverified.
|
|
@@ -5187,8 +5373,9 @@ receive fixed structural guidance, with no peer or first-row fallback. No
|
|
|
5187
5373
|
workflow action is issued and no filter is changed by attention navigation.
|
|
5188
5374
|
Invalid/legacy attention hides its badge and restores the base title.
|
|
5189
5375
|
|
|
5190
|
-
The in-page pet, its SVG and character/pixel payload are removed.
|
|
5191
|
-
|
|
5376
|
+
The in-page pet, its SVG and character/pixel payload are removed. Floating pet
|
|
5377
|
+
presentation belongs to acon Mini; the standalone macOS host is retired (#1012).
|
|
5378
|
+
Existing snapshot poll, session,
|
|
5192
5379
|
request types and CSP hashes remain; no route, request or timer is added.
|
|
5193
5380
|
Browser screenshots/CSP-console verification are separate manual evidence on
|
|
5194
5381
|
the implementation PR; VM/HTTP fixtures do not establish human visual results.
|
|
@@ -5244,45 +5431,23 @@ Release cut audits return exact counts with at most 32 example IDs per category;
|
|
|
5244
5431
|
|
|
5245
5432
|
Release cards include task states in their refresh key, so completion of an outside prerequisite updates blocked counts even when the release and audit preview are unchanged.
|
|
5246
5433
|
|
|
5247
|
-
##
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
pointer is over the character. Deep state colors and a dark rim shadow keep the
|
|
5265
|
-
pixel silhouette readable on light backgrounds. `pet.palette` selects the base
|
|
5266
|
-
color: teal (default, b), blue (a), violet (c) or ochre (d), each with its own
|
|
5267
|
-
rim line; the waiting/blocked/review/offline colors stay fixed. While the
|
|
5268
|
-
window is key, 1/2/3/4 switch blue/teal/violet/ochre and save the choice.
|
|
5269
|
-
From a terminal, `ahub pet --palette <blue|teal|violet|ochre>` writes the
|
|
5270
|
-
choice to `pet.palette` in `.agenthub/config.local.json`.
|
|
5271
|
-
While working, the pixel art bobs in a 0.7-second stepped CSS loop; reduced-motion preferences keep it still.
|
|
5272
|
-
|
|
5273
|
-
A detached Bun host refreshes `pet-view.json` once per second using `readPet`
|
|
5274
|
-
and `loadPetConfig`. The file contains only state/counts/character/blink and
|
|
5275
|
-
built-in pixels. It uses no dashboard session or HTTP listener. An unavailable
|
|
5276
|
-
hub displays Offline for two seconds, then the panel and host exit. Closing
|
|
5277
|
-
JXA exits the host too. `pet-window.pid` holds the host's process signature;
|
|
5278
|
-
an uncertain owner is retained rather than signalled. A stale owner requires
|
|
5279
|
-
an explicit `--close` before restarting; a malformed pidfile requires operator
|
|
5280
|
-
inspection. A send failure is unconfirmed: check the stream before retrying.
|
|
5281
|
-
|
|
5282
|
-
Native transparency/floating and the bridge were verified in the macOS spike.
|
|
5283
|
-
Real keystrokes, dragging and persistence, Spaces, message delivery and body
|
|
5284
|
-
click need the manual PR checklist before merge; automated fixtures do not
|
|
5285
|
-
establish those native results.
|
|
5434
|
+
## Floating pet in acon Mini (#1012)
|
|
5435
|
+
|
|
5436
|
+
Run `acon ui` and open Mini for the floating pet. The former
|
|
5437
|
+
`ahub pet --window [--close]` command prints that pointer and exits successfully
|
|
5438
|
+
from a person terminal, an agent shell or `--live-test`. It starts no window,
|
|
5439
|
+
host, JXA process or network connection. The console's `o` shortcut and automatic
|
|
5440
|
+
window startup from `ahub up` are retired.
|
|
5441
|
+
|
|
5442
|
+
The terminal pet remains available through `ahub pet`, `ahub pet --short` and
|
|
5443
|
+
the console's line/mini/full frames. `ahub pet --palette <blue|teal|violet|ochre>`
|
|
5444
|
+
is also retired: it validates the argument, prints the same Mini pointer and
|
|
5445
|
+
writes no configuration. Existing `pet.window` settings are ignored with one notice;
|
|
5446
|
+
remove the obsolete key when updating configuration.
|
|
5447
|
+
|
|
5448
|
+
The composer already lives in the agent-hub console plugin's **Console message**
|
|
5449
|
+
view (#935), available through `acon ui`. It sends through the existing plugin
|
|
5450
|
+
`send` action and retains that action's audience and authority checks.
|
|
5286
5451
|
|
|
5287
5452
|
## Additional headless peer instances
|
|
5288
5453
|
|
|
@@ -5393,7 +5558,7 @@ Default-branch capture runs only at daemon startup when a Claude implementer is
|
|
|
5393
5558
|
|
|
5394
5559
|
Project Git retains the core policy that clears credential.helper and core.askpass; an HTTPS push needing those helpers may fail, rather than importing credentials or relaxing that policy. Task branch/config proof reads are bounded synchronous reads (1.5 seconds per reader); slow or unknown evidence asks. The existing sandbox profile discovery is also synchronous; moving it to an asynchronous inventory proof with a shared deadline remains a follow-up. The nonce is visible in a permission response, so it proves a bounded grant rather than native-dispatch provenance.
|
|
5395
5560
|
|
|
5396
|
-
The [native permission receipt](verification/2026-10-23-headless-claude-permissions.md) covers Claude Code 2.1.309, and the [2.1.310 receipt](verification/2026-10-26-claude-implementer-2.1.310.md) repeats it on 2.1.310 (with 2.1.309 as a control), and the [2.1.314 receipt](verification/2026-10-31-claude-implementer-2.1.314.md) repeats it and the host-wrapper procedure on 2.1.314 (with 2.1.310 as a control), and the [2.1.316 receipt](verification/2026-10-31-claude-implementer-2.1.316.md) repeats both on 2.1.316 (with 2.1.314 as a control), each with a deterministic loopback fixture and no real account/model call. It is not sandbox proof or a runtime receipt gate. The real account/model/person interaction remains a separate live leg.
|
|
5561
|
+
The [native permission receipt](verification/2026-10-23-headless-claude-permissions.md) covers Claude Code 2.1.309, and the [2.1.310 receipt](verification/2026-10-26-claude-implementer-2.1.310.md) repeats it on 2.1.310 (with 2.1.309 as a control), and the [2.1.314 receipt](verification/2026-10-31-claude-implementer-2.1.314.md) repeats it and the host-wrapper procedure on 2.1.314 (with 2.1.310 as a control), and the [2.1.316 receipt](verification/2026-10-31-claude-implementer-2.1.316.md) repeats both on 2.1.316 (with 2.1.314 as a control), and the [2.1.318 receipt](verification/2026-11-05-claude-implementer-2.1.318.md) repeats both on 2.1.318 (with 2.1.316 as a control), each with a deterministic loopback fixture and no real account/model call. It is not sandbox proof or a runtime receipt gate. The real account/model/person interaction remains a separate live leg.
|
|
5397
5562
|
|
|
5398
5563
|
A headless Claude reviewer is run by the hub instead (task 223): declare
|
|
5399
5564
|
`"claude-review": { "kind": "claude", "roles": ["reviewer"], "start_mode": "headless" }`
|
|
@@ -5531,7 +5696,22 @@ Native launcher connections retry transport timeouts/unclean closes with bounded
|
|
|
5531
5696
|
|
|
5532
5697
|
## amem runtime (agent-mem#13 P4)
|
|
5533
5698
|
|
|
5534
|
-
The hub exact-pins @staix/agent-mem 0.
|
|
5699
|
+
The hub exact-pins @staix/agent-mem 0.21.0 for recall, curated evidence and local deterministic capture. No runtime call reaches a claude-mem worker; `memory.worker_url` is ignored. The person's `ahub memory import claude-mem` remains explicit and off by default. Existing profile, alias, PII and private-turn fences still apply. `ask --remember` and context checkpoints propose machine-local candidates, never automatic curated evidence. See [memory integration](memory.md#in-process-recall-and-capture-agent-mem13-p4) for changed behavior and bounded-view ceilings.
|
|
5700
|
+
|
|
5701
|
+
## Person-run backlog legs (#1176)
|
|
5702
|
+
|
|
5703
|
+
A leg only the person can run (live receipts, their accounts, machines or approvals) is marked with `ahub backlog person <id> <revision> true <reason...>` (`false` clears it; `ahub backlog plan <id> <revision> '{"needsPerson":true}' <reason...>` is the same write). The mark is the person's alone: a planner or any agent that sends `fields.needsPerson`, or plans a marked card, is refused with the reason. A marked card keeps its `reserved` peer as the "who will run it" hint, and:
|
|
5704
|
+
|
|
5705
|
+
- `tasks.auto_pull` and a planner's `hub_backlog_pull` never pull it (the pull refuses with "person-run leg"), and the planner notice never names it as ready;
|
|
5706
|
+
- `assign()` gives it no owner and no reviewer, whatever its reservation says, and `ahub route explain` prints the same `person-run` line (it is the same function);
|
|
5707
|
+
- the idle sweep never escalates it, and a marked card in To Do is not reported as stalled for lacking an owner;
|
|
5708
|
+
- it counts toward no planner's WIP;
|
|
5709
|
+
- a planner's `hub_backlog_split` of a marked card is refused (its children would be unmarked cards an agent could take); the person's own split marks every child person-run, so person-only work stays person-only until the person clears each mark;
|
|
5710
|
+
- an agent's `accept` and `acceptReviewed` of a marked card are refused, a queued offer for a card marked since is dropped at delivery, and `hub_task_assign` names no agent owner of a marked card (the conductor, a planner and the person alike: clear the mark first);
|
|
5711
|
+
- marking a card an agent already owns (an offer in its queue, or accepted work) is refused with the way out (the owner declines, or `ahub task cancel`), so a mark never leaves an agent on the card;
|
|
5712
|
+
- `ahub backlog list` shows it as `<peer> (person)` and ends with `waiting on you: #N...`, and `ahub status` carries a `WAITING ON YOU #N` line (ids only).
|
|
5713
|
+
|
|
5714
|
+
An unmarked reserved card behaves exactly as before. The column is additive (`needs_person`, default 0): an older hub ignores it, and a card marked by this hub is then offered by the older one as an ordinary reserved card.
|
|
5535
5715
|
|
|
5536
5716
|
## Backlog issue identity and notes
|
|
5537
5717
|
|
|
@@ -5584,7 +5764,7 @@ The selected project's configured conductor may run the commands below through i
|
|
|
5584
5764
|
| logs / export | Bounded daemon projections, with unsupported/private records withheld; logs -f ends when authority ends |
|
|
5585
5765
|
| settings set | Only the thirteen existing live registry keys listed below |
|
|
5586
5766
|
|
|
5587
|
-
The exact settings keys are `task_sweep.enabled`, `task_sweep.auto_reassign`, `task_sweep.no_writes_turns`, `task_sweep.interval_s`, `task_sweep.unaccepted_min`, `task_sweep.idle_min`, `task_sweep.review_min`, `task_sweep.ready_min`, `task_sweep.ladder_min`, `snapshots.enabled`, `research.enabled`, `approvals.notify` and `tasks.escalate_after`. New keys receive no authority by prefix. Generic roster setting writes still use the dedicated roster lifecycle. Conductor setting records name the initiating peer, and conductor writes preserve the person's pending undo record. An intervening write can still invalidate that undo through the existing file-digest guard; preserving the record does not bypass that guard. Permission modes, roles, `
|
|
5767
|
+
The exact settings keys are `task_sweep.enabled`, `task_sweep.auto_reassign`, `task_sweep.no_writes_turns`, `task_sweep.interval_s`, `task_sweep.unaccepted_min`, `task_sweep.idle_min`, `task_sweep.review_min`, `task_sweep.ready_min`, `task_sweep.ladder_min`, `snapshots.enabled`, `research.enabled`, `approvals.notify` and `tasks.escalate_after`. New keys receive no authority by prefix. Generic roster setting writes still use the dedicated roster lifecycle. Conductor setting records name the initiating peer, and conductor writes preserve the person's pending undo record. An intervening write can still invalidate that undo through the existing file-digest guard; preserving the record does not bypass that guard. Permission modes, roles, `models start|stop`, arbitrary configuration reload and undo remain person commands. `task cancel` remains a separate own-task `hub_task_cancel` permission, not a conductor operation.
|
|
5588
5768
|
|
|
5589
5769
|
Log history is limited to the last 100 retained lines and export to the last 1000 retained events, each within a 128 KiB read. Truncation is explicit. An incomplete public projection reports one bounded reason on stderr, preserving export JSON on stdout. The complete privacy inventory has no 500-task cutoff and is cached until board or privacy/config revisions change, so log-follow does not rebuild it for every line. Export accepts closed metadata shapes; unknown fields and nested records are withheld rather than copied. Task titles, paths and private delivery bodies are not part of this projection. It does not change the person's ordinary logs/export output.
|
|
5590
5770
|
|
|
@@ -5633,6 +5813,8 @@ restoration uses the target-owned snapshot through a tools connection.
|
|
|
5633
5813
|
|
|
5634
5814
|
An unmanaged reconnect-only Claude channel may reattach itself without a native launch. The source keeps a SHA-256 fingerprint of its observed session identity separate from restoration metadata (the raw unmanaged session id is omitted from the plan) and verifies the exact peer, kind and attachment against the live channel. This exception requires no terminal or restoration arguments, no managed launch proof, and an absent or confirmed-ended launcher; unknown launcher evidence refuses. Other peer identities still compare exactly.
|
|
5635
5815
|
|
|
5816
|
+
Claude channel push mode also requires the plugin's direct parent process row to begin with the exact `claude --dangerously-load-development-channels <plugin-or-server-target>` argv prefix. The inherited `AGENTHUB_CHANNEL=1` marker alone is insufficient: Claude's `daemon run` and `bg-spare` children inherit it but do not load the development channel, and print forms ignore it. The bounded `ps -ww` read is display/attachment evidence, not authentication; unreadable, truncated, changed-parent or unrecognized rows attach tools-only and keep messages for `hub_inbox`. `ahub status` shows the attach mode and the closed evidence label.
|
|
5817
|
+
|
|
5636
5818
|
|
|
5637
5819
|
Only the conductor that created the restart or authorized upgrade may run
|
|
5638
5820
|
`recovery resume|abort` for that operation. A different conductor cannot take
|
|
@@ -5775,6 +5957,25 @@ to ordinary automatic assignment. This PR changes no live repository setting or
|
|
|
5775
5957
|
routing template; real-use adoption metrics remain separate from fixture checks.
|
|
5776
5958
|
|
|
5777
5959
|
|
|
5960
|
+
### Presence and full broker queues (#1204 T1)
|
|
5961
|
+
|
|
5962
|
+
Unchanged presence snapshots are skipped. Presence is ephemeral: an offline
|
|
5963
|
+
member does not accumulate observations, and the broker keeps only the latest
|
|
5964
|
+
per sender for connected members. Explicit refresh exchanges still work.
|
|
5965
|
+
|
|
5966
|
+
On `queue_full`, the link retains the sealed frame and retries with exponential
|
|
5967
|
+
backoff from 250 ms to at most 30 s. Applications stay in the existing local
|
|
5968
|
+
outbox, and later sequences wait for broker storage acceptance. Stop/refresh
|
|
5969
|
+
clears connection timers. The broker storage ACK remains transport metadata;
|
|
5970
|
+
application receipt and retry rules are described below. No layer cap is raised.
|
|
5971
|
+
|
|
5972
|
+
|
|
5973
|
+
A hub uses the ephemeral bit only after the broker advertises it to that
|
|
5974
|
+
connection. Against an older broker, presence uses the legacy wire shape and
|
|
5975
|
+
chat stays usable; upgrade the broker to avoid offline presence retention.
|
|
5976
|
+
The supporting broker withholds ephemeral frames from older member hubs; they
|
|
5977
|
+
must upgrade to see upgraded hubs' presence. Chat wire shapes remain unchanged. See [wire compatibility](design/bus.md#room-wire-compatibility-1204-t1).
|
|
5978
|
+
|
|
5778
5979
|
## Screened room chat (#446 X4)
|
|
5779
5980
|
|
|
5780
5981
|
After joining and confirming fingerprints, expose each receiving native peer with
|
|
@@ -5804,10 +6005,15 @@ peer queue. Native/model execution is independent. Incoming messages remain
|
|
|
5804
6005
|
untrusted text and grant no local task, role, approval, tool or control authority.
|
|
5805
6006
|
|
|
5806
6007
|
Offline queues are capped at 200 per room. In untracked config.local.json, optional
|
|
5807
|
-
`rooms.ack_timeout_s` defaults to 600 and `rooms.queue_ttl_h` to 24.
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
6008
|
+
`rooms.ack_timeout_s` defaults to 600 and `rooms.queue_ttl_h` to 24. The ACK
|
|
6009
|
+
deadline schedules another attempt under the same application id, while the
|
|
6010
|
+
original queue TTL stays fixed. Active sends resume after restart. Only queue
|
|
6011
|
+
expiry or a permanent refusal ends automatic sending; an ordinary remote chat
|
|
6012
|
+
`needs_review` row does not hold the rest of that peer's queue. A valid late signed
|
|
6013
|
+
receipt can settle an unresolved ordinary remote row once, with an ids-only event.
|
|
6014
|
+
Invocation uncertainty keeps its person-only hold; a late transport receipt is
|
|
6015
|
+
advisory and does not assert the invoked operation's outcome. The person's prior
|
|
6016
|
+
disposition is never overridden. Old text cannot be
|
|
5811
6017
|
retried to a replacement fingerprint reusing a label. An unproved terminal retry
|
|
5812
6018
|
refuses and requires a deliberately authored new message.
|
|
5813
6019
|
An expired or missing original enqueue deadline likewise refuses retry without
|
|
@@ -5816,6 +6022,20 @@ recording a successful disposition. Send a new message deliberately instead.
|
|
|
5816
6022
|
The ACK timeout starts when the application is handed to the room link, even if
|
|
5817
6023
|
the broker never confirms storage. A reconnect or restart requests fresh signed
|
|
5818
6024
|
presence from the other hub without waiting for its peer state to change.
|
|
6025
|
+
The receiver commits receipt ciphertext to its local durable outbox before
|
|
6026
|
+
transport-ACKing an admitted chat, then replays the receipt until broker storage
|
|
6027
|
+
confirmation. This stays safe at broker capacity one and across receiver restart;
|
|
6028
|
+
transport settlement still proves admission rather than native execution.
|
|
6029
|
+
An application awaiting local admission may instead ACK after its crypto inbox
|
|
6030
|
+
entry commits durably. Later admission uses the same durable receipt outbox;
|
|
6031
|
+
the waiting chat does not pin broker capacity.
|
|
6032
|
+
Pauses and lifecycle/recovery holds also block resends. A pause after local
|
|
6033
|
+
enqueue retains the same delivery id and original expiry. Missing local durable
|
|
6034
|
+
intent after restart is held as `needs_review`; inspect the delivery named by
|
|
6035
|
+
`ahub queue show` before choosing a disposition.
|
|
6036
|
+
Restart and inbound-receipt recovery apply any previously recorded person
|
|
6037
|
+
disposition before automatic settlement. A known signed transport outcome remains
|
|
6038
|
+
evidence alongside the decision; it does not undo the person's disposition.
|
|
5819
6039
|
Capacity refusal of one incoming chat retains that pending chat while allowing
|
|
5820
6040
|
later packets and receipts through; a later online or person-disposition event
|
|
5821
6041
|
rechecks admission. Merely reading room status applies no disposition.
|
|
@@ -5844,7 +6064,10 @@ Neither sends, re-admits, or produces a signed completion. The displayed state i
|
|
|
5844
6064
|
|
|
5845
6065
|
Application-id and trace metadata retain 30 days/10,000 per room, evicting settled
|
|
5846
6066
|
rows first. Protected uncertainty remains until person disposition. Outside that
|
|
5847
|
-
retention no historical app-id or trace claim is made
|
|
6067
|
+
retention no historical app-id or trace claim is made. Automatic resend can reach
|
|
6068
|
+
this ceiling and admit an application again after settled eviction; the guarantee
|
|
6069
|
+
is "exactly once within dedupe ceiling". Pinning retryable identities or #737
|
|
6070
|
+
receipt confirmation would extend it. Permanent seq floors and
|
|
5848
6071
|
MAX_HOP 3 still apply. Status prioritizes uncertainty and bounds each direction's
|
|
5849
6072
|
rows to 200; queue inspection remains the delivery-history entry point. Broker,
|
|
5850
6073
|
TLS/proxy and real two-machine/account receipts remain separate live proof.
|
|
@@ -5930,19 +6153,24 @@ settled stubs fit the current response ceiling.
|
|
|
5930
6153
|
Work that belongs to another repository that runs agent-hub on this machine goes onto that repository's board, not into this session. Its own roles plan, implement and review it, and each state change it reaches is reported back here. The first case: after a library you maintain publishes a release, raising its exact pin in a consumer belongs on the consumer's board.
|
|
5931
6154
|
|
|
5932
6155
|
```
|
|
5933
|
-
ahub task handoff --project <root|id> [<class>] <title...> [--path <p>]... [--issue <n>] [--task <n>] [--detail <text>]
|
|
6156
|
+
ahub task handoff --project <root|id> [<class>] <title...> [--path <p>]... [--issue <n>] [--task <n>] [--detail <text>] [--duplicate-ok <reason>] [--key <uuid>]
|
|
5934
6157
|
```
|
|
5935
6158
|
|
|
5936
6159
|
- `--project` is the other project's canonical root or its id from `ahub projects`. It must be registered and its hub must be running (`ahub up` in that project). Nothing is queued: a hub that is not running is refused with that action.
|
|
5937
6160
|
- A feature or behavior change first gets a spec issue in the other repository: pass its number as `--issue`. A mechanical chore (an exact version pin, a regenerated file) goes straight to a task.
|
|
6161
|
+
- A spec issue that already has an open task on the other board is refused with those task ids (#1175): a task counts when its lifecycle receipt names the issue, its title has a bare `#N` or an `owner/repo#N` of that repository, or its detail holds the `spec issue: #N in this repository` line a handoff keeps; a closed (approved or cancelled) task and a `[pii]` task do not count, so a private task's id is never named to another project. Use the open task, or pass `--duplicate-ok <reason>` (the tool's `duplicate_ok`, at most 300 characters) when the work is genuinely separate; the reason is kept as a line of the new task. The check runs on the target right before the task is written and stores nothing when it refuses, so a refused duplicate is never offered to an owner or escalated by the idle sweep. A handoff with no `--issue` has nothing to compare and is not refused.
|
|
5938
6162
|
- `--path` names files in the other project, repository-relative (no absolute path, `~` or `..`). `--task` names your own task this comes from, so a `[pii]` one is refused.
|
|
5939
6163
|
- `ahub task handoff` is the person's command (an agent's shell is refused it as a console command). Agents use `hub_task_handoff` (the same fields) when they hold the planner or conductor role; `hub_task_handoffs` and `ahub board --handoffs` list what this project handed over and the last state each target reported.
|
|
5940
6164
|
|
|
5941
|
-
What the other project sees: an ownerless proposed task, made by its hub, whose detail ends with where it came from; `ahub board` and `ahub task show` there name the origin project and peer. Its own routing offers it as it would a local proposal. The requesting peer has no identity or authority there: it cannot accept, review, approve, assign or cancel.
|
|
6165
|
+
What the other project sees: an ownerless proposed task, made by its hub, whose detail ends with where it came from; `ahub board` and `ahub task show` there name the origin project and peer. Its own routing offers it as it would a local proposal. The requesting peer has no identity or authority there: it cannot accept, review, approve, assign or cancel. The receiving project's configured conductor can cancel such a task with `hub_task_cancel` (or `ahub task cancel` as the person), with a reason, while nobody has accepted it and it has no branch, commit, PR, check, done or verdict (#1175); the history records the conductor as the actor, and the origin hears `agent-hub task N cancelled` through the follow-back, never the reason. Any other peer keeps the planner's own-work rule.
|
|
6166
|
+
|
|
6167
|
+
What comes back: each change is recorded in `ahub board --handoffs`, and an agent that handed the task over also gets one `kind: task` message per change, `agent-hub task 123 accepted`, `in review`, `approved: PR #7 at <sha>`, `declined` or `cancelled` (a handoff you made from the terminal sends you no message: read the list). It carries an event name, a PR number and a full head, never the other project's text. If this project's hub was stopped meanwhile, it asks each running target hub where its open handoffs stand when it starts again; a target that is down then is asked at the next start. From #1203 T2 the origin also asks every 5 minutes, and at once when a target's hub restarts or moves, for every handoff that is not cancelled (an approved one for a week), in requests of 200, so a state change that missed the first notify arrives within one period; an event that arrives out of order is ignored by its sequence, and a reviewer's `changes requested` and a reopen are reported (`agent-hub task 123 changes requested`, `reopened`).
|
|
5942
6168
|
|
|
5943
|
-
|
|
6169
|
+
A handoff the target did not confirm (#1203 T1): a timeout or a closed connection does not mean refused, because the target may have filed the task. Each request carries a key (`handoffKey`, a UUID the origin mints), the target files it once, and the origin sends the same key once more and then asks the target by key before it gives up. The command waits for that whole recovery (up to about 90 seconds when the target is slow), not the usual 30. If it still cannot tell, the refusal is `outcome_unknown` and names the key: run the same `ahub task handoff` again with `--key <uuid>` (an agent passes `handoffKey`), and the target answers with the task it already made instead of a second one. The same key with a different request is refused. A target without `task_handoff_key` gets no key: it keeps the old behavior, and `outcome_unknown` then says to check its board (`ahub board` there) before handing the task off again.
|
|
5944
6170
|
|
|
5945
|
-
|
|
6171
|
+
Diagnostics and repair (#1203 T3): `ahub task handoff --list` shows every handoff this project made with its age since the last report and whether its target can be reached now: `reachable`, `unreachable` with the cause and what to run (`ahub up` in its root, `ahub upgrade`, `ahub status`), or `moved` when the project id is no longer in `ahub projects` (its root moved or it was removed: run `ahub up` in the new root, then hand the work off again; the old id is not repaired). It reads the registry and the target's descriptor, so it answers at once. `ahub task handoff --sync` (the person or the conductor) asks every target now instead of at the next 5-minute pass and prints the refreshed list; it waits at most 20 seconds, and if several targets are slow or down it prints the list so far with "catch-up still running for N targets: run `ahub task handoff --list` in a minute" (the pass goes on in the background) instead of timing out. A target on another wire version is refused as `older_target` with the upgrade step. An instance mismatch names `ahub projects`, and `ahub up` only if the intended target is not running. A failed notify or catch-up writes one `hub.log` line per target and cause every 15 minutes (`handoff catch-up of <project> failed: <cause>`). A catch-up request that gets no usable reply (the target refused it, timed out or dropped the connection) is a failure like any other: its target reads `unreachable` with the cause "no answer to the state request" and the step `ahub status` in that project, one log line is written, and the earlier failure is not cleared. If the pass itself fails, `--sync` answers `synced: false` with that cause instead of `synced: true`.
|
|
6172
|
+
|
|
6173
|
+
Refusals, each named with the action: an unregistered target, this very project, a hub that is not running, a request over 8 KiB or with an unknown field, a caller that is not a planner, the conductor or the person, a private (PII) turn, a spec issue that already has an open task there (the refusal lists their ids; `--duplicate-ok <reason>` overrides it; an issue number only matches work of the target's own repository, and an imported backlog row counts by its `external` issue; a target from before #1175 refuses `duplicate_ok` as an unknown field and the refusal says to run `ahub upgrade` there or hand off without it), a `[pii]` task named with `--task`, text that matches the target's PII patterns or that the target's screen cannot clear, a target hub in recovery or shutting down (hand it off again after that ends), and an older target hub (it lacks the `task_handoff` feature: run `ahub upgrade` in that project).
|
|
5946
6174
|
|
|
5947
6175
|
Recovery: `task_handoff` is its own recovery label. A project that holds a handoff row, in either direction, refuses a recovery target that lacks it.
|
|
5948
6176
|
|
|
@@ -5968,3 +6196,99 @@ kimi: not started: kimi starts in its TUI and the hub could not open a terminal
|
|
|
5968
6196
|
- **Who and when:** only a person's own `ahub up` and the dashboard manager's "start" (which counts as one). An agent's `ahub up` is refused by the CLI before this runs. A daemon restart, a crash recovery, a config reload (`start` applies at the next `ahub up`) and the `ahub up` that an upgrade or recovery relaunches (it carries `AGENTHUB_RECOVERY_OPERATION`) start nothing from the list, and the running hub never reads it. `--live-test` starts none either.
|
|
5969
6197
|
- **What can be listed:** `claude`, `codex`, `kimi`, `pi`, `local` and `jcode`. `qwen` is refused when saved ("the hub never opens its TUI"), as are `agy`, a declared instance, a Claude channel extra, an unknown id and a duplicate, each with a named reason; the loader and the settings writer say the same words. Pi in the list is the user-facing switch; `pi.auto_start` keeps working for configs that have it.
|
|
5970
6198
|
- **Failure is local to one agent:** a refusal, a terminal provider that fails or a request that times out prints its own line and never stops the hub or the other agents. The lines come from the hub's own reply, so a provider's error text stays in `hub.log`.
|
|
6199
|
+
|
|
6200
|
+
## The worktree shelf (#1057)
|
|
6201
|
+
|
|
6202
|
+
Implementers work in `.worktrees/<name>`, and after a guarded merge only the owner removes its local worktree and branch (`docs/sdlc.md`, Merge result and cleanup), so finished worktrees pile up. The shelf shows which ones are finished. It never removes anything itself.
|
|
6203
|
+
|
|
6204
|
+
```
|
|
6205
|
+
ahub worktrees # live worktrees, then the shelf with each settled row's reason
|
|
6206
|
+
ahub worktrees --json
|
|
6207
|
+
ahub worktrees tidy # a preview: what is safe to remove, what is refused and why, and a fingerprint
|
|
6208
|
+
ahub worktrees tidy --confirm <fingerprint> # the person's own terminal: re-reads everything, then removes
|
|
6209
|
+
```
|
|
6210
|
+
|
|
6211
|
+
- **Settled is derived, never stored.** The hub stores facts and two person overrides, and works the groups out on every read. Rules, in order: the main checkout and the declared instance worktrees (`.worktrees/<instance>`) are never shelved; an override that is still in force wins; a merged or closed PR with no work newer than its change time settles the worktree; `worktrees.quiet_days` without activity settles it (`quiet`); everything else is live. A settled row names its reason: `merged`, `closed`, `quiet` or `parked`; a row bound to a PII task shows `settled` and `task: private` instead of its PR reason, task id and PR.
|
|
6212
|
+
- **What counts as activity.** The latest of the HEAD commit time, the mtime of the worktree's own index (uncommitted editing) and the bound task's latest history entry written by anyone but the hub. The hub's own entries (the merge result, the owner notice) are left out, or a merge would always look like newer work. The tidy preview's own git reads run with `--no-optional-locks`, so previewing does not touch the index and make a settled worktree look active. A worktree whose commit time or index could not be read (a failed git call, or the read budget used up) is listed live with `complete: false` and is never shelved by a PR or by quiet time: unknown is not settled.
|
|
6213
|
+
- **Where the PR state comes from.** From the board only: a guarded merge's own record says `merged`. A cancelled task says nothing about its PR, and a task with no record reads `unknown`. Nothing is fetched from GitHub when you open the panel, run `ahub worktrees`, or when the inbox alert is computed.
|
|
6214
|
+
- **Park, Pin and Unset.** The Agents panel offers Park (move a live row to the shelf), Pin (keep a settled row live) and Unset (back to what the rules derive). An override counts only while the worktree has had no newer activity (`lastActiveAt <= at`); later work makes it inert and the next write removes it. They are control operations `worktree_override_set` and `worktree_override_clear`, console role only: an agent's tools connection is refused.
|
|
6215
|
+
- **Refresh PR states.** The one button that reads GitHub, and the control operation `worktrees_refresh_prs` behind it (console role). It reads each bound task's PR with the same `readSdlcPr` the guarded merge uses, at most 8 PRs, 8 s per call and 25 s in all, one refresh at a time, and keeps what it read in the hub's memory (a restart forgets it and those rows read `unknown` again). A PR GitHub could not answer for keeps its old state and is counted as unreadable. The plugin asks you to confirm it first, because it calls GitHub.
|
|
6216
|
+
- **The panel's list.** The Agents view gets a `worktrees` field from a cache at most 30 s old that a background read refreshes: a snapshot never waits for git. Paths are project-relative (or the basename outside the project root), never absolute. The panel shows removal as the command to copy, never as a button.
|
|
6217
|
+
- **The inbox alert.** acon's inbox raises one `alert` item per project when the settled count is above `worktrees.alert_over` (0 never). It carries the count and a link to the Agents panel, nothing else: no path, branch or task.
|
|
6218
|
+
- **Settings.** `worktrees.quiet_days` (default 7, 0 = never shelve by quiet time) and `worktrees.alert_over` (default 10, 0 = never alert), both live, both on the Switches group of `ahub settings` and the dashboard.
|
|
6219
|
+
- **Tidy is the person's.** `tidy` previews each settled row that is safe to remove and each refused row with its reasons: dirty, locked, commits not pushed to the upstream or no upstream, branch not merged into the default branch, the main checkout, an instance worktree, a bound task that is not approved or cancelled, or anything git could not tell. The preview ends with a fingerprint over the rows. `--confirm <fingerprint>` is console class (an agent can only preview, and `--live-test` refuses it), re-reads everything, refuses the whole run if the set changed, and runs exactly two argv shapes per row, `git worktree remove <path>` and `git branch -d <branch>`, then reads each result back. `--force` and `-D` never appear: git itself refuses a dirty tree or an unmerged branch. A worktree edited between the confirm's re-read and the removal is not guarded by anything but git's own refusal.
|
|
6220
|
+
- **The daemon deletes nothing.** The shelf's git port runs only `worktree list --porcelain -z`, `log -1 --format=%ct HEAD` and `rev-parse --absolute-git-dir`, and refuses any other argv before spawning. Removal exists only in the CLI process (`src/cli/worktree-tidy.ts`), which the daemon never imports; `test/worktree-shelf.test.ts` greps the daemon-reachable modules for a removal.
|
|
6221
|
+
- **Limits.** At most 256 worktrees are listed and 1024 overrides read; git reads run 4 at a time under a 3 s total budget (5 s per call), asynchronously, so a slow git never holds the daemon. The quiet threshold is the owner's call after a week of use.
|
|
6222
|
+
|
|
6223
|
+
## Results: what a run you started left behind (#1054)
|
|
6224
|
+
|
|
6225
|
+
A run you started (a message you sent to a peer, from the console, `ahub say` or acon) settles into one **result** when the adapter's own signal says it ended and nothing else is pending: no queued continuation, open permission or question, owned child, running check or held delivery. Peers whose adapter declares no settle signal (Kimi in its own TUI, agy, person-typed Codex turns) leave none. Outcomes are `done`, `failed`, `limit` and `interrupted` (the hub restarted mid-run); an explicit stop by you and a budget pause leave no result. A result is **unread** until you mark it read; nothing a snapshot, `ahub status` or `ahub results` reads ever marks one.
|
|
6226
|
+
|
|
6227
|
+
- `ahub results [--unread]` lists them, newest first, unread ones marked `*`: id, `<peer>: <outcome word>` (a private result is `a private result`), when it settled and how long it ran. It prints no prompt and no reply.
|
|
6228
|
+
- `ahub results --read <id>` marks one read (it must exist and be unread). `--read-all` marks every unread result of the project. `--unread-last` lights the most recent read one again by deleting its receipt.
|
|
6229
|
+
- An unread result is a `result` need at level `watch` in `ahub status` and `ahub console` (ids, the peer and the time only): it never makes the state read as waiting, blocked or review. The console stream tells you once, with no text.
|
|
6230
|
+
- `result_seen` and `results` are console-role control messages that always reply; an agent's connection and an agent shell (`ahub results` is the person's command) are refused, and nothing a peer writes counts as a receipt.
|
|
6231
|
+
- Retention: the table is bounded. At each start the hub keeps the newest 500 READ results and deletes older read ones with their receipts; an unread result is never deleted, and neither is an open run. A hub restart while a peer is under a budget pause ends its open run with no result (a pause stays a budget need, `ahub budget`), whatever work was still pending; any other open run settles `interrupted`, once.
|
|
6232
|
+
- Recovery: a hub from before this feature ignores the tables, so a target without the `completions` label is refused while a run is open (let it settle) or a result is unread (`ahub results --read-all`, or use a supporting release).
|
|
6233
|
+
- **In the dashboard and the acon console (#1054 T6).** The Agents view of `ahub ui` and of the acon panel has a Results section: the unread results (the newest 50, with a count of any older ones and the command that lists them), each with `<peer>: <outcome word>`, when it settled, how long it ran and a one-line **detail**, and the buttons Mark read, Mark all read and Mark last unread again (the relight; it appears only when a read result exists). Opening or refreshing the panel never marks anything read: a poll is not a person looking.
|
|
6234
|
+
- **The detail line is built when you look, never stored.** A completion row keeps envelope ids only, so the head of the request you started (one line, 120 characters) is read from the envelope the bus still holds, passed through the hub's own secret, PII and private-path screens, shown, and thrown away. A private run shows `a private request` without its body being read; a head the screens refuse shows `request withheld by the privacy screen`; a result whose request the bus no longer holds (a long-running hub whose cache turned over, or a restarted one) shows no detail. A live-test dashboard session gets no results and is refused every receipt.
|
|
6235
|
+
- **In the acon inbox.** With a console that advertises both `inbox.result` and `action.meta`, an unread result is an inbox item in the `result` group: kind `result`, title `<peer>: <outcome word>` (`<peer>: a private result` when private), the detail, a chip by outcome (done, failed, limit, interrupted), one `open` verb that links to the Agents panel, and `seen: { action: "result_seen" }`, which acon runs once per page session when the result has been in view (the seeing rule is agent-console#27, not the hub's). With either feature missing, nothing is published and results stay in the Agents panel, `ahub console`, `ahub status` and `ahub results`. A read item leaves the inbox, so **mark unread is not an inbox verb**: it is the panel's button and `ahub results --unread-last`.
|
|
6236
|
+
|
|
6237
|
+
## Questions for the person: `hub_ask` (#1053)
|
|
6238
|
+
|
|
6239
|
+
A peer asks with `hub_ask` (the same tool for Claude, Codex, Kimi, Jcode, Pi and the local worker). The call waits for the person, then answers one of:
|
|
6240
|
+
|
|
6241
|
+
| status | meaning |
|
|
6242
|
+
|---|---|
|
|
6243
|
+
| `answered` | the person's options, inside the wait window |
|
|
6244
|
+
| `pending` | the window ended; the row stays open and the answer arrives later as one message of kind `answer` whose first line is `reply_to: <questionSet>` |
|
|
6245
|
+
| `superseded` | the person sent this peer a normal message instead; that message is delivered as usual |
|
|
6246
|
+
| `cancelled` | `stopped` (a stop, kill or roster removal), `turn_aborted`, `session_changed` or `expired`, as `reason` |
|
|
6247
|
+
| `unavailable` | `unattended`: the hub is, or the peer was started, with `--unattended`; nothing was asked and nothing waits |
|
|
6248
|
+
|
|
6249
|
+
- **Wait window.** Per adapter (`questionWaitMs`): 45 s for the MCP peers, 300 s for Pi and the local worker. These are provisional until T1 measures each client's real tool-call timeout. Override per kind with `questions.wait_ms.<kind>` (1000 to 600000 ms). The Claude channel holds its control request open past the client's 30 s cap. Pi's bridge lifts its 60 s idle timeout for this one call and streams the reply (headers at once, a space every 15 s, then the JSON), because Pi installs a global undici dispatcher with a 300 s headers and body timeout (Pi 1.4.0, measured `UND_ERR_HEADERS_TIMEOUT`); a client that drops anyway leaves the question open, so its answer arrives as the late envelope.
|
|
6250
|
+
- **Expiry.** `questions.ttl_s` (60 to 2592000, default 86400) expires an unanswered question. The peer gets a hub notice of kind `status`, never an answer, and a waiting call is told `cancelled` with reason `expired`.
|
|
6251
|
+
- **Restart.** Open questions are stored in `hub.db` and survive a restart. A waiting call ends `pending` at shutdown and at a recovery `prepare`; the row stays open and its answer takes the late path. A row whose peer is back with a different native session is cancelled (`session_changed`); a peer that reports no session is never cancelled for it.
|
|
6252
|
+
- **Bounds.** At most 8 open questions per peer and 64 in all: a loop of questions turns into a refusal, not a flood.
|
|
6253
|
+
- **Answering.** Three surfaces, one control message (`answer`, console only; `questions`, console only, lists the open rows). In `ahub console`, `A` answers the oldest open question key by key: a digit picks an option (single choice moves on, multi toggles and Enter moves on), `o` types free text where the question allows it (a paste goes into that text, printable characters only, so a pasted Enter or Esc cannot send or leave the answer), Esc leaves and the question stays open. The question and every numbered option are shown in a wrapped area (the body in panels mode, the stream in stream mode), never in the one-line footer, which holds only the keys and the text being typed, so no option is ever off screen while a digit can pick it. A question id is the agent's, so the flow keeps its picks in Maps: `constructor` and `toString` are valid ids; `n` (the attention key) opens the same flow for the question it selects. The last answer is sent at once with no confirm step: answering is neither outward nor destructive. `ahub answer` lists the open questions; `ahub answer <set> <question>=<option>[,<option>]... [--other [<question>=]<text>]...` answers one set (person only: an agent shell is refused before it reaches the hub). In the acon console an open question is an inbox item (`group: decision`, `kind: question`, title `<peer> asks: <first prompt>`, a stub for a private question) whose `answer` verb carries a form built from the stored row; it needs a console that advertises `inbox.form` and `action.meta`, otherwise the item is a plain decision with an `open` verb that links to the Agents panel. The plugin accepts an answer only with the console's own verified person `meta` (`via: "console"`), and refuses one without it before it reaches the hub; the verified identity is recorded on the answered row and on its `question` event (`person`, acon answers only). A stale or superseded set answers `{ ok: false, error }` naming its terminal state.
|
|
6254
|
+
- **Attention.** An open question is a `question` need (level `act`) and the status `waiting` while one is open, ranked after approvals and permission defaults. It is level-triggered: viewing or listing it never clears it; only an answer, a supersede, a cancel or an expiry does. The model carries the set id, the asking peer and the time, never a prompt or an option. The console reads the list only from a hub whose status lists the `questions` feature, and prints one stream line (peer and count, no text) when a new question arrives.
|
|
6255
|
+
- **Recovery.** A new daemon feature label, `questions`, marks the protocol. Recovery refuses a target without it while a question is open or an answer is still owed (`target lacks questions`), because an older daemon would silently ignore the table; answer or cancel the questions first. A recovery `prepare` ends every waiting call as `pending` at once, so a waiting `hub_ask` never holds the prepare for its window. The Claude plugin reports a hub without the label as "this hub does not support questions".
|
|
6256
|
+
- **Events.** `question` records `set`, `peer`, `event` (`asked`, `answered`, `pending`, `superseded`, `cancelled`, `expired`, `unavailable`), `latencyMs`, `surface`, `reason`, `questions` (a count) and `private`; never any text.
|
|
6257
|
+
|
|
6258
|
+
## Anchored review comments (#1056)
|
|
6259
|
+
|
|
6260
|
+
Open a task review in acon and refresh explicitly to read current immutable material. Routine dashboard polls do not query GitHub or Git for review comments. Standalone `ahub ui` is read-only. Unavailable public comments retain their stored text in the person view, but Send refuses those selected IDs until their material is available.
|
|
6261
|
+
|
|
6262
|
+
The hub exact-quote limit is 512 UTF-8 bytes, stricter than acon's character allowance; prefix and suffix each allow 64 bytes. A refusal identifies the field and limit. Shorten the selection, or delete and recreate a stale-head draft from refreshed material. Stored selectors keep exact source text. Delete or dismiss requires confirmation.
|
|
6263
|
+
|
|
6264
|
+
An unconfirmed Send keeps its saved package. Inspect `ahub queue list --peer <owner>` and `ahub queue show <id>` before using the confirmed Retry package action in acon. Recovery reuses the saved envelope identity and text; an already published package starts no new turn. A failed or discarded delivery refuses resend with its state and the queue inspection step instead of reporting queued success. Reviewer requests have a distinct marker and their terminal delivery rows are pruned normally. A previously unpublished package whose comments were dismissed or became private refuses: inspect the saved queue, dismiss the old comments and recreate safe comments when appropriate. An unchanged count-only private stub can recover without revealing text. Legacy or unavailable evidence refuses rather than inventing a fresh message. A queued receipt proves publication, not owner consumption. Package receipts retain terminal delivery payloads alongside their board packages until a future archival transaction can replace both with IDs-only tombstones.
|
|
6265
|
+
|
|
6266
|
+
Comment IDs resolve only after final successful `hub_task_done`, not while a check runs or after it fails. Until resolution or person dismissal, open sent comments and outstanding anchored findings keep scoped responses out of memory and observer views; this does not hide the summary or check tail from its intended recipient.
|
|
6267
|
+
|
|
6268
|
+
For a memory note naming that task, anchored-finding scope conservatively lasts until task close, including a finding later marked fixed. Sent-comment task scope lasts until resolution or person dismissal. Unknown or over-budget task metadata refuses that named-task memory write; it does not impose a peer-wide capture hold based on another task. Capture, progress and session titles follow the current review input instead. Public comment edits from another person appear on the next explicit refresh.
|
|
6269
|
+
|
|
6270
|
+
An owner/reviewer change does not dispose of an earlier review delivery. Its original recipient remains excluded from shared-memory writes naming that task while that delivery is queued or unsettled. Dismissing comments does not dispose of the envelope: inspect `ahub queue list --peer <original-recipient>` and explicitly settle the relevant delivery when appropriate.
|
|
6271
|
+
|
|
6272
|
+
Comment resolution does not end the current review input. A delivered quote-bearing input or a submitted anchored verdict keeps that input's capture and shared-memory writes held through the final answer. Ordinary next-turn input can release it where the transport confirms replacement; restored pull-only sessions follow the native-identity rule below. Presence-only traffic does not release the hold; neither does additional input within the same active turn. Previously saved incoming-label bindings to a review-bearing batch are ignored; a later ordinary input can establish a fresh binding. The local worker latches before the whole anchored-verdict tool batch and does not retain that turn in history, even if the verdict is refused. Historical review scope on another task alone does not block an ordinary new turn. Restarting the daemon does not release a surviving session's recorded review-input hold. The journal stores peer identity, session/input ID hashes and receipt-integrity metadata. In an intact, readable, complete store, a new session with no matching held row is clean immediately. Unreadable or corrupt storage, or unconfirmed coverage for the current session, keeps capture, progress, titles and unscoped shared-memory writes excluded. A validated release receipt confirms its own session while other unconfirmed identities remain held. For an identified pull-only session, a positive held row stays excluded across restart until confirmed native identity changes. Its own incomplete marker clears after verified ordinary replacement or a confirmed new session; legacy coverage alone does not create a sticky hold. A peer with no stable native session id can still receive review input under an in-RAM unknown-held scope, with a peer-level incomplete marker retained until release. For a never-identified peer with no positive or incomplete SID record, a later verified ordinary replacement in that daemon run releases its RAM hold and own marker; in an intact complete store that released absence stays clean after restart. If earlier positive or incomplete SID records exist and the current id cannot be matched, delivery remains available but observer writes stay held. `ahub status` names the peer as "held: session unidentified, earlier review input" and asks for reconnection so its real id is known. A fresh confirmed SID uses its own state; old SID rows remain protected. First confirmation persists any current RAM quote under that SID before clearing the peer-level marker. This records current-input replacement, not erasure of vendor-native transcript history. No launch, attach or socket id is treated as native identity. Presence and additional input within a known active held turn cannot clear the hold. Required provenance persistence happens before a review package is handed over, and a failure refuses that handout. Recovery targets must support `review_observer_input_state` while held or unknown provenance exists. Provenance receipts are bounded at 4096 rows per project. Legacy coverage completes once the journal has no unsettled pre-upgrade review-scoped delivery. At complete coverage, NULL clean receipts are pruned because absence is clean. Positive and uncertain holds remain; a confirmed new session clears only the peer-level incomplete marker, not an older session's held row. Closed fresh-reviewer receipts can still be removed with matching disposal proof. The cap refuses new quote handoffs rather than evicting surviving or uncertain holds. A reviewer still receives the owner's completion summary; recipient output remains distinct from observer exclusion.
|
|
6273
|
+
|
|
6274
|
+
A local tool batch containing an anchored `hub_review` refuses `hub_remember` and `hub_task_propose` before either can write, including siblings listed before the verdict and later steps of that held turn. Save notes or propose new work in a later ordinary turn. Reading a non-empty inbox during an invocation does not replace its answer-routing input; pulled review provenance still protects observers. If provenance admission refuses `hub_inbox`, reconnect the session and retry; if the refusal persists, inspect `ahub status` for delivery journal health. The refused delivery remains queued.
|
|
6275
|
+
|
|
6276
|
+
### Review-input provenance health (#728)
|
|
6277
|
+
|
|
6278
|
+
Read the separate provenance health in `ahub status`. Legacy coverage can remain incomplete while a captured review delivery is unsettled; inspect it with `ahub queue list` and `ahub queue show <id>`, and give it an explicit disposition rather than replaying it as a repair. Reopen/import conservatively recaptures all handed non-terminal rows present then, so a guarded B can keep this window open after the original legacy A settles. Timeout to needs_review does not itself close the window. Delivery still proceeds, and legacy coverage alone does not create a sticky pull-only hold. Ordinary input and confirmed session changes release only the applicable incomplete marker. A healthy positive hold is expected protection, not a journal failure.
|
|
6279
|
+
|
|
6280
|
+
Corrupt or unreadable provenance stays unknown and held. The status next step directs the person to arrange review-input provenance inspection/repair while preserving task rows, delivery dispositions and known positive holds. No reset command or automatic repair is provided in this slice. Do not replace the whole database with an older copy or edit a live journal to make the warning disappear; that can lose disposition evidence and replay work. Keep affected work held until a maintainer can recover trustworthy provenance.
|
|
6281
|
+
|
|
6282
|
+
## Memory sync diagnosis (#1173)
|
|
6283
|
+
|
|
6284
|
+
A ready memory profile does not prove a successful sync. Read the separate automatic-sync result and timestamp in `ahub status` or Memory. It resets to not run after daemon restart; it is not a machine-global record of manual CLI attempts. Missing remote configuration is the neutral `not-configured` state; an interrupted/stopped attempt is neutral `stopped`. Both keep their safe next step and produce no failure log under `quietSyncError`.
|
|
6285
|
+
|
|
6286
|
+
For policy-declined rows, a person runs `ahub memory declined --json` to inspect IDs and safe rule categories, never note text. The pinned agent-mem 0.21.0 public `inspectSyncPolicy` API bounds physical outbound inspection for shared-v1 and generation profiles. A complete result supplies the declined IDs and rules; `complete:false` means the scan is unavailable, stale or over its diagnostic bound, not zero declined rows. The command stays read-only and rechecks its profile binding. No migration or policy edit is performed automatically.
|
|
6287
|
+
|
|
6288
|
+
The hub projects verified withheld/exported counts when a trusted SDK sync returns a successful placement result. That projection is covered by an injected-result fixture, not an activated-store sync. Agent-mem 0.21.0 requires a fresh `placementAttestation` even for an already active v3 store; the default hub supplies no such integration and therefore cannot perform that sync yet. No attestation is fabricated. A nonzero withheld count in a successful result is not a transport failure and does not mean those rows were deleted, rewritten or published. Inspect the IDs and rules before deliberately changing any source or approved policy; a forget operation does not remove its original text from physical history.
|
|
6289
|
+
|
|
6290
|
+
A legacy store without active per-row placement still blocks a sync containing declined rows. Status says: `machine sync blocked: N declined rows; per-row placement is not active on this store (agent-mem has no activation command yet, agent-mem#281). Inspect with ahub memory declined.` Here `N` is the known declined count. Agent-mem 0.21.0 has no activation command, so there is no migration or activation step to run in this release. The hub does not replace the core placement protocol or fabricate its activation proof. [Agent-mem#281](https://github.com/STAIxBWLB/agent-mem/issues/281) owns the missing supported activation path.
|
|
6291
|
+
|
|
6292
|
+
The bounded diagnostic addresses #1173 AC4; AC5 has result projection only; supported activation and fresh host-attestation integration remain necessary for default-host v3 sync. #1173 remains open until #281 ships and its supported path is adopted here.
|
|
6293
|
+
|
|
6294
|
+
For a transport or unknown failure, run `ahub memory sync` as a person to see the local diagnostic. Logs keep only the cause class and known declined count, once per unchanged failure episode. Complete declined-ID sets can distinguish a changed failure without placing IDs or bodies in the log; incomplete inspection keeps the set unknown. Existing write-time screening and profile/privacy fences remain. SDK adoption and isolated fixtures do not prove live rollout or a successful sync of the person's memory home.
|