memhouse 0.18.11 → 0.18.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/AGENTS.md +10 -11
  2. package/CHANGELOG.md +28 -15
  3. package/SECURITY.md +4 -2
  4. package/bin/memhouse.js +6 -6
  5. package/docs/guides/admin-password.md +1 -1
  6. package/docs/guides/configuration.md +2 -2
  7. package/docs/guides/install.md +1 -1
  8. package/docs/guides/invite.md +1 -1
  9. package/docs/guides/storage.md +2 -2
  10. package/docs/releases/README.md +1 -0
  11. package/docs/releases/v0.18.10.md +7 -7
  12. package/docs/releases/v0.18.11.md +9 -13
  13. package/docs/releases/v0.18.12.md +59 -0
  14. package/docs/tutorials/01-first-house.md +2 -2
  15. package/editors/claude.js +3 -3
  16. package/editors/cursor-agent.js +1 -1
  17. package/examples/01-local-one-machine/README.md +4 -4
  18. package/examples/02-existing-clickhouse/README.md +7 -7
  19. package/memhouse/RESUME-AND-UPDATE.md +1 -1
  20. package/memhouse/capabilities.js +1 -1
  21. package/memhouse/convert.js +3 -3
  22. package/memhouse/delivery/PROMPT.md +1 -1
  23. package/memhouse/delivery/plugin/.claude-plugin/plugin.json +1 -1
  24. package/memhouse/delivery/plugin/reference/HOUSE.md +3 -3
  25. package/memhouse/delivery/plugin/skills/access/SKILL.md +1 -1
  26. package/memhouse/delivery/plugin/skills/admin/SKILL.md +2 -2
  27. package/memhouse/delivery/plugin/skills/house/SKILL.md +1 -1
  28. package/memhouse/delivery/plugin/skills/recall/SKILL.md +2 -2
  29. package/memhouse/delivery/plugin/skills/sql/SKILL.md +1 -1
  30. package/memhouse/house/HOUSE.md +5 -5
  31. package/memhouse/house/house.js +4 -4
  32. package/memhouse/self-update.js +1 -1
  33. package/memhouse/server/queries.js +2 -2
  34. package/package.json +3 -3
  35. package/ui/README.md +16 -0
package/AGENTS.md CHANGED
@@ -3,18 +3,18 @@
3
3
  Conventions for any coding agent in this repository — Claude Code, Codex, Gemini CLI,
4
4
  OpenCode, whatever comes next. `CLAUDE.md` points here; this file is the canonical copy.
5
5
 
6
- Constellation-wide rules (worktrees, branch naming, never pushing to `ramazanpolat/*`)
7
- live in [`~/agent-realm/CLAUDE.md`](../CLAUDE.md) and are not repeated here.
6
+ Constellation-wide rules (worktrees, branch naming, which remotes are frozen) live in the
7
+ parent directory's [`CLAUDE.md`](../CLAUDE.md) and are not repeated here.
8
8
 
9
9
 
10
10
  ## Release lines — read before tagging, publishing, or merging a release
11
11
 
12
- memhouse shipped two lines while zeo ran the pre-0.18 layout. Since its conversion there
13
- is one line; the rules below are kept because a second line can happen again.
12
+ memhouse shipped two lines while the first production house ran the pre-0.18 layout. Since
13
+ its conversion there is one line; the rules below are kept because a second line can happen again.
14
14
 
15
15
  | line | git branch | npm dist-tag | versions | who installs it |
16
16
  |---|---|---|---|---|
17
- | the one line | `main` (default) | `latest`, and `team` as an alias | 0.18.x | everyone — `npm install -g memhouse` (zeo was converted to the one layout with `memhouse convert`; `release/0.17` is retired) |
17
+ | the 0.18 line | `release/0.18` (cut at v0.18.11; `main` stays the default branch) | `latest`, and `team` as an alias | 0.18.x | everyone — `npm install -g memhouse` (the production house was converted to the one layout with `memhouse convert`; `release/0.17` is retired) |
18
18
 
19
19
  Rules, each learned once:
20
20
 
@@ -28,18 +28,17 @@ Rules, each learned once:
28
28
  its own CHANGELOG entry, never assumed. The one-layout (0.18) renamed every room to
29
29
  `<member>_*`; anything touching room names ports with care (`house/HOUSE.md`).
30
30
  - **`memhouse update` follows the channel a machine was installed from** (`MEMHOUSE_CHANNEL`),
31
- so a zeo machine never receives a team build by accident, and vice versa.
31
+ so a machine on the old line never receives a team build by accident, and vice versa.
32
32
  - **`master` is retired.** It was the pre-0.18 default; `main` is the default now. Do not
33
33
  branch from it, tag on it, or push to it.
34
34
  - **A publish is live when `npm view` says so.** `npm publish` prints `+ memhouse@x.y.z`;
35
35
  confirm with `npm view memhouse dist-tags --prefer-online`. A version that seems missing
36
36
  right after a publish is registry lag or a stale local npm cache (`npm cache verify`),
37
37
  not a "staged" publish. That misdiagnosis cost three releases.
38
- - **Which token.** The pilot's publish token lives in the macOS keychain as `npmjs-token`
39
- (`~/.pilot-profile/online/npm.md` has the temp-userconfig recipe). Lend it to the one
40
- command; never print it.
41
- - **One owner per line at a time.** Before releasing, check `ListAgents`/herdr for another
42
- session on the same repo and agree who cuts it; the release record lives in `CHANGELOG.md`
38
+ - **Which token.** The publish token is a secret reference, resolved at the moment of use
39
+ and lent to the one `npm publish` (a temporary userconfig); never print it.
40
+ - **One owner per line at a time.** Before releasing, check for another
41
+ session working on the same repo and agree who cuts it; the release record lives in `CHANGELOG.md`
43
42
  on the line's branch and in `drills/`.
44
43
 
45
44
  ## What memhouse is
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ Versions before 0.8.0 were beta-only. Beta installs of 0.7.x and earlier should
4
4
  uninstall and reinstall — the 0.8.0 layout is new, and an in-place `update` +
5
5
  migration path is planned work, not a promise the old versions can cash.
6
6
 
7
+ ## 0.18.12 — 2026-10-29
8
+
9
+ Release notes: [`docs/releases/v0.18.12.md`](docs/releases/v0.18.12.md).
10
+
11
+ - **Skills:** each `/mem` skill's `allowed-tools` is restricted to the read-only memhouse
12
+ commands it teaches, instead of `Bash` as a whole. Any other command goes through the
13
+ normal permission prompt. `memhouse update` refreshes installed skills; then
14
+ `/reload-plugins`.
15
+ - `misc/skill-allowlist-test.js` and `misc/env-guard-test.js` join `npm test`. Test tooling
16
+ reads its deploy targets from an untracked `deploy/targets.env`, and fixtures use stand-ins.
17
+ - The 0.18 line is cut from `release/0.18`.
18
+ - No drill was run for this patch release.
19
+
7
20
  ## 0.18.11 — 2026-10-10
8
21
 
9
22
  Release notes: [`docs/releases/v0.18.11.md`](docs/releases/v0.18.11.md). Read its upgrade
@@ -14,7 +27,7 @@ subagents once.
14
27
  - **Security:** `invite` no longer sends a stored credential to `--url` (G4).
15
28
  - The 0.18.10 pre-tag list is finished, and the gentar kit is v0.9.3.
16
29
  - The dashboard ships the license notices of every package it bundles (`public/THIRD_PARTY_NOTICES.txt`).
17
- - **No drill was run for this release; waived (2026-10-08) under the pilot's 0.18.10 ruling. The drill runs before 0.19.0.**
30
+ - **No drill was run for this release; waived (2026-10-08) under the maintainer's 0.18.10 ruling. The drill runs before 0.19.0.**
18
31
 
19
32
  - **The dashboard now ships the license notices of what it bundles.** The built dashboard
20
33
  (`public/`) includes React, chart.js, lucide-react (ISC), react-markdown, the remark and
@@ -78,7 +91,7 @@ subagents once.
78
91
  earlier time than a sibling's, it moved ahead of it, renumbered every sibling after it,
79
92
  and the session forked and re-shipped whole. Now the shipper waits a pass (`held for one
80
93
  pass` in the log) and ranks it by its real start time. A file that never gets a
81
- timestamped line stops holding the session after 10 minutes. (GLM-F1)
94
+ timestamped line stops holding the session after 10 minutes. (SUB-1)
82
95
  - **An option that takes no value no longer swallows the next word.**
83
96
  - `memhouse update --no-install yes` set no-install to "yes", and ran the npm install it
84
97
  was told to skip.
@@ -138,7 +151,7 @@ changed, the upgrade steps, and the status of the 0.18.10 pre-tag list.
138
151
 
139
152
  - **A security release; everyone on 0.18.x should upgrade.** It covers G23 (#20), the admin
140
153
  password off argv (#14) and the scoped share boundary (#13).
141
- - **No drill was run for this release; waived by the pilot (2026-10-08). The drill runs before 0.19.0.**
154
+ - **No drill was run for this release; waived by the maintainer (2026-10-08). The drill runs before 0.19.0.**
142
155
  - **Moved to 0.18.11:** the subagent re-ship fix and the gentar kit v0.9.3 bump.
143
156
  - **Docs:** the repository now meets the documentation standard (#17): a short README,
144
157
  `docs/` tutorials and guides, `examples/`, and the `AGENTS.md` install section.
@@ -165,7 +178,7 @@ changed, the upgrade steps, and the status of the 0.18.10 pre-tag list.
165
178
  stdin), from `MEMHOUSE_ADMIN_PASSWORD` (so `with-secret` lends it to one command), from a
166
179
  credential this install already keeps for the same admin, or from a prompt. Before, giving
167
180
  `--admin-user` as a flag switched every other source off, so the only scriptable admin
168
- path put the password on argv, where `ps` and shell history keep it. Found by O's sandbox
181
+ path put the password on argv, where `ps` and shell history keep it. Found in a sandbox
169
182
  rehearsal. **Deprecation:** `--admin-password <value>` still works in this release, with a
170
183
  warning, and is **removed in 0.19.0**, the next minor release after this one (deprecated
171
184
  2026-10-08). Move scripts to `MEMHOUSE_ADMIN_PASSWORD` or `--admin-password-file`.
@@ -265,14 +278,14 @@ The upgrade path itself, and a machine that stays the same machine.
265
278
 
266
279
  ## 0.18.5 — 2026-09-18
267
280
 
268
- The first release on **one line**: published to `latest` and `team` alike. zeo was converted to the one layout the same evening with `memhouse convert` (six members, every row count identical before and after, shares carried).
281
+ The first release on **one line**: published to `latest` and `team` alike. The first production house was converted to the one layout the same evening with `memhouse convert` (six members, every row count identical before and after, shares carried).
269
282
 
270
- - **One release line.** With zeo converted to the one layout there is no 0.17 line to keep:
283
+ - **One release line.** With the production house converted to the one layout there is no 0.17 line to keep:
271
284
  `latest` now points at the same 0.18.x build as `team` (kept as an alias), the publish
272
285
  guard and `AGENTS.md` say so, and `release/0.17` is retired.
273
286
 
274
287
  - **`memhouse convert` — an operator moves a pre-one-layout house to the one layout.**
275
- Before 0.18 each member owned a database (`polat.messages`, `ALL ON polat.*`). `convert`
288
+ Before 0.18 each member owned a database (`sam.messages`, `ALL ON sam.*`). `convert`
276
289
  finds every such member, renames their five rooms into `mem.<name>_*` in one atomic
277
290
  statement (nothing copied), swaps the database-wide grant for the one wildcard, carries
278
291
  whole-house shares and row policies to the new names, drops the 0.17.1 refreshable
@@ -291,7 +304,7 @@ On the `team` channel. Found by the operator's own second machine on its first `
291
304
 
292
305
  - **`memhouse update` never crosses release lines on its own.** An unpinned 0.18.2 whose
293
306
  `team` tag had moved to 0.18.3 matched no tag, and the picker fell back to `latest` —
294
- zeo's 0.17.1, a different house layout. A real member was downgraded on her first update.
307
+ the 0.17 line's 0.17.1, a different house layout. A real member was downgraded on her first update.
295
308
  The picker now follows the tag on the install's own major.minor line, and when no tag is
296
309
  on that line, or the registry does not answer, it stops and says so; `--channel` is the
297
310
  only way across.
@@ -422,7 +435,7 @@ possible.
422
435
  every adapter is watching and the variable that changes it. A name or directory that
423
436
  does not exist is refused against that adapter, never shipped from the default instead.
424
437
 
425
- - **One layout.** Every member's rooms are named for them — `mem.polat_messages`,
438
+ - **One layout.** Every member's rooms are named for them — `mem.sam_messages`,
426
439
  `mem.alice_messages` — and one grant covers them: `GRANT … ON mem.<name>_* TO <name>
427
440
  WITH GRANT OPTION`. A wildcard on the member's own name, verified on 25.11 and 26.7: it
428
441
  lets the member create and rebuild their own rooms and share them, and reaches nothing
@@ -458,7 +471,7 @@ possible.
458
471
  (25.11, the default local tag).
459
472
 
460
473
  - **Bringing a housemate into a house you already own now works, and moves nothing.** A
461
- member alone in their own database holds `ALL ON polat.*`. That grant is **dynamic** —
474
+ member alone in their own database holds `ALL ON sam.*`. That grant is **dynamic** —
462
475
  it covers rooms created later — so a housemate's rooms would be readable *and
463
476
  droppable* by the owner the moment they existed (both measured). `invite` used to
464
477
  refuse and point at a migration command that did not exist.
@@ -574,7 +587,7 @@ possible.
574
587
  fourteen places, which names nothing in a house holding `alice_messages`. Rather than
575
588
  teach fourteen query sites about prefixes, the `q()` helper in `reference/HOUSE.md` —
576
589
  the single connection every skill routes through — now rewrites room names after
577
- `FROM`/`JOIN`. A needle like `LIKE '%messages%'` is untouched, and `FROM yigit_messages`
590
+ `FROM`/`JOIN`. A needle like `LIKE '%messages%'` is untouched, and `FROM bob_messages`
578
591
  is left alone so a shared room still reads.
579
592
 
580
593
  Written with `[[:space:]]` classes, not `\b`: **BSD `sed` does not support `\b`**, and
@@ -823,7 +836,7 @@ possible.
823
836
 
824
837
  - **The skills no longer fall back to a hardcoded `mem` house.** A house is a database
825
838
  named for its owner — `resolveConfig` defaults `MEMHOUSE_DB` to the connection's
826
- username (`polat` ships into `polat.messages`), and `memhouse invite` mints a per-user
839
+ username (`sam` ships into `sam.messages`), and `memhouse invite` mints a per-user
827
840
  database. But the plugin skills hardcoded `${MEMHOUSE_DB:-mem}` in their connection
828
841
  recipes, so a config missing `MEMHOUSE_DB` would silently query a `mem` house that the
829
842
  user-named convention had moved on from. All eight skills now fall back to
@@ -858,10 +871,10 @@ possible.
858
871
  - **Read a friend's shared memory by naming their house.** A share is a read-only GRANT on
859
872
  a whole house (a ClickHouse database), and the rooms resolve by the connection's
860
873
  database — so `/mem:ask`, `/mem:search` and `/mem:sql` now recognize a house named in the
861
- question ("how did yigit fix X", "search … in yigit", "query yigit's house"), resolve it
874
+ question ("how did bob fix X", "search … in bob", "query bob's house"), resolve it
862
875
  against `SHOW DATABASES`, and point the connection at that house with your own
863
876
  credentials, read-only. A name that matches a readable house wins over the `in <project>`
864
- qualifier — otherwise "in yigit" silently filtered your own project column and returned
877
+ qualifier — otherwise "in bob" silently filtered your own project column and returned
865
878
  nothing. `/mem:hello` now names the phrase, and `/mem:users` still lists the houses shared
866
879
  with you.
867
880
 
@@ -1042,7 +1055,7 @@ now the whole install.
1042
1055
  stamp cannot be skipped) and `host` (a random fingerprint minted once per install).
1043
1056
  - **Joining any ClickHouse is two statements**: `CREATE USER` + `GRANT ALL ON <house>.*`.
1044
1057
  The member's own shipper creates and evolves the rooms.
1045
- - The house name defaults to the username (`polat` ships to `polat.messages`) and is
1058
+ - The house name defaults to the username (`sam` ships to `sam.messages`) and is
1046
1059
  freely decoupled (`--db`); `system` and `information_schema` are refused everywhere —
1047
1060
  previously `--db system` granted a member everything on the server's own database.
1048
1061
  - Removed: per-member suffixed rooms, Merge rooms, the narrowed grant set,
package/SECURITY.md CHANGED
@@ -64,5 +64,7 @@ makes the security model short, and worth stating without varnish.
64
64
 
65
65
  ## Reporting
66
66
 
67
- The repository is private during beta. Report security issues to the maintainer
68
- directly (ramazanpolat@gmail.com) rather than in a public channel.
67
+ The repository is private during beta. Report a security issue privately, never in a
68
+ public issue or channel: once the repository is public, through GitHub's private
69
+ vulnerability reporting (the **Security** tab, **Report a vulnerability**); until then,
70
+ to the maintainer through the channel that gave you access.
package/bin/memhouse.js CHANGED
@@ -80,7 +80,7 @@ function resolveConfig() {
80
80
  url: pick('url', 'MEMHOUSE_URL', 'http://localhost:8123'),
81
81
  user: pick('user', 'MEMHOUSE_USER', 'memhouse_root'),
82
82
  password: pick('password', 'MEMHOUSE_PASSWORD', ''),
83
- // The house defaults to the USER'S OWN NAME (`polat` ships into `polat.messages`),
83
+ // The house defaults to the USER'S OWN NAME (`sam` ships into `sam.messages`),
84
84
  // because a house is a database and the natural first house is your own. Any name
85
85
  // works — user 'alice' with house 'default' is a supported pairing.
86
86
  // ONE house name unless somebody has a reason. The member's rooms are named for them
@@ -770,7 +770,7 @@ function printLocalHouseOffer(engines) {
770
770
  // The ClickHouse user IS the identity; rooms are named for whatever the server answers
771
771
  // to currentUser(). The home directory only produces a SUGGESTION, and a suggestion that
772
772
  // had to be changed is printed rather than applied quietly — sanitizing collides
773
- // (`ramazan.polat` and `ramazan-polat` both land on `ramazan_polat`), so the human has to
773
+ // (`jane.doe` and `jane-doe` both land on `jane_doe`), so the human has to
774
774
  // see it.
775
775
  function suggestMember() {
776
776
  const base = path.basename(os.homedir() || '');
@@ -1087,7 +1087,7 @@ async function cmdInstall({ interactive }) {
1087
1087
  for (const k of wanted) process.env[k] = parsed[k];
1088
1088
  // The invite also carries what the inviter's house is ON: its channel (a `team` house
1089
1089
  // is 0.18.x, published under `team`). Dropping it wrote an env with no pin, and the
1090
- // member's first `memhouse update` followed `latest` — zeo's 0.17 line — and
1090
+ // member's first `memhouse update` followed `latest` — then the 0.17 line — and
1091
1091
  // downgraded a working team install onto the wrong layout. A flag still wins.
1092
1092
  for (const k of ['MEMHOUSE_CHANNEL', 'MEMHOUSE_EDITORS', 'MEMHOUSE_CLAUDE_ROOTS']) if (parsed[k]) process.env[k] = parsed[k];
1093
1093
  console.log(ok(`using the invite file ${String(flags.env)} (nothing persisted until the install proves out)`));
@@ -2500,7 +2500,7 @@ async function cmdUpdate() {
2500
2500
  // Every Claude Code instance on this machine, not just the default one.
2501
2501
  //
2502
2502
  // A pilot rarely has one. `~/.claude` is the stock install, `CLAUDE_CONFIG_DIR` points at
2503
- // whichever they are running right now, and Kommander-style playbooks live under
2503
+ // whichever they are running right now, and playbook installs live under
2504
2504
  // `~/.claude-playbooks/<name>[/playbook]`, each a complete config directory with its own
2505
2505
  // skills/. Installing into one and calling it done leaves /mem:recall missing from
2506
2506
  // every other instance the pilot uses — silently, because a missing skill does not announce
@@ -4612,7 +4612,7 @@ async function cmdUninstall() {
4612
4612
  process.exitCode = 2; break;
4613
4613
  }
4614
4614
  // Who owns this house. A local deploy is the pilot's own machine and their own
4615
- // memory, so the house user is THEM — suggested from the OS username (`polat`, not
4615
+ // memory, so the house user is THEM — suggested from the OS username (`sam`, not
4616
4616
  // `memhouse_root`) — created by the container itself at first init with full
4617
4617
  // rights. No admin/member split, no provisioning dance: a URI and a credential is
4618
4618
  // the whole install. The name is fixed at volume init exactly like the password,
@@ -4673,7 +4673,7 @@ async function cmdUninstall() {
4673
4673
  // STATED sources only, then the house user. priorCfg.db is unusable here: resolveConfig
4674
4674
  // computes a DEFAULT for it (the user's name, itself defaulted), so going through it
4675
4675
  // handed a fresh deploy `memhouse_root` as the house name while the superuser was
4676
- // 'polat' — the memory would live in a database named after a role account nobody
4676
+ // 'sam' — the memory would live in a database named after a role account nobody
4677
4677
  // chose.
4678
4678
  const targetDb = flags.db || process.env.MEMHOUSE_DB || readEnvFile().MEMHOUSE_DB || 'mem';
4679
4679
  // Same check install runs, but EARLY — deploy initialises the container volume and
@@ -40,7 +40,7 @@ options. It never hangs, and it never guesses.
40
40
  The best form: the value exists only in the one command's environment.
41
41
 
42
42
  ```bash
43
- with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:pilot/house-admin -- \
43
+ with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:house-admin -- \
44
44
  memhouse invite alice --url https://house.example.com --admin-user default
45
45
 
46
46
  # 1Password
@@ -33,7 +33,7 @@ it:
33
33
 
34
34
  ```
35
35
  Watched directories (override with the variable shown, in the env file):
36
- claude ~/.claude, ~/.claude-playbooks/kommander, … [MEMHOUSE_CLAUDE_ROOTS]
36
+ claude ~/.claude, ~/.claude-playbooks/work, … [MEMHOUSE_CLAUDE_ROOTS]
37
37
  codex ~/.codex [MEMHOUSE_CODEX_ROOTS]
38
38
  gemini-cli ~/.gemini [MEMHOUSE_GEMINI_CLI_ROOTS]
39
39
  cursor ~/Library/Application Support/Cursor/User, … [built-in]
@@ -43,7 +43,7 @@ Two kinds of line in the env file narrow it, or `--editors` / `--claude-roots` a
43
43
 
44
44
  ```
45
45
  MEMHOUSE_EDITORS='claude'
46
- MEMHOUSE_CLAUDE_ROOTS='~/.claude-playbooks/kommander-chaos'
46
+ MEMHOUSE_CLAUDE_ROOTS='~/.claude-playbooks/work-team'
47
47
  ```
48
48
 
49
49
  - `MEMHOUSE_EDITORS` names the adapters to run.
@@ -64,7 +64,7 @@ MEMHOUSE_PASSWORD=… memhouse install --url https://house.example.com --user al
64
64
  memhouse install --env invite-alice.env
65
65
 
66
66
  # you hold the server's admin: memhouse creates the member, then ships as the member
67
- with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:pilot/house-admin -- \
67
+ with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:house-admin -- \
68
68
  memhouse install --url https://house.example.com --admin-user default --member alice
69
69
 
70
70
  # you hold nothing: print the SQL for whoever administers the server
@@ -33,7 +33,7 @@ memhouse invite alice --url https://house.example.com
33
33
  `--admin-password-file`, or from a prompt.
34
34
 
35
35
  ```bash
36
- with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:pilot/house-admin -- \
36
+ with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:house-admin -- \
37
37
  memhouse invite alice --url https://house.example.com --admin-user default
38
38
  ```
39
39
 
@@ -23,8 +23,8 @@ database once leaked into each other. A member can read their isolation back wit
23
23
 
24
24
  | | rooms | each member holds |
25
25
  |---|---|---|
26
- | alone on a laptop | `mem.polat_*` | one grant on `mem.polat_*` |
27
- | a team on one server | `mem.polat_*`, `mem.alice_*`, … | one grant each, on their own |
26
+ | alone on a laptop | `mem.sam_*` | one grant on `mem.sam_*` |
27
+ | a team on one server | `mem.sam_*`, `mem.alice_*`, … | one grant each, on their own |
28
28
 
29
29
  Reading across members is a `UNION ALL` over the rooms you hold: your own, and any shared
30
30
  with you. Naming a room you were not granted is an error, never a silent omission.
@@ -5,6 +5,7 @@ do, how to upgrade, what is deprecated and when it goes, and what was deferred.
5
5
 
6
6
  | version | date | headline |
7
7
  |---|---|---|
8
+ | [0.18.12](v0.18.12.md) | 2026-10-29 | skills: allowed tools restricted to read-only commands |
8
9
  | [0.18.11](v0.18.11.md) | 2026-10-10 | sessions with subagents stop re-shipping; security: no stored credential sent to `invite --url` |
9
10
  | [0.18.10](v0.18.10.md) | 2026-10-08 | security: the admin password never on argv; no member password printed; a scoped share reaches only its scope |
10
11
 
@@ -8,7 +8,7 @@ A security release:
8
8
 
9
9
  Everyone on 0.18.x should upgrade.
10
10
 
11
- **No drill was run for this release; waived by the pilot (2026-10-08). The drill runs before 0.19.0.**
11
+ **No drill was run for this release; waived by the maintainer (2026-10-08). The drill runs before 0.19.0.**
12
12
 
13
13
  ```bash
14
14
  memhouse update # or: npm install -g memhouse@latest, then memhouse update --no-install
@@ -34,14 +34,14 @@ The admin-assisted commands (`install --member`, `invite`, `passwd`, `convert`,
34
34
  5. a prompt, when there is a terminal to prompt on.
35
35
 
36
36
  ```bash
37
- with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:pilot/house-admin -- \
37
+ with-secret MEMHOUSE_ADMIN_PASSWORD=keychain:house-admin -- \
38
38
  memhouse invite alice --url https://house.example.com --admin-user default
39
39
  printf '%s' "$ADMIN_PASSWORD" | memhouse invite alice --url … --admin-user default --admin-password-file -
40
40
  ```
41
41
 
42
42
  Before this release, `--admin-user` as a flag switched every other source off. The only
43
43
  scriptable admin path therefore put the password on argv, where `ps` shows it for as long
44
- as the command runs and shell history keeps it. Found by O's sandbox rehearsal (finding 6).
44
+ as the command runs and shell history keeps it. Found in a sandbox rehearsal (finding 6).
45
45
  With no source and no terminal, the command stops and prints the three ways above instead
46
46
  of hanging or guessing.
47
47
 
@@ -179,7 +179,7 @@ before release by four models. Three said "ship with fixes"; the fourth said "do
179
179
  mostly for pre-existing issues. Its pre-tag fixes are not all done, and this release was
180
180
  not held for them.
181
181
 
182
- Status of the 0.18.10 pre-tag list (`review-0.18.10-consolidated`):
182
+ Status of the 0.18.10 pre-tag list (the consolidated pre-tag review):
183
183
 
184
184
  | item | what | status |
185
185
  |---|---|---|
@@ -197,7 +197,7 @@ Status of the 0.18.10 pre-tag list (`review-0.18.10-consolidated`):
197
197
  | G4 | `invite --url` connects with the stored credential to the invitee-facing URL | deferred to 0.18.11 (security) |
198
198
  | G26 | skills point at `../reference/HOUSE.md`; the file is `../../reference/HOUSE.md` | deferred to 0.18.11 |
199
199
  | G11 | an idle house's dashboard goes empty after the stats TTL | deferred to 0.18.11 |
200
- | GLM-F1 | a subagent file read before its first line is written re-sorts its siblings | deferred to 0.18.11 (with the RC) |
200
+ | SUB-1 | a subagent file read before its first line is written re-sorts its siblings | deferred to 0.18.11 (with the RC) |
201
201
 
202
202
  ## Documentation
203
203
 
@@ -219,8 +219,8 @@ every tag and what it changed.
219
219
  - CI is green on `main` at the release commit: the syntax gate, unit tests, the
220
220
  one-layout and invite matrices, and a headless e2e on ClickHouse 25.11 and 26.7.
221
221
  - No live house was touched to prepare this release.
222
- - **No drill was run for this release; waived by the pilot (2026-10-08). The drill runs before 0.19.0.**
222
+ - **No drill was run for this release; waived by the maintainer (2026-10-08). The drill runs before 0.19.0.**
223
223
  `AGENTS.md` asks for a drill before a release that changes a surface a person touches,
224
224
  and this one changes install, invite and share. A drill was prepared on the testbed, but
225
- its setup was refused by this session's permission layer, and the pilot chose to release
225
+ its setup could not run in the release environment, and the maintainer chose to release
226
226
  without it.
@@ -9,7 +9,7 @@ This release does three things:
9
9
  typed on the command line.
10
10
  - **The 0.18.10 pre-tag list is finished**, and the gentar test kit is bumped.
11
11
 
12
- **No drill was run for this release; waived (2026-10-08) under the pilot's 0.18.10 ruling. The drill runs before 0.19.0.**
12
+ **No drill was run for this release; waived (2026-10-08) under the maintainer's 0.18.10 ruling. The drill runs before 0.19.0.**
13
13
 
14
14
  ## Read this before upgrading
15
15
 
@@ -27,13 +27,10 @@ rows. Two things widen that first pass:
27
27
 
28
28
  **Where that write lands, and when to do it (2026-10-08):**
29
29
 
30
- - The pilot's machines (macminim, macbokum) ship to **zeo.memhouse.io**: VM 146 on arf,
31
- ClickHouse 26.7.4.58.
32
- - It is **not** LXC 112 "memhouse-production"; that is an archive, not a live house.
33
- - zeo's data disk still sits on arf's degraded array. It was backed up to SSD on
34
- 2026-10-08 (data and access storage), but the disk itself has not moved.
35
- - **Upgrade those machines only once zeo's data disk is off the degraded array, or once
36
- the array is repaired. Time it against the SSD moves.**
30
+ - Upgrade together any installs that ship the same session files (above).
31
+ - A house whose data disk sits on degraded storage: back it up first (data and access
32
+ storage), and upgrade its machines only once the disk is off the degraded array or the
33
+ array is repaired.
37
34
  - Any house on healthy storage can upgrade normally.
38
35
 
39
36
  ```bash
@@ -78,7 +75,7 @@ Measured on a real house:
78
75
 
79
76
  - 1.07 M message rows written in 24 h, against 10.2 M in total;
80
77
  - one 6,120-line session stored 60 times in a day;
81
- - polat's house at about 19 M message rows for roughly 295 k real ones.
78
+ - one member's house at about 19 M message rows for roughly 295 k real ones.
82
79
 
83
80
  What changed:
84
81
 
@@ -175,7 +172,7 @@ Earlier published packages carried those copies without the notices.
175
172
  | G4 `invite --url` and stored credentials (**security**) | #22 |
176
173
  | G26 skills' reference path | #22 |
177
174
  | G11 idle house's dashboard | #22 |
178
- | GLM-F1 unstamped subagent file | #21 |
175
+ | SUB-1 unstamped subagent file | #21 |
179
176
 
180
177
  ## Verification
181
178
 
@@ -186,6 +183,5 @@ Earlier published packages carried those copies without the notices.
186
183
  - skill recipe 18/18;
187
184
  - invite 58/58;
188
185
  - one-layout 62/62.
189
- - **Second looks:** agy (gemini-3.8-flash-high) on #21 and #22. Codex was at its daily
190
- quota.
191
- - **Labs:** kept light, because arf's RAID is degraded. No live house was touched.
186
+ - **Second looks:** a second model reviewed #21 and #22.
187
+ - **Labs:** kept light, because the lab host's RAID was degraded. No live house was touched.
@@ -0,0 +1,59 @@
1
+ # memhouse 0.18.12 — 2026-10-29
2
+
3
+ A patch release on the 0.18 line. It does one thing for users:
4
+
5
+ - **The `/mem` skills pre-approve read-only commands only.** Each skill's `allowed-tools`
6
+ now lists the memhouse read commands it teaches, instead of `Bash` as a whole.
7
+
8
+ No drill was run for this patch release. Its one user-facing change is held by
9
+ `misc/skill-allowlist-test.js`, which runs in `npm test`.
10
+
11
+ ## Upgrade
12
+
13
+ ```bash
14
+ memhouse update # refreshes the /mem skills wherever they are installed
15
+ ```
16
+
17
+ Then reload the skills in Claude Code with `/reload-plugins`, or restart the session.
18
+
19
+ If you upgraded with `npm install -g memhouse` instead, run `memhouse plugins install claude`
20
+ once, so the installed skills match the package.
21
+
22
+ Nothing else changes: same house layout, same schema, same daemons.
23
+
24
+ ## Changed
25
+
26
+ ### Skills: allowed tools restricted to read-only commands
27
+
28
+ Each `/mem` skill's `allowed-tools` names the memhouse read commands it uses:
29
+
30
+ | skill | runs without a prompt |
31
+ |---|---|
32
+ | `/mem:house` | `memhouse instance`, `whoami`, `status`, `stats`, `doctor`, and `share --list` (with or without `--json`) |
33
+ | `/mem:recall` | `memhouse search`, `resume`, `sessions-query`, `status`, `whoami` |
34
+ | `/mem:sql` | `memhouse sessions-query`, `stats`, `status`, `whoami` |
35
+ | `/mem:access` | `memhouse whoami`, `status`, and `share --list` (with or without `--json`) |
36
+ | `/mem:admin` | `memhouse whoami`, `status`, `instance` |
37
+
38
+ Any other command goes through Claude Code's normal permission prompt, as does a read
39
+ command with another command chained to it. Expect a prompt where a skill used to run a
40
+ command without one; approve it as you would any other command.
41
+
42
+ ## Repository and tests
43
+
44
+ These do not change the installed package's behaviour:
45
+
46
+ - `misc/skill-allowlist-test.js` keeps every skill's `allowed-tools` to read-only memhouse
47
+ commands. It joins `npm test`.
48
+ - The test tooling's deploy targets (lab address, test machine, engine checkout) are read
49
+ from an untracked `deploy/targets.env`. `deploy/targets.example.env` shows the shape.
50
+ - Test fixtures, examples, drill records and docs use stand-in names, hosts and paths.
51
+ `misc/env-guard-test.js` checks tracked files for real environment values, and it joins
52
+ `npm test`.
53
+ - Security reports go through GitHub's private vulnerability reporting (`SECURITY.md`).
54
+ - The 0.18 line is now cut from the `release/0.18` branch. `AGENTS.md` and
55
+ `misc/publish-guard.js` say so.
56
+
57
+ ## Deferred
58
+
59
+ Nothing new. Later work ships on the current line's next release.
@@ -41,8 +41,8 @@ This does four things:
41
41
  1. It starts ClickHouse in a container bound to `127.0.0.1:8123`, so only this machine
42
42
  can reach it. The data lives in a named volume.
43
43
  2. It creates two users. `memhouse_root` administers the house. A **member** named after
44
- your OS user (`polat`, say) ships your sessions, and holds one grant: `mem.polat_*`.
45
- Your rooms are `mem.polat_sessions`, `mem.polat_messages`, `mem.polat_tool_calls`, and
44
+ your OS user (`sam`, say) ships your sessions, and holds one grant: `mem.sam_*`.
45
+ Your rooms are `mem.sam_sessions`, `mem.sam_messages`, `mem.sam_tool_calls`, and
46
46
  so on.
47
47
  3. It writes both credentials to `~/.memhouse/env`, mode 600. A local house is the one
48
48
  case where the admin credential is kept, so that `memhouse invite` works later with
package/editors/claude.js CHANGED
@@ -7,7 +7,7 @@ const HOME = os.homedir();
7
7
 
8
8
  // Discover all Claude Code config roots — ports memory-house agent-sync's
9
9
  // discover_roots("claude-code"). Claude sessions don't live only under ~/.claude:
10
- // every CLAUDE_CONFIG_DIR (e.g. Kommander playbook installs under
10
+ // every CLAUDE_CONFIG_DIR (e.g. playbook installs under
11
11
  // ~/.claude-playbooks/<name>[/playbook]) has its own projects/ dir. A dir qualifies
12
12
  // as a root if it holds a projects/ subdir or a history.jsonl. Deduped by realpath.
13
13
  function discoverClaudeRoots() {
@@ -60,7 +60,7 @@ function getChats() {
60
60
  const dir = path.join(PROJECTS_DIR, projDir);
61
61
  try { if (!fs.statSync(dir).isDirectory()) continue; } catch { continue; }
62
62
 
63
- // Decode folder path from dir name (e.g. -Users-fka-Code-foo -> /Users/fka/Code/foo)
63
+ // Decode folder path from dir name (e.g. -Users-user-Code-foo -> /Users/user/Code/foo)
64
64
  const decodedFolder = projDir.replace(/-/g, '/');
65
65
 
66
66
  // Read sessions-index.json for indexed sessions
@@ -293,7 +293,7 @@ function getMessages(chat) {
293
293
  // A subagent caught before its first line is written has no start time, so it ranks
294
294
  // last — and when its first line lands with an EARLIER timestamp than a sibling's, it
295
295
  // moves, renumbers every sibling after it, and the session forks and re-ships whole
296
- // (GLM-F1). So a fresh one defers the whole session to the next pass, when it has a
296
+ // (SUB-1). So a fresh one defers the whole session to the next pass, when it has a
297
297
  // time. Bounded by age: a file that never gets a timestamped line stops deferring after
298
298
  // SUBAGENT_STAMP_GRACE_MS and ranks last, as before.
299
299
  if (info.firstTs === undefined && !unstamped) {
@@ -13,7 +13,7 @@ const name = 'cursor-agent';
13
13
 
14
14
  /**
15
15
  * Decode project directory name back to folder path.
16
- * e.g. "Users-fka-Code-Wapple" → "/Users/fka/Code/Wapple"
16
+ * e.g. "Users-user-Code-myapp" → "/Users/user/Code/myapp"
17
17
  */
18
18
  function decodeProjectDir(dirName) {
19
19
  // The encoding replaces "/" with "-". We reconstruct by prepending "/"
@@ -46,8 +46,8 @@ Trimmed from a run on a Linux VM with Docker, ClickHouse 26.7 and memhouse 0.18.
46
46
  == 1. a house: ClickHouse in a container, bound to loopback, plus the install
47
47
  ✓ ClickHouse starting via docker on http://localhost:8123 (loopback only)
48
48
  ✓ ClickHouse ready
49
- ✓ member 'polat' holds mem.polat_* and nothing else; 'memhouse_root' administers the house
50
- ✓ rooms for 'polat': polat_sessions, polat_messages, polat_tool_calls
49
+ ✓ member 'sam' holds mem.sam_* and nothing else; 'memhouse_root' administers the house
50
+ ✓ rooms for 'sam': sam_sessions, sam_messages, sam_tool_calls
51
51
  ✓ installed
52
52
  ✓ shipper started in the background (pid 617049) — loading your history now
53
53
 
@@ -55,10 +55,10 @@ Trimmed from a run on a Linux VM with Docker, ClickHouse 26.7 and memhouse 0.18.
55
55
  [memhouse] shipped 2 sessions (0 skipped) → 6 msg rows, 2 tool rows in 0.7s
56
56
 
57
57
  == 3. what the house holds
58
- ✓ connected: http://localhost:8123 / mem as polat
58
+ ✓ connected: http://localhost:8123 / mem as sam
59
59
  ✓ house: 2 sessions, 6 messages (freshest ingest 2026-10-07 21:08:06 UTC)
60
60
  ✓ fleet: 1 active writer(s)
61
- polat@testbed-7edeca38 0.18.9 last ship 0m ago
61
+ sam@linux-vm-1f2e3d4c 0.18.9 last ship 0m ago
62
62
  ✓ shipper: running — daemon (pid 617049)
63
63
 
64
64
  == 4. find a past conversation
@@ -74,10 +74,10 @@ Trimmed from a run against ClickHouse 26.7.1.1315 with memhouse 0.18.9 (the test
74
74
  credential from: MEMHOUSE_ADMIN_* environment
75
75
  may create users: yes
76
76
 
77
- == 2. install: build member 'polat' with the admin credential, then verify as the member
78
- ✓ created ClickHouse user 'polat'
79
- ✓ granted 'polat' mem.polat_* — their rooms and nothing else; async_insert pinned
80
- ✓ verified as 'polat' with the member credential
77
+ == 2. install: build member 'sam' with the admin credential, then verify as the member
78
+ ✓ created ClickHouse user 'sam'
79
+ ✓ granted 'sam' mem.sam_* — their rooms and nothing else; async_insert pinned
80
+ ✓ verified as 'sam' with the member credential
81
81
  ✓ installed
82
82
  the admin credential was used for this install and not saved. To invite later:
83
83
  with-secret MEMHOUSE_ADMIN_PASSWORD=<reference> -- memhouse invite <name> --url … --admin-user admin
@@ -87,7 +87,7 @@ Trimmed from a run against ClickHouse 26.7.1.1315 with memhouse 0.18.9 (the test
87
87
  [memhouse] shipped 2 sessions (0 skipped) → 6 msg rows, 2 tool rows in 0.2s
88
88
 
89
89
  == 4. whoami: the credential this machine keeps, and what it may do
90
- ✓ polat at https://ch.example.com:8443 — member
90
+ ✓ sam at https://ch.example.com:8443 — member
91
91
  may create users: no
92
92
 
93
93
  == 5. status
@@ -108,8 +108,8 @@ Deletes the example's home. The member and its rooms stay in the house: dropping
108
108
  an administrator's decision. As the admin:
109
109
 
110
110
  ```sql
111
- DROP USER polat;
112
- -- then each of mem.polat_sessions, _messages, _tool_calls, _meta, _events,
111
+ DROP USER sam;
112
+ -- then each of mem.sam_sessions, _messages, _tool_calls, _meta, _events,
113
113
  -- _session_stats, _session_model_stats, _session_tool_stats
114
114
  ```
115
115
 
@@ -136,7 +136,7 @@ the supervisor's own restart line.
136
136
  ### The gap
137
137
 
138
138
  Nothing tells a running daemon that its files were replaced. `status` prints the version of
139
- the CLI you just typed, not the version the daemon is executing. On macminim a shipper ran
139
+ the CLI you just typed, not the version the daemon is executing. On one machine a shipper ran
140
140
  **1d16h** out of a directory that had been moved.
141
141
 
142
142
  ### Why not `postinstall`
@@ -9,7 +9,7 @@
9
9
  //
10
10
  // SCOPE IS THE WHOLE POINT. A grant is `GRANT <privileges> ON <scope> TO <user>`, and a
11
11
  // privilege only means what its scope allows: an ordinary member holds CREATE DATABASE
12
- // inside `ON polat.*`, which lets them do nothing whatsoever about creating a NEW
12
+ // inside `ON sam.*`, which lets them do nothing whatsoever about creating a NEW
13
13
  // database. Matching the privilege name anywhere in the text — which an earlier draft of
14
14
  // this did — reads that member as a server administrator. So parse the line, keep the
15
15
  // scope, and only count a privilege that is granted server-wide.
@@ -1,8 +1,8 @@
1
1
  // Convert a pre-one-layout house to the one layout — the plan, as SQL, pure.
2
2
  //
3
- // Before 0.18 every member owned a DATABASE named for them: `polat.messages`,
4
- // `polat.house_meta`, granted ALL ON polat.*. The one layout puts everyone in one database
5
- // as `mem.polat_messages`, `mem.polat_meta`, with one wildcard grant and nothing on the
3
+ // Before 0.18 every member owned a DATABASE named for them: `sam.messages`,
4
+ // `sam.house_meta`, granted ALL ON sam.*. The one layout puts everyone in one database
5
+ // as `mem.sam_messages`, `mem.sam_meta`, with one wildcard grant and nothing on the
6
6
  // database itself. Moving is a RENAME per table — metadata only, nothing copied — plus the
7
7
  // grant swap, and shares re-expressed on the new names. The 0.17.1 dashboard views are
8
8
  // dropped: in the one layout the shipper fills the stat tables (a refreshable view needs
@@ -79,6 +79,6 @@ the retained epochs are the only place that content still exists.
79
79
  when the user may want to dig deeper.
80
80
  - Other users' HOUSES (other databases on the same server) are readable only when
81
81
  shared with this credential (`/mem:access` on their side). Query a shared house by
82
- qualified names — `polat.messages` — with the same CUR filter. An empty result
82
+ qualified names — `sam.messages` — with the same CUR filter. An empty result
83
83
  means "nothing visible", not "nothing ever happened".
84
84
  - Do not paste credentials from `{{ENV_FILE}}` into responses, commits, or logs.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mem",
3
3
  "description": "Conversation memory for AI agents over the memhouse typed ClickHouse store: recall past sessions and answer from them, run analytics, check the house, bring people in, and administer the server. Skills install as /mem:recall, /mem:sql, /mem:house, /mem:access, and /mem:admin.",
4
- "version": "0.18.11",
4
+ "version": "0.18.12",
5
5
  "author": {
6
6
  "name": "Ramazan Polat"
7
7
  },
@@ -73,8 +73,8 @@ server, not by discipline.
73
73
 
74
74
  **The `sed` is what makes every query below work in both layouts** — write room names
75
75
  bare and it supplies the prefix when there is one. It rewrites only after `FROM`/`JOIN`,
76
- so a needle like `LIKE '%messages%'` is untouched, and `FROM yigit_messages` is left
77
- alone — the room name must follow whitespace, and there is none inside `yigit_messages`.
76
+ so a needle like `LIKE '%messages%'` is untouched, and `FROM bob_messages` is left
77
+ alone — the room name must follow whitespace, and there is none inside `bob_messages`.
78
78
  With no prefix set it expands to nothing and the query passes through verbatim.
79
79
 
80
80
  It is spelled with `[[:space:]]` classes rather than `\b` because **BSD `sed` does not
@@ -84,7 +84,7 @@ which is the right way round — but it fails.
84
84
 
85
85
  **Reading a housemate's memory.** A share is `GRANT SELECT ON mem.<them>_*` — their
86
86
  rooms, not the database. `SHOW TABLES` lists exactly what you may read: your own rooms plus
87
- any shared with you. Name a housemate's rooms in full (`FROM yigit_messages`); the `q()`
87
+ any shared with you. Name a housemate's rooms in full (`FROM bob_messages`); the `q()`
88
88
  rewrite leaves an already-prefixed name alone, since applying yours would point at the
89
89
  wrong rooms. Say whose memory an answer came from.
90
90
 
@@ -3,7 +3,7 @@ name: access
3
3
  description: Bring someone onto this memhouse ClickHouse, or let them read your house — mint a new member with their own house and the env file their install needs, grant a housemate read-only access to yours, list who can currently read it, or revoke. Use when the user says "invite X", "add X to memhouse", "get my friend set up", "share my memory with X", "let X see my sessions", "who can read my memory", "stop sharing with X". Inviting comes BEFORE sharing — you can only grant a user who already exists. Read-only by construction on the sharing side: a share can never let anyone write to or delete your memory.
4
4
  user-invocable: true
5
5
  argument-hint: "invite <name> | share <name> | list | revoke <name>"
6
- allowed-tools: Bash
6
+ allowed-tools: Bash(memhouse whoami *), Bash(memhouse status *), Bash(memhouse share --list), Bash(memhouse share --list --json)
7
7
  ---
8
8
 
9
9
  # /mem:access — who exists, and who may read
@@ -3,7 +3,7 @@ name: admin
3
3
  description: Operate the memhouse ClickHouse as its administrator — list and inspect every user and house, provision or remove members, grant and revoke access, and read server-wide health (disk, parts, mutations, running queries). Use when the user asks to "do X as admin", "manage users", "drop a house", "see disk usage", "who is on this server", or when a member-scoped skill refused for want of privileges. Requires an administrator credential in the environment; says so plainly, and how to supply one, when there is not.
4
4
  user-invocable: true
5
5
  argument-hint: "<what you want done>"
6
- allowed-tools: Bash
6
+ allowed-tools: Bash(memhouse whoami *), Bash(memhouse status *), Bash(memhouse instance *)
7
7
  ---
8
8
 
9
9
  # /mem:admin — operate the house as its administrator
@@ -128,7 +128,7 @@ Before any of them:
128
128
 
129
129
  1. **Look at the target and report what is really there** — row counts per room, who
130
130
  wrote them, the date span, which machines. A house you expected to be empty may not
131
- be: one `ege` house looked disposable and held 3,733 messages belonging to somebody
131
+ be: one `carol` house looked disposable and held 3,733 messages belonging to somebody
132
132
  else entirely.
133
133
  2. **Name the collateral.** Dropping a user stops that account's shipper on every machine
134
134
  it runs on. Revoking a grant closes a share someone may be mid-query on. Rotating a
@@ -3,7 +3,7 @@ name: house
3
3
  description: The state of your memory and who is around it — what memhouse is and how to use it, whether shipping is working, what the house holds (sessions, messages, tokens per editor), how fresh it is, which machines write into it, which houses you can read, and who can read yours. Use for "what is memhouse", "how do I use this", "is my memory working", "how much is stored", "when did it last ship", "which machines are shipping", "who can see my memory", "whose memory can I see", "who else is on this server" — and as the first answer when another /mem skill fails because nothing is configured yet, or before debugging why a search found nothing.
4
4
  user-invocable: true
5
5
  argument-hint: ""
6
- allowed-tools: Bash
6
+ allowed-tools: Bash(memhouse instance *), Bash(memhouse whoami *), Bash(memhouse status *), Bash(memhouse stats *), Bash(memhouse doctor *), Bash(memhouse share --list), Bash(memhouse share --list --json)
7
7
  ---
8
8
 
9
9
  # /mem:house — what this is, whether it works, and who is around it
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: recall
3
- description: Retrieve from past agent conversations and answer from them — search every session ever shipped from all 17 editors (Claude Code, Codex, Cursor, VS Code, Zed, Gemini CLI, …) across every project and machine, read the actual transcripts, and answer with citations. Use whenever the user refers to something not in the current context - "how did I fix X last time", "what approach did we settle on", "why did we choose Z", "find that conversation about Y", "did I ever try W", "what was I working on", "show my recent sessions", "sessions from last week", "remind me how I did it". Reach for this BEFORE saying you do not know about prior work. Also reads a housemate's memory when they name it ("how did yigit fix X"). For numbers rather than transcripts — spend, model mix, tool rankings — use /mem:sql.
3
+ description: Retrieve from past agent conversations and answer from them — search every session ever shipped from all 17 editors (Claude Code, Codex, Cursor, VS Code, Zed, Gemini CLI, …) across every project and machine, read the actual transcripts, and answer with citations. Use whenever the user refers to something not in the current context - "how did I fix X last time", "what approach did we settle on", "why did we choose Z", "find that conversation about Y", "did I ever try W", "what was I working on", "show my recent sessions", "sessions from last week", "remind me how I did it". Reach for this BEFORE saying you do not know about prior work. Also reads a housemate's memory when they name it ("how did bob fix X"). For numbers rather than transcripts — spend, model mix, tool rankings — use /mem:sql.
4
4
  user-invocable: true
5
5
  argument-hint: "<question, terms, or 'recent sessions'>"
6
- allowed-tools: Bash
6
+ allowed-tools: Bash(memhouse search *), Bash(memhouse resume *), Bash(memhouse sessions-query *), Bash(memhouse status *), Bash(memhouse whoami *)
7
7
  ---
8
8
 
9
9
  # /mem:recall — find it, read it, answer from it
@@ -3,7 +3,7 @@ name: sql
3
3
  description: Run read-only SQL over memhouse conversation memory for numbers rather than transcripts — token spend, cost by model or editor or project, tool-call rankings, activity over time, busiest days, cache-hit ratios, session length distributions, or any custom aggregate across the typed sessions/messages/tool_calls tables. Use when the user wants a figure, a ranking, a trend or a breakdown - "what did I spend on Opus", "which tools do I use most", "how many sessions per project", "my busiest week", "compare editors". For finding or answering FROM past conversations, use /mem:recall instead. Works over your own house, or a housemate's when they name it.
4
4
  user-invocable: true
5
5
  argument-hint: "<the question, or the SQL>"
6
- allowed-tools: Bash
6
+ allowed-tools: Bash(memhouse sessions-query *), Bash(memhouse stats *), Bash(memhouse status *), Bash(memhouse whoami *)
7
7
  ---
8
8
 
9
9
  # /mem:sql — analytics over the rooms
@@ -1,12 +1,12 @@
1
1
  # The house — a database, and the rooms in it
2
2
 
3
3
  **A house is a ClickHouse database.** Any database, named whatever its people name it —
4
- `polat`, `team_a`, even `default`. Its rooms are tables: `sessions`, `messages`,
4
+ `sam`, `team_a`, even `default`. Its rooms are tables: `sessions`, `messages`,
5
5
  `tool_calls`. No views, no Merge rooms, no settings profile.
6
6
 
7
- **Every member's rooms are named for them, and one grant covers them.** `mem.polat_*`
8
- for polat, `mem.alice_*` for alice, in the same database — `mem` unless somebody has a
9
- reason. The grant is `GRANT … ON mem.polat_* TO polat WITH GRANT OPTION`: it lets the
7
+ **Every member's rooms are named for them, and one grant covers them.** `mem.sam_*`
8
+ for sam, `mem.alice_*` for alice, in the same database — `mem` unless somebody has a
9
+ reason. The grant is `GRANT … ON mem.sam_* TO sam WITH GRANT OPTION`: it lets the
10
10
  member create and rebuild their own rooms, share them, and reach nothing else. Nobody is
11
11
  granted the database itself. A house with one member is a house of one, not a different
12
12
  kind of house — a colleague joins as one more member and nothing about the first changes.
@@ -19,7 +19,7 @@ Two columns say where every row came from:
19
19
  | `user_id` | who wrote it | `String MATERIALIZED currentUser()` — stamped by the server, unforgeable by clients. `async_insert = 0 CONST` is pinned on each user (`ADD SETTING`, which merges — a bare `SETTINGS` clause replaces the user's whole list) because an async flush stores the stamp as the empty string (measured on 25.11.9.34) |
20
20
  | `host` | which machine | the machine's fingerprint (`../host.js`) — derived from the OS machine id (random only where none can be read), so two machines with the same hostname cannot collide and renaming one cannot split its history |
21
21
 
22
- `WHERE user_id = 'alice'` is one person. `WHERE host = 'macbook-4127a95b'` is one
22
+ `WHERE user_id = 'alice'` is one person. `WHERE host = 'my-laptop-1f2e3d4c'` is one
23
23
  machine. No filter is the whole house — which is what a team dashboard wants.
24
24
 
25
25
  ## Joining a house
@@ -14,13 +14,13 @@
14
14
  // That pair IS the provenance model.
15
15
  //
16
16
  // ONE LAYOUT. A house is a database — `mem` unless somebody has a reason — and every
17
- // member's rooms in it carry the member's name: `mem.alice_messages`, `mem.polat_messages`.
17
+ // member's rooms in it carry the member's name: `mem.alice_messages`, `mem.sam_messages`.
18
18
  // A member holds one grant, on the wildcard `mem.<name>_*`, and nothing else in the
19
19
  // database. That is the whole access model, and roomNames() below is the only place a
20
20
  // table name is produced.
21
21
  //
22
- // alone on a laptop mem.polat_* a house of one
23
- // a team on one server mem.polat_*, mem.alice_*
22
+ // alone on a laptop mem.sam_* a house of one
23
+ // a team on one server mem.sam_*, mem.alice_*
24
24
  // an agency on a kernel the same, in the kernel's `mem`
25
25
  //
26
26
  // Nobody ever holds ALL ON <db>.*. That grant is dynamic — it covers rooms created later —
@@ -460,7 +460,7 @@ const READ_SETTINGS = { final: 1, join_use_nulls: 1 };
460
460
  * The table a room type lands in. THE naming rule, and the only copy of it.
461
461
  *
462
462
  * ONE LAYOUT. Every member's rooms carry the member's own name: `mem.alice_messages`,
463
- * and `mem.polat_messages` even when polat is the only one in there. A house with one
463
+ * and `mem.sam_messages` even when sam is the only one in there. A house with one
464
464
  * member is a house of one, not a different kind of house — so there is no second case
465
465
  * here, no prefix to configure, and nothing for an invite file to carry.
466
466
  *
@@ -3,7 +3,7 @@
3
3
  // `npm i -g memhouse@latest` replaces the files under the global prefix and does not touch
4
4
  // the running processes, so the shipper keeps parsing with the old adapters and the
5
5
  // dashboard keeps serving the old bundle. Nothing reports it: `status` prints the version
6
- // of the CLI you just typed, not the version the daemon is running. On macminim a shipper
6
+ // of the CLI you just typed, not the version the daemon is running. On one machine a shipper
7
7
  // ran 1d16h out of a directory that had been MOVED — the fix was live, the machine was not.
8
8
  //
9
9
  // npm's own `postinstall` is the obvious hook and the wrong one. npm >= 12 blocks install
@@ -478,8 +478,8 @@ async function getChats(opts = {}) {
478
478
  // per call, three endpoints calling it — and getChats used ~4% of what it asked for.
479
479
  // In CHUNKS. The scope travels as `{scopeIds:Array(String)}` query parameters, and the
480
480
  // driver puts query parameters in the REQUEST URI — so a page of N sessions builds a URI
481
- // of roughly 60 bytes per id, twice (ids and users). Zeo is reached through a Cloudflare
482
- // tunnel, which rejects a URI far below ClickHouse's own 1 MiB `http_max_uri_size`: at
481
+ // of roughly 60 bytes per id, twice (ids and users). A house reached through a Cloudflare
482
+ // tunnel sits behind a proxy that rejects a URI far below ClickHouse's own 1 MiB `http_max_uri_size`: at
483
483
  // 925 sessions the request came back 500 with an EMPTY message (the driver reports a
484
484
  // transport-level refusal as `new Error('')`), so `/api/chats?limit=1000` — exactly what
485
485
  // the Sessions page asks for — returned 500 and the page rendered blank. 900 worked,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memhouse",
3
- "version": "0.18.11",
3
+ "version": "0.18.12",
4
4
  "description": "memhouse \u2014 agent conversation memory across 17 editors: parse-on-client shippers, a typed ClickHouse store with one set of rooms per member, kernel-agency install, and the agentlytics dashboard",
5
5
  "main": "bin/memhouse.js",
6
6
  "bin": {
@@ -34,7 +34,7 @@
34
34
  "start": "node bin/memhouse.js",
35
35
  "build": "cd ui && npm install && npm run build",
36
36
  "dev": "cd ui && npm run dev",
37
- "test": "node misc/syntax-check.js && node misc/unit-test.js",
37
+ "test": "node misc/syntax-check.js && node misc/unit-test.js && node misc/env-guard-test.js && node misc/skill-allowlist-test.js",
38
38
  "test:house": "node misc/house-test.js",
39
39
  "prepack": "cd ui && npm install --no-audit --no-fund && npm run build",
40
40
  "prepublishOnly": "node misc/publish-guard.js"
@@ -50,7 +50,7 @@
50
50
  "analytics",
51
51
  "memhouse"
52
52
  ],
53
- "author": "Ramazan Polat <ramazanpolat@gmail.com> (built on agentlytics by fkadev)",
53
+ "author": "Ramazan Polat (built on agentlytics by fkadev)",
54
54
  "license": "MIT",
55
55
  "engines": {
56
56
  "node": ">=24.0.0"
package/ui/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # React + Vite
2
+
3
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
+
5
+ Currently, two official plugins are available:
6
+
7
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9
+
10
+ ## React Compiler
11
+
12
+ The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
13
+
14
+ ## Expanding the ESLint configuration
15
+
16
+ If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.