@staix/agent-hub 0.12.29 → 0.12.30
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 +18 -0
- package/README.md +79 -219
- package/docs/agent-notes/README.md +12 -0
- package/docs/agent-notes/adapters.md +1 -1
- package/docs/agent-notes/bus.md +3 -1
- package/docs/agent-notes/daemon.md +10 -0
- package/docs/agent-notes/local-worker.md +2 -2
- package/docs/agent-notes/tasks.md +9 -0
- package/docs/agent-notes/tests.md +1 -1
- package/docs/memory.md +70 -152
- package/docs/operations.md +199 -14
- package/docs/plans/2026-10-16-amem-failure-registry.md +101 -0
- package/docs/plans/2026-10-16-amem-p0-baseline.md +110 -0
- package/docs/plans/2026-10-16-amem-p2-read-tools.md +28 -0
- package/docs/plans/amem-cases.json +482 -0
- package/docs/quickstart.md +9 -2
- package/docs/security.md +13 -1
- package/docs/smoke.md +11 -0
- package/docs/specs/2026-09-19-agent-hub-design.md +105 -4
- package/docs/verification/2026-10-17-0.12.30.md +70 -0
- package/docs/verified.json +13 -13
- package/package.json +5 -2
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +64 -44
- package/src/cli/console-state.ts +92 -20
- package/src/cli/console.ts +22 -5
- package/src/cli/help.ts +3 -2
- package/src/cli/identity.ts +1 -1
- package/src/cli/main.js +2 -2
- package/src/cli/main.ts +36 -14
- package/src/cli/memory.ts +87 -187
- package/src/cli/output.ts +6 -0
- package/src/cli/recovery-package.ts +59 -10
- package/src/cli/upgrade-runtime.ts +54 -17
- package/src/cli/upgrade.ts +8 -0
- package/src/hub/board.ts +2 -1
- package/src/hub/bus.ts +33 -12
- package/src/hub/daemon.ts +134 -27
- package/src/hub/envelope.ts +30 -0
- package/src/hub/git.ts +2 -38
- package/src/hub/hub-tools.ts +5 -1
- package/src/hub/manager.ts +1 -1
- package/src/hub/memory-candidates.ts +103 -0
- package/src/hub/memory-fail.ts +25 -0
- package/src/hub/memory-observations.ts +47 -0
- package/src/hub/memory-plan-guard.ts +33 -0
- package/src/hub/memory-policy.ts +42 -0
- package/src/hub/memory-profile-check.ts +170 -0
- package/src/hub/memory-profile.ts +192 -0
- package/src/hub/memory-staleness.ts +55 -0
- package/src/hub/path-policy.ts +8 -0
- package/src/hub/project.ts +4 -37
- package/src/hub/read-tools.ts +127 -0
- package/src/hub/tasks.ts +201 -41
- package/src/local/deny.ts +4 -17
- package/src/memory/brief.ts +8 -5
- package/src/memory/capture.ts +2 -1
- package/src/memory/recall.ts +50 -110
- package/src/pi/process-signature.ts +2 -42
- package/src/memory/import.ts +0 -90
- package/src/memory/store.ts +0 -805
- package/src/memory/sync.ts +0 -145
package/docs/memory.md
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
|
-
# Hub memory
|
|
1
|
+
# Hub memory integration
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Agent-hub consumes the exact-pinned first-party [`@staix/agent-mem`](https://github.com/STAIxBWLB/agent-mem) library (current pin `0.3.0`, initial pin `0.1.1`). The package owns portable storage, tiers, graph, goals, sync, import and raw commands. Agent-hub owns caller authority, current project privacy policy, task lifecycle integration and presentation. Optional claude-mem remains a separate capture and session-recall source.
|
|
4
|
+
|
|
5
|
+
## Portable core and data directory
|
|
6
|
+
|
|
7
|
+
The [agent-mem repository](https://github.com/STAIxBWLB/agent-mem) is the reference for the data model, immutable entry IDs, append-only segments, derived SQLite index and rebuild equality, home selection, import cursors, dedupe and machine sync. Shared v1 remains the default and needs no migration: schema `agent-hub.memory/v1`, canonical hashes and log/machine/lock paths remain compatible. `memoryHome()` comes from the package and selects `AMEM_HOME`, then `$AGENTHUB_HOME/memory`, then `~/.agenthub/memory`; an explicit `StoreOptions.home` keeps its parent-directory meaning. The test preload (`test/hub-home.ts`) clears inherited `AMEM_HOME` and supplies an isolated `AGENTHUB_HOME` when none is provided.
|
|
8
|
+
|
|
9
|
+
`src/memory/` contains hub integration only: briefs, recall, the claude-mem worker client and capture. `src/hub/memory-policy.ts` supplies `withoutPii`, `promotionScreen` and `mentionsPrivatePath`; `src/hub/read-tools.ts` supplies screened peer reads. Deny, hardened git, realPath and process identity come from the package's Node-safe `@staix/agent-mem/platform` entry and are re-exported through the existing local/hub/Pi modules. No core implementation is vendored in agent-hub. The `0.1.1` platform subpath is required because `0.1.0` exposes only a root entry that loads `bun:sqlite`, which Node-hosted Pi extensions cannot import. This is a packaging compatibility export; the platform algorithms are unchanged.
|
|
10
|
+
|
|
11
|
+
## Selected memory profile
|
|
12
|
+
|
|
13
|
+
The memory root `M` is independent of the project state directory. The package's `M/profile.json` selects shared v1 or an explicit generation `G`; an absent selector means shared v1. The hub opens the selected profile with its current privacy screen and configured TTL. A generation uses `M/generations/G`, reads legacy prefixes through the package's readonly bridge, and writes its own rows and sync history there. The bridge does not migrate legacy bytes or use the legacy index. Exact-entry prune remains the package's person-only operation; it adds no shared-v1 operation and gives hub tools no prune authority.
|
|
14
|
+
|
|
15
|
+
All hub consumers share that binding: Tasks notes and lifecycle operations, leases, suggestions, briefs, recall, peer read tools, dashboard, ask and automatic sync. Standalone `amem` and `ahub memory`/`ahub goal` must resolve the same root and profile to see one another's writes. An invalid selector or missing/corrupt generation disables native memory without taking down the bus or task board; it never silently opens shared v1. The daemon reports its package/profile binding and availability separately from ordinary hub health.
|
|
16
|
+
|
|
17
|
+
Person-facing status and memory output show the profile and nonzero malformed-row count. Allowed agent-shell reads retain current row screening and receive only a short profile label; full generation IDs, the memory home and home-wide skipped totals are available through authenticated person status and person CLI receipts, never the shell-readable status.json file or agent CLI output. Domain JSON shapes are unchanged; the additive `memoryProfile` receipt belongs to status, profile-check and the person-only decay object. Profile-check reports the registry scope it inspected; inventory separate custom registries too before treating zero live claims as quiescence.
|
|
18
|
+
|
|
19
|
+
A running daemon keeps its original binding. Explicit checks at hub operation entry and before sidecar writes fence later operations when the selector changes or becomes unavailable; they do not switch stores in place. These checks are not atomic with an in-flight core operation: changing selection during such an operation is outside the supported cutover contract. Before migration or a selector change, quiesce every consumer of this memory home and close its handles; reopen through the supported session-preserving lifecycle afterward. A public core pre-write hook is the upgrade path for atomic in-flight cutover. Current policy screening, PII-turn refusal, capture exclusion and fail-open task delivery remain in force.
|
|
20
|
+
|
|
21
|
+
Candidate/counter data stays at `M/candidates.db`, independently of the selected note profile, using the package's explicit sidecar home convention. It is not copied into `G`, migrated or synced. The hub fences sidecar producers with the note-profile binding. Standalone `amem review` still refuses a selected generation; this integration does not add generation candidate acceptance or dashboard acceptance.
|
|
22
|
+
|
|
23
|
+
Source and synthetic fixture checks do not authorize migration of the person's memory home. Before real migration, every hub sharing the memory home must run 0.12.30. Real rollout still needs separately approved installation, matching live package/root/profile/selector bindings, synthetic cross-write and prune readbacks, and a supported quiesce/close/reopen sequence before separately confirmed real migration. 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. Real account/device sync, native capture and live memory receipts remain distinct acceptance legs. See [agent-mem migration and prune](https://github.com/STAIxBWLB/agent-mem#generation-migration-and-exact-entry-prune) for the person CLI and recovery limits.
|
|
24
|
+
|
|
25
|
+
For a standalone CLI refusal, inspect the selector and generation state and run `ahub memory profile-check`. If deliberately abandoning the selected generation, use the person-only `amem migrate --deactivate` recovery path; a CLI error does not itself require restarting a hub.
|
|
6
26
|
|
|
7
27
|
## Turning it on and off
|
|
8
28
|
|
|
@@ -12,28 +32,9 @@ short-term entries live after their task is approved, and `memory.sync_interval_
|
|
|
12
32
|
hub syncs once a remote is set. Writing and
|
|
13
33
|
reading are fail-open: a store that cannot be written costs one notice, and never a tool call or a turn.
|
|
14
34
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
-
|
|
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).
|
|
35
|
+
## Task lifecycle and host policy
|
|
36
|
+
|
|
37
|
+
Notes on open tasks stay short-term. Approval settles the task and can promote decision, contract and fail notes; findings stay short-term. The hub injects its current project screen through `StoreOptions.screen`: another project's notes are left to that project's processes, and secret-looking text, current PII patterns and private paths keep a note local rather than promoting it. A task's current paths are screened as well as its stored nodes. Task-specific deadlines retain the existing configured TTL and package lifecycle semantics.
|
|
37
38
|
|
|
38
39
|
## What gets written
|
|
39
40
|
|
|
@@ -44,57 +45,15 @@ repositories with the same name never share entries (that name is this machine's
|
|
|
44
45
|
same PII and secret rules. Nothing about a PII task is written.
|
|
45
46
|
- 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
|
|
|
47
|
-
##
|
|
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.
|
|
48
|
+
## Graph integration and suggestions
|
|
78
49
|
|
|
79
|
-
|
|
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.
|
|
50
|
+
The hub supplies task refs, plan paths/symbols and note context when extracting deterministic nodes. Briefs and ask use the package graph; the portable node and edge model is documented in agent-mem.
|
|
84
51
|
|
|
85
|
-
|
|
52
|
+
Model-suggested edges are off by default (`"memory": { "suggest_edges": true }`). After a note is saved, the hub's model (the digest-condensation route) may name `contradicts` or `same_topic` between it and up to six near entries. Answers are checked against that closed list and stored as `hub-model` suggestions. They are dashed on the dashboard and excluded from briefs, recall and `ahub ask` until a person confirms one (`ahub memory confirm <id>`); a rejected suggestion disappears.
|
|
86
53
|
|
|
87
|
-
|
|
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:
|
|
54
|
+
## Long-term task integration
|
|
91
55
|
|
|
92
|
-
|
|
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) |
|
|
56
|
+
Goal storage and leases are supplied by agent-mem. The hub integrates them with board tasks:
|
|
98
57
|
|
|
99
58
|
- **Titles** and milestones are kept to one line (whatever another machine wrote), and recall lines are sanitized, so
|
|
100
59
|
they cannot carry a forged message header into an agent's context.
|
|
@@ -124,39 +83,11 @@ ahub goal state 1a2b3c4d blocked
|
|
|
124
83
|
ahub goal done 1a2b3c4d
|
|
125
84
|
```
|
|
126
85
|
|
|
127
|
-
##
|
|
86
|
+
## Automatic sync integration
|
|
128
87
|
|
|
129
|
-
|
|
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.
|
|
88
|
+
A person configures the private remote with `ahub memory sync --remote <private-git-url>` and can sync immediately with `ahub memory sync`. Machine labels use `ahub memory machine --label <name>`.
|
|
132
89
|
|
|
133
|
-
|
|
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.
|
|
90
|
+
A running hub syncs 5 seconds after start and every `memory.sync_interval_min` minutes (default 10; 0 disables it) once a remote is set. Failure produces one log line and never blocks a turn; without a remote it does nothing and creates nothing. The package retains one sync per machine, public-GitHub-remote refusal and unknown-visibility warnings. Credential-helper use is restricted to the memory repository the hub creates, never a project's git repository, and never prompts. Transport, segment merge, lock and retained-history semantics belong to agent-mem.
|
|
160
91
|
|
|
161
92
|
## Reading it
|
|
162
93
|
|
|
@@ -164,12 +95,11 @@ not match their content are skipped with one log line.
|
|
|
164
95
|
the task's paths, symbols, issue and task: a linked fail first, then nearer, then newer; superseded entries dropped;
|
|
165
96
|
other projects' entries only when shared), then claude-mem's, `memory.brief_items` lines in all. A peer is never
|
|
166
97
|
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),
|
|
168
|
-
lead the recall block; claude-mem's recent work follows. Each gets half of `memory.inject_tokens` when both answer.
|
|
98
|
+
- **Session-start recall**: this project's long-term decisions, contracts and fails (and shared ones) lead the recall block; display-only filtering omits automatic approval notes, while changes-requested notes show their nonempty reasons. Lines preserve their headers and end at word boundaries with a visible marker when capped; each delivery deduplicates memory ids across prefaces and note lines. Stored notes and brief evidence are unchanged. Claude-mem's recent work follows; each gets half of `memory.inject_tokens` when both answer.
|
|
169
99
|
- **`ahub ask`**: entries that match the question and the graph neighbourhood of what they are about are evidence, cited
|
|
170
100
|
as `[mem:<8 hex>]`. A question that carries PII skips them. `ahub ask --remember` still saves only to claude-mem, so a
|
|
171
101
|
model's answer never becomes hub memory.
|
|
172
|
-
- **`ahub memory`**
|
|
102
|
+
- **`ahub memory`** needs no running hub. The hub CLI identity gate allows screened list/search/show reads in agent shells; graph and unscreened views are a person's. Managed peers use the bounded `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` tools through the daemon, with project scope, `memory_read`, PII-turn refusal and capture exclusion:
|
|
173
103
|
|
|
174
104
|
```bash
|
|
175
105
|
ahub memory # this project's entries, newest first, with tier counts
|
|
@@ -200,54 +130,15 @@ ahub memory dedupe # inspect legacy claude-mem duplicate gro
|
|
|
200
130
|
ahub memory dedupe --apply # append supersede relations, never rewrite log bytes
|
|
201
131
|
```
|
|
202
132
|
|
|
203
|
-
A forgotten
|
|
204
|
-
person's rewrite of that history. Forgetting a claude-mem import forgets every known non-forgotten member of its tuple group (source, project, source timestamp and text), including hidden duplicates, so they cannot reappear when their replacement is forgotten.
|
|
133
|
+
For storage-level forget, supersede, expiry and dedupe semantics, see [agent-mem](https://github.com/STAIxBWLB/agent-mem). A forgotten shared entry remains in log and remote git history; removing that history is a person's operation. The hub keeps current project privacy checks around every raw command callback. The standalone `amem --policy-free` choice is not available through `ahub memory` and never grants a peer extra authority.
|
|
205
134
|
|
|
206
135
|
## Importing from claude-mem
|
|
207
136
|
|
|
208
|
-
`ahub memory import claude-mem [--db <path>] [--limit N] [--restart]`
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
and secret-looking text are skipped. The source database is opened read-only and never changed.
|
|
214
|
-
|
|
215
|
-
- Import graph nodes are derived from text only: no checkout existence check and no machine-local `local.deny`.
|
|
216
|
-
Built-in denylisted names, relative-path normalization, absolute/parent exclusion, sorting and the 64-node cap still apply.
|
|
217
|
-
The source's timestamp and the existing content hash stay unchanged. Matching observations on different checkouts now
|
|
218
|
-
produce the same id; old ids, references and content validation remain valid. The local tuple fallback keeps re-import
|
|
219
|
-
idempotent even for legacy ids (its known ceiling is that the tuple excludes title).
|
|
220
|
-
- A machine-local `memory/import-state.json` records the last fully handled row, including all skips. The cursor key
|
|
221
|
-
combines the source DB's real path, claude-mem project name and hub project key. The file uses mode 0600 and atomic
|
|
222
|
-
replacement; it never syncs. Unreadable or malformed state replays from zero, write failure logs a warning and preserves
|
|
223
|
-
the import result, and a source whose maximum candidate id for this project is below the cursor resets it (unrelated projects cannot mask a recreated source). Completed progress is saved even if a later
|
|
224
|
-
row throws. `--restart` starts from zero; use it after changing a PII policy to revisit rows skipped under the old policy.
|
|
225
|
-
- The default limit is 10000. JSON reports `read` (project-matched, peer-tagged SQL rows this run), `added`,
|
|
226
|
-
`skipped.model`, `skipped.pii`, `skipped.secret`, `cursor` (last handled id), and `more` (`read === limit`). Malformed
|
|
227
|
-
metadata, non-string peers and empty text count only in `read`; already imported rows add nothing. `more` asks for
|
|
228
|
-
another run, which can return zero rows when the last batch exactly filled the limit. There is no project-skip counter.
|
|
229
|
-
- Repository identity still depends on the local real path without an origin remote, and non-GitHub remotes spelled
|
|
230
|
-
differently can yield different project keys. These affect all hub memory and remain outside this import fix.
|
|
231
|
-
|
|
232
|
-
### Legacy duplicate imports
|
|
233
|
-
|
|
234
|
-
`ahub memory dedupe [--apply] [--json]` is console-only, including the listing, because it shows unscreened note text.
|
|
235
|
-
It groups this project's non-forgotten claude-mem entries by `(source, project, at, text)`. Listing reports only actionable
|
|
236
|
-
groups, their members, heads and chosen target; `--apply` appends ordinary supersede operations in this machine's log.
|
|
237
|
-
Historical log bytes are never rewritten. Forget operates on the whole known tuple group.
|
|
238
|
-
|
|
239
|
-
- Heads have no current replacement. Existing replacement relations, including a person's distinct outside notes, stay
|
|
240
|
-
intact. If every head can reach a valid synced outside terminal (shared when any head is shared), the newest qualifying
|
|
241
|
-
terminal by `(at, id)` replaces all heads, even a single head. Otherwise multiple heads converge onto the smallest id
|
|
242
|
-
among the heads; zero heads or one head without a qualifying outside terminal require no writes. A refused supersede
|
|
243
|
-
is reported as an error. Re-running after convergence writes nothing.
|
|
244
|
-
- When `A -> B` already exists inside a group, dedupe connects another head `C -> B`, without trying the cyclic `B -> A`.
|
|
245
|
-
When `B -> X` and `C -> Y` name outside user replacements, `X` and `Y` both remain visible; a remaining head moves to
|
|
246
|
-
the newer qualifying terminal. A later outside replacement can make a previously settled group actionable again.
|
|
247
|
-
- Old or mixed extractor versions can still introduce duplicate ids. Run dedupe after syncing them. Two machines acting
|
|
248
|
-
on divergent prior relations can choose different targets; sync folds relations deterministically using the existing
|
|
249
|
-
latest-relation and cycle guards. If several group members remain visible, one more dedupe run converges them. New
|
|
250
|
-
same-version imports with stable project keys converge automatically in either sync order.
|
|
137
|
+
`ahub memory import claude-mem [--db <path>] [--limit N] [--restart]` is a person's command. It imports peer-tagged hub observations for the current project through the package's read-only SQLite importer. The hub supplies the current routing PII patterns and `pii.paths` screen; model answers and secret-looking text remain excluded. The source database is never changed.
|
|
138
|
+
|
|
139
|
+
The package owns deterministic import identity, text-only graph extraction, cursor bookkeeping, tuple fallback and result counts. `--restart` revisits rows skipped under an earlier policy. Claude-mem's basename namespace can still collide between unrelated repositories; a superproject's observations stay out. A repository without an origin still uses machine-local project identity. These ceilings are unchanged by the library switch.
|
|
140
|
+
|
|
141
|
+
`ahub memory dedupe [--apply] [--json]` remains console-only, including listing, because it shows unscreened note text. The package's reconciliation appends ordinary supersede operations; historical log bytes are never rewritten.
|
|
251
142
|
|
|
252
143
|
## Measuring it
|
|
253
144
|
|
|
@@ -266,3 +157,30 @@ Whether hub memory helps is measured, not assumed (#258 AC11, with #248):
|
|
|
266
157
|
- Nothing about a PII task enters the store: the tool refuses it and the hub's own notes skip it. Text that matches a
|
|
267
158
|
PII pattern, that the PII screen does not clear, or that looks like a secret is refused or skipped with a notice.
|
|
268
159
|
- Hub log lines about memory carry ids and counts only.
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
## Stage A plan guard and fail notes (#412 P7-1)
|
|
163
|
+
|
|
164
|
+
A plan's explicit paths/symbols and refs paths are matched against live, screened fail `about` nodes (the source of v1 `rules_out` graph edges). Matching fails lead the owner's brief and the review delivery's checklist; accepting a plan or claiming work returns the same current advice. Existing related-memory fails-first ordering is retained. Unrelated fails do not gain plan priority. The guard informs, never blocks or changes the task, and PII tasks never invoke it.
|
|
165
|
+
|
|
166
|
+
`hub_remember` accepts optional string fields `approach`, `symptom`, `cause`, `evidence`, and `retry_when` only with `kind: "fail"`. Provided fields appear in that order with labels `Approach`, `Symptom`, `Cause`, `Evidence`, and `Retry when`, after optional plain text. A structured-only fail is valid; plain text remains valid. The completed text is validated before policy, storage or display: at most 4000 UTF-8 bytes, with actual/limit byte counts on refusal and no truncation. Every composed field passes the existing secret/PII/private-path checks.
|
|
167
|
+
|
|
168
|
+
## Decay review
|
|
169
|
+
|
|
170
|
+
`ahub memory decay [--days N] [--json]` is person-only, including in delegated live-test sessions. Default age is 90 days. It lists this project's long-term, live, non-superseded notes strictly older than the cutoff, excluding links to open/active/blocked goals through the note's task or `about` nodes. Reads use current privacy screening and defer automatic promotions; authoritative JSONL bytes do not change. Index maintenance remains derived-only. A person acts separately through existing `demote` or `forget`. These are review rows, with no candidate-sidecar write.
|
|
171
|
+
|
|
172
|
+
## Read-time staleness hint
|
|
173
|
+
|
|
174
|
+
Recall lines, native brief items, `hub_memory_show` lines and human `ahub memory show` output mark `(stale?)` when an allowed `path:` or symbol-file path is missing. CLI `--json` keeps the v1 row unchanged. The marker is never stored or used as evidence of correctness.
|
|
175
|
+
|
|
176
|
+
Each rendered batch has a shared cache and a hard bound of 32 metadata probes. On a tree not modified during the call, no hint probe reaches a `pii.paths`/`local.deny` path: declared private paths and the common deny policy are checked lexically first, including folded spellings and globs. Absolute/escaping paths, symlinks observed by a probe, denied paths, unreadable metadata and exhausted budgets are unknown and produce no marker. A concurrent ancestor swap by a process running as you can expose one existence bit; it is outside the [security threat model](security.md), and the deterministic ceiling witness is retained in the tests. Descriptor-anchored traversal is needed before supporting that scenario. Symbol nodes are checked only through their allowed file; this hint does not parse source symbols or read file contents. Current privacy screening still precedes rendering and peer-output byte caps. No new memory operation or candidate writer is introduced.
|
|
177
|
+
|
|
178
|
+
## Review candidates and local usage counters
|
|
179
|
+
|
|
180
|
+
Agents propose a correction with `hub_memory_correct {id, text, reason}`. The target is an exact id or unique visible prefix, screened under this project's current policy. The tool requires `memory_correct`, refuses private turns, and records a candidate with the full target id and revision. It does not edit a note or notify the other peers with the proposed text. Arguments and results are excluded from capture.
|
|
181
|
+
|
|
182
|
+
A `changes_requested` review with unmet items can create one fail candidate. Tasks screens the public task title, unmet items and review evidence before the sidecar write; private tasks, private turns, withheld text and failed or unknown screens produce no candidate. Cause and retry conditions are explicitly unknown unless a person supplies them when reviewing.
|
|
183
|
+
|
|
184
|
+
Candidates and rendered/delivered/cited counters live only in agent-mem's machine-local `M/candidates.db` (package retention: 500 candidates/project for 30 days, 10,000 counters/project for 90 days). They are never imported or synced and are not evidence for recall, briefs, ask or graph. For shared v1, a person reviews them with `amem review` and accepts or rejects through that CLI's TTY and policy checks; generation review remains unsupported and refused. Dashboard acceptance is a later step. Accepted results are ordinary v1 notes under the package's acceptance contract; the hub tool has no acceptance authority.
|
|
185
|
+
|
|
186
|
+
Rendered observations use the final journal payload, including memory lines in prefaces and briefs, with the real delivery id. Delivered observations require the journal's first positive transport acknowledgement (or the pull path's completed read receipt). Failed or uncertain handoffs do not establish delivery; journal-less transports leave it unknown. Citation observations resolve `mem:<id8+>` in a peer message or task completion summary against screened project-visible entries. Citations use explicit `message:<envelope-id>` or `summary:<task>:<history-index>` observation keys when the source delivery is not proven; their rendered/delivered values remain unknown. They do not establish a per-delivery causal ratio. Duplicate observations are idempotent per entry/context/observation, not cumulative usage claims. Unavailable task, turn or session identity and unobserved metrics remain unknown, never zero. No observation is written for a private envelope, PII task or PII turn. These are delivery and citation proxies, not proof that an agent understood or used a note correctly.
|
package/docs/operations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Operations guide
|
|
2
2
|
|
|
3
|
-
This guide describes ahub 0.12.
|
|
3
|
+
This guide describes ahub 0.12.30 and control protocol 16. Live verification
|
|
4
4
|
results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
|
|
5
5
|
|
|
6
6
|
## Agent-operated live verification
|
|
@@ -176,6 +176,48 @@ decisions and a never-ask permission mode require confirmation; delivery resolut
|
|
|
176
176
|
status state counts and never fetches the board. Leaving restores
|
|
177
177
|
the terminal and returning from panels replays the bounded stream buffer.
|
|
178
178
|
|
|
179
|
+
Tasks and Queue selections follow the selected id across refreshes. If that row
|
|
180
|
+
disappears, no replacement row inherits the action. Task actions also bind the
|
|
181
|
+
row's `flowRevision` (its history length); queue actions bind the delivery
|
|
182
|
+
revision. The id and revision in a row-started command cannot be edited. Peer,
|
|
183
|
+
reason and the final role/action remain editable, and the confirmation names the
|
|
184
|
+
validated result. An older hub without `flowRevision` refuses revision-bound task
|
|
185
|
+
row actions instead of silently running them unchecked.
|
|
186
|
+
|
|
187
|
+
In Tasks, `a` assigns the owner in ordinary open states and the reviewer in
|
|
188
|
+
`in_review`; a waiting task says when assignment is a reservation. `u` unassigns
|
|
189
|
+
the corresponding role, and `r` reviews only in `in_review`. In Queue, `r`
|
|
190
|
+
prefills `discard` for a queued row and `retry` for a needs_review row, with the
|
|
191
|
+
action still editable before confirmation. `completed` is never the default.
|
|
192
|
+
Every resolution needs a reason. Queue `discard` removes queued originals or
|
|
193
|
+
settles a needs_review receipt; it never cancels a task or native turn.
|
|
194
|
+
|
|
195
|
+
`ahub task unassign <id> [--role owner|reviewer] [--revision N]` is the terminal
|
|
196
|
+
equivalent. Owner removal is allowed in `proposed`, `in_progress` and
|
|
197
|
+
`changes_requested`, returns active work to `proposed`, and clears any owner
|
|
198
|
+
reservation. It is refused in `in_review`, `approved` and `backlog`. Reviewer
|
|
199
|
+
removal retains the state, including `in_review`, and refuses to remove the human
|
|
200
|
+
reviewer of PII work. No replacement is routed and no native process or external
|
|
201
|
+
effect is rolled back. A person-unassigned task stays out of automatic owner
|
|
202
|
+
offers across dependency release, planner-pull processing, release timers and
|
|
203
|
+
restarts until an explicit assignment or reservation. The later unassign also
|
|
204
|
+
fences planner undo, so undo and re-pull cannot restore the removed reservation.
|
|
205
|
+
Former queued assignment or review requests are withdrawn without resolving
|
|
206
|
+
uncertain deliveries, and the former agent loses current authority. A withdrawal
|
|
207
|
+
notice uses delivery evidence or that peer's own accept/self-claim after the
|
|
208
|
+
latest assignment; another owner's in-progress state or an earlier acceptance
|
|
209
|
+
does not count. Withdrawing an unread queue alone sends none. If a later person
|
|
210
|
+
assignment supersedes an escalation or offline relay, the stale success result
|
|
211
|
+
and decision note are suppressed, but the former owner is still told the current
|
|
212
|
+
owner and to stop working.
|
|
213
|
+
|
|
214
|
+
`ahub task assign <id> <peer> [--role owner|reviewer] [--revision N]` uses a
|
|
215
|
+
checked console operation when a revision is present. Without it, existing CLI
|
|
216
|
+
behavior is unchanged. `ahub queue resolve ... [--revision N]` uses the supplied
|
|
217
|
+
revision instead of a fresh show. Revision mismatches and superseded post-await
|
|
218
|
+
publications fail without a board or delivery side effect; a reviewer-only change
|
|
219
|
+
keeps a valid owner assignment but refreshes its reviewer content.
|
|
220
|
+
|
|
179
221
|
The Tasks panel summarizes the whole public board with an approved/all fraction,
|
|
180
222
|
a 20-cell ASCII bar and state counts. Proposed tasks with unapproved or missing
|
|
181
223
|
`after` dependencies count as waiting; PII stubs count normally. Each task has a
|
|
@@ -388,9 +430,136 @@ The Stop hook acknowledgement is not a counted completion. The daemon checks the
|
|
|
388
430
|
native transcript after the hook can return; missing or changed-session evidence
|
|
389
431
|
stays unknown.
|
|
390
432
|
|
|
433
|
+
## Pi with DGX and MLX
|
|
434
|
+
|
|
435
|
+
Pi is optional. Install Pi separately and set `pi.enabled` to `true` in
|
|
436
|
+
`.agenthub/config.json`. Set `pi.auto_start` to `true` to start it with the hub.
|
|
437
|
+
Pi starts in its TUI by default; `ahub pi --headless`, or the start mode
|
|
438
|
+
setting (`ahub settings set peers.pi.start_mode headless`), asks for the
|
|
439
|
+
background peer instead. The project uses its existing OmniRoute connection for DGX;
|
|
440
|
+
`pi.dgx_coding` and `pi.dgx_fast` select the gateway's configured model IDs.
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
ahub models setup # prepare bounded Qwen3.5 4B MLX in an existing Ollama service
|
|
444
|
+
ahub models start # verify loopback Ollama/model readiness (no daemon spawn)
|
|
445
|
+
ahub models status
|
|
446
|
+
ahub pi --headless --backend auto
|
|
447
|
+
ahub say @pi "Read the project and summarize the next small implementation task"
|
|
448
|
+
ahub pi # its TUI in this terminal; an idle headless session moves into it
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
The default routing template assigns implementation, bulk edits and tests to
|
|
452
|
+
DGX, and summaries/triage to MLX. Pi and the existing local worker take priority
|
|
453
|
+
before cloud peers; planning and final review stay with Claude/Codex. Existing
|
|
454
|
+
projects keep their routing file, so add `pi` to the relevant `peers` lists and
|
|
455
|
+
set `pi_backend = "dgx"` or `"mlx"` for each class. PII tasks remain local-worker
|
|
456
|
+
only. `--backend dgx` or `--backend mlx` explicitly pins a Pi session's backend.
|
|
457
|
+
|
|
458
|
+
Pi connects to an authenticated relay with model aliases `dgx/coding`,
|
|
459
|
+
`dgx/fast`, and `mlx/fast`; upstream gateway credentials stay in the hub.
|
|
460
|
+
Its managed tools use the existing path guards, shell sandbox and terminal
|
|
461
|
+
approval flow. Keep `ahub console` open to approve write/edit/shell operations:
|
|
462
|
+
a request nobody answers expires, and two in a row end Pi's turn.
|
|
463
|
+
Tool-call receipts survive daemon restart; an interrupted operation with an
|
|
464
|
+
unknown outcome must be reconciled before repeating it. Cancelling a Pi turn
|
|
465
|
+
does not automatically hand its task to a cloud peer.
|
|
466
|
+
|
|
467
|
+
The `mlx/fast` alias now defaults to an externally managed Ollama MLX backend.
|
|
468
|
+
Install and start Ollama separately, with `OLLAMA_NO_CLOUD=1`,
|
|
469
|
+
`OLLAMA_NUM_PARALLEL=1`, `OLLAMA_MAX_LOADED_MODELS=1`, and a finite
|
|
470
|
+
`OLLAMA_KEEP_ALIVE` (five minutes is the tested setting). `models setup`
|
|
471
|
+
prepares `agenthub-fast-mlx:4b-8k` from `qwen3.5:4b-mlx`, with an 8K total
|
|
472
|
+
context and a 2K output cap. The relay budgets input separately at 6,000
|
|
473
|
+
estimated tokens and serializes local requests across project hubs.
|
|
474
|
+
|
|
475
|
+
`models status` distinguishes model availability from memory residency.
|
|
476
|
+
`models stop` refuses to unload an externally managed Ollama model: other
|
|
477
|
+
clients may be using it. Ollama owns idle eviction; stopping a hub never
|
|
478
|
+
kills Ollama. The OpenAI compatibility endpoint does not enforce a request
|
|
479
|
+
`keep_alive` field, so configure the server and verify its expiry readback.
|
|
480
|
+
The relay can fall back to DGX before streaming starts as before. See the
|
|
481
|
+
[Ollama migration procedure](#ollama-mlx-migration-issue-51)
|
|
482
|
+
for existing Python runtime/configuration cleanup and rollback.
|
|
483
|
+
|
|
484
|
+
A project has one managed Pi session owner. Mode changes require the agent to
|
|
485
|
+
settle and preserve the session file. Before the first generation, a live source
|
|
486
|
+
verified to be empty can instead retain its exact session ID without a file.
|
|
487
|
+
Missing history from a nonempty session blocks handover. Protocol 9 adds Pi
|
|
488
|
+
recovery metadata. Protocol 10, released in 0.7.0, adds durable delivery
|
|
489
|
+
receipts and conservative queue recovery; it is verified live (see the
|
|
490
|
+
[smoke checklist](smoke.md)).
|
|
491
|
+
Older protocol hubs still require their matching CLI and an attended bootstrap.
|
|
492
|
+
|
|
493
|
+
## Local dashboard
|
|
494
|
+
|
|
495
|
+
With a running daemon, `ahub ui` opens a local dashboard for messages, peer states
|
|
496
|
+
and queues, the task board, budget windows, pending approvals and this machine's
|
|
497
|
+
benchmark runs. Use `ahub ui --no-open` to print a single-use link when the
|
|
498
|
+
browser cannot be opened.
|
|
499
|
+
Open the link within 60 seconds; the browser session lasts one hour.
|
|
500
|
+
|
|
501
|
+
The dashboard can send console messages, propose and assign tasks, pause or resume
|
|
502
|
+
peers, answer approvals, start a peer in its start mode and show the settings.
|
|
503
|
+
An ordinary session changes the safe switches and lowers a mode to `ask`; the
|
|
504
|
+
rest needs `ahub ui --settings` or `ahub settings` in a terminal. See
|
|
505
|
+
[Settings](#settings-from-the-dashboard-and-the-terminal) and
|
|
506
|
+
[Start modes](#start-modes-tui-by-default-headless-as-opt-in).
|
|
507
|
+
Budget pauses still require the terminal override.
|
|
508
|
+
Private envelopes and PII tasks stay redacted. Local-worker and Pi tool details and
|
|
509
|
+
allow decisions stay in `ahub tail` / `ahub permit`; the page can deny them.
|
|
510
|
+
No dashboard port is opened until requested. See [the session security model](security.md#local-dashboard-sessions-issue-6).
|
|
511
|
+
|
|
512
|
+
## Multiple projects and worktrees
|
|
513
|
+
|
|
514
|
+
Version 0.4.0 adds one independent hub per repository or Git worktree.
|
|
515
|
+
Subdirectory commands resolve to that project; symlink aliases resolve to the same
|
|
516
|
+
hub. Explicit selection works from any directory:
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
ahub --project /path/to/project-a init
|
|
520
|
+
ahub --project /path/to/project-b init
|
|
521
|
+
ahub --project /path/to/project-a up
|
|
522
|
+
ahub --project /path/to/project-b up
|
|
523
|
+
ahub projects
|
|
524
|
+
ahub status --all
|
|
525
|
+
ahub --project /path/to/project-a codex
|
|
526
|
+
ahub ui --all
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The unified dashboard lists registered roots and opens their boards, streams,
|
|
530
|
+
messages, approvals and budgets. It can start hubs and stop a selected hub after
|
|
531
|
+
confirmation. Its Start control opens a peer's TUI only through a terminal provider
|
|
532
|
+
(`terminal.open` or Orca); without one, launch Claude/Codex TUIs from a terminal. The manager stays available
|
|
533
|
+
when a project stops; `ahub ui --all --stop` stops only the manager. Existing
|
|
534
|
+
`ahub ui` still opens the current project's dashboard.
|
|
535
|
+
|
|
536
|
+
`ahub projects --json` returns machine-readable live status. Use a listed ID or a
|
|
537
|
+
path with `--project`; the selector must precede the command. `ahub projects remove
|
|
538
|
+
<id>` forgets a stopped registration without deleting project data. A moved root
|
|
539
|
+
gets a new registration. Missing roots remain visible until removed.
|
|
540
|
+
|
|
541
|
+
Runtime state stays in each project's `.agenthub/state/`. The machine registry is
|
|
542
|
+
`~/.agenthub/registry.db`; existing `ports.json` allocations are imported once.
|
|
543
|
+
`AGENTHUB_HOME` selects an isolated machine registry (also used by tests). An
|
|
544
|
+
inherited state directory from a different project cannot redirect a new CLI
|
|
545
|
+
invocation. Explicit custom state requires a matching project marker or the
|
|
546
|
+
initialization pair `AGENTHUB_PROJECT_DIR` / `AGENTHUB_STATE_DIR`.
|
|
547
|
+
|
|
548
|
+
Manager-started hubs use attended mode and project configuration, including
|
|
549
|
+
credential-file references. They do not inherit the launching project's gateway
|
|
550
|
+
URL/key overrides. Native memory remains shared according to claude-mem aliases;
|
|
551
|
+
worktrees recall their parent and composite identity. A shared-alias notice does
|
|
552
|
+
not mean that task boards or agent sessions are shared. Provider quota readings
|
|
553
|
+
may describe the same account and should not be added across projects.
|
|
554
|
+
|
|
555
|
+
Before upgrading an older hub, inspect the plan with the matching CLI.
|
|
556
|
+
Incompatible or unverified processes are shown explicitly and are never killed by
|
|
557
|
+
PID-name matching. See the operations guide and the
|
|
558
|
+
[multi-project specification](specs/2026-09-19-multi-project-design.md).
|
|
559
|
+
|
|
391
560
|
## Install and start
|
|
392
561
|
|
|
393
|
-
Use Bun 1.
|
|
562
|
+
Use Bun 1.4.2 or newer. Install the released package and install its Claude
|
|
394
563
|
channel plugin:
|
|
395
564
|
|
|
396
565
|
```bash
|
|
@@ -472,8 +641,9 @@ does not list), needs its directory in `local.read_allow`, for example
|
|
|
472
641
|
hub's tools: list a peer and it keeps only the capabilities named, from
|
|
473
642
|
`propose` (`hub_task_propose`), `assign` (proposing with another peer as owner),
|
|
474
643
|
`remember` (the `hub_remember` tool; the notes the hub itself keeps of done
|
|
475
|
-
summaries and review verdicts are not gated)
|
|
476
|
-
|
|
644
|
+
summaries and review verdicts are not gated), `memory_correct` (propose a local correction candidate for person review), `memory_read`
|
|
645
|
+
(`hub_memory_search`, `hub_memory_show`, `hub_memory_graph`) and `important`
|
|
646
|
+
(`[IMPORTANT]` messages). For example `"capabilities": { "local": ["propose", "remember"] }`.
|
|
477
647
|
A peer that is not listed keeps all of them, a listed peer whose value is not a
|
|
478
648
|
list gets none, and an unknown capability name grants nothing; `hub.log` says
|
|
479
649
|
so for each, and logs every refusal (`capabilities:`). A refused tool call says
|
|
@@ -523,8 +693,7 @@ resolves an uncertain delivery automatically. The same rule holds on every path
|
|
|
523
693
|
assigns a task (#297): once the move is saved on the board, a failed delivery prints
|
|
524
694
|
exactly one console notice ("the move is saved... delivery is not confirmed"), printed
|
|
525
695
|
where the error is thrown, and the caller (a peer in its turn, or the CLI) still gets
|
|
526
|
-
its error. Two exceptions, by construction: a move superseded while the assignment was being prepared, meaning a later history entry that moves or settles the task (another assignment, an unassign, the owner's accept, done, approval, close; the hub's quiet bookkeeping such as a late check result or a reviewer change does not supersede), is
|
|
527
|
-
the caller's error as before, with no notice naming either owner; and a claim is its own hand-over, so its
|
|
696
|
+
its error. Two exceptions, by construction: a move superseded while the assignment was being prepared, meaning a later history entry that moves or settles the task (another assignment, an unassign, the owner's accept, done, approval, close; the hub's quiet bookkeeping such as a late check result or a reviewer change does not supersede), returns the current task without a failed tool call and with no notice naming either owner; and a claim is its own hand-over, so its
|
|
528
697
|
accepted write and line stay outside the delivery rule (its overlap and routing announcements to earlier
|
|
529
698
|
owners are deliveries and share it). The repair is always
|
|
530
699
|
to look for a queued or needs_review delivery with
|
|
@@ -735,7 +904,7 @@ ahub task label 12 reverted # a later verdict (ok, regressed, reverted, i
|
|
|
735
904
|
|
|
736
905
|
## Hub memory
|
|
737
906
|
|
|
738
|
-
The hub
|
|
907
|
+
The hub opens the selected memory profile under `memoryHome()` (default `~/.agenthub/memory/`) beside claude-mem ([how it works](memory.md)): notes saved
|
|
739
908
|
against an open task are short-term; when the task is approved its decisions, contracts and fails become long-term.
|
|
740
909
|
Task briefs, session-start recall and `ahub ask` read it first, and the dashboard has a Memory section.
|
|
741
910
|
|
|
@@ -748,6 +917,20 @@ ahub memory forget 1a2b3c4d # a person's; also promote, demote, sup
|
|
|
748
917
|
|
|
749
918
|
`"memory": { "native": false }` in `.agenthub/config.json` turns it off for a project.
|
|
750
919
|
|
|
920
|
+
The exact-pinned `@staix/agent-mem` 0.3.0 resolves `AMEM_HOME`, then `$AGENTHUB_HOME/memory`, then `~/.agenthub/memory`. An absent `M/profile.json` selects shared v1; an explicit generation selects `M/generations/G` with the package's readonly legacy bridge. All daemon memory consumers and the hub memory/goal CLI use that selected profile. Invalid metadata or a missing selected generation makes native memory unavailable while the bus and board continue; there is no fallback to legacy writes. Inspect the daemon's memory binding/availability before interpreting missing memory as an empty store.
|
|
921
|
+
|
|
922
|
+
The daemon checks its selector at hub operation entry and before candidate/counter writes. It does not hot-switch handles or provide an atomic fence against selection changes during an in-flight core call. Quiesce consumers and close their handles before migration or selection changes; reopen through the supported session-preserving lifecycle afterward. Candidate/counter storage remains `M/candidates.db`, independent of `G`; `amem review` on a generation is still refused. Every running hub using this home needs an authenticated receipt: a matching ready binding, or a generation-capable unbound receipt (`disabled` when native memory is off, `unavailable` when opening failed) proving it holds no memory handle. An unbound daemon and zero running hubs are quiesced for memory; a stale bound handle, unreadable registry or unknown runtime is not ready. Existing JSON memory/goal results remain unchanged; the additive binding receipt belongs to daemon status, profile-check and the decay object. This source integration does not authorize installing a new runtime, migrating real memory, restarting sessions or claiming real-machine sync/capture receipts. Migration/deactivation and their limits belong to [agent-mem](https://github.com/STAIxBWLB/agent-mem); see [the hub profile contract](memory.md#selected-memory-profile).
|
|
923
|
+
|
|
924
|
+
Run `ahub memory profile-check [--json]` from the person's terminal for the read-only preflight. It identifies live registry owners by signed process identity and authenticated daemon replies, then reports their loaded memory package and bound home/profile. The receipt names the current `AGENTHUB_HOME` registry scope; zero results establish no live daemon in that inventory, not system-wide process absence. Inventory and check separate custom registries too when they share `AMEM_HOME`. A missing or unreadable runtime receipt never counts as a different home or permission to migrate.
|
|
925
|
+
|
|
926
|
+
Before real migration, first upgrade every hub sharing the home to 0.12.30. Obtain positive ready or unbound/quiesced receipts in every relevant registry; then quiesce consumers and close bound handles before changing the selector. A matching ready handle proves compatibility but is still an open handle. Verify synthetic cross-writes before the separately approved real migration, then reopen through the supported session-preserving lifecycle afterward. Merely installing this release does not authorize migration or provide live capture/device-sync evidence.
|
|
927
|
+
|
|
928
|
+
Managed agents read through `hub_memory_search`, `hub_memory_show` and `hub_memory_graph`, with the server's project identity, the `memory_read` capability and current privacy screening. They cannot supply another project; private turns are refused. The tools bound UTF-8 input/output, screen before counts and truncation, and exclude their arguments/results from hub-managed capture. `hub_memory_correct` has its own `memory_correct` capability and records a screened correction candidate, not a note change. See [the complete memory contract](memory.md) for caps and refusal semantics.
|
|
929
|
+
|
|
930
|
+
Review candidates and rendered/delivered/cited counters stay in machine-local `M/candidates.db`, outside sync, import, recall, briefs, ask and graph evidence. Public changes-requested reviews with unmet items may propose a fail candidate; missing cause/retry details stay unknown. Shared-v1 acceptance is a person's `amem review` action with its TTY/policy checks; selected generations still refuse that command. Read-time `(stale?)` hints and plan-fail advice never change stored rows or task authority. Structured fail notes are validated against 4000 UTF-8 bytes before screening or writes, with no silent truncation.
|
|
931
|
+
|
|
932
|
+
Recall presentation omits generated task-approval outcome notes and shows only nonempty reasons from generated changes-requested notes; an ordinary decision that merely resembles a header stays visible. Contracts and fails remain eligible. Capped recall lines preserve memory headers and end at word boundaries, and one delivery deduplicates ids across restored/current prefaces and shared note lines. Stored notes and brief evidence are unchanged; platform recall retains its budget split.
|
|
933
|
+
|
|
751
934
|
Between your machines, through a private git remote, with long-term tasks that span them:
|
|
752
935
|
|
|
753
936
|
```bash
|
|
@@ -1659,21 +1842,21 @@ section is what they run.
|
|
|
1659
1842
|
|
|
1660
1843
|
Upgrade running projects with the target release's own coordinator. It accepts
|
|
1661
1844
|
a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
|
|
1662
|
-
11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.
|
|
1845
|
+
11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.30), and only
|
|
1663
1846
|
a target on its own protocol, so the target's coordinator fits every supported
|
|
1664
1847
|
source and carries every recovery fix released up to it. Protocol 8 and older
|
|
1665
1848
|
(0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
|
|
1666
1849
|
project directory, without replacing the global CLI first:
|
|
1667
1850
|
|
|
1668
1851
|
```bash
|
|
1669
|
-
bunx --package @staix/agent-hub@0.12.
|
|
1670
|
-
bunx --package @staix/agent-hub@0.12.
|
|
1852
|
+
bunx --package @staix/agent-hub@0.12.30 ahub upgrade --to 0.12.30 --dry-run
|
|
1853
|
+
bunx --package @staix/agent-hub@0.12.30 ahub upgrade --to 0.12.30 --yes
|
|
1671
1854
|
```
|
|
1672
1855
|
|
|
1673
1856
|
| Running now | Coordinator to use |
|
|
1674
1857
|
| --- | --- |
|
|
1675
1858
|
| 0.6.x (protocol 9) | the target's, through `bunx` as above |
|
|
1676
|
-
| 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.
|
|
1859
|
+
| 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.30 (protocol 16) | the target's, through `bunx` as above |
|
|
1677
1860
|
| any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
|
|
1678
1861
|
| 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
|
|
1679
1862
|
|
|
@@ -1705,14 +1888,14 @@ projects first:
|
|
|
1705
1888
|
|
|
1706
1889
|
```bash
|
|
1707
1890
|
ahub restart --dry-run
|
|
1708
|
-
ahub upgrade --to 0.12.
|
|
1891
|
+
ahub upgrade --to 0.12.30 --dry-run
|
|
1709
1892
|
```
|
|
1710
1893
|
|
|
1711
1894
|
Apply only after reviewing the plan:
|
|
1712
1895
|
|
|
1713
1896
|
```bash
|
|
1714
1897
|
ahub restart --yes
|
|
1715
|
-
ahub upgrade --to 0.12.
|
|
1898
|
+
ahub upgrade --to 0.12.30 --yes
|
|
1716
1899
|
ahub recovery status [<operation-id>]
|
|
1717
1900
|
ahub recovery resume [<operation-id>]
|
|
1718
1901
|
ahub recovery abort [<operation-id>]
|
|
@@ -1777,7 +1960,9 @@ release. The global CLI is promoted last.
|
|
|
1777
1960
|
|
|
1778
1961
|
A lost commit or start reply is reconciled against the actual daemon identity,
|
|
1779
1962
|
package digest, terminal binding, and phase receipt. An uncertain terminal
|
|
1780
|
-
creation is never repeated blindly.
|
|
1963
|
+
creation is never repeated blindly. Recovery retains the exact-pinned first-party memory package with the preserved runtime, includes its identity and bytes in the digest, and refuses missing, symlinked or changed retained dependencies instead of resolving a mutable ancestor/global installation. It does not copy the full dependency tree.
|
|
1964
|
+
|
|
1965
|
+
After creating a managed terminal, the coordinator saves its binding before waiting up to 90 seconds for authenticated attachment to the expected target hub and conversation. An idle terminal alone is not attachment proof. Timeout retains the terminal and its diagnostic receipt; resume waits on that same binding rather than opening a duplicate. The zero-turn Claude exception still applies only when no original transcript exists. If Claude shows its development-channel confirmation screen, confirm it in
|
|
1781
1966
|
the captured terminal, then run `ahub recovery resume <operation-id>`; resume must not open a duplicate terminal.
|
|
1782
1967
|
Kimi and local sessions may start fresh with preserved routing and task context.
|
|
1783
1968
|
A Claude session that never persisted a transcript (zero turns) also starts fresh:
|