@staix/agent-hub 0.12.22 → 0.12.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/README.md +22 -9
  3. package/docs/addons/claude-mem.md +24 -0
  4. package/docs/addons/codex-plugin.md +8 -0
  5. package/docs/addons/dot-admit.md +8 -0
  6. package/docs/addons/open-code-review.md +8 -0
  7. package/docs/addons/ponytail.md +23 -0
  8. package/docs/addons/ripwire.md +22 -0
  9. package/docs/agent-notes/README.md +5 -0
  10. package/docs/agent-notes/adapters.md +18 -6
  11. package/docs/agent-notes/benchmarks.md +3 -0
  12. package/docs/agent-notes/budget.md +4 -0
  13. package/docs/agent-notes/bus.md +3 -1
  14. package/docs/agent-notes/daemon.md +14 -1
  15. package/docs/agent-notes/local-worker.md +6 -3
  16. package/docs/agent-notes/tasks.md +6 -1
  17. package/docs/agent-notes/tests.md +4 -1
  18. package/docs/bench.md +28 -3
  19. package/docs/cooperbench.md +4 -0
  20. package/docs/data-policy.md +36 -0
  21. package/docs/events.md +10 -3
  22. package/docs/gsd-collaboration-analysis.md +48 -0
  23. package/docs/memory.md +231 -0
  24. package/docs/operations.md +873 -30
  25. package/docs/plans/2026-10-11-issues-109-sequential.md +81 -0
  26. package/docs/plans/2026-10-11-routing-evaluation-proposal.md +30 -0
  27. package/docs/profiles.md +57 -0
  28. package/docs/quickstart.md +9 -4
  29. package/docs/research.md +31 -1
  30. package/docs/roles.md +85 -0
  31. package/docs/sdlc.md +170 -0
  32. package/docs/security.md +124 -8
  33. package/docs/smoke.md +354 -5
  34. package/docs/specs/2026-09-19-agent-hub-design.md +676 -15
  35. package/docs/specs/2026-10-12-backlog-implementation-plan.md +186 -0
  36. package/docs/specs/2026-10-12-office-view-design.md +212 -0
  37. package/docs/text-projection.md +19 -0
  38. package/docs/verification/2026-10-10-cli-output-phase1.md +309 -0
  39. package/docs/verification/2026-10-10-cli-output-phase2.md +672 -0
  40. package/docs/verification/2026-10-11-0.12.23.md +90 -0
  41. package/docs/verification/2026-10-11-acp-watch-t0.md +33 -0
  42. package/docs/verification/2026-10-11-agent-config-inventory.md +20 -0
  43. package/docs/verification/2026-10-11-jcode-peer-contract.md +27 -0
  44. package/docs/verification/2026-10-13-0.12.24.md +94 -0
  45. package/docs/verification/2026-10-13-board-phone.md +31 -0
  46. package/docs/verification/2026-10-13-fsmonitor-fixture-attribution.md +19 -0
  47. package/docs/verified.json +34 -16
  48. package/package.json +2 -1
  49. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  50. package/plugins/agent-hub/ROLE-NOTICE.md +26 -0
  51. package/plugins/agent-hub/server.js +1108 -261
  52. package/scripts/check-docs.mjs +129 -0
  53. package/src/adapters/acp-quota.ts +13 -0
  54. package/src/adapters/acp.ts +201 -20
  55. package/src/adapters/claude-channel.ts +48 -11
  56. package/src/adapters/codex-appserver.ts +54 -13
  57. package/src/adapters/jcode.ts +110 -0
  58. package/src/adapters/local-worker.ts +10 -7
  59. package/src/adapters/pi.ts +94 -20
  60. package/src/cli/attention.ts +60 -0
  61. package/src/cli/bench.ts +26 -6
  62. package/src/cli/board-read.ts +12 -0
  63. package/src/cli/console-state.ts +131 -39
  64. package/src/cli/console.ts +73 -17
  65. package/src/cli/facts-hook.ts +12 -4
  66. package/src/cli/help.ts +52 -21
  67. package/src/cli/identity.ts +19 -8
  68. package/src/cli/init.ts +48 -10
  69. package/src/cli/jcode-mcp.ts +58 -0
  70. package/src/cli/kimi-mcp.ts +53 -0
  71. package/src/cli/launch.ts +16 -1
  72. package/src/cli/main.ts +641 -193
  73. package/src/cli/memory.ts +193 -0
  74. package/src/cli/output.ts +404 -0
  75. package/src/cli/pet-config.ts +1 -0
  76. package/src/cli/pet.ts +83 -0
  77. package/src/cli/preview.ts +40 -6
  78. package/src/cli/reset.ts +3 -0
  79. package/src/cli/status-lines.ts +1 -29
  80. package/src/cli/tail-render.ts +1 -0
  81. package/src/cli/terminal-recovery.ts +27 -1
  82. package/src/cli/upgrade-runtime.ts +56 -10
  83. package/src/cli/upgrade.ts +23 -5
  84. package/src/cli/watch.ts +31 -0
  85. package/src/hub/activity.ts +53 -0
  86. package/src/hub/ask.ts +10 -5
  87. package/src/hub/bench.ts +10 -3
  88. package/src/hub/board.ts +224 -16
  89. package/src/hub/budget.ts +39 -7
  90. package/src/hub/bus.ts +58 -20
  91. package/src/hub/child-process.ts +11 -0
  92. package/src/hub/citations.ts +7 -0
  93. package/src/hub/conductor.ts +34 -17
  94. package/src/hub/config-trust.ts +20 -7
  95. package/src/hub/conflicts.ts +2 -0
  96. package/src/hub/context-window.ts +8 -1
  97. package/src/hub/crash.ts +11 -1
  98. package/src/hub/daemon.ts +1218 -113
  99. package/src/hub/db-timeout.ts +3 -0
  100. package/src/hub/delivery-journal.ts +7 -1
  101. package/src/hub/envelope.ts +1 -1
  102. package/src/hub/events.ts +14 -2
  103. package/src/hub/execution-budget.ts +2 -0
  104. package/src/hub/facts.ts +28 -8
  105. package/src/hub/git.ts +38 -0
  106. package/src/hub/github-import.ts +28 -0
  107. package/src/hub/hub-tools.ts +49 -10
  108. package/src/hub/inference.ts +1 -1
  109. package/src/hub/lifecycle-schema.ts +17 -0
  110. package/src/hub/lifecycle.ts +10 -4
  111. package/src/hub/listen.ts +15 -0
  112. package/src/hub/manager.ts +26 -6
  113. package/src/hub/path-policy.ts +96 -0
  114. package/src/hub/peer-catalog.ts +28 -0
  115. package/src/hub/peers.ts +5 -3
  116. package/src/hub/permission-mode.ts +33 -5
  117. package/src/hub/planning.ts +70 -0
  118. package/src/hub/profiles.ts +74 -0
  119. package/src/hub/project.ts +2 -1
  120. package/src/hub/projected-diff.ts +73 -0
  121. package/src/hub/projection-exec.ts +24 -0
  122. package/src/hub/recovery-error.ts +31 -0
  123. package/src/hub/recovery-store.ts +6 -5
  124. package/src/hub/registry.ts +2 -1
  125. package/src/hub/research.ts +144 -21
  126. package/src/hub/roles.ts +123 -0
  127. package/src/hub/roster.ts +23 -0
  128. package/src/hub/routing.ts +132 -18
  129. package/src/hub/sdlc-queue.ts +112 -0
  130. package/src/hub/sdlc-release.ts +125 -0
  131. package/src/hub/sdlc.ts +250 -0
  132. package/src/hub/settings.ts +411 -0
  133. package/src/hub/shipped-roles.ts +25 -0
  134. package/src/hub/snapshots.ts +92 -16
  135. package/src/hub/start-mode.ts +50 -0
  136. package/src/hub/supervision.ts +1 -0
  137. package/src/hub/task-sweep.ts +1 -1
  138. package/src/hub/tasks.ts +1014 -111
  139. package/src/hub/terminal-open.ts +64 -0
  140. package/src/hub/text-projection.ts +126 -0
  141. package/src/hub/tooling.ts +159 -0
  142. package/src/hub/ui.ts +40 -14
  143. package/src/hub/workflow.ts +71 -0
  144. package/src/local/deny.ts +29 -7
  145. package/src/local/sandbox.ts +50 -10
  146. package/src/local/tools.ts +11 -6
  147. package/src/memory/brief.ts +28 -14
  148. package/src/memory/import.ts +55 -0
  149. package/src/memory/recall.ts +86 -2
  150. package/src/memory/store.ts +750 -0
  151. package/src/memory/sync.ts +145 -0
  152. package/src/models/mlx.ts +2 -1
  153. package/src/pet/NOTICE.md +10 -0
  154. package/src/pet/characters.ts +1438 -0
  155. package/src/pet/config.ts +31 -0
  156. package/src/pet/frame.ts +17 -0
  157. package/src/pet/pixels.ts +28 -0
  158. package/src/pi/tool-receipts.ts +2 -1
  159. package/src/role-text.d.ts +1 -0
  160. package/src/ui/index.html +983 -40
  161. package/src/ui/needs.ts +58 -0
  162. package/src/ui/office-model.ts +440 -0
  163. package/src/ui/peer-palette.ts +16 -0
  164. package/src/ui/task-board.ts +49 -0
  165. package/src/ui/task-progress.ts +5 -1
  166. package/templates/AGENTS.block.md +3 -2
  167. package/templates/config.json +5 -1
  168. package/templates/profiles/dev.json +22 -0
  169. package/templates/profiles/general.json +26 -0
  170. package/templates/profiles/research.json +57 -0
  171. package/templates/profiles/writing.json +28 -0
  172. package/templates/roles/NOTICE.md +26 -0
  173. package/templates/roles/dev/backend-engineer.md +26 -0
  174. package/templates/roles/dev/code-reviewer.md +26 -0
  175. package/templates/roles/dev/frontend-engineer.md +26 -0
  176. package/templates/roles/dev/security-reviewer.md +26 -0
  177. package/templates/roles/dev/software-architect.md +26 -0
  178. package/templates/roles/dev/test-engineer.md +26 -0
  179. package/templates/roles/research/analyst.md +26 -0
  180. package/templates/roles/research/fact-checker.md +26 -0
  181. package/templates/roles/research/research-lead.md +26 -0
  182. package/templates/roles/research/researcher.md +26 -0
  183. package/templates/roles/research/statistician.md +26 -0
package/docs/bench.md CHANGED
@@ -97,9 +97,10 @@ record reads `interrupted`.
97
97
  machine. Schema `agent-hub.bench/v1`:
98
98
 
99
99
  - `run` header: suite name and SHA-256 of the suite file, arm, fingerprint (the peers attached at the start, with the requested model and
100
- permission mode where the hub's status reports them: today the model for Pi only; the SHA-256 of `routing.toml`; the
101
- hub version), task order, repeats, the runner's process.
102
- - `attempt`: task id, repeat, outcome, error reason, verify exit code, hub task id, start, end, duration, and, for an
100
+ permission mode where the hub's status reports them: today the model for Pi only, and each peer's add-ons by name and
101
+ version as `ahub research addons` detects them (docs/research.md); the SHA-256 of `routing.toml`; the
102
+ hub version), the declared add-on `condition` when the arm has one, task order, repeats, the runner's process.
103
+ - `attempt`: arm, task id, repeat, outcome, error reason, verify exit code, hub task id, start, end, duration, and, for an
103
104
  approved task, its #247 measures (tokens, wall and active time, review rounds, changes requested, failed checks, first
104
105
  pass, turns, files changed, models). They are read once the turns started since the task's proposal have ended (the
105
106
  runner waits only while their peers are still busy or paused, at most 10 minutes), so the turn that approved the task is
@@ -130,6 +131,30 @@ ms, tokens, wallMs, activeMs, reviewRounds, changesRequested, checkFailed, first
130
131
  The dashboard's Benchmarks section shows the latest runs with their progress (the attempt in progress, elapsed time and
131
132
  attempts left while one runs) and, per suite with two or more arms, a bar per arm and measure with its number as text.
132
133
 
134
+ ## Add-on arms (#248)
135
+
136
+ `--addon <name>=on|off` (repeatable; names: `claude-mem`, `ponytail`, `ripwire`, `open-code-review`, `codex-plugin`,
137
+ `dot-admit`) declares an arm's add-on state. Before anything is recorded or reset, the runner reads each attached peer's
138
+ add-ons: an add-on declared `on` must be with at least one of them and one declared `off` with none; otherwise the run is
139
+ refused and names the add-on. The header keeps the declaration as
140
+ `condition.addons`, and every attempt names its arm. The study for one add-on is its arms with every add-on on, that one
141
+ off, and all off, on the same suite, refs and peers, interleaved and with the task order randomized per run:
142
+
143
+ ```bash
144
+ ahub bench run ../suites/s.json --arm all-on --addon claude-mem=on --addon ponytail=on --addon ripwire=on --repeat 5
145
+ ahub bench run ../suites/s.json --arm ripwire-off --addon claude-mem=on --addon ponytail=on --addon ripwire=off --repeat 5
146
+ ahub bench run ../suites/s.json --arm all-off --addon claude-mem=off --addon ponytail=off --addon ripwire=off --repeat 5
147
+ ahub bench compare all-on ripwire-off all-off
148
+ ```
149
+
150
+ `--memory off|claude-mem|native|both` declares which memory the arm's hub runs with (#258): `off` is neither
151
+ claude-mem nor hub memory, `claude-mem` only claude-mem, `native` only hub memory, `both` both. The runner reads the
152
+ project's `memory.enabled` and `memory.native` and refuses a mismatch before anything runs; restart the hub after
153
+ changing them. The header keeps it as `condition.memory`.
154
+
155
+ Switching an add-on is the person's setup between runs (a plugin's `enabledPlugins` entry, PATH); the runner only
156
+ checks it. CooperBench (`docs/cooperbench.md`) keeps every add-on off by design, so add-on arms run here.
157
+
133
158
  ## A fair comparison
134
159
 
135
160
  - Change one thing per arm (a model, a permission mode, an add-on, a routing rule) and keep the suite, the refs and the
@@ -127,6 +127,10 @@ Manifest v3 run directories (headless Pi/Qwen, `protocol: native-pq-v3` in every
127
127
 
128
128
  Contributions are a heuristic for possible loss, never a certificate: per agent and file, the identifiers and changed fragments its applied writes introduced (only a Claude tool call with a successful result, or a completed Codex patch, counts; a Write replaces the agent's earlier contribution and is not credited with what other agents wrote; a delete removes it; when a file is moved, every agent's contributions to it are checked at its new path) that the final tree lacks, a fragment counting as present anywhere in the file. A same-name overwrite shows as a lost fragment. Shell commands run during the task are not attributed and are counted under `coverage`, with a missing transcript or an unreadable file. Correctness comes from the official grader, for every arm.
129
129
 
130
+ ## Routing-time prediction preregistration (#109, 2026-10-11)
131
+
132
+ The owner approved 120 controlled matched task pairs, 60 development and 60 held-out, comparing split execution of the same work units against both solo controls. The input/outcome, exclusion, unknown-value and reporting contract is [the routing evaluation preregistration](plans/2026-10-11-routing-evaluation-proposal.md). This freezes the design and sample budget, not the execution manifests: task-family/split membership, source/check hashes, native versions, profiles and warmup history must be sealed before the first scored attempt. No collection is authorized in the solo implementation session; automatic routing remains off. AC5, T3 and T4 remain open until their measured evidence and implementation gates pass.
133
+
130
134
  ## Preregistration (v2)
131
135
 
132
136
  Fixed before outcomes are collected (issue #110):
@@ -0,0 +1,36 @@
1
+ # Private and read-only data paths (#259)
2
+
3
+ - Optional shared or machine-local config declares `pii.paths` and `data.readonly`, each at most 64 project-relative paths/patterns of at most 200 characters. Entries name exact paths/subtrees or bounded globs, with no command execution. Empty or absent lists preserve existing behavior. These initial policies apply at daemon start; edit config deliberately and restart to refresh them.
4
+ - Example: `{ "pii": { "paths": ["data/private"] }, "data": { "readonly": ["data/raw"] } }`.
5
+ - Matching compares declared spellings and real targets, including symlink aliases and case variants. Unknown resolution conservatively matches an active policy. Paths outside the project cannot be selected as policy entries; managed tools retain their existing project boundary.
6
+
7
+ # Private task flow
8
+
9
+ - Declared refs, plan paths and section file anchors matching pii.paths receive a hard private signal before triage, board writes, notices or memory. The task remains local-only even if ordinary pattern-based PII routing is off.
10
+ - Directory scopes containing a protected path are private too. Automatic facts omit configured private files even without an open private task. Public titles/views stay stubs, private envelopes stay private, and automatic notes skip memory. Newly accepted plans cannot silently add a private path to an ordinary task. Existing pattern screening and unknown verdict handling remain in force.
11
+ - This governs declared task paths and the managed flow. It does not contain a same-user external shell or another native peer reading arbitrary files outside its declared task.
12
+
13
+ # Read-only managed tools
14
+
15
+ - Local/Pi read operations retain access. Managed write/edit refuse protected paths before asking for approval and re-check real targets after approval. With an active read-only policy, hardlinked write targets are refused because their identity cannot be attributed safely to one declared name.
16
+ - Managed command execution (bash and git) becomes filesystem read-only whenever data.readonly is active. It keeps reads and stdout/stderr, allows /dev/null, and grants no project or temporary-directory writes. Commands that create output files or caches must instead return stdout or use managed write/edit for an unprotected output path. This restriction is required by the reproduced hardlink-alias bypass of path-only Seatbelt denies.
17
+ - The command profile and runner must both use read-only mode; the runner refuses a profile that still carries a broad project write grant. No approval or permission mode overrides the data policy. Existing network and credential boundaries stay in force.
18
+ - This policy controls managed local/Pi tools, not the owner or other native processes. The hub's state, receipts, explicitly configured completion checks and temporary command directory are maintained by the daemon outside the managed command.
19
+
20
+ # Evidence boundary
21
+
22
+ - Source tests cover bounded config/layers, real-path aliases, private flow before triage, public redaction, approval re-checks and managed hardlink refusal.
23
+ - Native macOS command tests cover direct write, parent rename, existing/new hardlinks, temporary aliases and preserved reads. Linux runs the source guards and retains its existing no-sandbox/no-command behavior.
24
+ - Real-account/model execution remains unverified; no live research study runs as part of this implementation. Profile converters and shadow repositories are later #259 slices.
25
+
26
+
27
+ # Bounded glob policy
28
+
29
+ - `*` matches any characters within one path segment, `?` matches one character, and a whole-segment `**` matches zero or more segments. Matching includes dot names and folds case consistently with the existing exact policy. A matched directory protects its subtree. Directory task scopes are private if they can contain a future matching descendant, even before a file exists.
30
+ - Examples: `pii.paths = ["data/**/*.csv"]` and `data.readonly = ["data/raw-*/**"]`. Up to 16 wildcard characters per pattern. Absolute paths, parent traversal, bracket classes, braces, negation and mixed `**suffix` forms are refused. Backslashes remain literal in exact entries but are refused in glob entries; no escape syntax is interpreted.
31
+ - Match both declared spelling and real target. Wildcard directory/file aliases are discovered from compatible prefixes, including symlink aliases to future targets. Discovery is refreshed per decision, with no stale cached expansion. It reads at most 4096 directory entries and traverses at most 32 levels. An unreadable/dangling/cyclic/out-of-project alias or an exhausted discovery bound conservatively protects rather than declaring a path public/writable. No discovered name or policy body is logged.
32
+ - Managed local/Pi write/edit and private Tasks/facts use this same matcher. Existing hardlink refusal, post-approval recheck and filesystem-read-only command profile remain unchanged.
33
+ - Claude's managed `ask-when-needed` hook receives `ask` for a write matching data.readonly. Reads and ordinary project writes retain their existing scoped decisions. The daemon evaluates policy locally only for the current managed PreToolUse ask-when-needed write grant and sends no pattern list to the hook. PostToolUse, unavailable/ask/never-ask modes and non-write tools perform no grant-policy discovery. Explicit native approval and `never-ask` remain the person's native authority; this is scoped auto-grant filtering, not a new Claude sandbox or containment claim.
34
+ - The previous malformed-config fixture that refused every wildcard now refuses an unsupported bracket class; its rejection assertion is retained. New tests establish the deliberately added glob grammar, future paths, wildcard aliases/retargeting, private scopes, discovery failures and actual daemon hook replies. Native account/model consumption is unverified.
35
+
36
+ - Hardlink identity refusal precedes path matching for managed writes, including an already protected original. This keeps the refusal stable across platform-specific real-path alias choices; read access and policy-off behavior remain unchanged.
package/docs/events.md CHANGED
@@ -25,6 +25,9 @@ marked `private: true`, and PII tasks `pii: true`.
25
25
  | `progress` | `peer`, `task` (task id), `severity`, `spinning`, `exploring`, `production`: normalized tool activity dimensions for an open task; coverage differs by peer and no commands or task text are recorded |
26
26
  | `stuck` | `peer`, `task` (task id), `category` (`repetition`, `false_progress`, `drift`, `desperation`, `capability_gap`), `streak`, `latched`: an escalation verdict; it recommends considering reassignment and never reassigns automatically |
27
27
  | `capability` | `peer`, `state` (`verified` or `lost`), `via`: a peer's context path for facts |
28
+ | `memory_brief` | `peer`, `task`, `native`, `fails`, `claudeMem`: what a task brief carried, as counts (#258, docs/memory.md) |
29
+ | `hub_start` | `instance`: a hub run began, written once it holds its control port and before any peer can attach (a daemon that cannot bind writes none); every peer counts as detached until its next `state` event |
30
+ | `tooling` | `peer`, `addons` (`{ name, version }` from a closed list, version null when unknown): the add-ons a peer works with, at each attach (#248, docs/research.md) |
28
31
  | `native_turn_end` | `peer`, `id` (an opaque hash that names the completed turn): the end of a Claude turn, recorded once the hub finds the turn its Stop hook reported completed in the native transcript (Codex's is its `turn_end`); quiescence evidence for an integration |
29
32
  | `supervision_turn` | `peer`, `turn` (the hub turn a supervision notice was delivered into, or `supervision-<uuid>` when none was open), `tokens` (when the adapter reported any for it), `ms` (from that turn's start, or from the delivery when none was open, to its native end): a completed native turn that received supervision, which `ahub report` counts; a failed delivery or turn, a peer that went offline or a changed native session records none |
30
33
  | `conduct` | `peer` (the conductor, or `user` when the console releases a conductor hold), `action`, `task` (when the action names or creates one), `target` (the peer an assignment, start, hold or release names): one action of the conductor that ran, the structured twin of the console's `conductor` notice. `action` is a tool name without its `hub_` prefix: a conductor tool (`status`, `task_show`, `task_assign`, `task_escalate`, `peer_start`, `peer_hold`, `peer_release`), or one of the conductor peer's own task tools, which are not conductor tools (`task_propose`, `task_accept`, `task_decline`, `task_done`, `review`, `checkpoint`, `remember`). The role-free reads and redirects (a task's owner or reviewer with `hub_task_show`, its proposer with `hub_task_assign`) record none, and neither does `hub_task_list` |
@@ -41,17 +44,21 @@ marked `private: true`, and PII tasks `pii: true`.
41
44
  | `task` | `id`, `event` (the board history event, e.g. `proposed`, `assigned`, `done`, `check failed`, `blocked`, `ready`), `by`, `state`, `owner`, `reviewer`, `class`, `pii`, and `reason` when the board recorded a move reason (`manual`, `budget`, `offline`, `idle`, `rejections`, `declined`, `inference_failed`, `delivery_failed`) |
42
45
  | `overlap` | `task`, `owner`, `others` (`task`, `owner`, `paths`, and `symbols` when plans name the same symbol; a name that matches a PII pattern is left out, so either list can be empty), the structured twin of the console notice |
43
46
  | `permission_mode` | `peer`, `from`, `to` (`ask`, `ask-when-needed`, `never-ask`): a person set a peer's permission mode (`from` equals `to` when it was already in force) or confirmed a never-ask default (issue #242) |
47
+ | `settings` | `key` (a registry key such as `permission.kimi` or `routing.classes.implement.peers`), `from`, `to` (the value before and after: the one in force for a setting that applies at once, the stored one for a setting read at a start; a closed word, a boolean, a list of peer ids, a route id, or null for none), `source` (`dashboard`, `terminal`), and `undo: true` for an undo: a person changed a setting from the dashboard or `ahub settings` (issue #269). A mode change also writes its `permission_mode` event |
44
48
  | `permission` | `id`, `peer`, `event` (`requested`, then one of `answered`, `expired`, `cancelled`) and, on the closing event, `latencyMs`, `surface` (`console`, `dashboard`, `terminal`: where a person answered; absent when the hub closed the request) and `option` (the kind of the option chosen: `allow_once`, `allow_always`, `reject_once`, `reject_always`): one approval request relayed to the console and how it ended. `expired` is `approvals.timeout_s` without an answer. `cancelled` with a `surface` is a person's deny in the console or by `ahub permit <id> deny` (a deny on the dashboard is `answered` with a reject option); without one, the hub withdrew the request (its call or turn ended, the peer was stopped, or the hub is stopping). Never the title or the tool |
45
49
  | `pii_screen` | `task` (absent for a budget hand-off or a note not about a task), `item` (`task`, `summary`, `review note`, `handoff`, `note`), `label` (`pii`, `clear`), `source` (`regex`: a pattern matched and no call was made; `screen`; `unknown`: no verdict, handled as PII), `category` (`name`, `student_id`, `phone`, `address`, `grade`, `health`, `other`), `miss` (why there was no verdict: `too long`, `off campus`, `timeout`, `unreadable`, `failed`), `ms` (absent for `regex`): one PII screen verdict while `signals.pii_screen = "local"` (issue #198); never the text |
46
- | `context_pressure` | `peer`, `source` (`claude_statusline`, `codex_token_usage`), `measuredAt` (epoch ms of the reading), `used` (the fraction of the context window in use, 0 to 1), `window` (its size in tokens, or null): a fresh reading of a peer's native context reached `context.gate`. Recorded once per crossing, until a reading below the gate or a new native session rearms it, and not while the peer is paused or offline or the hub is in recovery or stopping |
50
+ | `context_pressure` | `peer`, `source` (`claude_statusline`, `codex_token_usage`, `acp_usage_update`), `measuredAt` (epoch ms of the reading), `used` (the fraction of the context window in use, 0 to 1), `window` (its size in tokens, or null): a fresh reading of a peer's native context reached `context.gate`. Recorded once per crossing, until a reading below the gate or a new native session rearms it, and not while the peer is paused or offline or the hub is in recovery or stopping |
47
51
  | `quota` | `peer`, `windows` (`id`, `used`, `resetsAt`), `hard`, `measuredAt` (when the reading was taken, if not when it arrived: Claude's numbers come through a file) |
48
52
  | `conflict` | `peer`, `task` (its task in progress, when it had one), `other` (the other owner's open task), `owner`, `paths` (names that match a PII pattern left out, so it can be empty), `concurrent` (another peer worked during the turn), `turns` (the two turn ids, when two overlapping turns' snapshots both hold the change) |
49
53
 
50
54
  Token usage by adapter:
51
55
 
52
56
  - Kimi (ACP `usage_update`, and the usage a `session/prompt` result carries): recorded when it holds a checked
53
- total or an input/output pair. The `{used, size}` shape Kimi sends is context occupancy and is not recorded
54
- (issue #285 tracks showing Kimi's usage).
57
+ total or an input/output pair. The `{used, size}` shape Kimi sends is context occupancy: it is shown as the peer's
58
+ native context reading (source `acp_usage_update`, #285 phase 1) and no `tokens` event is written from it; Kimi's
59
+ consumption is not recorded yet (phase 2). The adapter accepts the update whenever it names the current session;
60
+ Kimi 2.1.1's source text emits it after the prompt resolves, when the peer may already be idle, and that order is
61
+ not yet observed live through the hub (docs/smoke.md).
55
62
  - Codex (app-server `thread/tokenUsage/updated`): recorded as the growth of the thread's running total, so
56
63
  compaction estimates, usage-limit refreshes and the replay to a reattaching connection add nothing. A thread
57
64
  started under the hub counts from zero; a resumed thread's first update is its history and only sets the
@@ -0,0 +1,48 @@
1
+ # GSD-shaped collaboration in agent-hub (#252)
2
+
3
+ Source review: 2026-10-11, agent-hub 5647038. Recommendation: preserve the default flow; offer a bounded gsd-lite checklist/dependency presentation through #257's opt-in lifecycle. Defer a bidirectional GSD artifact bridge until it has a separately reviewed import contract and measured value.
4
+
5
+ ## Evidence boundary
6
+
7
+ This is source-based analysis, not a measured claim that GSD improves quality or cost. No matched default/GSD comparison or add-on arm ran in this solo implementation. Research records (#247, docs/research.md) store task outcomes, counts, tokens and timings, not task/plan text. The #251 bench infrastructure can compare configurations on a common suite, but infrastructure existence does not provide an effect estimate.
8
+
9
+ The inspected local adapter is `/Users/yj.lee/.agents/skills/gsd-execute-phase/SKILL.md`, SHA-256 `b10610df4d9b55bdf39141cbf469525f1429cea4ae774dc4cd486520a62cae51`. Its installation revision was not recorded, so it is not asserted to equal an upstream release. Independently reviewed upstream [execute-phase command](https://github.com/gsd-build/get-shit-done/blob/bdcaab2c752d9a33a1a1ca9acf3a3c81fb991815/commands/gsd/execute-phase.md), [workflow](https://github.com/gsd-build/get-shit-done/blob/bdcaab2c752d9a33a1a1ca9acf3a3c81fb991815/get-shit-done/workflows/execute-phase.md) and [installer](https://github.com/gsd-build/get-shit-done/blob/bdcaab2c752d9a33a1a1ca9acf3a3c81fb991815/bin/install.js) at full commit `bdcaab2c752d9a33a1a1ca9acf3a3c81fb991815` establish Codex support, dependency waves and context handoff. Codex worktree isolation is explicitly refused by that workflow; support is not a blanket guarantee of runtime parity. Therefore the issue's older claim that non-Claude runtimes cannot use GSD is too broad: Codex integration exists. Kimi/Pi/local runtime coverage was not established. The skill was inspected as reference material; its delegation/autonomous workflow was not invoked.
10
+
11
+ ## Benefits and costs (qualitative)
12
+
13
+ | GSD idea | Current hub mechanism | Potential value | Cost or failure boundary |
14
+ | --- | --- | --- | --- |
15
+ | Shared written plan | Issue spec plus Task.plan signatures/paths/insertion points | More consistent implementation scope and fewer context rediscoveries | Copying the issue into an independently editable PLAN creates spec drift; derive it and preserve issue precedence |
16
+ | Dependency waves | Tasks.after waits for approval; overlap/cohort guards already protect integration | Expose safe concurrency and explain why work waits | A whole-wave barrier can idle independent successors; use exact predecessor edges, not an unconditional global wave barrier |
17
+ | Goal-backward verification | sendReview already renders a per-task checklist | Catch phase-level omissions that individually passing tasks miss | A checklist is not evidence; require exact artifacts/check results and permit inconclusive findings |
18
+ | Durable STATE/HANDOFF | Board/history, receipts, events, #247 records | Recover human understanding of purpose and remaining work | A second writable state authority loses or duplicates work; board remains authoritative, exports are derived |
19
+ | Codebase map/context packets | Plans, refs, briefs, facts and native context readings | Reduce repeated discovery across peers | Maps go stale; source hashes and bounded context are needed; privacy/PII rules remain at existing boundaries |
20
+ | Atomic per-task commits | Repository branch/PR conventions | Reviewable rollback and clearer scope | Additional commits are not proof of independent review; immutable head and CI gates still belong to SDLC |
21
+
22
+ These are hypotheses. There are no measured first-pass, rework, regression, token, wall-time or operator-overhead differences reported here.
23
+
24
+ ## Mapping and authority
25
+
26
+ - A phase maps to an issue/release slice, not a replacement spec. Its tasks are board tasks with explicit after edges; runtime-specific executors are ordinary owners under existing roles and capabilities.
27
+ - Verification is a reviewer task with the phase's deliverable checklist. Task approval and phase verification remain distinct; a failed phase check does not silently erase completed task history.
28
+ - STATE/HANDOFF are board-derived readbacks with artifact ids, current heads, pending gates and next actors. Import is a validated proposal, never an overwrite of accepted work.
29
+ - GSD's workspace-pinned no-auto-advance and branch-first rules are retained. This comparison grants no extra command, permission, tool, sandbox, native restart or coordinator authority.
30
+ - PII stays local/on campus, untrusted text is sanitized by existing output boundaries, and model-written guidance is not evidence merely because it is in a plan.
31
+
32
+ ## Recommended delivery contract (specified before implementation)
33
+
34
+ The initial option is gsd-lite, off by default, implemented with #257's lifecycle rather than a second scheduler:
35
+
36
+ - `workflow: none | gsd-lite` is a data choice, with none the default. It changes guidance/presentation only unless SDLC enforcement is separately selected.
37
+ - Planner input is a bounded list of task ids and predecessor ids. It resolves to exact existing after edges, validates acyclic dependencies, preserves accepted owners/reservations and rejects private text on cloud surfaces. No model-generated wave bypasses Tasks.
38
+ - A phase reviewer checklist stores criterion ids and evidence refs. The reviewer may pass, request changes or mark an item unverified; the parent slice is not complete while a required item remains unverified.
39
+ - route explain, console and dashboard show the active workflow and blocking predecessor/verification gates from the same data; defaults remain unchanged.
40
+ - No extra STATE/PLAN/HANDOFF authority is introduced. Explicit exports contain safe derived state and source hashes. No auto-advance or autonomous merge/release.
41
+
42
+ This bounded option is covered by a dated amendment to #257 before code. A full `workflow: gsd` bridge is not recommended for implementation yet: it needs bounded import size, source/phase identity, idempotency, conflict handling, authority and PII rules defined in a separate contract. That distinction prevents calling a partial bridge done.
43
+
44
+ ## Measurement plan
45
+
46
+ Use #251 on the same sealed suite, native/model/effort profiles, role set, tools, permission modes and resource limits. Compare default versus gsd-lite checklist/dependency presentation. Preregister the task-family split and attempt/token/wall-time budget; include failed/time-limited attempts, abstentions and operator interventions. Report approved-task rate, first-pass rate, rework/regressions, observed conflicts/idle time and normalized token/time measures with family-cluster intervals. Missing activity or provider costs stay unknown. #248 separately measures add-ons; they are not credited to the workflow without their own controlled condition.
47
+
48
+ No measurement was run here. AC1 is answered qualitatively and AC2 has the bounded #257 contract; #252 stays open for the built option and AC3 comparison. Native multi-agent research is outside this turn's solo/no-ahub execution.
package/docs/memory.md ADDED
@@ -0,0 +1,231 @@
1
+ # Hub memory
2
+
3
+ The hub's own memory (#258): notes the agents and the hub save while they work, kept in two tiers and linked into a
4
+ graph by what they are about. It sits beside claude-mem, which stays the capture and session-recall source where it is
5
+ installed. Every machine keeps its own copy in `~/.agenthub/memory/` (directory 0700, files 0600).
6
+
7
+ ## Turning it on and off
8
+
9
+ On with any project config (`.agenthub/config.json`); `"memory": { "native": false }` turns it off for a project.
10
+ `memory.short_ttl_days` (default 14, a whole number from 1 to 3650; anything else fails the config) sets how long
11
+ short-term entries live after their task is approved, and `memory.sync_interval_min` (default 10, 0 off, at most 1440) how often a running
12
+ hub syncs once a remote is set. Writing and
13
+ reading are fail-open: a store that cannot be written costs one notice, and never a tool call or a turn.
14
+
15
+ ## Tiers
16
+
17
+ - **Short-term**: notes saved against a task that is still open, and notes saved with no task. They stay on this
18
+ machine (`local/<machine>.jsonl`) and leave the index `short_ttl_days` after their task is approved (a note with no
19
+ task, or saved with `horizon: "short"` on purpose: after it was written, and it is never promoted; a demoted entry:
20
+ after the demotion; a note on a task that is never approved: 180 days after it was written, the same for every
21
+ reader). The deadline is written into the entry (`expires`)
22
+ or the op (`settle`, `demote`) when it is set, so every process reading the store prunes the same rows whatever its
23
+ own setting. Their log lines stay on disk.
24
+ - **Long-term**: decisions, contracts and fails that outlive their task. When a task is approved, its decision, contract
25
+ and fail notes are copied to long-term automatically (findings are not), and the short-term originals are hidden.
26
+ Each is screened again first under the project's current PII patterns and `pii.paths`; one that fails stays
27
+ short-term on this machine and expires. An
28
+ agent can save straight to long-term with `hub_remember(..., horizon: "long")`; a note against an already approved
29
+ task that is a decision, contract or fail is long-term at once. Long-term entries go to `log/<machine>.jsonl`, the
30
+ segment machine sync will carry.
31
+ - **Scope**: `project` (default) entries are read only in the project that wrote them; `shared`
32
+ (`hub_remember(..., scope: "shared")`) entries are read from every project on the machine.
33
+
34
+ A project is named by its `origin` remote, normalized to host and path (`github.com/owner/repo`, lowercased on GitHub, whose
35
+ names ignore case; a URL keeps a port that is not its scheme's default), the same on every machine; a repository without one is named by its git chain plus a hash of its directory, so two unrelated
36
+ repositories with the same name never share entries (that name is this machine's only).
37
+
38
+ ## What gets written
39
+
40
+ - `hub_remember` from any peer or `ahub remember`, after the existing checks: a note about a PII task, or one matching a
41
+ PII pattern, is refused; the PII screen (#198) must clear it; a note that looks like it holds a secret (a private key,
42
+ a cloud or GitHub token, `password: ...`) is refused.
43
+ - The hub's own notes on a task: the done summary (finding), the review verdict and an escalation (decision), with the
44
+ same PII and secret rules. Nothing about a PII task is written.
45
+ - Notes still go to claude-mem when it is enabled, as before; the other peers get the note line on their next delivery.
46
+
47
+ ## Entries (`agent-hub.memory/v1`)
48
+
49
+ One JSON line each. The id is the first 32 hex characters of the SHA-256 of the entry's canonical JSON (sorted keys,
50
+ without `id`), so the same content always has the same id and a line whose id does not match is skipped. Nothing is
51
+ ever rewritten: a change is a new entry.
52
+
53
+ | `op` | Fields |
54
+ | --- | --- |
55
+ | `note` | `project`, `scope`, `tier`, `kind` (`decision`, `finding`, `contract`, `fail`), `peer`, `title?`, `text` (at most 4000 characters), `task?` (`<project>#<id>@<created ms>`), `about` (nodes), `supersedes?`, `promotedFrom?`, `source` (`hub`, `person`, `claude-mem`), `expires?` (a short-term note with no task, on a task already settled, or saved short-term on purpose: its own deadline, whatever the task does); a promoted copy is dated as its source and keeps its fields, whoever promotes it |
56
+ | `forget` | `target`: the entry is gone from the index, and so is its promoted copy or original |
57
+ | `supersede` | `target`, `by`: the newer entry; superseded entries are dropped from briefs and recall while the newer one is live (forgetting it shows the old one again) |
58
+ | `demote` | `target`, `by`: a long-term entry becomes short-term and leaves the index at `by` |
59
+ | `settle` | `target`: a task key, `by`: when its short-term entries leave the index (written when the task is approved; a settlement a crash cut short is finished at the next read, and a held decision, contract or fail whose replacement is forgotten or expires moves to long-term then too) |
60
+
61
+ Every entry also has `schema`, `id`, `at` (ISO time) and `machine` (a random id per `~/.agenthub`, in
62
+ `memory/machine.json`, with a label a person can edit).
63
+
64
+ ## The graph
65
+
66
+ Nodes are entries (`mem:<id>`), files (`path:src/a.ts`, relative to the project root), symbols (`symbol:parse@src/a.ts`,
67
+ with the path when the task's plan names exactly one), issues (`issue:owner/repo#12`, the repo from the project's
68
+ `origin` remote on GitHub, else the project name), board tasks (`task:<project>#3@<proposal ms>` for the task a note was saved against, so a task id reused after
69
+ `ahub reset --all` is another node; `task #N` in a text names `task:<project>#N`), peers, machines and projects.
70
+ Edges are deterministic and fixed when the entry is written, so a rebuild never depends on the file system:
71
+
72
+ - `about`: from the task's refs and plan paths, plan symbols, paths named in the text that exist in the project at
73
+ write time (denylisted paths are left out), `#N` and `task #N`, and the task the note was saved against. A `fail`
74
+ draws them as `rules_out`.
75
+ - `by` (peer, machine) and `in` (project), from the entry's fields; `supersedes` between entries.
76
+
77
+ - `part_of` (board task to long-term task) and `depends_on` (between long-term tasks), from the links below.
78
+
79
+ - Model-suggested edges, off by default (`"memory": { "suggest_edges": true }`): after a note is saved, the hub's model
80
+ (the same route as digest condensation) names `contradicts` or `same_topic` between it and up to six near entries.
81
+ Its answer is read line by line against that closed list and stored as a suggestion by `hub-model` (`suggest`,
82
+ `confirm`, `reject` entries). Suggestions are drawn dashed on the dashboard and are never evidence: briefs, recall and
83
+ `ahub ask` ignore them until a person confirms one (`ahub memory confirm <id>`); a rejected one disappears.
84
+
85
+ ## Long-term tasks
86
+
87
+ A long-term task (a goal) spans sessions, board tasks, projects and machines: an epic issue, a migration. It has a
88
+ state (`open`, `active`, `blocked`, `done`, `dropped`), milestones, the long-term tasks it depends on, its linked board
89
+ tasks (project, task id and proposal time, so a reset's reused ids never join it) and a lease. All of it lives in the
90
+ synced log as entries:
91
+
92
+ | `op` | Fields |
93
+ | --- | --- |
94
+ | `goal` | `project`, `scope`, `title`, `milestones`, `dependsOn`, `actor` |
95
+ | `goal_state` | `target`, `by`: the state |
96
+ | `goal_link` | `target`, `by`: the board task key |
97
+ | `lease`, `lease_force` | `target`, `by`: until when (ISO) |
98
+
99
+ - **Titles** and milestones are kept to one line (whatever another machine wrote), and recall lines are sanitized, so
100
+ they cannot carry a forged message header into an agent's context.
101
+ - **Links**: a peer joins its own board task to one of this project's long-term tasks with
102
+ `hub_task_propose(..., goal: "<id>")`; a person links any board task of the project to any long-term task with
103
+ `ahub goal link <id> <task>` (through the running hub, so the board task is checked). Nothing about a PII task is linked.
104
+ - **Lease**: while a linked board task is in progress on this machine's hub, the hub holds the long-term task's lease
105
+ (default 4 hours, renewed past half its time). It looks at every in-progress task at start, every 10 minutes, when
106
+ a task changes on the board and when a person links one, so a task worked on for hours keeps its lease. It never takes a lease another machine holds: the console says who
107
+ holds it, and a person takes it over with `ahub goal take <id> --force`, which voids every earlier claim. A lease that
108
+ expired is free for anyone.
109
+ - **Conflicts**: sync is eventually consistent, so a lease is advisory. Two machines that claim inside one sync window
110
+ both stand: the earlier claim holds and the other shows as a conflict everywhere (status, dashboard, `ahub goal`)
111
+ until a person settles it with `--force`. There is no consensus; a broker would make it a real lock if concurrent
112
+ work across machines ever needs one.
113
+ - **Where it shows**: at hub start (a console line per open long-term task of the project), in `ahub status`, in
114
+ `ahub goal list`, on the dashboard's Long-term tasks tab, and leading the session-start recall. Briefs bring along
115
+ the entries of the long-term task's other board tasks.
116
+
117
+ ```bash
118
+ ahub goal new "native memory" --milestone "phase 1" --milestone "phase 2" # a person's
119
+ ahub goal link 1a2b3c4d 12
120
+ ahub goal # open long-term tasks, their state and lease
121
+ ahub goal show 1a2b3c4d
122
+ ahub goal take 1a2b3c4d [--force]
123
+ ahub goal state 1a2b3c4d blocked
124
+ ahub goal done 1a2b3c4d
125
+ ```
126
+
127
+ ## Machine sync
128
+
129
+ The memory directory is a git repository that tracks only `log/*.jsonl` (and its `.gitignore`); the index, the local
130
+ short-term segment and `machine.json` never leave the machine. Each machine commits only its own segment and starts
131
+ its own history, so merging another machine's history never conflicts.
132
+
133
+ ```bash
134
+ ahub memory sync --remote git@github.com:you/agent-hub-memory.git # once per machine, a person's
135
+ ahub memory sync # pull, then push, now
136
+ ahub memory machine --label "office mac" # a name shown beside the id
137
+ ```
138
+
139
+ - A sync commits this machine's segment, fetches, merges the remote's history, pushes (once more after a merge when
140
+ another machine pushed in between) and indexes what arrived. One sync runs per machine at a time.
141
+ - A running hub syncs 5 seconds after it starts and every `memory.sync_interval_min` minutes (default 10; 0 turns it
142
+ off) once a remote is set. A failure is one `hub.log` line and never blocks a turn; a store without a remote does
143
+ nothing and creates nothing.
144
+ - The remote must be private: long-term entries hold note text. A GitHub remote is checked with `gh repo view` and a
145
+ public one is refused; any other host, or a `gh` that cannot answer, is unknown and the sync goes on with a warning.
146
+ - Use an SSH remote, or HTTPS with a credential helper in your global git config: the hub keeps your credential helper
147
+ for this repository only, and never prompts.
148
+ - A forgotten entry stays in the remote's git history; removing it from there is a person's history rewrite.
149
+
150
+ ## Index
151
+
152
+ `index.db` (SQLite) is derived from the logs: entries, ops and edges are inserted with `INSERT OR IGNORE`, and every
153
+ state (superseded, forgotten, promoted, demoted, expired) is computed from those rows, so reading the segments in any
154
+ order gives the same index, and the index each hub keeps up to date as it writes equals a rebuild from the logs. Each
155
+ reader keeps the byte offset it reached per segment and reads only what was appended since; a line still being written
156
+ waits for the next read. A segment that got shorter, disappeared or was rewritten in place (the indexed part no longer
157
+ hashes to what was indexed) makes the reader rebuild the index from every segment. Malformed lines and lines whose id does
158
+ not match their content are skipped with one log line.
159
+ `ahub memory rebuild` drops the rows and reads every segment again; deleting `index.db` does the same on the next start.
160
+
161
+ ## Reading it
162
+
163
+ - **Task briefs**: when a task is handed to an owner, its brief lists hub memory first (entries one or two hops from
164
+ the task's paths, symbols, issue and task: a linked fail first, then nearer, then newer; superseded entries dropped;
165
+ other projects' entries only when shared), then claude-mem's, `memory.brief_items` lines in all. A peer is never
166
+ shown the same entry twice in one hub run.
167
+ - **Session-start recall**: this project's long-term decisions, contracts and fails (and shared ones), newest first,
168
+ lead the recall block; claude-mem's recent work follows. Each gets half of `memory.inject_tokens` when both answer.
169
+ - **`ahub ask`**: entries that match the question and the graph neighbourhood of what they are about are evidence, cited
170
+ as `[mem:<8 hex>]`. A question that carries PII skips them. `ahub ask --remember` still saves only to claude-mem, so a
171
+ model's answer never becomes hub memory.
172
+ - **`ahub memory`** (no hub needed; reading is anyone's):
173
+
174
+ ```bash
175
+ ahub memory # this project's entries, newest first, with tier counts
176
+ ahub memory list --tier long --kind fail --peer codex --since 2026-10-01 --json
177
+ ahub memory search parser quoting # every word must match the title, text or nodes
178
+ ahub memory show 1a2b3c4d # one entry with provenance and edges (this project's or a shared one)
179
+ ahub memory graph 1a2b3c4d --hops 2 # its neighbourhood as edges, a person's (labels are unscreened); also a node: path:src/csv.ts
180
+ ```
181
+
182
+ - **The dashboard** has a Memory section: short- and long-term tabs, search, filters by kind, peer, machine and time,
183
+ the list of entries, and for a selected entry or node its neighbourhood (one or two hops, at most 200 nodes) as an
184
+ inline SVG drawn in the page with the same edges as a text list, and its detail with provenance. It is read-only and
185
+ stays inside the page's content security policy: no requests other than the dashboard's own snapshot.
186
+
187
+ ## Changing it
188
+
189
+ `list`, `search` and `show` may run in agent shells, so they leave out notes that match the project's current PII
190
+ patterns or are about a path its `pii.paths` makes private (a shared note was accepted under another project's patterns) and say how many; the dashboard shows a person
191
+ everything. A person's, from a terminal (agent shells are refused):
192
+
193
+ ```bash
194
+ ahub memory promote 1a2b3c4d # a short-term entry gets a long-term copy
195
+ ahub memory demote 1a2b3c4d # a long-term entry becomes short-term and expires
196
+ ahub memory forget 1a2b3c4d # gone from the index here, and on other machines once synced
197
+ ahub memory supersede <old> <new> # the old one is dropped from briefs and recall
198
+ ahub memory rebuild
199
+ ```
200
+
201
+ A forgotten long-term entry stays in the log file and in the sync remote's git history; removing it from there is a
202
+ person's rewrite of that history.
203
+
204
+ ## Importing from claude-mem
205
+
206
+ `ahub memory import claude-mem [--db <path>] [--limit N]` (a person's) copies the hub's own notes from claude-mem
207
+ (observations whose metadata names a `peer`: `hub_remember` and the hub's task notes) into long-term hub memory as
208
+ `source: claude-mem`, for this project only (claude-mem files them under the repository's own name; a superproject's
209
+ notes stay out, and two unrelated repositories with one name share it). Model answers from `ahub ask --remember`, text
210
+ matching a PII pattern, text about a path the project's `pii.paths` makes private and secret-looking text are skipped. An
211
+ imported note is placed in the graph by the paths and symbols in its text (claude-mem keeps no task proposal time).
212
+ claude-mem's database is opened read-only and never changed; an observation always maps to the same entry, on any
213
+ machine, so importing again adds nothing.
214
+
215
+ ## Measuring it
216
+
217
+ Whether hub memory helps is measured, not assumed (#258 AC11, with #248):
218
+
219
+ - Each task brief writes a `memory_brief` event with counts only (hub-memory items, fails among them, claude-mem
220
+ items); research records keep `briefs` (`delivered`, `withFail`), and `ahub research` splits approved tasks into
221
+ "a fail note in its brief", "brief without a fail note" and "no brief recorded" (first pass, rework, check failures).
222
+ - `ahub bench run --memory off|claude-mem|native|both` declares an arm's memory and refuses a hub that runs with other
223
+ settings; compare the arms with `ahub bench compare`.
224
+ - Whether an agent retried an approach a fail note had ruled out cannot be read from ids and counts. A task whose brief
225
+ carried a fail note and was still sent back or failed a check is a candidate, to read by hand.
226
+
227
+ ## Privacy
228
+
229
+ - Nothing about a PII task enters the store: the tool refuses it and the hub's own notes skip it. Text that matches a
230
+ PII pattern, that the PII screen does not clear, or that looks like a secret is refused or skipped with a notice.
231
+ - Hub log lines about memory carry ids and counts only.