memhouse 0.18.12 → 0.20.1
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/AGENTS.md +22 -151
- package/CHANGELOG.md +263 -29
- package/LICENSE +202 -22
- package/LICENSES/agentlytics-MIT.txt +21 -0
- package/LICENSES/memhouse-MIT-until-0.18.11.txt +22 -0
- package/LICENSES/models.dev-MIT.txt +22 -0
- package/NOTICE +28 -0
- package/README.md +42 -20
- package/SECURITY.md +21 -8
- package/bin/memhouse.js +2223 -311
- package/docs/README.md +11 -9
- package/docs/guides/admin-password.md +37 -10
- package/docs/guides/configuration.md +13 -6
- package/docs/guides/daemons.md +64 -3
- package/docs/guides/import-claude-ai.md +204 -0
- package/docs/guides/install.md +11 -6
- package/docs/guides/invite.md +21 -7
- package/docs/guides/operate.md +114 -7
- package/docs/guides/search-and-resume.md +72 -3
- package/docs/guides/share.md +91 -52
- package/docs/guides/storage.md +44 -4
- package/docs/guides/troubleshooting.md +121 -14
- package/docs/guides/uninstall.md +4 -3
- package/docs/guides/update.md +16 -0
- package/docs/guides/upgrade-to-0.20.md +188 -0
- package/docs/releases/README.md +2 -1
- package/docs/releases/v0.18.10.md +5 -5
- package/docs/releases/v0.18.11.md +3 -3
- package/docs/releases/v0.20.0.md +627 -0
- package/docs/releases/v0.20.1.md +114 -0
- package/docs/tutorials/01-first-house.md +10 -7
- package/docs/tutorials/02-join-a-house.md +24 -15
- package/docs/tutorials/03-share-your-memory.md +40 -31
- package/editors/antigravity.js +1 -80
- package/editors/base.js +463 -9
- package/editors/bridge.js +119 -0
- package/editors/claude.js +273 -105
- package/editors/codex.js +278 -52
- package/editors/copilot.js +1 -70
- package/editors/cursor.js +1 -75
- package/editors/derive-fingerprints.json +18 -0
- package/editors/harness-paths.js +69 -0
- package/editors/index.js +1 -20
- package/editors/normalise/agy.js +910 -0
- package/editors/normalise/copilot-cli.js +321 -0
- package/editors/normalise/cursor-agent.js +852 -0
- package/editors/normalise/cursor.js +474 -0
- package/editors/normalise/devin.js +575 -0
- package/editors/normalise/gemini-cli.js +602 -0
- package/editors/normalise/goose.js +673 -0
- package/editors/normalise/opencode.js +633 -0
- package/editors/normalise/vscode.js +549 -0
- package/editors/normalise/zed.js +473 -0
- package/editors/opencode-v4.js +119 -0
- package/editors/scope.js +14 -3
- package/editors/sessions-log.js +349 -0
- package/editors/sqlite.js +28 -1
- package/editors/vscode.js +1 -72
- package/editors/windsurf.js +1 -143
- package/examples/01-local-one-machine/README.md +24 -19
- package/examples/01-local-one-machine/run.sh +1 -1
- package/examples/02-existing-clickhouse/README.md +30 -22
- package/examples/02-existing-clickhouse/run.sh +5 -4
- package/examples/03-team-house/README.md +44 -37
- package/examples/03-team-house/run.sh +35 -18
- package/examples/04-self-hosted-team/README.md +29 -14
- package/examples/04-self-hosted-team/compose.yml +5 -2
- package/examples/04-self-hosted-team/smoke.sh +26 -12
- package/examples/README.md +8 -4
- package/examples/fixtures/README.md +4 -1
- package/examples/fixtures/make-sessions.js +8 -5
- package/memhouse/admin-secret.js +89 -24
- package/memhouse/argv-secrets.js +64 -0
- package/memhouse/channel.js +49 -9
- package/memhouse/codex-plugin.js +194 -0
- package/memhouse/delivery/AGENT-INSTALL-PROMPT.md +2 -1
- package/memhouse/delivery/AGENT-INSTALL.md +22 -11
- package/memhouse/delivery/INVITATION.md.tpl +44 -45
- package/memhouse/delivery/PROMPT.md +53 -5
- package/memhouse/delivery/UPGRADE.md.tpl +1 -1
- package/memhouse/delivery/codex/AGENTS-BLOCK.md +11 -0
- package/memhouse/delivery/codex/SKILL.md +50 -0
- package/memhouse/delivery/kernel-install.md +17 -9
- package/memhouse/delivery/plugin/.claude-plugin/plugin.json +2 -2
- package/memhouse/delivery/plugin/reference/HOUSE.md +168 -41
- package/memhouse/delivery/plugin/skills/access/SKILL.md +13 -5
- package/memhouse/delivery/plugin/skills/admin/SKILL.md +14 -6
- package/memhouse/delivery/plugin/skills/house/SKILL.md +25 -8
- package/memhouse/delivery/plugin/skills/recall/SKILL.md +66 -8
- package/memhouse/delivery/plugin/skills/sql/SKILL.md +66 -7
- package/memhouse/deploy.js +1 -1
- package/memhouse/flags.js +35 -18
- package/memhouse/help.js +37 -0
- package/memhouse/host.js +82 -2
- package/memhouse/house/HOUSE.md +2 -2
- package/memhouse/house/convert-profile.js +638 -0
- package/memhouse/house/convert-v3.js +742 -0
- package/memhouse/house/doctor-v3.js +324 -0
- package/memhouse/house/host-alias.js +85 -0
- package/memhouse/house/house.js +3 -3
- package/memhouse/house/migrate.js +2 -2
- package/memhouse/house/profile-dedupe.js +183 -0
- package/memhouse/house/profile-edges.js +554 -0
- package/memhouse/house/profile-house.js +430 -0
- package/memhouse/house/profile-rollup.js +190 -0
- package/memhouse/house/q-cli.js +863 -0
- package/memhouse/house/queries-v3.js +1013 -0
- package/memhouse/house/reconcile-v3.js +192 -0
- package/memhouse/house/records-to-profile.js +174 -0
- package/memhouse/house/records-to-rows.js +169 -0
- package/memhouse/house/relocate.js +2 -1
- package/memhouse/house/schema-choice.js +121 -0
- package/memhouse/house/schema-profile.js +290 -0
- package/memhouse/house/schema-profile.sql.tpl +398 -0
- package/memhouse/house/schema-v3.js +267 -0
- package/memhouse/house/schema-v3.sql.tpl +213 -0
- package/memhouse/import/claude-ai.js +420 -0
- package/memhouse/import/import.js +372 -0
- package/memhouse/import/pyjson.js +206 -0
- package/memhouse/import/records.js +64 -0
- package/memhouse/import/writer-profile.js +192 -0
- package/memhouse/import/writer-v3.js +240 -0
- package/memhouse/import/zip.js +112 -0
- package/memhouse/invitation.js +102 -0
- package/memhouse/invitefile.js +5 -2
- package/memhouse/plugin-copies.js +176 -0
- package/memhouse/provision.js +7 -2
- package/memhouse/release-hint.js +24 -0
- package/memhouse/resume.js +4 -4
- package/memhouse/server/api-v3.js +632 -0
- package/memhouse/server/dashboard-auth.js +181 -0
- package/memhouse/server/dashboard-port.js +91 -0
- package/memhouse/server/queries.js +30 -0
- package/memhouse/server/server.js +118 -20
- package/memhouse/service.js +1 -1
- package/memhouse/share.js +687 -1
- package/memhouse/shipper/adapter-capture.js +756 -0
- package/memhouse/shipper/capture.js +2571 -0
- package/memhouse/shipper/dedupe-profile.js +237 -0
- package/memhouse/shipper/dedupe-v3.js +1027 -0
- package/memhouse/shipper/forks.js +233 -0
- package/memhouse/shipper/log-adapter.js +219 -0
- package/memhouse/shipper/maintenance.js +49 -0
- package/memhouse/shipper/normalise-run.js +148 -0
- package/memhouse/shipper/passlog.js +68 -5
- package/memhouse/shipper/profile-capture.js +903 -0
- package/memhouse/shipper/ship.js +91 -8
- package/memhouse/shipper/snapshots.js +193 -0
- package/memhouse/shipper/source-roots.js +111 -0
- package/memhouse/version-notice.js +66 -0
- package/package.json +14 -7
- package/public/THIRD_PARTY_NOTICES.txt +2 -2
- package/public/assets/index-CcNnhfM3.js +78 -0
- package/public/index.html +1 -1
- package/ui/package-lock.json +56 -37
- package/ui/package.json +1 -0
- package/ui/src/App.jsx +29 -14
- package/ui/src/components/ChatSidebar.jsx +69 -12
- package/ui/src/lib/api.js +76 -0
- package/ui/src/lib/dashboard-token.js +41 -0
- package/ui/src/main.jsx +22 -5
- package/ui/src/pages/Dashboard.jsx +22 -36
- package/ui/third-party-notices.js +119 -0
- package/ui/vite.config.js +5 -1
- package/docs/releases/v0.18.12.md +0 -59
- package/memhouse/COMPETITION.md +0 -221
- package/memhouse/DESIGN.md +0 -222
- package/memhouse/RESUME-AND-UPDATE.md +0 -182
- package/public/assets/index-CnWzrjF3.js +0 -78
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
# memhouse 0.20.0 — 2026-10-29
|
|
2
|
+
|
|
3
|
+
0.20 changes how memhouse stores what it captures. It is the first release since 0.18.11;
|
|
4
|
+
there is no 0.19.
|
|
5
|
+
|
|
6
|
+
- **Schema 3.** A session is keyed by its store: the machine, the editor, the editor's data
|
|
7
|
+
folder (for OpenCode, its database file) and the session's own id. Each member gets six
|
|
8
|
+
conversation tables, the harness-sessions-sql profile: `<m>_session_parts`, `<m>_session_usage`,
|
|
9
|
+
`<m>_session_links`, `<m>_session_lifecycle`, `<m>_calls` and `<m>_sessions`. Each member also
|
|
10
|
+
gets a capture archive in `<db>_archive` (`<m>_session_units` and `<m>_session_sources`) that
|
|
11
|
+
keeps every transcript byte as captured.
|
|
12
|
+
- **Nothing is cut or lost.** Tool output is kept in full. A message an editor reverts,
|
|
13
|
+
rewinds or deletes stays in the house as a removed version: never counted, and listed by
|
|
14
|
+
`memhouse q removed`.
|
|
15
|
+
- **A fork is billed once.** Where a session copies another and the copy can be told, the copied
|
|
16
|
+
prefix counts only in the original: by the link agy and Copilot CLI state, or by a matching first
|
|
17
|
+
reply in OpenCode, VS Code, cursor-agent, Cursor and Goose. Other editors' copies, Claude
|
|
18
|
+
Code's and Codex's included, are not covered.
|
|
19
|
+
- **Ten editors read as they store their sessions.** Each has a normaliser that reads its
|
|
20
|
+
store directly: agy, Copilot CLI, Cursor, cursor-agent, Devin, Gemini CLI, Goose,
|
|
21
|
+
OpenCode, VS Code and Zed. Claude Code and Codex are read natively, and the remaining
|
|
22
|
+
editors through their 0.18 readers.
|
|
23
|
+
- **Moving a 0.18 house is a deliberate admin step, and `memhouse update` never does it.**
|
|
24
|
+
A 0.18 house keeps working on 0.20, unchanged, until its admin converts it.
|
|
25
|
+
- **memhouse is Apache-2.0 from this release.** Releases up to 0.18.11 remain MIT.
|
|
26
|
+
|
|
27
|
+
## Read this before upgrading
|
|
28
|
+
|
|
29
|
+
### `memhouse update` installs 0.20 and does not convert the house
|
|
30
|
+
|
|
31
|
+
A machine on 0.20 keeps shipping a 0.18 house's rooms until two things happen: the admin
|
|
32
|
+
converts the member, then the machine is switched with `memhouse migrate --v3-switch`.
|
|
33
|
+
Every machine can be upgraded first, days before the conversion.
|
|
34
|
+
|
|
35
|
+
Behind a registry mirror, 0.18's own `update` asks registry.npmjs.org and cannot see 0.20.
|
|
36
|
+
There, run `npm install -g memhouse@<version>`, then `memhouse update --no-install`.
|
|
37
|
+
|
|
38
|
+
`update` still does what every update does to the rooms it ships into: it creates a missing
|
|
39
|
+
room or column for the new code (`ship --ensure-schema`), and can run a pending 0.18
|
|
40
|
+
migration (it asks first; `--migrate` or `--yes` say yes). It never converts to schema 3.
|
|
41
|
+
|
|
42
|
+
### Converting a house is the admin's procedure
|
|
43
|
+
|
|
44
|
+
[Upgrade to 0.20](../guides/upgrade-to-0.20.md) is the whole procedure. Run each step with
|
|
45
|
+
`--dry-run` first; each refuses before changing anything when the house is not in the
|
|
46
|
+
state it expects.
|
|
47
|
+
|
|
48
|
+
1. `memhouse migrate --v3-prepare --member <m>` fences the 0.18 writers off and renames the
|
|
49
|
+
member's rooms into `<db>_archive` as `*_pre_v3`. Nothing is deleted.
|
|
50
|
+
2. `memhouse migrate --v3-convert --member <m>` converts the rooms into schema 3. It takes
|
|
51
|
+
the cached tokens out of 0.18's Gemini CLI input (see Fixed), and `--dry-run` says how
|
|
52
|
+
many rows and tokens that is.
|
|
53
|
+
3. `memhouse migrate --v3-reconcile --member <m>` compares the legacy and converted rows,
|
|
54
|
+
session by session.
|
|
55
|
+
4. `memhouse migrate --v3-shares --member <m>` moves the member's recorded shares.
|
|
56
|
+
5. `memhouse migrate --v3-switch`, on every machine, followed by a restart.
|
|
57
|
+
|
|
58
|
+
The upgrade guide also gives the rollback for before any machine has switched.
|
|
59
|
+
|
|
60
|
+
### A house in daily use is converted on its own schedule
|
|
61
|
+
|
|
62
|
+
**Converting a house people depend on is not part of `npm update` or of this release.** It
|
|
63
|
+
rewrites that house's data: the conversion, the host re-key to sessions-model/host/v0, and the
|
|
64
|
+
OpenCode key. Plan it first, as its admin decides: the steps, the rollback copy, the disk it
|
|
65
|
+
needs, and the downtime. Until then the house stays on the 0.18 rooms, and its machines can run
|
|
66
|
+
0.20 against it unchanged.
|
|
67
|
+
|
|
68
|
+
### New houses
|
|
69
|
+
|
|
70
|
+
A house created by 0.20 (`deploy --local`, `install --admin-user`, `invite` into an empty
|
|
71
|
+
server) is schema 3. Joining an existing house follows the layout the house already has,
|
|
72
|
+
and a house with members on both layouts is refused until `--schema` says which.
|
|
73
|
+
|
|
74
|
+
### Scripts that pass `--admin-password`
|
|
75
|
+
|
|
76
|
+
`--admin-password <value>` is refused in 0.20 (it was deprecated in 0.18.10). A script that
|
|
77
|
+
passes it stops with exit 2 and nothing done. Give the password in `MEMHOUSE_ADMIN_PASSWORD`
|
|
78
|
+
or with `--admin-password-file` (a file at mode 600, or `-` for stdin) instead. See
|
|
79
|
+
[the admin password guide](../guides/admin-password.md).
|
|
80
|
+
|
|
81
|
+
## Security note for 0.18 houses: member names that collide
|
|
82
|
+
|
|
83
|
+
**What it allows.** A member is granted its tables through one prefix wildcard: `bob` holds
|
|
84
|
+
`mem.bob_*`. That prefix also matches the tables of any member whose name is `bob` plus an
|
|
85
|
+
underscore and more, such as `bob_smith`. So `bob` can **read and write** `bob_smith`'s
|
|
86
|
+
sessions. Mostly the longer name's tables are exposed, to the shorter name. When the longer
|
|
87
|
+
name's extra part starts one of the shorter name's table names, the reverse holds too:
|
|
88
|
+
`mem.bob_session_*` matches `bob`'s `bob_session_parts`. Checked on ClickHouse 26.7
|
|
89
|
+
(2026-10-22). Every memhouse release up to 0.18.11 created such members without a warning, so
|
|
90
|
+
an existing house may have a pair.
|
|
91
|
+
|
|
92
|
+
**Check your house, as its admin:**
|
|
93
|
+
|
|
94
|
+
```sql
|
|
95
|
+
SELECT name FROM system.users ORDER BY name
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Look for one name that is another's plus `_`. On a schema-3 install, `memhouse doctor` run as
|
|
99
|
+
the shorter-named member names the pair too.
|
|
100
|
+
|
|
101
|
+
**What 0.20 does.** It refuses to create a member whose name collides (install and invite),
|
|
102
|
+
`memhouse doctor` names an existing pair, and `memhouse migrate --v3-shares` refuses to move
|
|
103
|
+
shares in such a house. memhouse cannot untangle an existing pair yet. If you find one, the
|
|
104
|
+
choices are in [Troubleshooting](../guides/troubleshooting.md#two-member-names-that-collide).
|
|
105
|
+
Both of them touch another person's data, so decide before acting.
|
|
106
|
+
|
|
107
|
+
## What changes for you
|
|
108
|
+
|
|
109
|
+
### Capture
|
|
110
|
+
|
|
111
|
+
- **Every row carries its store.** `host` is now sessions-model/host/v0: the first 32 hex
|
|
112
|
+
of a hash of the OS machine id, the same for every reader on the machine. Where no machine
|
|
113
|
+
id can be read, it is a random id kept on disk (`r-…`). `memhouse doctor` lists the 0.18
|
|
114
|
+
id under "host identity" as an alias of this machine.
|
|
115
|
+
- **The capture archive.** `<db>_archive.<m>_session_units` holds every captured byte;
|
|
116
|
+
`<m>_session_sources` holds the cursor of each source: its generation and how far it has been
|
|
117
|
+
read. Each read writes a manifest beside its units, so an emptied or shrunk source replays correctly
|
|
118
|
+
from the archive alone. A session file the editor deletes stays in the house, recorded
|
|
119
|
+
once as gone.
|
|
120
|
+
- **A session the editor deletes is recorded as gone only on the editor's own word.** On the
|
|
121
|
+
profile layout, a session or source the editor's store no longer lists is read once more, and
|
|
122
|
+
is recorded as gone (its records kept) only when the editor's reader answers that it is not
|
|
123
|
+
there. A session the list leaves out that still reads is captured as usual. In 0.20 this
|
|
124
|
+
covers the editors read through the harness-session-adapters package, Claude Code and Codex; the
|
|
125
|
+
others are read from their normalised logs, which are never swept (see Known issues), and
|
|
126
|
+
join when they move to the package. The Claude Code and Codex readers look a session up in
|
|
127
|
+
the store again, so a session whose folder is missing both when the store is listed and when
|
|
128
|
+
it is read is taken as gone; when it comes back it is read again in full, in a new
|
|
129
|
+
generation. Only a store whose list names none of the sessions the house holds of it (an
|
|
130
|
+
empty or unreadable store) is refused whole.
|
|
131
|
+
- **The shipper log says so.** After the pass line, a `vanish refused: <editor> <store>: …` line
|
|
132
|
+
names each refused store (and a session the list left out that still reads, or could not be
|
|
133
|
+
read), and `memhouse doctor` fails a line naming them until a later pass is clean. A
|
|
134
|
+
`vanish warning: …` line names a listed session's source the list left out that still reads;
|
|
135
|
+
doctor shows it and does not fail.
|
|
136
|
+
- **An emptied store needs one step.** A store whose every session was deleted lists nothing,
|
|
137
|
+
which is what an unreadable store looks like, so it is refused on every pass. If its
|
|
138
|
+
sessions were deleted, run the command the refusal names:
|
|
139
|
+
`memhouse doctor --confirm-empty-store <editor>:<store>` (the store path quoted when it has
|
|
140
|
+
spaces). It confirms the sessions the last pass refused (those recorded as gone already
|
|
141
|
+
replay without it). The next pass that finds the store there, its list still empty and no
|
|
142
|
+
other session held takes each as gone where the editor's reader says it is; a list that names
|
|
143
|
+
a session again, or a session held that it does not name, cancels the confirmation.
|
|
144
|
+
- At most 100 sessions a store are taken per pass; the rest follow on the next passes.
|
|
145
|
+
- **Normalisers.** The ten editors above write a normalised session log under
|
|
146
|
+
`$MEMHOUSE_HOME/session-logs/`, and the engine captures from it. Sub-agents are child
|
|
147
|
+
records, so a log grows by appending. Reading is bounded to 30 s a pass, and a store that
|
|
148
|
+
is busy or locked fails the pass rather than reading as fewer messages.
|
|
149
|
+
- **OpenCode is keyed by its database file** (`opencode.db`, `opencode-<channel>.db`, or
|
|
150
|
+
`OPENCODE_DB`), not its data folder (sessions-model §1).
|
|
151
|
+
- **Converted 0.18 rows dedupe against capture.** After the switch, each captured session
|
|
152
|
+
absorbs the converted rows of the same session, so nothing is counted twice. Rows whose
|
|
153
|
+
transcripts are gone stay, counted once.
|
|
154
|
+
- **A fork is billed once.** A fork that names its origin (agy, Copilot CLI) is checked against
|
|
155
|
+
it message by message, on content. Its usage that copies the origin's counts only in the
|
|
156
|
+
origin; a message the fork ran again is billed in the fork. `memhouse doctor` counts the forks
|
|
157
|
+
billed once and the links it could not verify. A fork that keeps no pointer to its origin
|
|
158
|
+
(OpenCode, VS Code, cursor-agent, Cursor, Goose) is found by its first reply: a session whose
|
|
159
|
+
first answer (at least 40 characters) is an earlier session's is checked against it the same
|
|
160
|
+
way. Two unrelated sessions whose first exchanges match word for word and token for token
|
|
161
|
+
cannot be told from a fork.
|
|
162
|
+
- **An adapter upgrade re-derives each session from its archive, and its first pass takes
|
|
163
|
+
longer.** The first pass after an adapter states a new version replays each of its sessions'
|
|
164
|
+
archived passes one by one under that version (harness-sessions-sql §8):
|
|
165
|
+
- every record it makes, current or a removed version, is written again at the new version;
|
|
166
|
+
- every key it no longer makes is deleted, a removed version included, except a key the new
|
|
167
|
+
version still holds back, which stays as last written.
|
|
168
|
+
|
|
169
|
+
A session with a single archived pass is refolded instead, which gives the same rows. The
|
|
170
|
+
upgrade pass takes longer the more passes a session's archive holds. The replay reads archived
|
|
171
|
+
units at most 32 MiB and 1,000 units a response, and a pass under an unchanged version is not
|
|
172
|
+
affected. On a lab ClickHouse reached through an SSH tunnel, with a synthetic store of
|
|
173
|
+
50 sessions, the upgrade pass took:
|
|
174
|
+
|
|
175
|
+
| archived passes a session | without the re-derive (a 0.20 dev build) | 0.20 | 0.20, per 1,000 sessions |
|
|
176
|
+
|---|---|---|---|
|
|
177
|
+
| 4 | 0.6 s a session | 0.55 s | about 9 min |
|
|
178
|
+
| 12 | 0.5 s | 0.8 s | about 13 min |
|
|
179
|
+
| 24 | 0.5 s | 1.0 s | about 17 min |
|
|
180
|
+
|
|
181
|
+
The second column is a 0.20 development build's upgrade, which refolded only each session's
|
|
182
|
+
last state; at 4 passes the two are within noise. The last column scales the 50-session runs.
|
|
183
|
+
These are single runs, and round trips to the house dominate them, so read them as an order of
|
|
184
|
+
magnitude for planning, not a measurement of any real house.
|
|
185
|
+
|
|
186
|
+
### Reading
|
|
187
|
+
|
|
188
|
+
- `memhouse q <name>` runs named queries over schema 3: `recent`, `session`, `window`,
|
|
189
|
+
`search`, `spend`, `models`, `tools`, `activity`, `hosts`, `coverage`, `removed` and more
|
|
190
|
+
(`memhouse q --list`). A session's ref names its store (`<harness>:<id>~…`); a bare id
|
|
191
|
+
still resolves when it is unique.
|
|
192
|
+
- `q window <ref>` reads around a search hit (`--at <message_id>`) or a moment (`--ts`); with
|
|
193
|
+
neither it opens at the session's first turn, so a ref from `q recent` reads as it is.
|
|
194
|
+
- `memhouse status`, `doctor`, `search`, `stats` and `resume`, the dashboard and the `/mem`
|
|
195
|
+
skills read schema 3 once an install is switched.
|
|
196
|
+
- The `/mem` skills install into Claude Code only. In Codex or another editor, an agent reads
|
|
197
|
+
the house with `memhouse q` and `memhouse room-sql`; `--help` and the install guide say so.
|
|
198
|
+
- `MEMHOUSE_URL` is the house, its port included; `MEMHOUSE_PORT` is this machine's dashboard
|
|
199
|
+
port. `--help`, the env file and the configuration guide say so.
|
|
200
|
+
|
|
201
|
+
### Importing a claude.ai export
|
|
202
|
+
|
|
203
|
+
`memhouse import claude-ai <export>` stores a claude.ai data export in the house: the export's
|
|
204
|
+
part zips or their folder, an older single `.zip`, an unpacked export, or an archive folder. Each
|
|
205
|
+
conversation with any text becomes a `claude-ai` session with origin `import`, in one batch per
|
|
206
|
+
run.
|
|
207
|
+
|
|
208
|
+
- It is a dry run unless `--write`. A later export adds only the conversations the house lacks;
|
|
209
|
+
`--update` also replaces the ones that changed.
|
|
210
|
+
- `--list` shows the batches and `--undo <batch> --write` tombstones one.
|
|
211
|
+
- On schema 3 a conversation is a session in the service's own store, not a machine's.
|
|
212
|
+
- A run that stops after all its rows went in is finished by the next `--write`. One whose
|
|
213
|
+
insert stopped early leaves its batch `applying`, and the next run writes those sessions in its
|
|
214
|
+
own batch.
|
|
215
|
+
|
|
216
|
+
[Import a claude.ai export](../guides/import-claude-ai.md) has the details.
|
|
217
|
+
|
|
218
|
+
### Sharing is narrower on schema 3
|
|
219
|
+
|
|
220
|
+
A share, full or scoped, is `SELECT` on exactly the member's six conversation tables
|
|
221
|
+
(`<m>_session_parts`, `<m>_session_usage`, `<m>_session_links`, `<m>_session_lifecycle`,
|
|
222
|
+
`<m>_calls`, `<m>_sessions`), never the archive.
|
|
223
|
+
|
|
224
|
+
- A scope is a row policy on each of the six. A `project=` or `folder=` scope lets no usage,
|
|
225
|
+
link or lifecycle row through (the `sessions` row carries the totals); a time scope lets no
|
|
226
|
+
link row through.
|
|
227
|
+
- A full share no longer reaches `meta`, `events` or tables added later. On the 0.18 rooms
|
|
228
|
+
it was `SELECT ON <m>_*`.
|
|
229
|
+
- A scope's row policies are written before any grant.
|
|
230
|
+
- `source=` is `harness=` on schema 3; `source=` still works.
|
|
231
|
+
|
|
232
|
+
`--v3-shares` moves the shares memhouse recorded. It refuses, changing nothing, when the
|
|
233
|
+
record and the grants ClickHouse holds disagree. [Share and revoke](../guides/share.md) has
|
|
234
|
+
the details.
|
|
235
|
+
|
|
236
|
+
## Security
|
|
237
|
+
|
|
238
|
+
- **Reading an editor's store never writes into it.** On 0.18, the SQLite readers (Cursor,
|
|
239
|
+
Goose, OpenCode, Zed, Antigravity) could create `-wal` and `-shm` files in the editor's
|
|
240
|
+
folder: a WAL database opened read-only creates them, and they stay after close. A WAL
|
|
241
|
+
store with no `-wal` is now read immutable, and a rollback-journal store (Zed's) with a
|
|
242
|
+
plain read under its lock. 0.18 machines that ran those readers may have such files left
|
|
243
|
+
in the editors' folders. They are SQLite's own, and the editor uses or replaces them.
|
|
244
|
+
- **No reader reads a credential.** The usage path that read an editor's credentials is
|
|
245
|
+
gone. The cursor-agent normaliser never decodes credential-bearing steps or untyped
|
|
246
|
+
arguments, and redacts them from the stored model context too.
|
|
247
|
+
- **A share cannot reach the archive.** The capture archive is granted to its member alone
|
|
248
|
+
(`SELECT, INSERT`, without grant option), so no share can hand over the raw transcripts.
|
|
249
|
+
- **The share commands fail closed.** Every name that reaches a grant statement is checked
|
|
250
|
+
and quoted. `migrate --v3-shares` matches a member's tables and filters by exact name,
|
|
251
|
+
never by prefix, and stops on any read it cannot make. A scoped share needs the server to
|
|
252
|
+
prove that a row policy hides nothing from other readers. A 0.18 wildcard grant
|
|
253
|
+
(`<m>_*`) is taken back only from a reader who holds it: by `migrate --v3-shares`, or by a
|
|
254
|
+
member's revoke when no other member's name starts with theirs. A new share refuses while
|
|
255
|
+
the reader holds it, or while that cannot be read.
|
|
256
|
+
- **Members no longer receive SHOW ROW POLICIES.** On a shared house that privilege let a
|
|
257
|
+
member list other members' scoped shares, including their filters. Admins of existing houses
|
|
258
|
+
run `memhouse migrate --v3-shares` (or the statement below) to remove it from existing
|
|
259
|
+
members.
|
|
260
|
+
|
|
261
|
+
```sql
|
|
262
|
+
-- for each member <m> of the house <db>; a house still on the 0.18 rooms too
|
|
263
|
+
REVOKE SHOW ROW POLICIES ON <db>.<m>_* FROM <m>;
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Sharing does not need it: `memhouse share --list` shows a share's scope from memhouse's own
|
|
267
|
+
record. Where `--v3-shares` refuses to move a member's shares (two names that collide, a grant
|
|
268
|
+
it did not record), it prints this statement instead.
|
|
269
|
+
- **Two member names that collide are refused.** See [the security note for 0.18
|
|
270
|
+
houses](#security-note-for-018-houses-member-names-that-collide) above.
|
|
271
|
+
- **The `/mem` skills pre-approve reads only.** Each skill pre-approves only the read
|
|
272
|
+
commands it teaches, drawn from `memhouse q`, `search`, `resume`, `room-sql`,
|
|
273
|
+
`sessions-query`, `status`, `whoami`, `stats`, `instance`, `doctor` and `share --list`.
|
|
274
|
+
Every other command asks first, including one chained to a read.
|
|
275
|
+
- **Joining always changes the invited password.** `install --env` changes it to a new one
|
|
276
|
+
only the member's machine knows, also when it runs without a terminal (as an agent runs
|
|
277
|
+
it). In a terminal it asks first. Only an explicit no, or `--keep-password`, keeps the
|
|
278
|
+
invited password, and the output then says the inviter still knows it. The invite file
|
|
279
|
+
and the invitation page now say the same, and both tell an agent not to open the file.
|
|
280
|
+
- **An admin password is never taken from the command line.** `--admin-password <value>`,
|
|
281
|
+
deprecated in 0.18.10, is refused: the command stops before doing anything, exits 2, and
|
|
282
|
+
names `MEMHOUSE_ADMIN_PASSWORD` and `--admin-password-file` instead, without printing the
|
|
283
|
+
value. `--admin-password-file` refuses a file that group or other users can read or
|
|
284
|
+
write (`chmod 600` fixes it); a container's secret mounts are the exception.
|
|
285
|
+
- **`setup` stores an administrator credential only on request.** Given a credential that
|
|
286
|
+
administers the server, `memhouse setup` writes nothing unless `--keep-admin` says so (a
|
|
287
|
+
terminal is asked, default no; `--yes` does not count). Such a password given as
|
|
288
|
+
`--password` is refused outright. Re-saving the credential already configured does not ask.
|
|
289
|
+
- **The dashboard requires a token.** The dashboard now requires a per-user token; a loopback
|
|
290
|
+
connection alone is no longer enough. Open it with `memhouse dashboard`.
|
|
291
|
+
- **The dashboard's port.** When it is in use, possibly by another account on this machine, the
|
|
292
|
+
dashboard takes the next free port up to 10 above and says which (`memhouse status` and
|
|
293
|
+
`memhouse dashboard` use it); a dashboard that cannot start is a warning from
|
|
294
|
+
`memhouse start`, not a failure.
|
|
295
|
+
- **Report a security issue to security@memhouse.io.** It is the public contact while the
|
|
296
|
+
repository is private (`SECURITY.md`), and npm shows it as the package's `bugs` address.
|
|
297
|
+
|
|
298
|
+
## Fixed
|
|
299
|
+
|
|
300
|
+
- **One number for "sessions".** `memhouse instance` printed each table's row count beside its
|
|
301
|
+
name, which read as a second, different count of sessions: a table holds every version of a
|
|
302
|
+
session that is not merged yet. It now says rows, and that `status` and `stats` count the
|
|
303
|
+
sessions. `status`, `stats`, `q hosts` and `q machines` count the same live sessions.
|
|
304
|
+
- **`memhouse update` reads the registry npm installs from.** It asked registry.npmjs.org
|
|
305
|
+
whatever npm was configured with, so behind a mirror it reported "the registry did not
|
|
306
|
+
answer" and could not update. It now reads `npm config get registry` (or
|
|
307
|
+
`npm_config_registry`), prints which registry it read and why one could not be read, and no
|
|
308
|
+
longer suggests `--channel` when the registry itself is the problem. Mirror users: a
|
|
309
|
+
registry that needs a login is still read without one; install by hand there, then
|
|
310
|
+
`memhouse update --no-install`.
|
|
311
|
+
- **The package ships what a user needs, not the repository's rules.** `AGENTS.md` is now the
|
|
312
|
+
install and deploy guide for agents only. The conventions for working on memhouse (release
|
|
313
|
+
lines, the instruments, what the codebase learned the hard way) moved to `CONTRIBUTING.md`,
|
|
314
|
+
which stays in the repository. `memhouse/DESIGN.md`, `COMPETITION.md` and
|
|
315
|
+
`RESUME-AND-UPDATE.md` no longer ship. An agent reading files in an installed package found
|
|
316
|
+
repository rules there and took them for the user's.
|
|
317
|
+
- **One machine is one writer after the move.** Converted rows keep a machine's 0.18 id and
|
|
318
|
+
captured ones carry the new one; the machine now records the pair in its member's meta (at
|
|
319
|
+
`--v3-switch` and each capture pass), and status, `q machines`, `q hosts` and doctor read the
|
|
320
|
+
0.18 id's rows as that machine. No row is rewritten.
|
|
321
|
+
- **The `/mem` skills follow the memhouse that runs them.** Only `memhouse update` refreshed
|
|
322
|
+
them, so an upgrade with `npm install -g` (or one behind a registry mirror, where `update`
|
|
323
|
+
cannot see the registry) left the 0.18 skills teaching the 0.18 rooms on a schema-3 house.
|
|
324
|
+
The first command after an upgrade, or the shipper's restart, now replaces every copy bound
|
|
325
|
+
to that install with its own version's skills, never one bound to another install and never
|
|
326
|
+
with an older version. `memhouse doctor` names any it could not refresh.
|
|
327
|
+
- **The `/mem` skills' pre-approved reads asked anyway.** The skills wrote each command with an
|
|
328
|
+
expansion in front of the verb, which no `allowed-tools` rule can match, so every read
|
|
329
|
+
prompted. They now write plain `memhouse …`, and those reads run without a prompt. They also
|
|
330
|
+
sent you to `SHOW DATABASES` for a share you received, which does not show it: a share is the
|
|
331
|
+
housemate's tables in your own database. It is found with `SHOW TABLES` (through
|
|
332
|
+
`memhouse room-sql`) and read with `memhouse q … --member <them>`.
|
|
333
|
+
- `memhouse room-sql "DESCRIBE sessions"` told a member it lacked the privilege to read its own
|
|
334
|
+
columns: only a name after `FROM`/`JOIN` was resolved, so the server was asked about a table
|
|
335
|
+
that is not the member's. The table a `DESCRIBE`, `DESC`, `SHOW CREATE` or `EXISTS` names is
|
|
336
|
+
now resolved too. Another member's tables stay closed.
|
|
337
|
+
- `status`, `doctor` and `stats` no longer call a house that answers "not connected" when
|
|
338
|
+
your tables are not where this install looks, and no longer print ClickHouse's
|
|
339
|
+
`UNKNOWN_TABLE` and the SQL behind it. They name the reason and the next step: the house
|
|
340
|
+
was moved to schema 3 (`memhouse migrate --v3-switch`), it was not moved yet, this install
|
|
341
|
+
holds an administrator credential with no rooms of its own, or there are no tables for you
|
|
342
|
+
in the configured house. `status --json` adds `reachable` and `rooms_problem`; `connected`
|
|
343
|
+
still means the house answered and its rooms could be read.
|
|
344
|
+
- A shipper keeps what it read when it started. After `memhouse migrate --v3-switch` or an
|
|
345
|
+
upgrade under a running shipper, `status` showed its failing passes as a warning and exited 0.
|
|
346
|
+
It now calls that shipper stale, says why (the env file changed, or the package was installed,
|
|
347
|
+
after it started), repeats `memhouse stop && memhouse start`, and exits 1 while its passes
|
|
348
|
+
fail. A shipper that re-read the env file itself (it adopts a moved house and a newer
|
|
349
|
+
credential) is not called stale. `status --json` adds `shipper.stale`.
|
|
350
|
+
- `memhouse instance` printed "schema 2" on a machine left on the 0.18 rooms after its house was
|
|
351
|
+
converted, as if all was well. It now asks the house what `status` asks and says the install
|
|
352
|
+
is stranded, with the fix. `memhouse q schema` with no house configured says `none` instead of
|
|
353
|
+
`2`.
|
|
354
|
+
- `memhouse invite` from an admin home with no install of its own minted 0.18 rooms in a
|
|
355
|
+
schema-3 house. It now detects the house, as install does.
|
|
356
|
+
- The invitation page `invite` writes beside the env file (`MEMHOUSE-INVITATION.md`) listed
|
|
357
|
+
the 0.18 rooms for every invite, and found the env file with `ls invite-*.env`, which matches
|
|
358
|
+
nothing written with `--out <dir>/<other-name>.env`. It now lists the tables the invite
|
|
359
|
+
created, by the house's layout, and names the env file the invite wrote.
|
|
360
|
+
- `memhouse migrate`'s admin steps (`--v3-prepare`, `--v3-convert`, `--v3-reconcile`,
|
|
361
|
+
`--v3-shares`) now take `MEMHOUSE_ADMIN_USER` and `MEMHOUSE_ADMIN_PASSWORD` (or `--admin-user`
|
|
362
|
+
and `--admin-password-file`), like the other admin commands. From an admin home with no install
|
|
363
|
+
of its own they acted as the default `memhouse_root` with no password, and reported "could not
|
|
364
|
+
list mem's tables". `MEMHOUSE_USER` and `MEMHOUSE_PASSWORD` still work for them in this
|
|
365
|
+
release, with a note (see Deprecated); with no admin credential at all a step refuses before it
|
|
366
|
+
connects and names the missing variables. An authentication failure is named as one, in
|
|
367
|
+
`migrate`, `doctor` and `--v3-switch`: `could not authenticate as '<user>' at <url>`.
|
|
368
|
+
- `memhouse deploy --local` stopped at the install on 0.20: only an admin may create the
|
|
369
|
+
member's archive tables. The superuser it has at hand now builds them.
|
|
370
|
+
- The self-hosted example's nightly backup (`examples/04-self-hosted-team`) now includes
|
|
371
|
+
`<db>_archive`.
|
|
372
|
+
- On schema 3, a machine with no Claude Code or Codex directory stopped every pass before the
|
|
373
|
+
other editors were read. It now ships whatever the normalisers and the bridge find.
|
|
374
|
+
- Gemini CLI tokens were stored as Gemini reports them. Gemini counts cached tokens inside the
|
|
375
|
+
input and thought tokens outside the output, so the house charged cached tokens twice (in
|
|
376
|
+
`input_tokens` and again as `cache_read_tokens`) and never charged thoughts. Gemini CLI rows
|
|
377
|
+
now use the house split: input without the cached tokens, output with the thoughts. Usage
|
|
378
|
+
records carry the two flags of sessions-model §2.4 (`input_includes_cache`,
|
|
379
|
+
`output_includes_reasoning`). A machine that ran a 0.20 pre-release re-derives its Gemini CLI
|
|
380
|
+
sessions on its first pass after the update.
|
|
381
|
+
- 0.18 stored Gemini CLI input with the cached tokens counted inside it, and stored the same
|
|
382
|
+
tokens again as cache reads, so they were charged twice. `--v3-convert` takes them out of
|
|
383
|
+
input (floor 0), and `--v3-reconcile` compares on the same rule. 0.18 never stored Gemini's
|
|
384
|
+
thought tokens, so converted Gemini CLI rows still leave them out: they cannot be recovered.
|
|
385
|
+
- **Zed tokens counted only each turn's last request.** The Zed normaliser took each turn's
|
|
386
|
+
`request_token_usage`, which holds only the turn's last request, and ignored the thread's own
|
|
387
|
+
total, `cumulative_token_usage`; in the test stores that was about a tenth of the total. A Zed
|
|
388
|
+
session's usage is now that total, as one per-session series (sessions-model §2.4 "No
|
|
389
|
+
overlap"), and no message carries usage. The log keeps the total as increments, so it still
|
|
390
|
+
only appends as a thread grows. Each increment is dated by the thread's save that first showed
|
|
391
|
+
it (Zed keeps no time per message or per request), so a thread memhouse reads late, or a
|
|
392
|
+
pre-release's thread re-derived after the update, has its whole total so far on the day of its
|
|
393
|
+
last save, not on the day of the read. A thread whose total is empty records no usage, even
|
|
394
|
+
when per-turn values exist: they are last-request snapshots, not a total.
|
|
395
|
+
- **Copilot CLI dropped usage that had no reply message.** A reply cut off by the output cap
|
|
396
|
+
leaves a `usage_record` and no `assistant.message`, and a compaction's own model call records
|
|
397
|
+
its tokens only on the compaction. Both are now usage rows of their own (keyed by the call's
|
|
398
|
+
`apiCallId`, or a short hash of it when it is VS Code's long opaque id, and
|
|
399
|
+
`compaction:<id>#1`), and so is a `usage_record` that has no `apiCallId` (keyed by its own
|
|
400
|
+
event id). A fork does not bill the ones it copied from its origin.
|
|
401
|
+
- **A Zed message this reader does not know no longer shifts the ids after it.** Zed's replies
|
|
402
|
+
have no ids of their own: each is the user message's id plus its position. An unknown entry
|
|
403
|
+
was skipped, so the replies after it took its position. It is now kept in its place as a
|
|
404
|
+
notice naming its kind (never its content), and an unknown part of a message is a notice too.
|
|
405
|
+
- **A Copilot CLI fork no longer claims its sibling.** A fork copies its origin's events,
|
|
406
|
+
including the origin's earlier "Forked this session into …" marker, which the fork read as a
|
|
407
|
+
fork of its own. Markers older than the session's own start are now the origin's history.
|
|
408
|
+
- A machine that ran a 0.20 pre-release re-derives its Zed and Copilot CLI sessions on its first
|
|
409
|
+
passes after the update: both normalisers' `VERSION` rose, so every session the editor still
|
|
410
|
+
holds is read again, and a changed log is re-derived at a higher rev. A session the editor has
|
|
411
|
+
since deleted keeps the rows it had: the archive holds the normalised log, not the editor's
|
|
412
|
+
store.
|
|
413
|
+
- `memhouse doctor` failed (exit 1) on an unpriced model alone, and told the reader to run
|
|
414
|
+
`memhouse update` even on the latest release, where update changes nothing and the gap stays.
|
|
415
|
+
An unpriced model is now a warning: doctor names `memhouse update` (and the release it would
|
|
416
|
+
install) only when a newer one exists, and otherwise says the cost stays unknown until a release
|
|
417
|
+
adds a price.
|
|
418
|
+
|
|
419
|
+
## Known issues
|
|
420
|
+
|
|
421
|
+
- **A session file deleted from disk before the move leaves no removed mark.** 0.18 recorded no
|
|
422
|
+
deletions and the conversion reads only rows, so such a session keeps its converted rows and
|
|
423
|
+
reads as current. A deletion after the switch is recorded when a capture sees it. See
|
|
424
|
+
[Upgrade to 0.20](../guides/upgrade-to-0.20.md#sessions-deleted-before-the-move).
|
|
425
|
+
- **A capture pass that stops before it records its read, and finds the source changed when it
|
|
426
|
+
runs again, leaves the stopped read in the archive.** The archive keeps every read, and nothing
|
|
427
|
+
marks a read as finished, so the stopped read's units stay in their own generation. The
|
|
428
|
+
current state is right, and so is a refold. Only a replay from the archive alone, pass by pass,
|
|
429
|
+
which rebuilds the removed versions, shows the stopped read's records as removed versions that
|
|
430
|
+
the live passes never wrote. It waits for harness-sessions-sql to define a commit mark for a read (its
|
|
431
|
+
spec question 20).
|
|
432
|
+
- **A session whose capture state is lost after its log was rewritten repeats its time-less
|
|
433
|
+
records.** memhouse dates a record that has no time of its own (every Zed message, for one)
|
|
434
|
+
when it first captures it, and keeps that date: it is part of the record's key in `turns`. If
|
|
435
|
+
the house loses the session's `files` row in `<db>_archive` and the machine loses its local
|
|
436
|
+
capture cache as well, memhouse reads the log again from the start and looks those dates up in
|
|
437
|
+
the archive by position. When the log was rewritten after it was first captured (a change to
|
|
438
|
+
its history, a rename), the positions have moved: the records get new dates and appear twice in
|
|
439
|
+
`turns`, once under each key. The session's own totals and counts are not affected, and Zed's
|
|
440
|
+
token increments, which carry the thread's own time, keep their keys.
|
|
441
|
+
- **An emptied store keeps doctor failing until it is confirmed.** On the profile layout, a store
|
|
442
|
+
whose every session the editor deleted is refused on every pass (see Capture), and doctor names
|
|
443
|
+
it, until `memhouse doctor --confirm-empty-store <editor>:<store>` is run. Its records are not
|
|
444
|
+
touched meanwhile. A replay from the archive alone into a house whose store lists nothing
|
|
445
|
+
rebuilds only the sessions whose sources were all recorded gone before; the others wait for
|
|
446
|
+
that confirmation too.
|
|
447
|
+
- **Deleted sessions of the normalised editors are not recorded as gone on the profile layout.**
|
|
448
|
+
The normaliser never deletes a session log, and a log missing from the list cannot be told from
|
|
449
|
+
one that cannot be read, so those stores are never swept: such a session's records stay current
|
|
450
|
+
and its archive replays its last read, which is what recording it gone (policy kept) would
|
|
451
|
+
give, without the event in the archive.
|
|
452
|
+
- **A house replaced under the same name is swept late.** A machine keeps, per store, what the
|
|
453
|
+
last pass listed, and asks the house what it holds only when a session goes missing from the
|
|
454
|
+
list or the last sweep left something pending. A house restored from its archive under the same
|
|
455
|
+
name, with the machine's capture state kept, has its vanished sessions recorded only once a
|
|
456
|
+
listed session next goes missing. Removing the folder `$MEMHOUSE_HOME/state/derive-profile/stores/`
|
|
457
|
+
(this machine's per-store sweep state) makes the next pass ask. It also holds any empty-store
|
|
458
|
+
confirmation not yet used (`*.confirm.json`, `*.confirm.claimed`): removing it drops those too,
|
|
459
|
+
and an emptied store has to be confirmed again. Do not remove its parent, which also holds each
|
|
460
|
+
session's capture state and would make every session be read again in full.
|
|
461
|
+
- **A replay takes at most 100 sessions a store per pass.** A replay from the archive alone of a
|
|
462
|
+
store with more sessions than its list names (sessions deleted since) rebuilds them over
|
|
463
|
+
several passes.
|
|
464
|
+
- **A vanished session's edges can wait.** When a session leaves its store and the pass's
|
|
465
|
+
budget defers its edge recompute, no later pass revisits it, because it is no longer listed:
|
|
466
|
+
its edges are recomputed when its origin's rows next change. This only happens when an
|
|
467
|
+
inferred-fork harness runs out of nomination budget in that pass.
|
|
468
|
+
- **Run one `memhouse import claude-ai` (import or undo) per member at a time.** They take no
|
|
469
|
+
lock. Two at once can:
|
|
470
|
+
- split a new conversation's rows between the two batches, since both write it at the same
|
|
471
|
+
`rev`. The read-back then disagrees, and undoing one batch removes part of the
|
|
472
|
+
conversation. Undo both batches and import again;
|
|
473
|
+
- record a batch's status wrong. An undo can be recorded `applied`: re-running it puts the
|
|
474
|
+
status right while any of its rows are still live, with partial counts; otherwise the batch
|
|
475
|
+
reads `applied` with no live sessions. An import still filling its sessions can be recorded
|
|
476
|
+
`applied` before it finishes: if it then stops, the next `--write` fills its rows.
|
|
477
|
+
- **Profile rows written before the schema step retyped their table keep their old values.**
|
|
478
|
+
The pre-release draft of harness-sessions-sql v1 changed three column types. The schema step
|
|
479
|
+
(`memhouse ship --ensure-schema`, which `memhouse update` runs) changes the types of an
|
|
480
|
+
existing profile table. It casts the stored values to the new types; it does not work them out
|
|
481
|
+
again:
|
|
482
|
+
- `adapter_ver` keeps the number that encodes the version, now as text (`1000002001` for
|
|
483
|
+
`0.2.1`). The capture compares it as that version; a query returns `1000002001`.
|
|
484
|
+
- `child_stored` stays `true` where the link did not say, until the link is written again.
|
|
485
|
+
- `orig_sha256` keeps the old empty value (64 zero bytes) where it would now be null.
|
|
486
|
+
|
|
487
|
+
Rows written afterwards carry the version string, and a null `child_stored` where no statement
|
|
488
|
+
says. The two `<db>_archive` tables are the exception: a member cannot change their types, so
|
|
489
|
+
the capture keeps writing them in the old types, and `--ensure-schema` says so, until an admin
|
|
490
|
+
runs, for member `<m>`:
|
|
491
|
+
|
|
492
|
+
```sql
|
|
493
|
+
ALTER TABLE <db>_archive.<m>_session_units MODIFY COLUMN adapter_ver LowCardinality(String), MODIFY COLUMN orig_sha256 Nullable(FixedString(64));
|
|
494
|
+
ALTER TABLE <db>_archive.<m>_session_units MODIFY COLUMN orig_sha256 REMOVE DEFAULT;
|
|
495
|
+
ALTER TABLE <db>_archive.<m>_session_sources MODIFY COLUMN adapter_ver LowCardinality(String);
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
The first pass under an adapter's next version re-derives each of its sessions (see Capture),
|
|
499
|
+
which writes the conversation rows again with the version string and a null `child_stored`
|
|
500
|
+
where no statement says. The archived units are never rewritten, and the cursor rows it writes
|
|
501
|
+
again keep the old number until an admin runs the statements above.
|
|
502
|
+
- **A session that moved to another adapter is not re-derived on a later upgrade.** A harness
|
|
503
|
+
whose sessions moved from one adapter to another (the log adapter's bridge rows, then a session
|
|
504
|
+
adapter's) leaves sessions that hold rows of both. On the new adapter's next version, such a
|
|
505
|
+
session is only refolded: its current records are written at the new version, and its removed
|
|
506
|
+
versions stay at the version that wrote them.
|
|
507
|
+
|
|
508
|
+
Differences between the in-repo normalisers and the harness-session-adapters package (sessions-model
|
|
509
|
+
v1.2), found by running both over the same stores. Each is retired when memhouse reads these
|
|
510
|
+
editors through that package, after 0.20.
|
|
511
|
+
|
|
512
|
+
- **Devin token totals exclude abandoned branches in 0.20.** The messages of a branch the user
|
|
513
|
+
reverted, and their usage, are not stored, so their tokens are not counted. The package keeps
|
|
514
|
+
them, flagged `on_active_branch: false`, and will count them.
|
|
515
|
+
- Copilot CLI: reasoning effort is never read; assistant messages carry an empty `effort`,
|
|
516
|
+
though the call's usage record has `reasoningEffort`.
|
|
517
|
+
- Copilot CLI: a tool result whose call is not in the session file is dropped. Gemini CLI keeps
|
|
518
|
+
such a result.
|
|
519
|
+
- Copilot CLI: encrypted reasoning (`encryptedContent`, written by VS Code's Copilot engine) is
|
|
520
|
+
not kept as an opaque reasoning part.
|
|
521
|
+
- VS Code: a tool call with no id of its own gets one built from the response's base id rather
|
|
522
|
+
than from the message that holds the call (sessions-model §1 rule 6). Only the call's key
|
|
523
|
+
differs.
|
|
524
|
+
- OpenCode: a URL cut to `scheme://host` carries no `<redacted len=N>` marker (sessions-model
|
|
525
|
+
§4.2). Nothing leaks either way.
|
|
526
|
+
- OpenCode v2: usage is read with basis `net`, where sessions-model §2.4 leaves both usage flags
|
|
527
|
+
unknown. No number changes while the reasoning count is zero.
|
|
528
|
+
- Optional fields left empty: the session `mode` (Devin, VS Code, Copilot CLI); the call that
|
|
529
|
+
started a sub-agent, on the parent's side of the link (agy, cursor-agent, Gemini CLI, Zed); and
|
|
530
|
+
`source: injected` on the file a Zed mention expands into.
|
|
531
|
+
|
|
532
|
+
## Deprecated
|
|
533
|
+
|
|
534
|
+
- **Passwords on the command line: `--password`, `--member-password`, `--to-password`.** They
|
|
535
|
+
still work, with a warning on every run, and are refused from the next minor release. Use
|
|
536
|
+
`MEMHOUSE_PASSWORD`, `MEMHOUSE_MEMBER_PASSWORD` or `MEMHOUSE_TO_PASSWORD`, or the new
|
|
537
|
+
`--password-file`, `--member-password-file` and `--to-password-file` (a file at mode 600,
|
|
538
|
+
or `-` for stdin). See [the admin password guide](../guides/admin-password.md).
|
|
539
|
+
- **`MEMHOUSE_USER` / `MEMHOUSE_PASSWORD` as the admin for `migrate --v3-*`.** They still work
|
|
540
|
+
when no admin variable is set, with a note on every run, and are not read for the admin steps
|
|
541
|
+
from the next minor release. Use `MEMHOUSE_ADMIN_USER` and `MEMHOUSE_ADMIN_PASSWORD`.
|
|
542
|
+
- **The 0.18 rooms layout.** 0.20 still writes it, for houses not yet converted. Its
|
|
543
|
+
removal version is not decided yet. New features are schema 3 only.
|
|
544
|
+
- **The 0.18 line:** 0.18 users who are not moving to 0.20 yet, upgrade to 0.18.12 or
|
|
545
|
+
later.
|
|
546
|
+
|
|
547
|
+
## Deferred
|
|
548
|
+
|
|
549
|
+
- `memhouse reset` and `relocate` on schema 3 (both refuse there).
|
|
550
|
+
- Moving the editor adapters to the shared harness-skeleton package. That comes after 0.20;
|
|
551
|
+
until then the in-repo readers take bug fixes only.
|
|
552
|
+
- A gentar suite for the 0.20 upgrade and the schema-3 install, and a phase-2 run on a
|
|
553
|
+
release candidate.
|
|
554
|
+
- A full fresh-stack restore of example 04 on 0.20. Only the archive's part was checked.
|
|
555
|
+
- Known follow-ups:
|
|
556
|
+
- an adapter upgrade re-emits rows at the same rev and relies on insertion order to win;
|
|
557
|
+
- `text_len` counts UTF-16 units, not code points;
|
|
558
|
+
- normaliser catch-alls for filesystem errors;
|
|
559
|
+
- Cursor sub-agent composer ids are still read from the session's first line.
|
|
560
|
+
|
|
561
|
+
## How this release was tested
|
|
562
|
+
|
|
563
|
+
- `npm test`: unit, v3 read and CLI, capture, dedupe, bridge, layout 3.2, the ten
|
|
564
|
+
normaliser suites, maintenance, no-credentials, and the sessions-model known-answer
|
|
565
|
+
vectors. CI runs it on ClickHouse 25.11 and 26.7, with the invite and
|
|
566
|
+
origin matrices and a headless e2e.
|
|
567
|
+
- `misc/v3-share-matrix.sh` (repository; in CI): what full, scoped, narrowed and revoked shares reach,
|
|
568
|
+
read with each person's own credential.
|
|
569
|
+
- `misc/upgrade-drill-0.20.sh` (repository), the upgrade drill (to be re-run on the release candidate; its
|
|
570
|
+
last full run predates the profile tables). It covers a 0.18.11
|
|
571
|
+
house with shares, and 0.20 install, join, fresh house and invites. It also covers grants the
|
|
572
|
+
move must refuse or leave alone: a schema-3 member's share, grants made by hand, a revoked
|
|
573
|
+
share that still holds a grant, a whole-database grant, and a colliding member name. It then
|
|
574
|
+
runs prepare, convert (including 0.18 OpenCode rows), reconcile, shares, switch and capture.
|
|
575
|
+
It ends with what each reader can see, doctor, search, `q removed`, and the known-answer
|
|
576
|
+
vectors on Linux.
|
|
577
|
+
- `misc/profile-lab/run-all.js` (repository) on a lab ClickHouse 26.7.4.58: twelve suites on the profile
|
|
578
|
+
capture engine, among them crashes and re-runs, resets, holds, forks billed once, the retype
|
|
579
|
+
of an older table to harness-sessions-sql v1's types, and an adapter upgrade's re-derive
|
|
580
|
+
against a twin captured by the new version.
|
|
581
|
+
- The harness-sessions-sql conformance kit (`misc/conformance/`, repository), kit v1 at harness-sessions-sql `96dcb3f`, on
|
|
582
|
+
ClickHouse: 22 pass, 2 not applicable to memhouse, and 1 fail, the crash-safe case of a
|
|
583
|
+
stopped read whose source changed before the re-run (Known issues).
|
|
584
|
+
- The four examples, run on a lab host against 0.20.0-dev.15. Each README quotes that run.
|
|
585
|
+
- The dev house has run the 0.20 dev builds since dev.1, capturing from
|
|
586
|
+
a maintainer's main machine.
|
|
587
|
+
- **Agent drill: owed.** The 0.18.11 notes promised a drill before the next minor
|
|
588
|
+
(`drills/DRILLS.md`, repository). It has not run for 0.20 yet. It must run,
|
|
589
|
+
or be explicitly waived, before this release is tagged.
|
|
590
|
+
|
|
591
|
+
## Not live-tested
|
|
592
|
+
|
|
593
|
+
What 0.20 has not yet done on a real house or machine:
|
|
594
|
+
|
|
595
|
+
- **Converting a real house end to end.**
|
|
596
|
+
- `--v3-prepare`, `--v3-shares` and `--v3-switch` have run only in the upgrade drill, on a
|
|
597
|
+
made-up house on a lab ClickHouse.
|
|
598
|
+
- `--v3-convert` has also run, during development, on a copy of a real member's data restored
|
|
599
|
+
from a backup.
|
|
600
|
+
- No production house has been converted yet (see [A house in daily use](#a-house-in-daily-use-is-converted-on-its-own-schedule)).
|
|
601
|
+
- **Moving real shares.** `--v3-shares` has met only the drill's made-up readers and the CI
|
|
602
|
+
matrix's. No house with real readers has been moved.
|
|
603
|
+
- **Upgrading a busy machine in place.** The drill upgrades a machine with two made-up Claude
|
|
604
|
+
Code sessions. A 0.18.11 machine shipping many editors has not been upgraded and switched.
|
|
605
|
+
- **The normalisers on real stores outside one Mac.** They read live editor stores only on a
|
|
606
|
+
maintainer's main machine (macOS), into the dev house. On Linux they ran against fixtures, and
|
|
607
|
+
Windows is untested: CI runs on Ubuntu only.
|
|
608
|
+
- **OpenCode channel databases** (`opencode-<channel>.db`, `OPENCODE_DB`): fixtures and the
|
|
609
|
+
conversion drill only. The machine that ran 0.20 has the default database alone.
|
|
610
|
+
- **ClickHouse Cloud.** The examples ran on a lab ClickHouse 26.7 and the self-hosted compose
|
|
611
|
+
stack.
|
|
612
|
+
- **Example 04's full restore** onto a fresh stack. Only the archive's part was checked on 0.20.
|
|
613
|
+
- **The colliding-names guard on every path.** It runs in install (as admin) and invite.
|
|
614
|
+
`--print-sql` prints the statements without checking, and `deploy --local` makes its single
|
|
615
|
+
member in a new house.
|
|
616
|
+
- **An agent drill** (`drills/DRILLS.md`, repository): owed, as said above.
|
|
617
|
+
- **gentar**: no 0.20 suite yet, and no bench run on a release candidate.
|
|
618
|
+
|
|
619
|
+
## Upgrade
|
|
620
|
+
|
|
621
|
+
```bash
|
|
622
|
+
memhouse update # 0.20; the house stays on the 0.18 rooms
|
|
623
|
+
memhouse status # every line a check mark
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
Then, once the admin has converted your member: `memhouse migrate --v3-switch`, `memhouse
|
|
627
|
+
stop && memhouse start`, and `memhouse doctor`.
|