memhouse 0.17.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -30
- package/bin/memhouse.js +555 -202
- package/editors/antigravity.js +2 -0
- package/editors/claude.js +3 -1
- package/editors/codebuff.js +2 -0
- package/editors/codex.js +4 -1
- package/editors/commandcode.js +2 -1
- package/editors/copilot-jetbrains.js +2 -1
- package/editors/copilot.js +2 -1
- package/editors/cursor-agent.js +2 -1
- package/editors/cursor.js +2 -0
- package/editors/gemini.js +2 -1
- package/editors/goose.js +2 -1
- package/editors/index.js +8 -1
- package/editors/kiro.js +3 -2
- package/editors/opencode.js +2 -1
- package/editors/scope.js +126 -0
- package/editors/vscode.js +2 -0
- package/editors/zed.js +2 -1
- package/memhouse/DESIGN.md +31 -8
- package/memhouse/binding.js +81 -0
- package/memhouse/channel.js +50 -0
- package/memhouse/delivery/AGENT-INSTALL-PROMPT.md +2 -1
- package/memhouse/delivery/AGENT-INSTALL.md +1 -1
- package/memhouse/delivery/INVITATION.md.tpl +147 -0
- package/memhouse/delivery/PROMPT.md +6 -5
- package/memhouse/delivery/kernel-install.md +4 -2
- package/memhouse/delivery/plugin/.claude-plugin/plugin.json +1 -1
- package/memhouse/delivery/plugin/reference/HOUSE.md +38 -12
- package/memhouse/delivery/plugin/skills/access/SKILL.md +9 -9
- package/memhouse/delivery/plugin/skills/admin/SKILL.md +1 -1
- package/memhouse/delivery/plugin/skills/house/SKILL.md +18 -2
- package/memhouse/flags.js +5 -4
- package/memhouse/house/HOUSE.md +25 -11
- package/memhouse/house/house.js +110 -27
- package/memhouse/house/migrate.js +7 -6
- package/memhouse/house/relocate.js +2 -2
- package/memhouse/house/schema.sql.tpl +3 -3
- package/memhouse/invitefile.js +38 -0
- package/memhouse/provision.js +100 -0
- package/memhouse/shipper/ship.js +87 -28
- package/package.json +1 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# You have been invited to a memhouse
|
|
2
|
+
|
|
3
|
+
{{INVITER}} set up a **house** — a ClickHouse database where a team keeps its coding-agent
|
|
4
|
+
memory — and made you a member of it. This page walks you from the file you were sent to a
|
|
5
|
+
working install, and shows what you get.
|
|
6
|
+
|
|
7
|
+
You received two things:
|
|
8
|
+
|
|
9
|
+
| file | what it is |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `{{FILE}}` | **your credential**, in this same folder. One-time: install consumes it and deletes it. Treat it like a password until then. |
|
|
12
|
+
| this page | the steps. Nothing secret in here. |
|
|
13
|
+
|
|
14
|
+
Do it yourself, or hand this page to your coding agent. From the directory holding both
|
|
15
|
+
files:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
claude "Read MEMHOUSE-INVITATION.md and follow it. Ask me before each step that changes this machine."
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Any agent that can run shell commands works the same way; the rules it must keep are at
|
|
22
|
+
the end of this page.
|
|
23
|
+
|
|
24
|
+
## 0. Find your credential
|
|
25
|
+
|
|
26
|
+
The install needs `{{FILE}}`, which was sent alongside this page. Confirm it is here first —
|
|
27
|
+
run this from the same directory, and if it prints the filename you are ready:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
ls invite-*.env
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If it is missing, it did not travel with this page; get it from whoever invited you before
|
|
34
|
+
going on. Do not print its contents — the last line of it is a password.
|
|
35
|
+
|
|
36
|
+
## 1. Install memhouse
|
|
37
|
+
|
|
38
|
+
{{INSTALL}}
|
|
39
|
+
|
|
40
|
+
On most Linux distros the global install needs `sudo`; if `npm` says `EACCES`, that is why.
|
|
41
|
+
`memhouse --version` should print `{{VERSION}}`.
|
|
42
|
+
|
|
43
|
+
## 2. Join the house
|
|
44
|
+
|
|
45
|
+
From the directory holding `{{FILE}}`, just run memhouse — it finds the invitation and asks:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
memhouse
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
(or, without the question: `memhouse install --env {{FILE}}`)
|
|
52
|
+
|
|
53
|
+
What that does, in order: connects to `{{URL}}` as `{{NAME}}`, **rotates your password to
|
|
54
|
+
one only your machine knows**, creates your rooms, writes your config to `~/.memhouse/env`,
|
|
55
|
+
deletes `{{FILE}}`, and starts shipping in the background. The password in the file stops
|
|
56
|
+
working the moment install finishes, so a copy left in a chat is dead.
|
|
57
|
+
|
|
58
|
+
## 3. Check it is working
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
memhouse status # your rooms, how much is in them, the shipper's pulse
|
|
62
|
+
memhouse doctor # every line a check mark = healthy
|
|
63
|
+
memhouse discover # what this machine ships, and where each editor's sessions were found
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`memhouse status` shows a session count that grows for a few minutes on a machine with
|
|
67
|
+
history; the first pass ships everything you have. After that it ships new turns as they
|
|
68
|
+
happen.
|
|
69
|
+
|
|
70
|
+
## 4. What you own, and who can see it
|
|
71
|
+
|
|
72
|
+
Your memory lives in five tables named for you inside `{{DB}}` — `{{DB}}.{{NAME}}_messages`,
|
|
73
|
+
`{{DB}}.{{NAME}}_sessions`, `{{DB}}.{{NAME}}_tool_calls` and two bookkeeping tables — and you
|
|
74
|
+
hold exactly one grant, on `{{DB}}.{{NAME}}_*`. Housemates cannot read your rooms, list
|
|
75
|
+
them, or grant them to anyone; you cannot read theirs. `memhouse whoami --json` reads that
|
|
76
|
+
grant back from the server. What can always see everything is the account that administers
|
|
77
|
+
the ClickHouse, which is {{INVITER}}'s — the same as any database you use at work.
|
|
78
|
+
|
|
79
|
+
Everything your editors write to disk ships verbatim: prompts, replies, tool calls and their
|
|
80
|
+
arguments, including anything an agent ever pasted into a session. The house is as
|
|
81
|
+
sensitive as your shell history. If some of your work should not go there, say so before
|
|
82
|
+
shipping — see "which sessions ship" below.
|
|
83
|
+
|
|
84
|
+
## 5. Things to try
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
memhouse search "the error you fixed last week"
|
|
88
|
+
memhouse resume <session-id> # prints the command that reopens that session
|
|
89
|
+
memhouse plugins install claude # /mem:recall, /mem:sql, /mem:house, /mem:access, /mem:admin
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Then, inside Claude Code:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
/mem:recall how did I set up the ClickHouse tunnel
|
|
96
|
+
/mem:sql what did I spend on Opus this month
|
|
97
|
+
/mem:house
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Sharing is yours to give and take back, no operator involved:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
memhouse share <housemate> everything you own
|
|
104
|
+
memhouse share <housemate> --only project=<name> one project
|
|
105
|
+
memhouse share --list
|
|
106
|
+
memhouse share <housemate> --revoke
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Which sessions ship
|
|
110
|
+
|
|
111
|
+
Everything memhouse finds on the machine — every supported editor, every Claude Code
|
|
112
|
+
config directory. `memhouse discover` lists what it found and the variable that narrows
|
|
113
|
+
each one. Two lines in `~/.memhouse/env` are the common case:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
MEMHOUSE_EDITORS='claude'
|
|
117
|
+
MEMHOUSE_CLAUDE_ROOTS='~/.claude-playbooks/<the one instance you mean>'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## If something refuses
|
|
121
|
+
|
|
122
|
+
Every refusal says what to do next. The two you might meet: `EACCES` on install means
|
|
123
|
+
`sudo`, and `needed rights this credential does not hold` means the grant on the server is
|
|
124
|
+
narrower than the one memhouse issues — ask {{INVITER}} to run `memhouse install --print-sql
|
|
125
|
+
--member {{NAME}}` and apply what it prints.
|
|
126
|
+
|
|
127
|
+
## For an agent following this page
|
|
128
|
+
|
|
129
|
+
You are installing memhouse for the person who handed you this file. Five rules; three of
|
|
130
|
+
them exist because an agent broke them:
|
|
131
|
+
|
|
132
|
+
0. **Your credential is `{{FILE}}` in the directory this page is in.** If `Read
|
|
133
|
+
MEMHOUSE-INVITATION.md` is all you were given, `ls invite-*.env` beside it is the file
|
|
134
|
+
the steps refer to; confirm it is there before step 1.
|
|
135
|
+
1. **Never print `{{FILE}}` or any `MEMHOUSE_*` value.** No `cat`, no `echo $MEMHOUSE_PASSWORD`,
|
|
136
|
+
no `set -x`. This very session will be shipped into the house; a password printed here is
|
|
137
|
+
a password archived.
|
|
138
|
+
2. **Run the commands as written, in order.** Do not substitute `CREATE USER`, `GRANT` or any
|
|
139
|
+
SQL of your own; there is nothing to fix on the server from this side.
|
|
140
|
+
3. **Ask before `memhouse install --env`.** It rotates the credential, deletes `{{FILE}}`,
|
|
141
|
+
and starts shipping this machine's transcripts. The person decides when that happens.
|
|
142
|
+
4. **A ✗ line is the end of that step, not an invitation to work around it.** Read the line
|
|
143
|
+
after it — every refusal names its remedy — do that or report it. `sudo` for `EACCES` is
|
|
144
|
+
the one you may apply yourself.
|
|
145
|
+
5. **Report what `memhouse status` and `memhouse doctor` say**, verbatim, when you are done.
|
|
146
|
+
A green install is those two commands, not your summary of them.
|
|
147
|
+
|
|
@@ -36,11 +36,12 @@ FIRST. Only say you don't know after a search comes back empty.
|
|
|
36
36
|
|
|
37
37
|
Without skills, query directly.
|
|
38
38
|
|
|
39
|
-
**Table names.** The
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
**Table names.** The rooms are `messages`, `sessions`, `tool_calls` in the connection's
|
|
40
|
+
database — unless this is a shared house, where they carry the member's own prefix
|
|
41
|
+
(`alice_messages`). `memhouse rooms` prints what yours are actually called; a bare
|
|
42
|
+
`FROM messages` is not a table you have in a shared house. `user_id` (server-stamped)
|
|
43
|
+
says whose row it is and `host` says which machine. To read across several members, UNION ALL over the rooms you hold — naming a room
|
|
44
|
+
you do not hold is an error rather than a silent omission. **There is no `sessions_v` object** — the rollup is a saved query, and
|
|
44
45
|
`memhouse sessions-query` prints it ready to drop into a `FROM (...) AS c`.
|
|
45
46
|
|
|
46
47
|
**One session can be stored more than once.** The shipper never deletes: when an editor
|
|
@@ -80,8 +80,10 @@ user so the stamp cannot be skipped). Her machines are told apart by `host`.
|
|
|
80
80
|
**A house is shared by its housemates.** The tables are common; `user_id` and `host` say
|
|
81
81
|
who wrote what, and `WHERE user_id = 'alice'` is one person. The boundary is the
|
|
82
82
|
DATABASE: a member of `mem` holds nothing on any other database, so two agencies on one
|
|
83
|
-
kernel ClickHouse cannot read each other.
|
|
84
|
-
|
|
83
|
+
kernel ClickHouse cannot read each other. WITHIN a house, members hold their own rooms
|
|
84
|
+
and nothing else — housemates are isolated from each other by grant, not by trust, and
|
|
85
|
+
each can verify it with `SHOW GRANTS`. A separate house remains the boundary between
|
|
86
|
+
groups that should not know of each other at all.
|
|
85
87
|
|
|
86
88
|
Row policies are still the only way to share a *subset* of rows, which is owner-mediated
|
|
87
89
|
and documented in `SHARING.md` — they are not how isolation works.
|
|
@@ -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.
|
|
4
|
+
"version": "0.18.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ramazan Polat"
|
|
7
7
|
},
|
|
@@ -8,13 +8,20 @@ or wrong everywhere.
|
|
|
8
8
|
|
|
9
9
|
## What this is
|
|
10
10
|
|
|
11
|
-
A **house** is a ClickHouse **database
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
A **house** is a ClickHouse **database** — on the user's machine, their server, or a
|
|
12
|
+
hosted ClickHouse; memhouse runs no service of its own. Its **rooms** are tables —
|
|
13
|
+
`sessions`, `messages`, `tool_calls` — and the server stamps who wrote every row. A
|
|
14
|
+
house's grants reach nothing outside it.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Every member's rooms are named for them — `mem.alice_messages`, `mem.alice_sessions`,
|
|
17
|
+
`mem.alice_tool_calls` — and one grant covers exactly those: `ON mem.alice_*`. Housemates
|
|
18
|
+
keep their own rooms beside yours and cannot read them, list them, or grant them onward;
|
|
19
|
+
you cannot read theirs. `SHOW GRANTS` shows you the one line you hold. **A bare
|
|
20
|
+
`FROM messages` names nothing you have** — the `q()` below prefixes room names with your
|
|
21
|
+
member name for you, and `memhouse rooms` prints what yours are called.
|
|
22
|
+
|
|
23
|
+
An **operator** owns the ClickHouse itself; an **admin credential** is what proves it.
|
|
24
|
+
`memhouse whoami` says which you are holding.
|
|
18
25
|
|
|
19
26
|
Rows arrive from a **shipper** that parses local transcripts from 17 editors. It only
|
|
20
27
|
ever inserts. Nothing in memhouse runs an LLM over your data — these skills retrieve
|
|
@@ -29,6 +36,13 @@ rows, and *you* read them.
|
|
|
29
36
|
memhouse ships back into the house — the archive is insert-only, so a leaked credential
|
|
30
37
|
cannot be withdrawn.
|
|
31
38
|
|
|
39
|
+
**Which memhouse.** `plugins install` stamps two variables into this config directory's
|
|
40
|
+
`settings.json`, so every session here carries them: `MEMHOUSE_HOME` is the instance whose
|
|
41
|
+
house these skills read, and `MEMHOUSE_BIN` is that instance's binary. **Every `memhouse …`
|
|
42
|
+
command in these skills means `"${MEMHOUSE_BIN:-memhouse}"`.** A machine can run two
|
|
43
|
+
instances on two channels; the bare name would be whichever the shell found first. Do not
|
|
44
|
+
override either variable.
|
|
45
|
+
|
|
32
46
|
Credentials resolve **flags > exported `MEMHOUSE_*` > `$MEMHOUSE_HOME/env`** (default
|
|
33
47
|
`~/.memhouse/env`) — the same order the CLI uses. The dance below snapshots the
|
|
34
48
|
environment first, because sourcing the file would otherwise clobber an already-exported
|
|
@@ -45,7 +59,8 @@ if [ -z "${MEMHOUSE_URL:-}" ] || [ -z "${MEMHOUSE_USER:-}" ]; then
|
|
|
45
59
|
fi
|
|
46
60
|
|
|
47
61
|
q() { # read-only by construction; every read path should use this
|
|
48
|
-
|
|
62
|
+
sed -E "s/([[:space:](]|^)(FROM|JOIN)[[:space:]]+(sessions|messages|tool_calls|meta|events)([[:space:];,)]|\$)/\1\2 ${MEMHOUSE_USER}_\3\4/g" \
|
|
63
|
+
| curl -sS --fail-with-body --user "$MEMHOUSE_USER:${MEMHOUSE_PASSWORD:-}" \
|
|
49
64
|
--data-binary @- "$MEMHOUSE_URL/?database=${MEMHOUSE_DB:-$MEMHOUSE_USER}&readonly=1"
|
|
50
65
|
}
|
|
51
66
|
q <<'SQL'
|
|
@@ -56,11 +71,22 @@ SQL
|
|
|
56
71
|
`readonly=1` is a ClickHouse-side setting: even a mis-generated `DROP` is refused by the
|
|
57
72
|
server, not by discipline.
|
|
58
73
|
|
|
59
|
-
**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
**The `sed` is what makes every query below work in both layouts** — write room names
|
|
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`.
|
|
78
|
+
With no prefix set it expands to nothing and the query passes through verbatim.
|
|
79
|
+
|
|
80
|
+
It is spelled with `[[:space:]]` classes rather than `\b` because **BSD `sed` does not
|
|
81
|
+
support `\b`**: on macOS the `\b` form matched nothing and sent the query through
|
|
82
|
+
unprefixed. That fails loudly as `UNKNOWN_TABLE` rather than quietly reading wrong rows,
|
|
83
|
+
which is the right way round — but it fails.
|
|
84
|
+
|
|
85
|
+
**Reading a housemate's memory.** A share is `GRANT SELECT ON mem.<them>_*` — their
|
|
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()`
|
|
88
|
+
rewrite leaves an already-prefixed name alone, since applying yours would point at the
|
|
89
|
+
wrong rooms. Say whose memory an answer came from.
|
|
64
90
|
|
|
65
91
|
---
|
|
66
92
|
|
|
@@ -26,7 +26,7 @@ This runs the `memhouse invite` CLI and nothing else. **Do not hand-run `CREATE
|
|
|
26
26
|
`GRANT` with an admin password substituted into a command** — that burns the credential
|
|
27
27
|
into a transcript on disk. The CLI passes it to one process and never echoes it.
|
|
28
28
|
|
|
29
|
-
1. **Check the binary:** `command -v memhouse`. Absent → tell the user to
|
|
29
|
+
1. **Check the binary:** `command -v "${MEMHOUSE_BIN:-memhouse}"`. Absent → tell the user to
|
|
30
30
|
`npm install -g memhouse`. There is no in-skill fallback, on purpose.
|
|
31
31
|
|
|
32
32
|
2. **Gather only two things:** the invitee's **name** (validate `[A-Za-z][A-Za-z0-9_]*`;
|
|
@@ -84,13 +84,13 @@ into a transcript on disk. The CLI passes it to one process and never echoes it.
|
|
|
84
84
|
5. **Say whether the house was fresh** — `SELECT count() FROM <db>.messages` reads 0 for a
|
|
85
85
|
new one. Second line of defence behind step 3's refusal.
|
|
86
86
|
|
|
87
|
-
6. **Write the message the user will send.**
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
6. **Write the message the user will send.** `invite` wrote TWO files beside each other:
|
|
88
|
+
`invite-<name>.env` (the credential, one-time) and `MEMHOUSE-INVITATION.md` (the steps,
|
|
89
|
+
nothing secret — install, verify, what they own, things to try). The guide does the
|
|
90
|
+
explaining, so the message is short: what memhouse is in a sentence; that the `.env` IS a
|
|
91
|
+
password (do not forward, do not paste in chat); open `MEMHOUSE-INVITATION.md` and follow
|
|
92
|
+
it. If `memhouse --version` shows a pre-release (a `-` in it), the invitee also needs the
|
|
93
|
+
tarball this build came from (`memhouse nightly --out …`); the guide says so and names it.
|
|
94
94
|
|
|
95
95
|
If they are REPLACING an existing credential, add `memhouse ship --full` — a plain
|
|
96
96
|
incremental pass skips sessions the new house has no record of, so their history would
|
|
@@ -105,7 +105,7 @@ for this** — partial sharing has four ways to go wrong quietly, and the comman
|
|
|
105
105
|
each one:
|
|
106
106
|
|
|
107
107
|
```
|
|
108
|
-
memhouse share <user>
|
|
108
|
+
memhouse share <user> everything you own
|
|
109
109
|
memhouse share <user> --only project=memhouse just one project
|
|
110
110
|
memhouse share <user> --only session=<id> just one conversation
|
|
111
111
|
memhouse share --list who can read it, and how much
|
|
@@ -8,7 +8,7 @@ allowed-tools: Bash
|
|
|
8
8
|
|
|
9
9
|
# /mem:admin — operate the house as its administrator
|
|
10
10
|
|
|
11
|
-
A member owns one
|
|
11
|
+
A member owns a house, or rooms in one. An **administrator** owns the ClickHouse: every house, every
|
|
12
12
|
account, every grant. This skill is the second one, and it is the only skill allowed to
|
|
13
13
|
act outside the caller's own house.
|
|
14
14
|
|
|
@@ -32,6 +32,22 @@ stop:
|
|
|
32
32
|
> `memhouse deploy --local` stands one up bound to loopback. Someone invited you?
|
|
33
33
|
> `memhouse install --env invite-<you>.env`.
|
|
34
34
|
|
|
35
|
+
## First: which memhouse this is
|
|
36
|
+
|
|
37
|
+
Before anything else, run and show verbatim:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
"${MEMHOUSE_BIN:-memhouse}" instance
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
One screen: the instance's name and home, the binary and channel, the house (server,
|
|
44
|
+
database, member, whether an admin credential is present), the five rooms with row counts,
|
|
45
|
+
what this machine ships, the host identity, the daemons, and which playbooks are bound to
|
|
46
|
+
this instance. A machine can run several instances on different channels; this is how the
|
|
47
|
+
user tells them apart, and how you know which house every answer below comes from. If the
|
|
48
|
+
instance shown is not the one the user meant, stop and say so — the fix is launching
|
|
49
|
+
under the right playbook, not overriding variables.
|
|
50
|
+
|
|
35
51
|
## The report
|
|
36
52
|
|
|
37
53
|
Lead with the one-line verdict — *working and current*, *working but stale*, or *not
|
|
@@ -83,12 +99,12 @@ thin. Say what could not be seen rather than guessing.
|
|
|
83
99
|
SHOW DATABASES
|
|
84
100
|
-- who you have granted (memhouse's own record of it)
|
|
85
101
|
SELECT substring(key, 7) AS user, value AS state
|
|
86
|
-
FROM
|
|
102
|
+
FROM meta FINAL WHERE key LIKE 'share:%' ORDER BY key
|
|
87
103
|
-- everyone on the server (names only — every member holds SHOW USERS)
|
|
88
104
|
SELECT name FROM system.users ORDER BY name
|
|
89
105
|
```
|
|
90
106
|
|
|
91
|
-
That `
|
|
107
|
+
That `meta` list is memhouse's own note-keeping, not ClickHouse's grant table —
|
|
92
108
|
a member cannot read `system.grants`. Present it as "what memhouse recorded", and say
|
|
93
109
|
that a grant made by hand would not appear.
|
|
94
110
|
|
package/memhouse/flags.js
CHANGED
|
@@ -16,16 +16,17 @@ const COMMAND_FLAGS = {
|
|
|
16
16
|
null: [], help: [], version: [],
|
|
17
17
|
whoami: ['admin'],
|
|
18
18
|
share: ['only', 'revoke', 'list'],
|
|
19
|
-
discover: [], stats: [], stop: [], doctor: [], 'sessions-query': [],
|
|
19
|
+
discover: [], stats: [], stop: [], doctor: [], 'sessions-query': [], rooms: [], instance: [], members: ['db','admin-user','admin-password'],
|
|
20
20
|
status: [], start: [],
|
|
21
21
|
onboard: ['url', 'user', 'password', 'db', 'port', 'no-ship', 'target', 'house-port', 'tag', 'local'],
|
|
22
22
|
install: ['url', 'user', 'password', 'db', 'port', 'no-ship', 'env', 'print-sql', 'member',
|
|
23
|
-
'member-password', 'admin-user', 'admin-password', 'ensure-schema', 'rotate-password', 'force'
|
|
24
|
-
|
|
23
|
+
'member-password', 'admin-user', 'admin-password', 'ensure-schema', 'rotate-password', 'force',
|
|
24
|
+
'editors', 'claude-roots', 'channel'],
|
|
25
|
+
setup: ['url', 'user', 'password', 'db', 'port', 'admin-user', 'admin-password', 'editors', 'claude-roots', 'channel'],
|
|
25
26
|
ship: ['full', 'loop', 'ensure-schema'],
|
|
26
27
|
search: ['limit'],
|
|
27
28
|
resume: [],
|
|
28
|
-
update: ['check', 'migrate', 'no-install'],
|
|
29
|
+
update: ['check', 'migrate', 'no-install', 'channel'],
|
|
29
30
|
reset: ['all-origins'],
|
|
30
31
|
invite: ['url', 'db', 'out', 'admin-user', 'admin-password', 'adopt', 'print-sql',
|
|
31
32
|
'allow-local', 'member-password'],
|
package/memhouse/house/HOUSE.md
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
# The house — a database,
|
|
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
|
|
5
|
-
`
|
|
6
|
-
Merge rooms, no views, no settings profile.
|
|
4
|
+
`polat`, `team_a`, even `default`. Its rooms are tables: `sessions`, `messages`,
|
|
5
|
+
`tool_calls`. No views, no Merge rooms, no settings profile.
|
|
7
6
|
|
|
8
|
-
**
|
|
9
|
-
|
|
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
|
|
10
|
+
member create and rebuild their own rooms, share them, and reach nothing else. Nobody is
|
|
11
|
+
granted the database itself. A house with one member is a house of one, not a different
|
|
12
|
+
kind of house — a colleague joins as one more member and nothing about the first changes.
|
|
13
|
+
`roomNames()` in `house.js` is the only place a table name is produced.
|
|
14
|
+
|
|
15
|
+
Two columns say where every row came from:
|
|
10
16
|
|
|
11
17
|
| Column | Meaning | Comes from |
|
|
12
18
|
|---|---|---|
|
|
@@ -31,9 +37,17 @@ shipper create and evolve the rooms (`ship.js --ensure-schema`) — no admin has
|
|
|
31
37
|
memhouse code. Joining a ClickHouse that happens to run a kernel is the same three
|
|
32
38
|
statements: a database and a credential, nothing else.
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
**Housemates do not have to trust each other with the house.** They used to: everyone
|
|
41
|
+
held `ALL` on the database, and the isolation mechanism between parties who should not
|
|
42
|
+
see each other was a separate house. That shape leaked — one member could `GRANT SELECT
|
|
43
|
+
ON db.* TO <outsider>` and hand over a housemate's transcripts, with no admin and no
|
|
44
|
+
notification.
|
|
45
|
+
|
|
46
|
+
In a shared house each member is granted their own rooms and nothing else, so isolation
|
|
47
|
+
lives INSIDE one house and is checkable: `SHOW GRANTS` lists what you hold, and `SHOW
|
|
48
|
+
TABLES` does not list what you do not. A separate house is still the boundary between
|
|
49
|
+
groups that should not even know of each other — names leak across a shared house even
|
|
50
|
+
when content does not.
|
|
37
51
|
|
|
38
52
|
## One user on two machines, same session id
|
|
39
53
|
|
|
@@ -91,9 +105,9 @@ for writes and DDL.
|
|
|
91
105
|
|
|
92
106
|
Two tables that are not rooms:
|
|
93
107
|
|
|
94
|
-
- `
|
|
108
|
+
- `meta` — house-wide key/value, latest-wins: `schema_version`, and the memhouse
|
|
95
109
|
version each member last shipped with.
|
|
96
|
-
- `
|
|
110
|
+
- `events` — append-only: migrations (`pending` → `applied` | `failed`), version
|
|
97
111
|
changes, schema observations, each with actor, host and row counts. Nothing is updated
|
|
98
112
|
in place, so a migration that failed and was retried reads as exactly that.
|
|
99
113
|
|