memhouse 0.3.2 → 0.4.2
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 +64 -6
- package/bin/memhouse.js +882 -40
- package/index.js +2 -2
- package/mem-house/COMPETITION.md +217 -0
- package/mem-house/DESIGN.md +61 -32
- package/mem-house/delivery/AGENT-INSTALL.md +5 -3
- package/mem-house/delivery/PROMPT.md +23 -10
- package/mem-house/delivery/install.sh +9 -7
- package/mem-house/delivery/kernel-install.md +56 -25
- package/mem-house/delivery/skills/memhouse-search/SKILL.md +46 -16
- package/mem-house/delivery/skills/memhouse-sessions/SKILL.md +38 -7
- package/mem-house/delivery/skills/memhouse-sql/SKILL.md +48 -17
- package/mem-house/deploy.js +333 -0
- package/mem-house/envfile.js +49 -0
- package/mem-house/per-member/INSTALL.md +183 -0
- package/mem-house/per-member/PLAN.md +174 -0
- package/mem-house/per-member/PROVISIONING.md +177 -0
- package/mem-house/per-member/README.md +48 -0
- package/mem-house/per-member/SCHEMA.md +73 -0
- package/mem-house/per-member/SHARING.md +102 -0
- package/mem-house/per-member/provision.js +142 -0
- package/mem-house/per-member/rooms.js +132 -0
- package/mem-house/per-member/schema-member.sql.tpl +85 -0
- package/mem-house/per-member/schema-merge.sql.tpl +24 -0
- package/mem-house/server/queries.js +103 -53
- package/mem-house/service.js +400 -0
- package/mem-house/shipper/ship.js +61 -18
- package/package.json +3 -3
- package/pricing.js +20 -2
- package/pricing.json +216 -24
- package/public/assets/{index-CCPh7a2Z.js → index-CtH-5i95.js} +5 -5
- package/public/index.html +1 -1
- package/ui/src/App.jsx +3 -2
- package/ui/src/pages/SqlViewer.jsx +39 -21
- package/mem-house/rls.sql +0 -17
- package/mem-house/schema.sql +0 -145
package/index.js
CHANGED
|
@@ -121,10 +121,10 @@ if (isJoin) {
|
|
|
121
121
|
// Fail fast: the relay join client still targets the removed synchronous SQLite
|
|
122
122
|
// cache (relay-client.js pickProjects → cache.getDb), which the ClickHouse
|
|
123
123
|
// cutover eliminated — it would crash after connecting. In memhouse, team
|
|
124
|
-
// sharing is
|
|
124
|
+
// sharing is grants on per-member rooms, not relay.
|
|
125
125
|
console.error(chalk.red('\n ✗ Relay join is not supported in memhouse.'));
|
|
126
126
|
console.error(chalk.dim(' Team sharing here is kernel-based: see mem-house/delivery/kernel-install.md'));
|
|
127
|
-
console.error(chalk.dim(' (register-member +
|
|
127
|
+
console.error(chalk.dim(' (register-member + per-member rooms + a GRANT on your own rooms).\n'));
|
|
128
128
|
process.exit(1);
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# mem-house — the competition
|
|
2
|
+
|
|
3
|
+
Companion to `DESIGN.md`. That file states **the four bets**; this one grades each
|
|
4
|
+
bet against the field as it actually stands.
|
|
5
|
+
|
|
6
|
+
**Surveyed 2026-08-07.** Every star/fork/date figure was pulled from the GitHub API
|
|
7
|
+
on that date and is a decaying fact — re-run before citing. Claims that could not be
|
|
8
|
+
verified are marked *unverified* rather than asserted. X/Twitter was not reachable
|
|
9
|
+
(HTTP 402 to the fetch tool), so nothing here reflects it.
|
|
10
|
+
|
|
11
|
+
The finding, in one line: **three of the four bets are already occupied by shipping
|
|
12
|
+
competitors, most of them free and further along. Bet 3 is the one that holds.**
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## The field splits four ways
|
|
17
|
+
|
|
18
|
+
The space shares vocabulary but not architecture. Distinguishing the camps is the
|
|
19
|
+
whole analysis, because most "agent memory" products are not competitors at all.
|
|
20
|
+
|
|
21
|
+
| Camp | What it means | Where memory comes from | Competes with us? |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| **Transcript readers** | Index the JSONL/SQLite stores the agents already wrote | Passive — reads disk | **Yes, directly** |
|
|
24
|
+
| **Hook capturers** | Install lifecycle hooks, compress with an LLM, re-inject | Passive, but must live inside the agent | Yes, on the same users |
|
|
25
|
+
| **Memory SDKs** | Developer calls `add()` / `search()` | Active — the developer writes it | No — different product |
|
|
26
|
+
| **Observability** | OTel/proxy traces of model calls | Passive, at the API layer | Only on analytics |
|
|
27
|
+
|
|
28
|
+
mem-house is a transcript reader with the observability camp's analytics attached.
|
|
29
|
+
That combination is the most defensible thing about the product's *shape*; the
|
|
30
|
+
individual pieces are not scarce.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## The four bets, graded
|
|
35
|
+
|
|
36
|
+
### Bet 1 — Parse on the client. **Occupied. Not differentiated.**
|
|
37
|
+
|
|
38
|
+
The reasoning in `DESIGN.md` is sound and the conclusion is correct — sqlite-backed
|
|
39
|
+
editors do force client-side parsing. But it is no longer a distinguishing choice.
|
|
40
|
+
At least five projects crack the same on-disk stores today, and one of them cracks
|
|
41
|
+
formats we do not touch (encrypted Protobuf sidecars for Antigravity CLI, Markdown
|
|
42
|
+
for aider).
|
|
43
|
+
|
|
44
|
+
Editor coverage — the number we lead the README with — is mid-pack:
|
|
45
|
+
|
|
46
|
+
| Project | Editors | Note |
|
|
47
|
+
|---|---:|---|
|
|
48
|
+
| AgentsView | **50+** | each with documented on-disk paths |
|
|
49
|
+
| lean-ctx | 30+ | claimed |
|
|
50
|
+
| CCHV | 28 | each with documented paths |
|
|
51
|
+
| **mem-house** | **17** | |
|
|
52
|
+
| deja-vu | 17 | different 17 — has Cline, aider, Qwen Code, Kimi Code, Roo Code |
|
|
53
|
+
| coding_agent_session_search | 11+ | |
|
|
54
|
+
| ctx | 8 | |
|
|
55
|
+
| Conare | 7 | |
|
|
56
|
+
| Contextify | 2 | Claude Code + Codex CLI only |
|
|
57
|
+
|
|
58
|
+
deja-vu's tagline is our pitch verbatim: *"it indexes the sessions your coding agents
|
|
59
|
+
already wrote to disk, months of history from before you installed it, across
|
|
60
|
+
seventeen harnesses."*
|
|
61
|
+
|
|
62
|
+
### Bet 2 — Typed common schema. **Occupied on outcome, distinct on method.**
|
|
63
|
+
|
|
64
|
+
Everyone arrives at structured storage; the axis that still separates us is **when
|
|
65
|
+
the extraction happens and what survives it**.
|
|
66
|
+
|
|
67
|
+
- **SQLite + FTS5 is the category default**, reached independently by AgentsView,
|
|
68
|
+
Agent Sessions, claude-code-chat-explorer, claude-mem, ccrecall and mnemo.
|
|
69
|
+
- **ClickHouse for editor transcripts is unclaimed.** The only other ClickHouse-based
|
|
70
|
+
agent memory found is `clickmem` (57 stars) and it is embedded chDB, single-user,
|
|
71
|
+
so it inherits none of the multi-member properties. Langfuse is ClickHouse-backed,
|
|
72
|
+
MIT and self-hostable — but ingests API traces, not editor stores.
|
|
73
|
+
- **Verbatim-with-no-LLM-on-the-write-path has one serious co-traveller**:
|
|
74
|
+
MemPalace (58k stars in four months) sells exactly that — *"verbatim storage,
|
|
75
|
+
zero API calls."* We are not alone on this axis, but the company is good.
|
|
76
|
+
|
|
77
|
+
Honest caveat: at single-team scale SQLite demonstrably suffices. ClickHouse is a
|
|
78
|
+
bet on a scale we have not yet had to prove.
|
|
79
|
+
|
|
80
|
+
### Bet 3 — Kernel-installable agency, own-only by absent grant. **This one holds.**
|
|
81
|
+
|
|
82
|
+
This is the finding worth acting on. Every competitor's multi-user story is a
|
|
83
|
+
**shared pool** or **metadata scoping**. Not one enforces isolation at the
|
|
84
|
+
datastore's own permission layer.
|
|
85
|
+
|
|
86
|
+
| Product | Team mechanism | Isolation |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| AgentsView | `pg push` / `pg serve` to shared PostgreSQL | **None.** Connection string is the whole boundary; `machine_name` is a label, not a fence |
|
|
89
|
+
| memsearch (Zilliz) | Docker + shared Milvus, documented "for team environments" | **None documented** — no RBAC, no per-user namespacing |
|
|
90
|
+
| mem0 | `user_id` + `agent_id` + `run_id` filters | Metadata filtering, not enforcement |
|
|
91
|
+
| Industry pattern | `tenant_id` column + row-level security | Policy layer, revocable by whoever owns the policy |
|
|
92
|
+
| Contextify | Cloud workspace, per-project opt-in | Real, but proprietary, cloud-first, 2 editors |
|
|
93
|
+
| **mem-house** | three `GRANT SELECT` on the member's own rooms | **A member cannot name another member's rooms.** `WITH GRANT OPTION` on `SELECT` and not on `ALL` makes sharing read-only by construction and operator-free |
|
|
94
|
+
|
|
95
|
+
Bet 3 is not a niche preference. It is a category-wide blind spot, and it is the
|
|
96
|
+
only thing in this document that nobody else is attempting.
|
|
97
|
+
|
|
98
|
+
### Bet 4 — Borrowed UI, zero fork. **Occupied. Not differentiated.**
|
|
99
|
+
|
|
100
|
+
Analytics over the same files is a crowded, mature niche: ccusage (17.8k stars),
|
|
101
|
+
CodexBar (19.8k). Agent Sessions beats us on the analytics *idea* with a per-session
|
|
102
|
+
"Quota Meter / Session Runway" priced per model against 5-hour and weekly windows.
|
|
103
|
+
AgentsView ships cache-aware, LiteLLM-priced cost reporting plus a REST usage API.
|
|
104
|
+
|
|
105
|
+
Zero-fork was the right call for build cost. It buys no position.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## The field, ranked by how directly it competes
|
|
110
|
+
|
|
111
|
+
| # | Project | What it is | Source | Store | Team | Editors | Licence | Signal (2026-08-07) |
|
|
112
|
+
|---|---|---|---|---|---|---:|---|---|
|
|
113
|
+
| 1 | **AgentsView** | Go binary + Tauri app + Docker image | reads disk | SQLite/FTS5, opt. DuckDB, opt. **PostgreSQL** | shared pool, free | 50+ | MIT | **4,723★**, 574 forks, 100 contributors, six months old, MCP server, semantic search |
|
|
114
|
+
| 2 | **claude-mem** | npm plugin + MCP + web viewer | **hooks** | SQLite + Chroma, opt. cloud | none | ~8 | Apache-2.0 | **89,967★**, 7,831 forks, **62,940 npm dl/mo**. The category's centre of gravity |
|
|
115
|
+
| 3 | **MemPalace** | local-first memory, verbatim | mixed, mining transcripts | pluggable | none | — | MIT | **58,182★ in four months**, 696 open issues, contested benchmarks |
|
|
116
|
+
| 4 | **deja-vu** | zero-dep Go binary, CLI + MCP + hook | reads disk | `records.bin`, no server | none — personal SSH sync | 17 | MIT | 593★, HN 131 pts, redacts secrets at index |
|
|
117
|
+
| 5 | **Contextify** | macOS app + CLI, cloud **and** self-hosted | reads disk | local + optional cloud | **real**: seats, roles, per-project opt-in | 2 | proprietary / FSL | $8–15/seat/mo; self-host $132/seat/yr |
|
|
118
|
+
| 6 | **ctx** | Rust CLI, event-level provenance | reads disk | local SQLite | **ctx cloud**, hosted, private beta | 8 | Apache-2.0 | 1,013★ |
|
|
119
|
+
| 7 | **SpecStory** | IDE extensions + CLI | **writes its own** | local + cloud | team rollups | 9 | Apache-2.0 | 1,296★; **Team $300/mo**; "Lore" mines history into installable skills |
|
|
120
|
+
| 8 | **Conare** | CLI + hosted, MCP | reads disk | vendor cloud | shared memory, audit logs, SSO | 7 | proprietary | **Team $500/mo** |
|
|
121
|
+
| 9 | **memsearch** | Markdown + Milvus shadow index | Stop hooks | Markdown truth + Milvus | Docker, no isolation | 4 | MIT | 2,431★, Zilliz-backed |
|
|
122
|
+
| 10 | **CCHV** | Tauri app + **headless server** | reads disk | provider files + cache | server mode w/ accounts | 28 | MIT | 2,020★, 45 contributors |
|
|
123
|
+
| 11 | **Agent Sessions** | native macOS app | reads disk | SQLite/FTS5 | none | 10 | MIT | 762★; best-in-class quota metering; resume + write-back restore |
|
|
124
|
+
| 12 | **ContextPool** | CLI + MCP | reads disk | local + repo dir | shared pool, $7.99/mo | 4 | mixed | 188 PH upvotes |
|
|
125
|
+
|
|
126
|
+
Adjacent and **not** competitors, but they own the vocabulary and the capital:
|
|
127
|
+
mem0 (62.8k★, $24M), cognee (29.8k★), graphiti (29.6k★), supermemory (28.8k★),
|
|
128
|
+
letta (24.1k★, $10M seed), memori (15.7k★), OpenViking (28.1k★, ByteDance),
|
|
129
|
+
Hindsight (19.2k★, $3.6M seed). All of them require the developer to write the
|
|
130
|
+
memory. None ingest agent sessions.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## What they do better
|
|
135
|
+
|
|
136
|
+
- **Distribution.** mem-house: 0 stars, 655 npm downloads/month, no HN or search
|
|
137
|
+
presence. claude-mem: 89,967 stars and 62,940 downloads/month, free, no company.
|
|
138
|
+
This dominates every other consideration in the document.
|
|
139
|
+
- **Automatic recall.** deja-vu installs a SessionStart hook; claude-mem injects into
|
|
140
|
+
future sessions; ContextPool loads at session start; SpecStory converts history
|
|
141
|
+
into *installed skills*. Our skills must be chosen. One independent analysis of 270
|
|
142
|
+
real sessions found **only 4.8% involved an explicit history query** — a pull-only
|
|
143
|
+
model gets invoked rarely.
|
|
144
|
+
- **Install weight — we are the heaviest in the category.** AgentsView, deja-vu and
|
|
145
|
+
ctx are single dependency-free binaries via Homebrew, Docker, `go install` or curl.
|
|
146
|
+
We are Node, need `--allow-scripts=better-sqlite3` (five adapters silently read
|
|
147
|
+
nothing without it), and additionally need a ClickHouse to point at. Our README
|
|
148
|
+
spends paragraphs on `EACCES`/`sudo` triage. That is a real adoption tax.
|
|
149
|
+
- **Semantic search.** AgentsView (opt-in index), claude-mem (Chroma),
|
|
150
|
+
claude-history (local embedding model). We are FTS-only. Contested rather than
|
|
151
|
+
settled — deja-vu made the same choice and was criticised for it on HN.
|
|
152
|
+
- **Secret redaction at ingest.** deja-vu redacts credential patterns on index *and*
|
|
153
|
+
on sync export. Whether we do is *unverified* — and it matters more here than
|
|
154
|
+
elsewhere, because Claude Code caches unredacted secrets in transcripts
|
|
155
|
+
(anthropics/claude-code#43675) and we ship those rows to a shared server.
|
|
156
|
+
- **Resume and write-back.** Agent Sessions copies resume commands for six CLIs and
|
|
157
|
+
restores into the archive; claude-history resumes *and forks* worktree-aware. We
|
|
158
|
+
read but do not hand the pilot back in.
|
|
159
|
+
- **Price ceiling.** AgentsView gives the whole stack away under MIT. That caps what
|
|
160
|
+
a self-hosted OSS competitor can charge for.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Unclaimed ground
|
|
165
|
+
|
|
166
|
+
Two positions nobody occupies, both reachable from where we already are.
|
|
167
|
+
|
|
168
|
+
**1. Evidence and claims as two layers.** The sharpest architectural critique found
|
|
169
|
+
anywhere in the survey, and no product in the field claims to do it: keep the capture
|
|
170
|
+
log and the memory layer distinct. The capture log is chronological evidence; memory
|
|
171
|
+
is a set of derived, revisable claims. Each claim cites the exact spans supporting
|
|
172
|
+
it, records when it was inferred, and marks itself current, disputed or superseded —
|
|
173
|
+
and deletion follows that lineage. This is available **only** to a system that keeps
|
|
174
|
+
verbatim transcripts with provenance. Every extract-only competitor has discarded the
|
|
175
|
+
evidence by the time the claim is written. We and MemPalace are the two systems
|
|
176
|
+
positioned to build it. Neither has.
|
|
177
|
+
|
|
178
|
+
**2. The 30-day deletion window.** Claude Code deletes JSONL transcripts after 30
|
|
179
|
+
days. Contextify was built because of it; vibe-replay documents it; **nobody markets
|
|
180
|
+
on it.** A durable server-side store is the strongest possible answer, and we are
|
|
181
|
+
better positioned than any local-index tool. This is free ground.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Three cautions
|
|
186
|
+
|
|
187
|
+
**Do not compete on benchmark scores.** The benchmarks are broken. An independent
|
|
188
|
+
LOCOMO audit found 99 score-corrupting errors in 1,540 questions (6.4%), and the
|
|
189
|
+
standard LLM judge accepted 62.81% of adversarially-generated wrong-but-topical
|
|
190
|
+
answers. Nine vendors claim mutually incompatible SOTA on it. MemPalace's claimed
|
|
191
|
+
100% was reverse-engineered publicly to 98.4%, achieved with `top-k=50` — which
|
|
192
|
+
exceeds the session count. deja-vu's 84.9% hit@1 carries the same asterisk. Entering
|
|
193
|
+
this contest means measuring the field against itself.
|
|
194
|
+
|
|
195
|
+
**Stars are not traction, and are farmed in this category.** `mindverse/Second-Me`
|
|
196
|
+
holds 15,648 stars and has been dead for ten months. MemPalace took 58k stars in four
|
|
197
|
+
months while accumulating 2,183 issues, one titled *"in short: This sucks shit."*
|
|
198
|
+
Screenpipe reportedly mails its stargazers.
|
|
199
|
+
|
|
200
|
+
**The free incumbent sets the floor.** claude-mem is Apache-2.0, free, no cloud tier,
|
|
201
|
+
no company, one dominant author. Any paid or heavier-install offering is measured
|
|
202
|
+
against that baseline, not against a vendor's price list.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Net position
|
|
207
|
+
|
|
208
|
+
Not differentiated on parse-on-client, editor breadth, self-hosting, analytics, or
|
|
209
|
+
agent-facing skills — all matched or beaten, most comprehensively by AgentsView
|
|
210
|
+
(MIT, free, 50+ editors, 4,723 stars, six months old).
|
|
211
|
+
|
|
212
|
+
Two things hold: **grant-enforced per-member isolation**, which nobody attempts, and
|
|
213
|
+
**verbatim transcripts with provenance**, which is the prerequisite for the
|
|
214
|
+
evidence/claims separation the field has identified but not built.
|
|
215
|
+
|
|
216
|
+
The liabilities are zero distribution and the heaviest install in the category.
|
|
217
|
+
Both are fixable; neither is fixed by adding another editor adapter.
|
package/mem-house/DESIGN.md
CHANGED
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
**mem-house** is agent conversation memory as a product: every coding-agent session
|
|
4
4
|
on your machines — across **all 17 editors** agentlytics supports — parsed locally,
|
|
5
|
-
shipped to
|
|
5
|
+
shipped to a typed ClickHouse store, shareable with a team, installable on the
|
|
6
6
|
ultimagent kernel as an **agency**, and visible through the agentlytics dashboard.
|
|
7
7
|
|
|
8
|
+
**One house, a set of rooms per member** — `sessions_<m>`, `messages_<m>`,
|
|
9
|
+
`tool_calls_<m>`. All of one member's machines ship into that member's rooms, told
|
|
10
|
+
apart by the `host` column; no member writes into another's. The shared-table layout
|
|
11
|
+
this once had was removed in 0.4.0; see `per-member/`.
|
|
12
|
+
|
|
8
13
|
**Agency, precisely.** In constellation terms (`../TERMINOLOGY.md`) mem-house is a
|
|
9
|
-
**house** — the `
|
|
14
|
+
**house** — the `mem` database — **plus a resident**: the shipper. That pairing
|
|
10
15
|
is what the word *agency* means; a house on its own only holds.
|
|
11
16
|
|
|
12
17
|
The test is mechanical — **residents write, routines read**. The shipper fires on a
|
|
@@ -18,27 +23,34 @@ kind = "worker" # deterministic code, no LLM
|
|
|
18
23
|
on = "loop" # a daemon — not an insert trigger, not a schedule
|
|
19
24
|
```
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
The session rollup is a **routine** — house machinery, not a second resident. Since
|
|
27
|
+
0.4.0 it is not even an object: it is SQL text (`per-member/rooms.js`), substituted with
|
|
28
|
+
the caller's own room names and computed during your query, for your query, writing
|
|
29
|
+
nothing. mem-house has **no materialized views at all** — in fact no stored views at all
|
|
30
|
+
— so the shipper is not merely a resident, it is the only candidate in the tree. Strip
|
|
31
|
+
it and every remaining moving part is a routine over rows nobody is writing any more.
|
|
26
32
|
|
|
27
33
|
Note that `user_id MATERIALIZED currentUser()` is a materialized *column*: it computes
|
|
28
|
-
during your own insert and is part of the table's definition. It
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
during your own insert and is part of the table's definition. It is not what isolates
|
|
35
|
+
members — the room they hold no grant on does that — but it records who wrote each row,
|
|
36
|
+
which keeps provenance across a share and keeps the `Merge` rooms meaningful. An identity
|
|
37
|
+
property, not what makes this an agency.
|
|
31
38
|
|
|
32
39
|
**Positioning:** an alternative agency **competing with memory-house**. It borrows
|
|
33
|
-
memory-house's proven ideas (server-stamped identity,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
memory-house's proven ideas (server-stamped identity, idempotent shipping,
|
|
41
|
+
skills/plugin delivery) and agentlytics' proven assets (adapters, UI, cost engine) —
|
|
42
|
+
but **not** its shared-table-plus-row-policy layout, which 0.4.0 removed in favour of
|
|
43
|
+
one set of rooms per member. If it wins, it can become memory-house v4; until then the
|
|
44
|
+
two run side by side as separate agencies, each in its own house. Naming: the product is
|
|
45
|
+
**mem-house**; the agency is **`memhouse`** and its house is the **`mem`** database
|
|
46
|
+
(identifiers can't carry a dash; the owner kept the longer name, `memhouse_root`).
|
|
39
47
|
|
|
40
48
|
## The four bets
|
|
41
49
|
|
|
50
|
+
`COMPETITION.md` grades each of these against the field as surveyed 2026-08-07.
|
|
51
|
+
Short version: bets 1, 2 and 4 are occupied by shipping competitors, several of
|
|
52
|
+
them free and further along; **bet 3 is the one nobody else attempts.**
|
|
53
|
+
|
|
42
54
|
1. **Parse on the client.** memory-house ships raw transcript lines and parses in
|
|
43
55
|
views — workable only because its 4 agents store sessions as JSON/JSONL files.
|
|
44
56
|
agentlytics' breadth includes sqlite-backed editors (Cursor, VS Code, Zed,
|
|
@@ -48,19 +60,20 @@ side by side as separate agencies, each in its own house. Naming: the product is
|
|
|
48
60
|
write axis this bet is precisely *moving work from routine to resident*:
|
|
49
61
|
memory-house parses when you query, mem-house parses before anyone asks and
|
|
50
62
|
writes the result down.
|
|
51
|
-
2. **Typed common schema** (`schema.sql
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
2. **Typed common schema** (`per-member/schema-member.sql.tpl`, applied once per
|
|
64
|
+
member; `schema-merge.sql.tpl` for the team rooms). Physical typed columns (what
|
|
65
|
+
memory-house derives in views) + `tool_calls_<m>` (memory-house has no tool table)
|
|
66
|
+
+ one `extra JSON` escape hatch per room so unnormalized adapter fields are never
|
|
67
|
+
lost. `ReplacingMergeTree(ingested_at)`; `messages_<m>` keyed
|
|
68
|
+
`(session_id, user_id, seq)` so a re-ship of a grown/changed session replaces stale
|
|
69
|
+
rows (latest-wins). FTS text indexes built in (CH ≥ 26.2).
|
|
57
70
|
3. **Kernel-installable agency.** Same install path proven for agentlytics-agency:
|
|
58
71
|
`install-agency{memhouse}` → house + `memhouse_root` + credential; members via
|
|
59
|
-
`register-member` + owner `GRANT
|
|
60
|
-
|
|
72
|
+
`register-member` + owner `GRANT` on that member's own rooms. Own-only visibility
|
|
73
|
+
needs no policy: a member is granted their rooms and nobody else's. The shipper is
|
|
61
74
|
the resident that lands with it. Identity is `user_id MATERIALIZED currentUser()`
|
|
62
|
-
(requires `async_insert=0`). Sharing
|
|
63
|
-
|
|
75
|
+
(requires `async_insert=0`). Sharing is a further GRANT, issued by the member
|
|
76
|
+
themselves (grant-option) or the owner.
|
|
64
77
|
4. **Borrowed UI, zero fork.** The React SPA consumes REST JSON, not tables. The
|
|
65
78
|
mem-house server implements the **same `/api/*` contract** as agentlytics'
|
|
66
79
|
`server.js` (same routes, same response shapes) over the mem-house schema, and
|
|
@@ -70,11 +83,13 @@ side by side as separate agencies, each in its own house. Naming: the product is
|
|
|
70
83
|
|
|
71
84
|
| Path | What | Notes |
|
|
72
85
|
|---|---|---|
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
86
|
+
| `per-member/rooms.js` | room-name resolution + the session rollup | one naming rule for both transports |
|
|
87
|
+
| `per-member/schema-member.sql.tpl` | one member's three rooms (typed) | the owner via `provision.js`, or the member on a house they own |
|
|
88
|
+
| `per-member/schema-merge.sql.tpl` | the three team Merge rooms | owner-managed; reduce to the caller's grants |
|
|
75
89
|
| `shipper/ship.js` | parse-on-client shipper CLI — the resident (`worker`) | reuses `../../editors`; incremental; idempotent |
|
|
76
90
|
| `server/server.js` | REST API + dashboard | same API contract as agentlytics; serves `../../public` |
|
|
77
91
|
| `delivery/` | delivery kit | installer, skills, plugin, AGENT-INSTALL.md, prompt |
|
|
92
|
+
| `COMPETITION.md` | the competitive landscape, graded against the four bets | surveyed 2026-08-07; figures decay, re-run before citing |
|
|
78
93
|
|
|
79
94
|
## Environment contract
|
|
80
95
|
|
|
@@ -83,7 +98,7 @@ side by side as separate agencies, each in its own house. Naming: the product is
|
|
|
83
98
|
| `MEMHOUSE_URL` | `http://localhost:8123` | ClickHouse HTTP(S) endpoint |
|
|
84
99
|
| `MEMHOUSE_USER` | `memhouse_root` | CH user (owner, or a member's own credential) |
|
|
85
100
|
| `MEMHOUSE_PASSWORD` | *(empty)* | credential |
|
|
86
|
-
| `MEMHOUSE_DB` | `
|
|
101
|
+
| `MEMHOUSE_DB` | `mem` | the house |
|
|
87
102
|
| `MEMHOUSE_PORT` | `4640` | dashboard/API port |
|
|
88
103
|
|
|
89
104
|
Config file: `~/.memhouse/config.json` (`hiddenProjects`, future prefs).
|
|
@@ -102,6 +117,15 @@ Config file: `~/.memhouse/config.json` (`hiddenProjects`, future prefs).
|
|
|
102
117
|
- Incremental shipping: read existing `(session_id, last_updated_at, message_count)`
|
|
103
118
|
(FINAL) and skip chats that haven't grown/changed; a full re-ship must remain
|
|
104
119
|
safe (ReplacingMergeTree collapses).
|
|
120
|
+
- Re-shipping a known session **deletes its message/tool rows first**: `ReplacingMergeTree`
|
|
121
|
+
collapses same-key rows but cannot remove a row the new parse no longer produces, so a
|
|
122
|
+
shrunken re-parse would leave a stale `seq` tail forever.
|
|
123
|
+
- **A mutation predicate must bind the user, never call `currentUser()`.** A mutation does
|
|
124
|
+
not evaluate it in the caller's context: measured on ClickHouse 25.11 and chdb, the same
|
|
125
|
+
`DELETE` matched 0 rows with `user_id = currentUser()` and 2000 with the value bound —
|
|
126
|
+
silently, both times. Read the identity once (`SELECT currentUser()`) and pass it as a
|
|
127
|
+
query parameter. This applies to `DELETE`/`ALTER … UPDATE`, not to `SELECT`, where
|
|
128
|
+
`currentUser()` behaves as expected.
|
|
105
129
|
- Costs are computed in the server from `pricing.js` (repo root) over per-model
|
|
106
130
|
token sums; `<synthetic>` and empty models excluded from model lists.
|
|
107
131
|
|
|
@@ -114,6 +138,11 @@ to use mem-house as memory), `kernel-install.md` (provision as agency `memhouse`
|
|
|
114
138
|
|
|
115
139
|
## Non-goals (v0)
|
|
116
140
|
|
|
117
|
-
Relay/team-server (the
|
|
118
|
-
|
|
119
|
-
|
|
141
|
+
Relay/team-server (per-room grants plus the `Merge` rooms already cover sharing),
|
|
142
|
+
migration tooling from memory-house's `memory` db, and per-adapter true message
|
|
143
|
+
timestamps.
|
|
144
|
+
|
|
145
|
+
OS-level daemonization **was** a non-goal — "ship `--loop` instead" — and is no longer:
|
|
146
|
+
`memhouse service install` writes a systemd `--user` unit or a launchd LaunchAgent. The
|
|
147
|
+
reason the non-goal did not survive is that `--loop` outlives the shell and nothing else,
|
|
148
|
+
so a machine that reboots stops shipping until somebody notices.
|
|
@@ -50,7 +50,7 @@ cat > ~/.memhouse/env <<'EOF'
|
|
|
50
50
|
MEMHOUSE_URL=http://localhost:8123
|
|
51
51
|
MEMHOUSE_USER=memhouse_root
|
|
52
52
|
MEMHOUSE_PASSWORD=<credential>
|
|
53
|
-
MEMHOUSE_DB=
|
|
53
|
+
MEMHOUSE_DB=mem
|
|
54
54
|
EOF
|
|
55
55
|
chmod 600 ~/.memhouse/env
|
|
56
56
|
```
|
|
@@ -76,11 +76,13 @@ warns by name about any adapter it had to skip — that warning is the only sign
|
|
|
76
76
|
that step 1's `--allow-scripts` flag was missed and five editors are dark.
|
|
77
77
|
|
|
78
78
|
`stats` should show one row per source (claude-code, codex, gemini-cli, …) with
|
|
79
|
-
non-zero sessions/messages. Or verify by SQL
|
|
79
|
+
non-zero sessions/messages. Or verify by SQL — rooms are named for your ClickHouse
|
|
80
|
+
user, and the session rollup is a saved query rather than an object, so
|
|
81
|
+
`memhouse sessions-query` prints it:
|
|
80
82
|
|
|
81
83
|
```bash
|
|
82
84
|
curl -s -u "$MEMHOUSE_USER:$MEMHOUSE_PASSWORD" "$MEMHOUSE_URL/?database=$MEMHOUSE_DB" \
|
|
83
|
-
--data-binary "SELECT source, count() FROM
|
|
85
|
+
--data-binary "SELECT source, count() FROM $(memhouse sessions-query) AS c GROUP BY source SETTINGS final=1, join_use_nulls=1 FORMAT PrettyCompact"
|
|
84
86
|
```
|
|
85
87
|
|
|
86
88
|
## 5. Start the dashboard and the shipper loop
|
|
@@ -9,10 +9,13 @@ long-term conversation memory.
|
|
|
9
9
|
|
|
10
10
|
You have persistent memory of past agent sessions — every conversation this user
|
|
11
11
|
has had with coding agents (Claude Code, Codex, Gemini CLI, Cursor, and other
|
|
12
|
-
editors), across machines, stored in
|
|
12
|
+
editors), across all of YOUR machines, stored in your own rooms in a ClickHouse
|
|
13
|
+
database called **mem**. Other members of the same house have their own rooms and
|
|
14
|
+
you hold no grant on them.
|
|
13
15
|
Connection: read `~/.memhouse/env` (`MEMHOUSE_URL/USER/PASSWORD/DB`); query over
|
|
14
16
|
HTTP with `curl -u "$MEMHOUSE_USER:$MEMHOUSE_PASSWORD" "$MEMHOUSE_URL/?database=$MEMHOUSE_DB"`
|
|
15
|
-
and always add `SETTINGS final=1` to reads
|
|
17
|
+
and always add `SETTINGS final=1, join_use_nulls=1` to reads — the second matters
|
|
18
|
+
wherever the session rollup is used (see below).
|
|
16
19
|
|
|
17
20
|
**When to reach for it — before claiming ignorance.** If the user refers to past
|
|
18
21
|
work that is not in your current context ("that session where…", "how did I solve
|
|
@@ -21,22 +24,32 @@ FIRST. Only say you don't know after a search comes back empty.
|
|
|
21
24
|
|
|
22
25
|
**How to query.** Prefer the installed skills when present: `/memhouse:search`
|
|
23
26
|
(full-text over messages), `/memhouse:sessions` (list/filter sessions),
|
|
24
|
-
`/memhouse:sql` (free-form read-only SQL). Without skills, query directly
|
|
27
|
+
`/memhouse:sql` (free-form read-only SQL). Without skills, query directly.
|
|
28
|
+
|
|
29
|
+
**Table names first.** Every member owns their rooms, so every table below takes your
|
|
30
|
+
username as a suffix — `messages_<you>`, `sessions_<you>`, `tool_calls_<you>`. There
|
|
31
|
+
are no unsuffixed rooms; the plain names fail with `UNKNOWN_TABLE` rather than
|
|
32
|
+
returning nothing. Get the suffix from `SELECT currentUser()`. **There is no
|
|
33
|
+
`sessions_v` object** — the rollup is a saved query over those same rooms, and
|
|
34
|
+
`memhouse sessions-query` prints it ready to drop into a `FROM (...) AS c`.
|
|
35
|
+
`all_messages` / `all_sessions` / `all_tool_calls` read across every member you hold a
|
|
36
|
+
grant for.
|
|
25
37
|
|
|
26
38
|
- Find sessions about a topic (FTS, lowercase your terms):
|
|
27
|
-
`SELECT DISTINCT session_id, any(project), min(ts) FROM
|
|
39
|
+
`SELECT DISTINCT session_id, any(project), min(ts) FROM messages_<you>
|
|
28
40
|
WHERE hasToken(text_word, 'clickhouse') GROUP BY session_id
|
|
29
|
-
ORDER BY 3 DESC LIMIT 10 SETTINGS final=1 FORMAT PrettyCompact`
|
|
41
|
+
ORDER BY 3 DESC LIMIT 10 SETTINGS final=1, join_use_nulls=1 FORMAT PrettyCompact`
|
|
30
42
|
- Recent sessions: `SELECT session_id, source, project, started, first_prompt
|
|
31
|
-
FROM
|
|
32
|
-
- Replay one session: `SELECT role, text FROM
|
|
33
|
-
WHERE session_id = '<id>' ORDER BY seq SETTINGS final=1`
|
|
43
|
+
FROM $(memhouse sessions-query) AS c ORDER BY started DESC LIMIT 20 SETTINGS final=1, join_use_nulls=1`
|
|
44
|
+
- Replay one session: `SELECT role, text FROM messages_<you>
|
|
45
|
+
WHERE session_id = '<id>' ORDER BY seq SETTINGS final=1, join_use_nulls=1`
|
|
34
46
|
|
|
35
47
|
**Rules.**
|
|
36
48
|
- Memory is READ-ONLY for you. Never INSERT/ALTER/DROP — ingestion belongs to the
|
|
37
49
|
mem-house shipper alone.
|
|
38
50
|
- Quote retrieved content as *the user's past sessions*, and cite the session_id
|
|
39
51
|
when the user may want to dig deeper.
|
|
40
|
-
- Other members' sessions
|
|
41
|
-
|
|
52
|
+
- Other members' sessions are invisible to you unless they have granted you their rooms.
|
|
53
|
+
You hold no grant on them otherwise, so naming one fails rather than returning nothing.
|
|
54
|
+
An empty result means "nothing visible", not "nothing ever happened".
|
|
42
55
|
- Do not paste credentials from `~/.memhouse/env` into responses, commits, or logs.
|
|
@@ -3,19 +3,19 @@
|
|
|
3
3
|
#
|
|
4
4
|
# Checks node >= 20 and a reachable ClickHouse, writes ~/.memhouse/env
|
|
5
5
|
# (MEMHOUSE_* vars), applies the house schema via the shipper
|
|
6
|
-
# (`ship.js --ensure-schema`), runs a first ship, and prints how to start the
|
|
6
|
+
# (`ship.js --ensure-schema` mints the caller's own rooms), runs a first ship, and prints how to start the
|
|
7
7
|
# dashboard and set up continuous shipping (`--loop`).
|
|
8
8
|
#
|
|
9
9
|
# Usage:
|
|
10
10
|
# ./install.sh # interactive (prompts for missing values)
|
|
11
|
-
# ./install.sh --url http://localhost:8123 --user memhouse_root --password 'pw' --db
|
|
11
|
+
# ./install.sh --url http://localhost:8123 --user memhouse_root --password 'pw' --db mem
|
|
12
12
|
# ./install.sh --yes # non-interactive, defaults / env / existing env file
|
|
13
13
|
#
|
|
14
14
|
# Flags:
|
|
15
15
|
# --url URL ClickHouse HTTP(S) endpoint (default http://localhost:8123)
|
|
16
16
|
# --user USER ClickHouse user (default memhouse_root; 'default' works for a local CH)
|
|
17
17
|
# --password PW credential (default empty)
|
|
18
|
-
# --db DB the house (database) (default
|
|
18
|
+
# --db DB the house (database) (default mem)
|
|
19
19
|
# --port PORT dashboard/API port (default 4640)
|
|
20
20
|
# --yes never prompt; take flags > current env > ~/.memhouse/env > defaults
|
|
21
21
|
# --no-ship stop after writing env + ensure-schema (skip the first ship)
|
|
@@ -43,7 +43,7 @@ fi
|
|
|
43
43
|
CH_URL="${MEMHOUSE_URL:-http://localhost:8123}"
|
|
44
44
|
CH_USER="${MEMHOUSE_USER:-memhouse_root}"
|
|
45
45
|
CH_PASSWORD="${MEMHOUSE_PASSWORD:-}"
|
|
46
|
-
CH_DB="${MEMHOUSE_DB:-
|
|
46
|
+
CH_DB="${MEMHOUSE_DB:-mem}"
|
|
47
47
|
DASH_PORT="${MEMHOUSE_PORT:-4640}"
|
|
48
48
|
|
|
49
49
|
ASSUME_YES=0
|
|
@@ -103,7 +103,7 @@ ONE="$(curl -sS --connect-timeout 5 --fail-with-body \
|
|
|
103
103
|
[ "$ONE" = "1" ] || die "unexpected reply from $CH_URL: $ONE"
|
|
104
104
|
info "ClickHouse ok"
|
|
105
105
|
|
|
106
|
-
# Ensure the house exists before ensure-schema (
|
|
106
|
+
# Ensure the house exists before ensure-schema (the room DDL is unqualified and the
|
|
107
107
|
# shipper binds to MEMHOUSE_DB — on a virgin standalone server the database must
|
|
108
108
|
# be created first). On a kernel realm the house is already provisioned; if the
|
|
109
109
|
# user lacks CREATE DATABASE but the house is reachable, that's fine too.
|
|
@@ -174,8 +174,10 @@ Next steps:
|
|
|
174
174
|
# -> installs memhouse-search / memhouse-sessions / memhouse-sql into
|
|
175
175
|
# \${CLAUDE_CONFIG_DIR:-\$HOME/.claude}/skills (loads next session)
|
|
176
176
|
|
|
177
|
-
Verify anytime:
|
|
177
|
+
Verify anytime (rooms are named for your ClickHouse user):
|
|
178
178
|
set -a; . "$ENV_FILE"; set +a
|
|
179
|
+
ME=\$(curl -sS --user "\$MEMHOUSE_USER:\$MEMHOUSE_PASSWORD" \\
|
|
180
|
+
--data-binary "SELECT currentUser() FORMAT TabSeparated" "\$MEMHOUSE_URL/")
|
|
179
181
|
curl -sS --user "\$MEMHOUSE_USER:\$MEMHOUSE_PASSWORD" --data-binary \\
|
|
180
|
-
"SELECT count() FROM
|
|
182
|
+
"SELECT count() FROM sessions_\$ME" "\$MEMHOUSE_URL/?database=\$MEMHOUSE_DB&final=1"
|
|
181
183
|
EOF
|