memhouse 0.18.9 → 0.18.11
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 +194 -0
- package/CHANGELOG.md +1097 -0
- package/README.md +54 -423
- package/SECURITY.md +68 -0
- package/bin/memhouse.js +299 -133
- package/docs/README.md +46 -0
- package/docs/guides/admin-password.md +95 -0
- package/docs/guides/configuration.md +109 -0
- package/docs/guides/daemons.md +53 -0
- package/docs/guides/install.md +128 -0
- package/docs/guides/invite.md +87 -0
- package/docs/guides/operate.md +112 -0
- package/docs/guides/search-and-resume.md +95 -0
- package/docs/guides/share.md +102 -0
- package/docs/guides/storage.md +93 -0
- package/docs/guides/troubleshooting.md +78 -0
- package/docs/guides/uninstall.md +37 -0
- package/docs/guides/update.md +68 -0
- package/docs/releases/README.md +11 -0
- package/docs/releases/v0.18.10.md +226 -0
- package/docs/releases/v0.18.11.md +191 -0
- package/docs/tutorials/01-first-house.md +132 -0
- package/docs/tutorials/02-join-a-house.md +91 -0
- package/docs/tutorials/03-share-your-memory.md +96 -0
- package/editors/claude.js +68 -10
- package/examples/01-local-one-machine/README.md +99 -0
- package/examples/01-local-one-machine/run.sh +61 -0
- package/examples/02-existing-clickhouse/README.md +121 -0
- package/examples/02-existing-clickhouse/run.sh +71 -0
- package/examples/03-team-house/README.md +129 -0
- package/examples/03-team-house/run.sh +124 -0
- package/examples/04-self-hosted-team/.env.example +22 -0
- package/examples/04-self-hosted-team/README.md +187 -0
- package/examples/04-self-hosted-team/compose.yml +158 -0
- package/examples/04-self-hosted-team/smoke.sh +113 -0
- package/examples/README.md +42 -0
- package/examples/fixtures/README.md +24 -0
- package/examples/fixtures/make-sessions.js +63 -0
- package/memhouse/DESIGN.md +9 -2
- package/memhouse/admin-secret.js +81 -0
- package/memhouse/delivery/plugin/.claude-plugin/plugin.json +1 -1
- package/memhouse/delivery/plugin/reference/HOUSE.md +18 -6
- package/memhouse/delivery/plugin/skills/access/SKILL.md +1 -1
- package/memhouse/delivery/plugin/skills/admin/SKILL.md +1 -1
- package/memhouse/delivery/plugin/skills/house/SKILL.md +1 -1
- package/memhouse/delivery/plugin/skills/recall/SKILL.md +34 -14
- package/memhouse/delivery/plugin/skills/sql/SKILL.md +1 -1
- package/memhouse/deploy.js +4 -2
- package/memhouse/flags.js +32 -5
- package/memhouse/host.js +11 -6
- package/memhouse/house/HOUSE.md +1 -1
- package/memhouse/house/house.js +27 -1
- package/memhouse/invite-target.js +37 -0
- package/memhouse/provision.js +12 -3
- package/memhouse/server/queries.js +9 -4
- package/memhouse/service.js +5 -0
- package/memhouse/shipper/ship.js +148 -31
- package/package.json +10 -2
- package/public/THIRD_PARTY_NOTICES.txt +2114 -0
- package/ui/vite.config.js +4 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Search, resume and skills
|
|
2
|
+
|
|
3
|
+
## Search
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
memhouse search "connection refused"
|
|
7
|
+
memhouse search clickhouse auth --limit 50
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
This is a full-text search across every session in your rooms, from every machine and
|
|
11
|
+
every editor. Each hit names the session id, project, date and the matching line.
|
|
12
|
+
|
|
13
|
+
## Resume
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
memhouse resume claude-code:6b1f…
|
|
17
|
+
# cd /path/to/project && claude --resume 6b1f…
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`resume` **prints** the command and does not run it. A resume from the wrong directory,
|
|
21
|
+
or with a stale id, does not fail: it opens a **new** session, and the tool reports
|
|
22
|
+
success while the transcript you wanted is still gone. Printing it lets you see the
|
|
23
|
+
directory and the id first.
|
|
24
|
+
|
|
25
|
+
| editor | resume |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Claude Code, Codex, OpenCode | verified: prints the command |
|
|
28
|
+
| Cursor, Zed, VS Code, Kiro, Copilot for JetBrains, Antigravity, Devin | no CLI that takes a session id; `resume` says so |
|
|
29
|
+
| goose, Gemini CLI, Cursor Agent, Copilot CLI | refused as *unverified*: nobody has confirmed the flag from the tool's own `--help` yet |
|
|
30
|
+
|
|
31
|
+
## Numbers
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
memhouse stats # sessions, messages and tokens per editor
|
|
35
|
+
memhouse sessions-query # the per-session rollup as SQL, to paste into your own queries
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The dashboard (`memhouse start`, then http://localhost:4640) shows the same and more:
|
|
39
|
+
|
|
40
|
+
- cost by model, editor and project;
|
|
41
|
+
- tool-call rankings;
|
|
42
|
+
- activity over time;
|
|
43
|
+
- which machine wrote what.
|
|
44
|
+
|
|
45
|
+
**Some editors record no token usage.** Kiro, VS Code, Zed and one of Cursor's two
|
|
46
|
+
storage paths extract none, so their cost shows as zero. Read that as *unknown*, not
|
|
47
|
+
*free*.
|
|
48
|
+
|
|
49
|
+
## Skills for your agents
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
memhouse plugins install claude # every Claude Code config dir found; choose, or --yes for all
|
|
53
|
+
memhouse plugins install claude --target ~/.claude
|
|
54
|
+
memhouse plugins list
|
|
55
|
+
memhouse plugins remove claude
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The five skills:
|
|
59
|
+
|
|
60
|
+
| skill | for |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `/mem:recall` | answer a question from past sessions: search, read the transcripts, answer, cite |
|
|
63
|
+
| `/mem:house` | is memory working, what does the house hold, which machines write, who can read it |
|
|
64
|
+
| `/mem:sql` | read-only SQL for numbers: spend, models, tools, activity |
|
|
65
|
+
| `/mem:access` | invite someone, share your house, list or revoke shares |
|
|
66
|
+
| `/mem:admin` | operate the server as its administrator, without the password entering the conversation |
|
|
67
|
+
|
|
68
|
+
`plugins install` acts on **every** Claude Code config directory on the machine:
|
|
69
|
+
`~/.claude`, whatever `CLAUDE_CONFIG_DIR` points at, and each playbook under
|
|
70
|
+
`~/.claude-playbooks/`. All are selected by default. Installing into the default config
|
|
71
|
+
alone is how `/mem:recall` ends up missing from the playbook you actually work in, and a
|
|
72
|
+
missing skill never announces itself.
|
|
73
|
+
|
|
74
|
+
For an agent that does not use Claude Code skills, `memhouse prompt` prints a snippet for
|
|
75
|
+
its system prompt: where memory lives and how to query it.
|
|
76
|
+
|
|
77
|
+
## Writing your own queries
|
|
78
|
+
|
|
79
|
+
The rooms are documented column by column in
|
|
80
|
+
[`memhouse/house/HOUSE.md`](../../memhouse/house/HOUSE.md). Two rules matter for every
|
|
81
|
+
query:
|
|
82
|
+
|
|
83
|
+
1. **Join on `(session_id, user_id)`**, never on `session_id` alone. Two members' editors
|
|
84
|
+
can produce the same local session id.
|
|
85
|
+
2. **Filter to the current parse.** A session's rows can hold more than one parse (an
|
|
86
|
+
`epoch`; see [How memory is stored](storage.md)). Counts must keep only the newest:
|
|
87
|
+
|
|
88
|
+
```sql
|
|
89
|
+
WHERE origin != 'ship'
|
|
90
|
+
OR (session_id, user_id, epoch) IN (
|
|
91
|
+
SELECT session_id, user_id, max(epoch) FROM mem.<you>_messages
|
|
92
|
+
WHERE origin = 'ship' GROUP BY session_id, user_id)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Read with `FINAL`, or the `final=1` setting, so that ReplacingMergeTree versions collapse.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Share and revoke
|
|
2
|
+
|
|
3
|
+
A share lets another member of the same server read your rooms. It is a ClickHouse
|
|
4
|
+
`GRANT SELECT`, so it is read-only, and you can withdraw it. Run these on a machine
|
|
5
|
+
installed as yourself. Each command acts on your own rooms only.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
memhouse share bob # full: everything in mem.<you>_*
|
|
9
|
+
memhouse share bob --only project=billing # scoped: three rooms, filtered
|
|
10
|
+
memhouse share --list # what memhouse has recorded
|
|
11
|
+
memhouse share bob --revoke # take it back
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Full or scoped
|
|
15
|
+
|
|
16
|
+
| | full (`share bob`) | scoped (`share bob --only …`) |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| grant | `SELECT ON mem.<you>_*` | `SELECT` on `<you>_sessions`, `<you>_messages`, `<you>_tool_calls` |
|
|
19
|
+
| rows | all | those matching the scope, through row policies |
|
|
20
|
+
| stats tables (`<you>_session_stats`, model and tool stats) | readable: first prompts, folders, projects and tokens of every session | not granted |
|
|
21
|
+
| `<you>_meta`, `<you>_events` | readable, including your other share records | not granted |
|
|
22
|
+
| rooms created later | readable | not granted |
|
|
23
|
+
|
|
24
|
+
**A full share is for someone you would hand your laptop to.** It reaches every table in
|
|
25
|
+
your pattern, including ones memhouse adds in a later release. The command says so when
|
|
26
|
+
you run it.
|
|
27
|
+
|
|
28
|
+
## Scopes
|
|
29
|
+
|
|
30
|
+
`--only key=value[,key=value…]`. All the keys must hold (AND):
|
|
31
|
+
|
|
32
|
+
| key | filters on |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `project=` | the project name |
|
|
35
|
+
| `folder=` | the working directory |
|
|
36
|
+
| `session=` | one session id |
|
|
37
|
+
| `host=` | one machine (its fingerprint, as `status` shows it) |
|
|
38
|
+
| `source=` | one editor, by the value stored in the `source` column (below) |
|
|
39
|
+
| `since=` / `until=` | a date range: message time, or session creation time for `sessions` |
|
|
40
|
+
|
|
41
|
+
`source=` compares against the stored value, which is not always the adapter name you
|
|
42
|
+
use in `MEMHOUSE_EDITORS`. Claude Code rows, for example, say `claude-code`, not `claude`.
|
|
43
|
+
The values:
|
|
44
|
+
|
|
45
|
+
| editor | `source` |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Claude Code | `claude-code` |
|
|
48
|
+
| Codex | `codex` |
|
|
49
|
+
| Cursor / Cursor Agent | `cursor` / `cursor-agent` |
|
|
50
|
+
| VS Code / VS Code Insiders | `vscode` / `vscode-insiders` |
|
|
51
|
+
| GitHub Copilot / Copilot for JetBrains | `copilot-cli` / `copilot-jetbrains` |
|
|
52
|
+
| Gemini CLI | `gemini-cli` |
|
|
53
|
+
| Zed, OpenCode, Goose, Kiro, Codebuff, Antigravity | `zed`, `opencode`, `goose`, `kiro`, `codebuff`, `antigravity` |
|
|
54
|
+
| Devin / Devin Next | `devin` / `devin-next` |
|
|
55
|
+
| Command Code | `commandcode` |
|
|
56
|
+
|
|
57
|
+
To see what your rooms actually hold:
|
|
58
|
+
`SELECT source, count() FROM mem.<you>_sessions FINAL GROUP BY source`.
|
|
59
|
+
|
|
60
|
+
An empty scope (`--only ""`, or `--only "$SCOPE"` with the variable unset) is refused.
|
|
61
|
+
It never falls back to a full share.
|
|
62
|
+
|
|
63
|
+
## How the server must be configured
|
|
64
|
+
|
|
65
|
+
Row policies in ClickHouse have one sharp edge. On some server configurations, the first
|
|
66
|
+
policy on a table hides every row from readers who have no policy of their own: you, and
|
|
67
|
+
your full-share grantees. Before it creates the first policy, `share` measures how this
|
|
68
|
+
server behaves, and refuses if a policy would blind you. The fix is server configuration
|
|
69
|
+
(`users_without_row_policies_can_read_rows`), and it is the administrator's to make.
|
|
70
|
+
|
|
71
|
+
## Changing a share
|
|
72
|
+
|
|
73
|
+
- **Scoped to full:** `memhouse share bob`.
|
|
74
|
+
- **Full to scoped:** `memhouse share bob --only …`. The wildcard grant is withdrawn
|
|
75
|
+
first, so a failure part-way leaves bob with less access, never more.
|
|
76
|
+
- **One scope to another:** run `--only` again with the new scope. It replaces the
|
|
77
|
+
policies.
|
|
78
|
+
|
|
79
|
+
**Scoped shares made before 0.18.10** granted the whole pattern while filtering only three
|
|
80
|
+
rooms. Re-run `memhouse share <user> --only <scope>` once for each, and it is narrowed to
|
|
81
|
+
the three rooms.
|
|
82
|
+
|
|
83
|
+
## Revoking
|
|
84
|
+
|
|
85
|
+
`--revoke` withdraws the grants (the wildcard and the three rooms), then drops the row
|
|
86
|
+
policies. If the server refuses a step, the policies are kept unless every grant is
|
|
87
|
+
confirmed gone, so a failed revoke never leaves an unfiltered share behind.
|
|
88
|
+
|
|
89
|
+
A revoke cannot recall what was already read.
|
|
90
|
+
|
|
91
|
+
## What `--list` shows
|
|
92
|
+
|
|
93
|
+
`share --list` reads memhouse's own record, the `share:` keys in `<you>_meta`. A grant
|
|
94
|
+
someone made by hand in SQL does not appear there. A member cannot read `system.grants`;
|
|
95
|
+
an administrator can, with `SHOW GRANTS FOR <user>`.
|
|
96
|
+
|
|
97
|
+
## Reading what was shared with you
|
|
98
|
+
|
|
99
|
+
Shared rooms sit in the same database as yours, under the other member's name, for
|
|
100
|
+
example `mem.alice_messages`. Query them with `/mem:sql` or any ClickHouse client, joining
|
|
101
|
+
on `(session_id, user_id)` as you would on your own rooms. A table you were not granted is
|
|
102
|
+
refused, and a scope you are under returns only its rows.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# How memory is stored
|
|
2
|
+
|
|
3
|
+
## A house, rooms, and members
|
|
4
|
+
|
|
5
|
+
- **A house is a ClickHouse database,** normally `mem`.
|
|
6
|
+
- **A member is a ClickHouse user** who ships into it.
|
|
7
|
+
- **Each member's rooms are tables named for them:**
|
|
8
|
+
|
|
9
|
+
| room | holds |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `<member>_sessions` | one row per session: editor, project, folder, branch, timestamps, title |
|
|
12
|
+
| `<member>_messages` | every turn: role, text, model, tokens, timestamp, position |
|
|
13
|
+
| `<member>_tool_calls` | every tool call: name, arguments, which message made it |
|
|
14
|
+
| `<member>_session_stats`, `_session_model_stats`, `_session_tool_stats` | precomputed rollups for the dashboard, refreshed after each pass |
|
|
15
|
+
| `<member>_meta` | memhouse's own records: schema version, writers, shares |
|
|
16
|
+
| `<member>_events` | an append-only log: migrations, version changes |
|
|
17
|
+
|
|
18
|
+
**A member holds one grant: `ON mem.<member>_*`.** That covers their own rooms, present and
|
|
19
|
+
future, and nothing else in the database. Nobody is granted the database itself:
|
|
20
|
+
`ALL ON mem.*` would also reach rooms created later, which is how two people in one
|
|
21
|
+
database once leaked into each other. A member can read their isolation back with
|
|
22
|
+
`SHOW GRANTS`.
|
|
23
|
+
|
|
24
|
+
| | rooms | each member holds |
|
|
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 |
|
|
28
|
+
|
|
29
|
+
Reading across members is a `UNION ALL` over the rooms you hold: your own, and any shared
|
|
30
|
+
with you. Naming a room you were not granted is an error, never a silent omission.
|
|
31
|
+
|
|
32
|
+
## Every row says where it came from
|
|
33
|
+
|
|
34
|
+
- **`user_id`** is stamped by the server: `MATERIALIZED currentUser()`. Async inserts are
|
|
35
|
+
pinned off for members, so the stamp cannot be skipped. `WHERE user_id = 'alice'` is one
|
|
36
|
+
person.
|
|
37
|
+
- **`host`** is the machine. Every row carries `<hostname>-<8 hex>`, where the 8 hex come
|
|
38
|
+
from a fingerprint of the OS's own machine id (IOPlatformUUID on macOS,
|
|
39
|
+
`/etc/machine-id` on Linux), hashed so the raw id never leaves the machine. It is kept in
|
|
40
|
+
`$MEMHOUSE_HOME/host.json`. It is not taken from the hostname:
|
|
41
|
+
- two laptops that both answer to `MacBook-Pro` still get different ids;
|
|
42
|
+
- a renamed machine keeps its id, and `status` reports the new name beside it;
|
|
43
|
+
- reinstalling, even after `uninstall --full-removal`, brings the same machine back
|
|
44
|
+
under the same id. Where no machine id can be read, it falls back to a random one.
|
|
45
|
+
|
|
46
|
+
`memhouse status` shows this machine's id. `memhouse doctor` names every host in your
|
|
47
|
+
rooms.
|
|
48
|
+
- **`origin`** says who wrote the row. The shipper writes `ship`; an import writes its own
|
|
49
|
+
value.
|
|
50
|
+
|
|
51
|
+
## The house never destroys what it cannot rebuild
|
|
52
|
+
|
|
53
|
+
**The shipper is insert-only.** It runs no `DELETE`, no `TRUNCATE`, and no mutation of
|
|
54
|
+
any kind, so no privilege it holds can lose you a row.
|
|
55
|
+
|
|
56
|
+
That has a cost. ReplacingMergeTree deduplicates but does not diff: a re-parse that yields
|
|
57
|
+
*fewer* messages leaves the old, higher-positioned rows in place. A shorter re-parse has
|
|
58
|
+
three possible causes:
|
|
59
|
+
|
|
60
|
+
- an adapter bug was fixed, and the extra rows were junk;
|
|
61
|
+
- Claude Code **compacted** the transcript;
|
|
62
|
+
- the editor's retention window removed it.
|
|
63
|
+
|
|
64
|
+
In the last two cases the house holds the only surviving copy. So rows carry an `epoch`,
|
|
65
|
+
which says which parse of the session they belong to:
|
|
66
|
+
|
|
67
|
+
- **Nothing changed**, or the session just grew: the same epoch. Rows deduplicate exactly,
|
|
68
|
+
and no extra storage is used.
|
|
69
|
+
- **Shorter, or rewritten at a position the house already holds:** the new parse goes to
|
|
70
|
+
`epoch + 1`. The old parse stays complete and readable.
|
|
71
|
+
|
|
72
|
+
Reads show one parse per session, the newest, so counts, tokens and cost are not
|
|
73
|
+
inflated. The skills, the dashboard and `memhouse search` all filter this way; hand-written
|
|
74
|
+
queries should too ([the clause](search-and-resume.md#writing-your-own-queries)).
|
|
75
|
+
|
|
76
|
+
**Imported history is protected the same way.** `origin` is in the sorting key of
|
|
77
|
+
`messages` and `tool_calls`, so a shipped row can never collapse an imported one. Anything
|
|
78
|
+
imported from an older house, another product, or a machine that no longer exists survives
|
|
79
|
+
every re-ship. `sessions` is the deliberate exception: it holds one row per session, with
|
|
80
|
+
no `origin` or `epoch` in its key. A session's metadata has a single current version, and
|
|
81
|
+
a second row would make every rollup count its messages twice.
|
|
82
|
+
|
|
83
|
+
The shipper checks the rooms' sorting keys before it writes, and refuses if they are
|
|
84
|
+
wrong. See [Update](update.md#when-the-house-itself-must-change).
|
|
85
|
+
|
|
86
|
+
## What is not in the house
|
|
87
|
+
|
|
88
|
+
- Nothing is embedded, summarised or rewritten. Text is stored as the editor wrote it,
|
|
89
|
+
truncated at 50,000 characters per message and 20,000 per tool argument.
|
|
90
|
+
- No LLM runs anywhere in memhouse's write or read path. The skills are read by your agent,
|
|
91
|
+
which does the reading and reasoning.
|
|
92
|
+
- The local transcript files stay where the editor put them. memhouse reads them and never
|
|
93
|
+
modifies them.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Start with the two diagnostics. Both are read-only.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
memhouse doctor # the whole pipeline, one line per check
|
|
7
|
+
memhouse discover # what each editor adapter sees on this machine
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## An editor ships nothing
|
|
11
|
+
|
|
12
|
+
`discover` lists every adapter. Each one is in one of three states:
|
|
13
|
+
|
|
14
|
+
- it has sessions, with a count;
|
|
15
|
+
- it has none, because the editor is not used on this machine;
|
|
16
|
+
- it was **skipped**, with the reason.
|
|
17
|
+
|
|
18
|
+
A skipped adapter and an editor you do not have both contribute zero sessions, so
|
|
19
|
+
memhouse always says which one it is. Common causes, one store at a time:
|
|
20
|
+
|
|
21
|
+
- **A SQLite store locked by the running editor:** `state.vscdb` for Cursor and VS Code.
|
|
22
|
+
The next pass retries.
|
|
23
|
+
- **A store the editor moved or changed** in a new release.
|
|
24
|
+
- **A scope that excludes it:** `MEMHOUSE_EDITORS` or a `MEMHOUSE_<EDITOR>_ROOTS` in the
|
|
25
|
+
env file. See [Configuration](configuration.md#which-sessions-ship).
|
|
26
|
+
|
|
27
|
+
SQLite comes from Node itself (`node:sqlite`), so there is no native module to rebuild.
|
|
28
|
+
|
|
29
|
+
## Status says the shipper runs, but nothing new arrives
|
|
30
|
+
|
|
31
|
+
`memhouse status` reads the shipper's last pass from its log, and shows a failing pass
|
|
32
|
+
as a failure.
|
|
33
|
+
|
|
34
|
+
- **`Authentication failed`:** the password in `~/.memhouse/env` is no longer the
|
|
35
|
+
member's. This happens after a `passwd` on another machine, or a reset by the admin. Put
|
|
36
|
+
the current password into `MEMHOUSE_PASSWORD` in `~/.memhouse/env` (or run
|
|
37
|
+
`memhouse setup`, which asks), then restart the shipper.
|
|
38
|
+
- **A pass that keeps withholding a session:** an adapter returned nothing for a session
|
|
39
|
+
the house already holds. The shipper refuses to replace a transcript with an empty one,
|
|
40
|
+
and says so on every pass, until the store is readable again.
|
|
41
|
+
- **Nothing to ship:** sessions are only shipped once the editor has written them.
|
|
42
|
+
|
|
43
|
+
## Daemons don't survive a reboot
|
|
44
|
+
|
|
45
|
+
`memhouse start` uses pidfiles. Its daemons outlive the shell but not a restart. Use
|
|
46
|
+
`memhouse service install` ([Daemons](daemons.md)). On Linux, also enable lingering, or
|
|
47
|
+
user services stop at logout. A rootless podman house from `deploy --local` has the same
|
|
48
|
+
exposure, and `deploy` prints the fix.
|
|
49
|
+
|
|
50
|
+
## The dashboard is empty, or stale
|
|
51
|
+
|
|
52
|
+
- **It reads the house, not the machine.** Check `memhouse status` for the connection
|
|
53
|
+
first.
|
|
54
|
+
- **It reads precomputed stats,** refreshed at the end of each pass that shipped
|
|
55
|
+
something. On a house where nothing has shipped for a day, the stats age out, and a
|
|
56
|
+
running dashboard keeps reading them. Restart it (`memhouse stop && memhouse start`). It
|
|
57
|
+
then reads the rooms directly, until the next pass that ships refreshes the stats.
|
|
58
|
+
A fix is planned.
|
|
59
|
+
- **After an upgrade it shows the old version:** restart it (`memhouse update` does this).
|
|
60
|
+
|
|
61
|
+
## `EACCES` during `npm install -g`
|
|
62
|
+
|
|
63
|
+
See [Install](install.md#eacces-on-install). `sudo` is right only when the npm prefix is
|
|
64
|
+
owned by root.
|
|
65
|
+
|
|
66
|
+
## `refused`, `ACCESS_DENIED`, `Not enough privileges`
|
|
67
|
+
|
|
68
|
+
- For a member, these are expected outside `mem.<you>_*` and the rooms shared with you.
|
|
69
|
+
`memhouse whoami` shows what your credential may do.
|
|
70
|
+
- For `invite`, `members` or `convert`: you need the admin credential. See
|
|
71
|
+
[Admin password](admin-password.md).
|
|
72
|
+
- A room that should be yours but is refused usually means the house is older than this
|
|
73
|
+
version. Run `memhouse doctor`, then `memhouse migrate` if it says so.
|
|
74
|
+
|
|
75
|
+
## Still stuck
|
|
76
|
+
|
|
77
|
+
Run `memhouse doctor` and `memhouse status --json`, and open an issue with both outputs.
|
|
78
|
+
Check them before posting, and remove anything private, such as a host name.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Uninstall
|
|
2
|
+
|
|
3
|
+
Three tiers. **None of them touches the memory in the house.**
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
memhouse uninstall # stop everything; KEEP the config and this machine's identity
|
|
7
|
+
memhouse uninstall --credentials # also forget the house and its password
|
|
8
|
+
memhouse uninstall --full-removal # all of ~/.memhouse, identity included
|
|
9
|
+
npm uninstall -g memhouse # then remove the package
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
- **The default is the conservative one.** Stopping the shipper is routine: before an
|
|
13
|
+
upgrade, while debugging, or when a laptop should go quiet for a week. It should not
|
|
14
|
+
also mean "forget which house I use and who this machine is".
|
|
15
|
+
- **`--full-removal` asks first.** It deletes `host.json`. A later reinstall derives the
|
|
16
|
+
same identity again from the machine's own id, so your history stays one machine, unless
|
|
17
|
+
the machine was renamed in between or has no readable machine id. Then it comes back as
|
|
18
|
+
a new host.
|
|
19
|
+
- **Your memory stays.** The rooms in ClickHouse are untouched by every tier. What the
|
|
20
|
+
shipper wrote can be rebuilt from the local session stores with `memhouse ship --full`,
|
|
21
|
+
for as long as the editors keep them.
|
|
22
|
+
|
|
23
|
+
## Removing the house itself
|
|
24
|
+
|
|
25
|
+
- **A local house** from `deploy --local`: `memhouse deploy --down` removes the container
|
|
26
|
+
**and its data volume**. That deletes the memory, and there is no undo.
|
|
27
|
+
- **A shared server:** an administrator drops your rooms and user. See
|
|
28
|
+
[Operate a house](operate.md).
|
|
29
|
+
|
|
30
|
+
## Removing the skills
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
memhouse plugins remove claude
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This removes the `/mem:*` skills, and the instance binding, from the Claude Code config
|
|
37
|
+
directories they were installed into.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Update
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
memhouse update # upgrade along this install's channel, restart the daemons, check the house
|
|
5
|
+
memhouse update --check # compare versions, change nothing
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
`update` does three things that a bare `npm install -g memhouse@latest` does not:
|
|
9
|
+
|
|
10
|
+
1. **It restarts the daemons.** A running shipper keeps parsing with the code it booted
|
|
11
|
+
with. One once ran for 1 day 16 hours out of a directory that had since been moved.
|
|
12
|
+
2. **It checks whether the house needs a migration** for the new version, and offers to run
|
|
13
|
+
it. `--migrate` runs it without asking.
|
|
14
|
+
3. **It stays on your channel** (`MEMHOUSE_CHANNEL`). See
|
|
15
|
+
[Configuration](configuration.md#channels).
|
|
16
|
+
|
|
17
|
+
Upgraded by hand already? Finish the job without reinstalling:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g memhouse@latest
|
|
21
|
+
memhouse update --no-install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The daemons also notice on their own. Each one compares the installed version with the
|
|
25
|
+
version it booted with, and hands over when they differ: under systemd or launchd it
|
|
26
|
+
exits so the supervisor restarts it; with nothing supervising, it re-executes itself.
|
|
27
|
+
`update` just makes the switch immediate.
|
|
28
|
+
|
|
29
|
+
## Several machines on one house
|
|
30
|
+
|
|
31
|
+
Every machine of every member runs its own shipper. Upgrade them all.
|
|
32
|
+
|
|
33
|
+
- The release notes for each version say whether the order matters and whether mixed
|
|
34
|
+
versions can ship side by side. See [`docs/releases/`](../releases/).
|
|
35
|
+
- `memhouse status` lists every machine writing to your rooms, with the version each
|
|
36
|
+
last reported and when it last shipped. A machine that is behind is named there.
|
|
37
|
+
- Machines that stopped writing long ago are folded into one line. That is history, not
|
|
38
|
+
a fault. `memhouse status --all` lists them.
|
|
39
|
+
|
|
40
|
+
## When the house itself must change
|
|
41
|
+
|
|
42
|
+
Some releases need the rooms rebuilt, for example when a sorting key changes. The shipper
|
|
43
|
+
checks the rooms' keys before it writes, and **refuses** to write into a house it does not
|
|
44
|
+
match, so an old house cannot be corrupted by a new shipper. To bring the house up to
|
|
45
|
+
date:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
memhouse migrate --dry-run # what would run
|
|
49
|
+
memhouse migrate # copy, atomic swap; nothing is deleted
|
|
50
|
+
memhouse doctor # every line a check mark
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A migration copies each room, swaps it in atomically, and keeps the old one as
|
|
54
|
+
`<room>_pre_<migration>` for you to drop when you are satisfied. The house records the move
|
|
55
|
+
in its `events` room, and `doctor` reads it back.
|
|
56
|
+
|
|
57
|
+
## Upgrading from 0.9.x
|
|
58
|
+
|
|
59
|
+
0.9.x predates migrations, and `update` runs the **old** version's code (it replaces itself
|
|
60
|
+
mid-run), so it cannot prompt. After the upgrade, the first ship refuses (nothing is lost)
|
|
61
|
+
and names the one command to run by hand: `memhouse migrate`.
|
|
62
|
+
|
|
63
|
+
## Upgrading a pre-0.18 house (a database per member)
|
|
64
|
+
|
|
65
|
+
0.18 moved every member's rooms into one database, as `mem.<member>_*`. An operator moves
|
|
66
|
+
an old house once with `memhouse convert`; see [Operate a house](operate.md#convert). After
|
|
67
|
+
that, members upgrade with `memhouse update`, and the shipper adopts the moved rooms
|
|
68
|
+
itself.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Release notes
|
|
2
|
+
|
|
3
|
+
One document per release, from 0.18.10 onward. Each says what changed, what you need to
|
|
4
|
+
do, how to upgrade, what is deprecated and when it goes, and what was deferred.
|
|
5
|
+
|
|
6
|
+
| version | date | headline |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| [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
|
+
| [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
|
+
Earlier versions: [`CHANGELOG.md`](../../CHANGELOG.md).
|