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.
- package/AGENTS.md +10 -11
- package/CHANGELOG.md +28 -15
- package/SECURITY.md +4 -2
- package/bin/memhouse.js +6 -6
- package/docs/guides/admin-password.md +1 -1
- package/docs/guides/configuration.md +2 -2
- package/docs/guides/install.md +1 -1
- package/docs/guides/invite.md +1 -1
- package/docs/guides/storage.md +2 -2
- package/docs/releases/README.md +1 -0
- package/docs/releases/v0.18.10.md +7 -7
- package/docs/releases/v0.18.11.md +9 -13
- package/docs/releases/v0.18.12.md +59 -0
- package/docs/tutorials/01-first-house.md +2 -2
- package/editors/claude.js +3 -3
- package/editors/cursor-agent.js +1 -1
- package/examples/01-local-one-machine/README.md +4 -4
- package/examples/02-existing-clickhouse/README.md +7 -7
- package/memhouse/RESUME-AND-UPDATE.md +1 -1
- package/memhouse/capabilities.js +1 -1
- package/memhouse/convert.js +3 -3
- package/memhouse/delivery/PROMPT.md +1 -1
- package/memhouse/delivery/plugin/.claude-plugin/plugin.json +1 -1
- package/memhouse/delivery/plugin/reference/HOUSE.md +3 -3
- package/memhouse/delivery/plugin/skills/access/SKILL.md +1 -1
- package/memhouse/delivery/plugin/skills/admin/SKILL.md +2 -2
- package/memhouse/delivery/plugin/skills/house/SKILL.md +1 -1
- package/memhouse/delivery/plugin/skills/recall/SKILL.md +2 -2
- package/memhouse/delivery/plugin/skills/sql/SKILL.md +1 -1
- package/memhouse/house/HOUSE.md +5 -5
- package/memhouse/house/house.js +4 -4
- package/memhouse/self-update.js +1 -1
- package/memhouse/server/queries.js +2 -2
- package/package.json +3 -3
- 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,
|
|
7
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
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. (
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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 (`
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
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 (`
|
|
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
|
|
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
|
|
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 (`
|
|
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
|
|
68
|
-
|
|
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 (`
|
|
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
|
-
// (`
|
|
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` —
|
|
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
|
|
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 (`
|
|
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
|
-
// '
|
|
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:
|
|
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/
|
|
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/
|
|
46
|
+
MEMHOUSE_CLAUDE_ROOTS='~/.claude-playbooks/work-team'
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
- `MEMHOUSE_EDITORS` names the adapters to run.
|
package/docs/guides/install.md
CHANGED
|
@@ -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:
|
|
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
|
package/docs/guides/invite.md
CHANGED
|
@@ -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:
|
|
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
|
|
package/docs/guides/storage.md
CHANGED
|
@@ -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.
|
|
27
|
-
| a team on one server | `mem.
|
|
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.
|
package/docs/releases/README.md
CHANGED
|
@@ -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
|
|
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:
|
|
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
|
|
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 (
|
|
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
|
-
|
|
|
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
|
|
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
|
|
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
|
|
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
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
-
|
|
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
|
-
|
|
|
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:**
|
|
190
|
-
|
|
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 (`
|
|
45
|
-
Your rooms are `mem.
|
|
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.
|
|
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-
|
|
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
|
-
// (
|
|
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) {
|
package/editors/cursor-agent.js
CHANGED
|
@@ -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-
|
|
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 '
|
|
50
|
-
✓ rooms for '
|
|
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
|
|
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
|
-
|
|
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 '
|
|
78
|
-
✓ created ClickHouse user '
|
|
79
|
-
✓ granted '
|
|
80
|
-
✓ verified as '
|
|
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
|
-
✓
|
|
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
|
|
112
|
-
-- then each of mem.
|
|
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
|
|
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`
|
package/memhouse/capabilities.js
CHANGED
|
@@ -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
|
|
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.
|
package/memhouse/convert.js
CHANGED
|
@@ -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: `
|
|
4
|
-
// `
|
|
5
|
-
// as `mem.
|
|
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 — `
|
|
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.
|
|
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
|
|
77
|
-
alone — the room name must follow whitespace, and there is none inside `
|
|
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
|
|
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 `
|
|
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
|
|
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
|
package/memhouse/house/HOUSE.md
CHANGED
|
@@ -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
|
-
`
|
|
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.
|
|
8
|
-
for
|
|
9
|
-
reason. The grant is `GRANT … ON mem.
|
|
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 = '
|
|
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
|
package/memhouse/house/house.js
CHANGED
|
@@ -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.
|
|
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.
|
|
23
|
-
// a team on one server mem.
|
|
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.
|
|
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
|
*
|
package/memhouse/self-update.js
CHANGED
|
@@ -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
|
|
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).
|
|
482
|
-
// tunnel
|
|
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.
|
|
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
|
|
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.
|