memhouse 0.18.12 → 0.20.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.
Files changed (169) hide show
  1. package/AGENTS.md +22 -151
  2. package/CHANGELOG.md +263 -29
  3. package/LICENSE +202 -22
  4. package/LICENSES/agentlytics-MIT.txt +21 -0
  5. package/LICENSES/memhouse-MIT-until-0.18.11.txt +22 -0
  6. package/LICENSES/models.dev-MIT.txt +22 -0
  7. package/NOTICE +28 -0
  8. package/README.md +42 -20
  9. package/SECURITY.md +21 -8
  10. package/bin/memhouse.js +2223 -311
  11. package/docs/README.md +11 -9
  12. package/docs/guides/admin-password.md +37 -10
  13. package/docs/guides/configuration.md +13 -6
  14. package/docs/guides/daemons.md +64 -3
  15. package/docs/guides/import-claude-ai.md +204 -0
  16. package/docs/guides/install.md +11 -6
  17. package/docs/guides/invite.md +21 -7
  18. package/docs/guides/operate.md +114 -7
  19. package/docs/guides/search-and-resume.md +72 -3
  20. package/docs/guides/share.md +91 -52
  21. package/docs/guides/storage.md +44 -4
  22. package/docs/guides/troubleshooting.md +121 -14
  23. package/docs/guides/uninstall.md +4 -3
  24. package/docs/guides/update.md +16 -0
  25. package/docs/guides/upgrade-to-0.20.md +188 -0
  26. package/docs/releases/README.md +2 -1
  27. package/docs/releases/v0.18.10.md +5 -5
  28. package/docs/releases/v0.18.11.md +3 -3
  29. package/docs/releases/v0.20.0.md +627 -0
  30. package/docs/releases/v0.20.1.md +114 -0
  31. package/docs/tutorials/01-first-house.md +10 -7
  32. package/docs/tutorials/02-join-a-house.md +24 -15
  33. package/docs/tutorials/03-share-your-memory.md +40 -31
  34. package/editors/antigravity.js +1 -80
  35. package/editors/base.js +463 -9
  36. package/editors/bridge.js +119 -0
  37. package/editors/claude.js +273 -105
  38. package/editors/codex.js +278 -52
  39. package/editors/copilot.js +1 -70
  40. package/editors/cursor.js +1 -75
  41. package/editors/derive-fingerprints.json +18 -0
  42. package/editors/harness-paths.js +69 -0
  43. package/editors/index.js +1 -20
  44. package/editors/normalise/agy.js +910 -0
  45. package/editors/normalise/copilot-cli.js +321 -0
  46. package/editors/normalise/cursor-agent.js +852 -0
  47. package/editors/normalise/cursor.js +474 -0
  48. package/editors/normalise/devin.js +575 -0
  49. package/editors/normalise/gemini-cli.js +602 -0
  50. package/editors/normalise/goose.js +673 -0
  51. package/editors/normalise/opencode.js +633 -0
  52. package/editors/normalise/vscode.js +549 -0
  53. package/editors/normalise/zed.js +473 -0
  54. package/editors/opencode-v4.js +119 -0
  55. package/editors/scope.js +14 -3
  56. package/editors/sessions-log.js +349 -0
  57. package/editors/sqlite.js +28 -1
  58. package/editors/vscode.js +1 -72
  59. package/editors/windsurf.js +1 -143
  60. package/examples/01-local-one-machine/README.md +24 -19
  61. package/examples/01-local-one-machine/run.sh +1 -1
  62. package/examples/02-existing-clickhouse/README.md +30 -22
  63. package/examples/02-existing-clickhouse/run.sh +5 -4
  64. package/examples/03-team-house/README.md +44 -37
  65. package/examples/03-team-house/run.sh +35 -18
  66. package/examples/04-self-hosted-team/README.md +29 -14
  67. package/examples/04-self-hosted-team/compose.yml +5 -2
  68. package/examples/04-self-hosted-team/smoke.sh +26 -12
  69. package/examples/README.md +8 -4
  70. package/examples/fixtures/README.md +4 -1
  71. package/examples/fixtures/make-sessions.js +8 -5
  72. package/memhouse/admin-secret.js +89 -24
  73. package/memhouse/argv-secrets.js +64 -0
  74. package/memhouse/channel.js +49 -9
  75. package/memhouse/codex-plugin.js +194 -0
  76. package/memhouse/delivery/AGENT-INSTALL-PROMPT.md +2 -1
  77. package/memhouse/delivery/AGENT-INSTALL.md +22 -11
  78. package/memhouse/delivery/INVITATION.md.tpl +44 -45
  79. package/memhouse/delivery/PROMPT.md +53 -5
  80. package/memhouse/delivery/UPGRADE.md.tpl +1 -1
  81. package/memhouse/delivery/codex/AGENTS-BLOCK.md +11 -0
  82. package/memhouse/delivery/codex/SKILL.md +50 -0
  83. package/memhouse/delivery/kernel-install.md +17 -9
  84. package/memhouse/delivery/plugin/.claude-plugin/plugin.json +2 -2
  85. package/memhouse/delivery/plugin/reference/HOUSE.md +168 -41
  86. package/memhouse/delivery/plugin/skills/access/SKILL.md +13 -5
  87. package/memhouse/delivery/plugin/skills/admin/SKILL.md +14 -6
  88. package/memhouse/delivery/plugin/skills/house/SKILL.md +25 -8
  89. package/memhouse/delivery/plugin/skills/recall/SKILL.md +66 -8
  90. package/memhouse/delivery/plugin/skills/sql/SKILL.md +66 -7
  91. package/memhouse/deploy.js +1 -1
  92. package/memhouse/flags.js +35 -18
  93. package/memhouse/help.js +37 -0
  94. package/memhouse/host.js +82 -2
  95. package/memhouse/house/HOUSE.md +2 -2
  96. package/memhouse/house/convert-profile.js +638 -0
  97. package/memhouse/house/convert-v3.js +742 -0
  98. package/memhouse/house/doctor-v3.js +324 -0
  99. package/memhouse/house/host-alias.js +85 -0
  100. package/memhouse/house/house.js +3 -3
  101. package/memhouse/house/migrate.js +2 -2
  102. package/memhouse/house/profile-dedupe.js +183 -0
  103. package/memhouse/house/profile-edges.js +554 -0
  104. package/memhouse/house/profile-house.js +430 -0
  105. package/memhouse/house/profile-rollup.js +190 -0
  106. package/memhouse/house/q-cli.js +863 -0
  107. package/memhouse/house/queries-v3.js +1013 -0
  108. package/memhouse/house/reconcile-v3.js +192 -0
  109. package/memhouse/house/records-to-profile.js +174 -0
  110. package/memhouse/house/records-to-rows.js +169 -0
  111. package/memhouse/house/relocate.js +2 -1
  112. package/memhouse/house/schema-choice.js +121 -0
  113. package/memhouse/house/schema-profile.js +290 -0
  114. package/memhouse/house/schema-profile.sql.tpl +398 -0
  115. package/memhouse/house/schema-v3.js +267 -0
  116. package/memhouse/house/schema-v3.sql.tpl +213 -0
  117. package/memhouse/import/claude-ai.js +420 -0
  118. package/memhouse/import/import.js +372 -0
  119. package/memhouse/import/pyjson.js +206 -0
  120. package/memhouse/import/records.js +64 -0
  121. package/memhouse/import/writer-profile.js +192 -0
  122. package/memhouse/import/writer-v3.js +240 -0
  123. package/memhouse/import/zip.js +112 -0
  124. package/memhouse/invitation.js +102 -0
  125. package/memhouse/invitefile.js +5 -2
  126. package/memhouse/plugin-copies.js +176 -0
  127. package/memhouse/provision.js +7 -2
  128. package/memhouse/release-hint.js +24 -0
  129. package/memhouse/resume.js +4 -4
  130. package/memhouse/server/api-v3.js +632 -0
  131. package/memhouse/server/dashboard-auth.js +181 -0
  132. package/memhouse/server/dashboard-port.js +91 -0
  133. package/memhouse/server/queries.js +30 -0
  134. package/memhouse/server/server.js +118 -20
  135. package/memhouse/service.js +1 -1
  136. package/memhouse/share.js +687 -1
  137. package/memhouse/shipper/adapter-capture.js +756 -0
  138. package/memhouse/shipper/capture.js +2571 -0
  139. package/memhouse/shipper/dedupe-profile.js +237 -0
  140. package/memhouse/shipper/dedupe-v3.js +1027 -0
  141. package/memhouse/shipper/forks.js +233 -0
  142. package/memhouse/shipper/log-adapter.js +219 -0
  143. package/memhouse/shipper/maintenance.js +49 -0
  144. package/memhouse/shipper/normalise-run.js +148 -0
  145. package/memhouse/shipper/passlog.js +68 -5
  146. package/memhouse/shipper/profile-capture.js +903 -0
  147. package/memhouse/shipper/ship.js +91 -8
  148. package/memhouse/shipper/snapshots.js +193 -0
  149. package/memhouse/shipper/source-roots.js +111 -0
  150. package/memhouse/version-notice.js +66 -0
  151. package/package.json +14 -7
  152. package/public/THIRD_PARTY_NOTICES.txt +2 -2
  153. package/public/assets/index-CcNnhfM3.js +78 -0
  154. package/public/index.html +1 -1
  155. package/ui/package-lock.json +56 -37
  156. package/ui/package.json +1 -0
  157. package/ui/src/App.jsx +29 -14
  158. package/ui/src/components/ChatSidebar.jsx +69 -12
  159. package/ui/src/lib/api.js +76 -0
  160. package/ui/src/lib/dashboard-token.js +41 -0
  161. package/ui/src/main.jsx +22 -5
  162. package/ui/src/pages/Dashboard.jsx +22 -36
  163. package/ui/third-party-notices.js +119 -0
  164. package/ui/vite.config.js +5 -1
  165. package/docs/releases/v0.18.12.md +0 -59
  166. package/memhouse/COMPETITION.md +0 -221
  167. package/memhouse/DESIGN.md +0 -222
  168. package/memhouse/RESUME-AND-UPDATE.md +0 -182
  169. package/public/assets/index-CnWzrjF3.js +0 -78
@@ -8,7 +8,7 @@ import ActivityHeatmap from '../components/ActivityHeatmap'
8
8
  import DateRangePicker from '../components/DateRangePicker'
9
9
  import { editorColor, editorLabel, formatNumber, formatCost, dateRangeToApiParams } from '../lib/constants'
10
10
  import EditorIcon from '../components/EditorIcon'
11
- import { fetchDailyActivity, fetchOverview as fetchOverviewApi, fetchDashboardStats, fetchChats, fetchCosts } from '../lib/api'
11
+ import { fetchLanding } from '../lib/api'
12
12
  import ChatSidebar from '../components/ChatSidebar'
13
13
  import AnimatedLoader from '../components/AnimatedLoader'
14
14
  import ShareModal from '../components/ShareModal'
@@ -26,7 +26,7 @@ const MODE_COLORS = {
26
26
  copilot: '#f59e0b', thread: '#ec4899', opencode: '#f43f5e', claude: '#f97316',
27
27
  }
28
28
 
29
- export default function Dashboard({ overview }) {
29
+ export default function Dashboard({ overview, refreshKey = 0 }) {
30
30
  const navigate = useNavigate()
31
31
  const [dailyData, setDailyData] = useState(null)
32
32
  const [filteredData, setFilteredData] = useState(null)
@@ -37,6 +37,7 @@ export default function Dashboard({ overview }) {
37
37
  const [costs, setCosts] = useState(null)
38
38
  const [shareOpen, setShareOpen] = useState(false)
39
39
  const [largeContextChats, setLargeContextChats] = useState(null)
40
+ const [largeContextTotal, setLargeContextTotal] = useState(null)
40
41
  const [selectedChatId, setSelectedChatId] = useState(null)
41
42
  const txtColor = dark ? '#888' : '#555'
42
43
  const txtDim = dark ? '#555' : '#999'
@@ -56,40 +57,25 @@ export default function Dashboard({ overview }) {
56
57
  }
57
58
  const noLegend = { legend: { display: false }, tooltip: { bodyFont: { family: MONO, size: 10 }, titleFont: { family: MONO, size: 10 } } }
58
59
 
60
+ // ONE request for the whole page (/api/landing). It used to be five — overview, daily
61
+ // activity, dashboard stats, costs and a 500-session chat list priced only to find the ten
62
+ // largest — 33–34 SQL statements behind them. `refreshKey` moves when Live sees the house
63
+ // version change or Refetch completes.
59
64
  useEffect(() => {
60
- const dateParams = dateRangeToApiParams(dateRange)
61
- const chatParams = { limit: 500, named: false, ...dateParams }
62
- if (selectedEditor) chatParams.editor = selectedEditor
63
-
64
- fetchChats(chatParams).then(r => {
65
- const big = (r.chats || []).filter(c => c.bubbleCount >= 100).sort((a, b) => b.bubbleCount - a.bubbleCount)
66
- setLargeContextChats(big)
67
- })
68
-
69
- if (!selectedEditor) {
70
- // A date range without an editor must still refresh the overview widgets
71
- // (KPIs, monthly trend, top projects) — falling back to the all-time
72
- // `overview` prop would disagree with the date-scoped heatmap/stats/costs.
73
- const hasDates = dateParams.dateFrom || dateParams.dateTo
74
- if (hasDates) fetchOverviewApi(dateParams).then(setFilteredData)
75
- else setFilteredData(null)
76
- fetchDailyActivity(dateParams).then(setDailyData)
77
- fetchDashboardStats(dateParams).then(setStats)
78
- fetchCosts(dateParams).then(setCosts)
79
- return
80
- }
81
- Promise.all([
82
- fetchOverviewApi({ editor: selectedEditor, ...dateParams }),
83
- fetchDailyActivity({ editor: selectedEditor, ...dateParams }),
84
- fetchDashboardStats({ editor: selectedEditor, ...dateParams }),
85
- fetchCosts({ editor: selectedEditor, ...dateParams }),
86
- ]).then(([ov, daily, st, c]) => {
87
- setFilteredData(ov)
88
- setDailyData(daily)
89
- setStats(st)
90
- setCosts(c)
91
- })
92
- }, [selectedEditor, dateRange])
65
+ const params = { ...dateRangeToApiParams(dateRange) }
66
+ if (selectedEditor) params.editor = selectedEditor
67
+ let cancelled = false
68
+ fetchLanding(params).then(r => {
69
+ if (cancelled) return
70
+ setFilteredData(r.overview)
71
+ setDailyData(r.daily)
72
+ setStats(r.stats)
73
+ setCosts(r.costs)
74
+ setLargeContextChats(r.largeContext.chats)
75
+ setLargeContextTotal(r.largeContext.total)
76
+ }).catch(() => {})
77
+ return () => { cancelled = true }
78
+ }, [selectedEditor, dateRange, refreshKey])
93
79
 
94
80
  if (!overview) return <AnimatedLoader label="Loading dashboard..." />
95
81
 
@@ -500,7 +486,7 @@ export default function Dashboard({ overview }) {
500
486
  <span className="inline-flex items-center gap-1">
501
487
  <AlertTriangle size={10} className="text-amber-400" />
502
488
  large context
503
- <span style={{ color: 'var(--c-text3)' }}>({largeContextChats.length})</span>
489
+ <span style={{ color: 'var(--c-text3)' }}>({largeContextTotal ?? largeContextChats.length})</span>
504
490
  </span>
505
491
  </SectionTitle>
506
492
  <div className="space-y-1">
@@ -0,0 +1,119 @@
1
+ /* global process */
2
+ // Writes THIRD_PARTY_NOTICES.txt beside the built dashboard (public/), listing every
3
+ // third-party package whose code ends up in the bundle, with its license text.
4
+ //
5
+ // Why: the bundle carries React, chart.js, lucide, react-markdown and others, all under
6
+ // licenses (MIT, ISC, …) whose one condition is that the notice travels with every copy.
7
+ // Vite strips their license comments when it minifies, so the published package shipped
8
+ // those copies with no notice at all. This plugin reads the bundle's own module graph, so
9
+ // the list is exactly what was bundled, never a hand-kept list that drifts.
10
+ //
11
+ // No dependency of its own on purpose: it reads each package's package.json and license
12
+ // file straight off node_modules.
13
+ import fs from 'node:fs'
14
+ import path from 'node:path'
15
+
16
+ const LICENSE_FILE = /^(licen[sc]e|copying|notice)([.-].*)?$/i
17
+
18
+ // Bundled packages that genuinely ship no license file, each with its declared license
19
+ // and why it may be listed without a text. Any other package without one fails the build.
20
+ // Empty today: every bundled package ships its license file.
21
+ // 'name': { license: 'MIT', reason: 'one line: why there is no file, and what was checked' },
22
+ export const NO_LICENSE_FILE = {}
23
+
24
+ // '/abs/ui/node_modules/react-dom/cjs/x.js' -> { name: 'react-dom', dir: '/abs/ui/node_modules/react-dom' }
25
+ // The LAST node_modules segment wins, so a nested copy is attributed to itself.
26
+ export function packageOf(id) {
27
+ const clean = String(id).replace(/^\0/, '').split('?')[0].split(path.sep).join('/')
28
+ const i = clean.lastIndexOf('/node_modules/')
29
+ if (i < 0) return null
30
+ const parts = clean.slice(i + '/node_modules/'.length).split('/')
31
+ const name = parts[0].startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0]
32
+ if (!name || name.startsWith('.')) return null
33
+ return { name, dir: clean.slice(0, i + '/node_modules/'.length) + name }
34
+ }
35
+
36
+ function readPackage(dir) {
37
+ let pkg = {}
38
+ try { pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8')) } catch { /* no manifest */ }
39
+ let files = []
40
+ try { files = fs.readdirSync(dir).filter((f) => LICENSE_FILE.test(f)).sort() } catch { /* unreadable dir */ }
41
+ const texts = files.map((f) => {
42
+ try { return { file: f, text: fs.readFileSync(path.join(dir, f), 'utf-8').trim() } } catch { return null }
43
+ }).filter(Boolean)
44
+ const license = typeof pkg.license === 'string' ? pkg.license
45
+ : (pkg.license && pkg.license.type) || (Array.isArray(pkg.licenses) ? pkg.licenses.map((l) => l.type || l).join(' OR ') : '')
46
+ const repo = typeof pkg.repository === 'string' ? pkg.repository : (pkg.repository && pkg.repository.url) || pkg.homepage || ''
47
+ return { version: pkg.version || '', license: license || 'UNKNOWN', repo, texts }
48
+ }
49
+
50
+ /**
51
+ * @param {object} [o]
52
+ * @param {string} [o.fileName] where the notices land, relative to outDir
53
+ * @param {string[]} [o.extra] packages that reach the bundle without showing up as a JS
54
+ * module: tailwindcss (its preflight CSS is in the stylesheet),
55
+ * react-router-dom (it only re-exports react-router, so the
56
+ * graph holds react-router's modules, not its own)
57
+ * @param {string} [o.root] where to resolve `extra` from (the ui/ directory)
58
+ */
59
+ export default function thirdPartyNotices({ fileName = 'THIRD_PARTY_NOTICES.txt', extra = [], root = process.cwd() } = {}) {
60
+ return {
61
+ name: 'memhouse-third-party-notices',
62
+ apply: 'build',
63
+ generateBundle(_options, bundle) {
64
+ // Keyed by INSTALL DIRECTORY, not by name: two versions of one package can both be
65
+ // bundled (a nested copy beside the top-level one), and each carries its own license.
66
+ const found = new Map() // dir -> name
67
+ for (const out of Object.values(bundle)) {
68
+ if (out.type !== 'chunk') continue
69
+ for (const id of Object.keys(out.modules || {})) {
70
+ const p = packageOf(id)
71
+ if (p && !found.has(p.dir)) found.set(p.dir, p.name)
72
+ }
73
+ }
74
+ for (const name of extra) {
75
+ const dir = path.join(root, 'node_modules', name).split(path.sep).join('/')
76
+ if (!found.has(dir) && fs.existsSync(dir)) found.set(dir, name)
77
+ }
78
+ // One entry per name@version; two install dirs holding the same version are one notice.
79
+ const entries = new Map()
80
+ for (const [dir, name] of found) {
81
+ const info = readPackage(dir)
82
+ const key = `${name}@${info.version}`
83
+ if (!entries.has(key)) entries.set(key, { name, ...info })
84
+ }
85
+ const list = [...entries.values()].sort((a, b) => (a.name === b.name
86
+ ? a.version.localeCompare(b.version, undefined, { numeric: true })
87
+ : (a.name < b.name ? -1 : 1)))
88
+ // A bundled package whose license text cannot be shipped fails the build. A notice
89
+ // file that silently omits one is the defect this plugin exists to prevent. The only
90
+ // exceptions are packages that genuinely ship no license file, named in
91
+ // NO_LICENSE_FILE with their declared license and the reason.
92
+ const missing = list.filter((e) => !e.texts.length && !NO_LICENSE_FILE[e.name])
93
+ if (missing.length) {
94
+ this.error(`bundled without a license text: ${missing.map((e) => `${e.name}@${e.version} (declares ${e.license})`).join(', ')}. `
95
+ + 'Add the license text, or list the package in NO_LICENSE_FILE (ui/third-party-notices.js) with its declared license and why.')
96
+ }
97
+ const blocks = list.map((e) => {
98
+ const allowed = NO_LICENSE_FILE[e.name]
99
+ const head = `${e.name}${e.version ? ` ${e.version}` : ''} — ${e.license}${e.repo ? `\n${e.repo}` : ''}`
100
+ const body = e.texts.length
101
+ ? e.texts.map((t) => (e.texts.length > 1 ? `[${t.file}]\n${t.text}` : t.text)).join('\n\n')
102
+ : `(this package ships no license file; declared license: ${allowed.license}. ${allowed.reason})`
103
+ return `${'='.repeat(72)}\n${head}\n${'-'.repeat(72)}\n${body}\n`
104
+ })
105
+ const source = [
106
+ 'memhouse dashboard — third-party software included in this directory (public/)',
107
+ '',
108
+ 'The built dashboard bundles the packages below. Each is listed with its version,',
109
+ 'its declared license, and the license text it ships. Generated at build time by',
110
+ 'ui/third-party-notices.js from the bundle\'s module graph.',
111
+ '',
112
+ `${list.length} packages.`,
113
+ '',
114
+ ...blocks,
115
+ ].join('\n')
116
+ this.emitFile({ type: 'asset', fileName, source })
117
+ },
118
+ }
119
+ }
package/ui/vite.config.js CHANGED
@@ -12,10 +12,14 @@ export default defineConfig({
12
12
  outDir: '../public',
13
13
  emptyOutDir: true,
14
14
  },
15
+ // The dev server proxies /api to the memhouse dashboard (127.0.0.1:MEMHOUSE_PORT, default 4640).
16
+ // The dashboard needs its token: open the dev server with the URL `memhouse dashboard` prints in
17
+ // a terminal, on this origin (http://localhost:5173/#token=…); the page sends it as a Bearer
18
+ // header, which this proxy passes on.
15
19
  server: {
16
20
  proxy: {
17
21
  '/relay': 'http://localhost:4638',
18
- '/api': process.env.RELAY ? 'http://localhost:4638' : 'http://localhost:4637',
22
+ '/api': process.env.RELAY ? 'http://localhost:4638' : `http://127.0.0.1:${process.env.MEMHOUSE_PORT || 4640}`,
19
23
  },
20
24
  },
21
25
  })
@@ -1,59 +0,0 @@
1
- # memhouse 0.18.12 — 2026-10-29
2
-
3
- A patch release on the 0.18 line. It does one thing for users:
4
-
5
- - **The `/mem` skills pre-approve read-only commands only.** Each skill's `allowed-tools`
6
- now lists the memhouse read commands it teaches, instead of `Bash` as a whole.
7
-
8
- No drill was run for this patch release. Its one user-facing change is held by
9
- `misc/skill-allowlist-test.js`, which runs in `npm test`.
10
-
11
- ## Upgrade
12
-
13
- ```bash
14
- memhouse update # refreshes the /mem skills wherever they are installed
15
- ```
16
-
17
- Then reload the skills in Claude Code with `/reload-plugins`, or restart the session.
18
-
19
- If you upgraded with `npm install -g memhouse` instead, run `memhouse plugins install claude`
20
- once, so the installed skills match the package.
21
-
22
- Nothing else changes: same house layout, same schema, same daemons.
23
-
24
- ## Changed
25
-
26
- ### Skills: allowed tools restricted to read-only commands
27
-
28
- Each `/mem` skill's `allowed-tools` names the memhouse read commands it uses:
29
-
30
- | skill | runs without a prompt |
31
- |---|---|
32
- | `/mem:house` | `memhouse instance`, `whoami`, `status`, `stats`, `doctor`, and `share --list` (with or without `--json`) |
33
- | `/mem:recall` | `memhouse search`, `resume`, `sessions-query`, `status`, `whoami` |
34
- | `/mem:sql` | `memhouse sessions-query`, `stats`, `status`, `whoami` |
35
- | `/mem:access` | `memhouse whoami`, `status`, and `share --list` (with or without `--json`) |
36
- | `/mem:admin` | `memhouse whoami`, `status`, `instance` |
37
-
38
- Any other command goes through Claude Code's normal permission prompt, as does a read
39
- command with another command chained to it. Expect a prompt where a skill used to run a
40
- command without one; approve it as you would any other command.
41
-
42
- ## Repository and tests
43
-
44
- These do not change the installed package's behaviour:
45
-
46
- - `misc/skill-allowlist-test.js` keeps every skill's `allowed-tools` to read-only memhouse
47
- commands. It joins `npm test`.
48
- - The test tooling's deploy targets (lab address, test machine, engine checkout) are read
49
- from an untracked `deploy/targets.env`. `deploy/targets.example.env` shows the shape.
50
- - Test fixtures, examples, drill records and docs use stand-in names, hosts and paths.
51
- `misc/env-guard-test.js` checks tracked files for real environment values, and it joins
52
- `npm test`.
53
- - Security reports go through GitHub's private vulnerability reporting (`SECURITY.md`).
54
- - The 0.18 line is now cut from the `release/0.18` branch. `AGENTS.md` and
55
- `misc/publish-guard.js` say so.
56
-
57
- ## Deferred
58
-
59
- Nothing new. Later work ships on the current line's next release.
@@ -1,221 +0,0 @@
1
- # memhouse — 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
- memhouse 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
- | **memhouse** | **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
- | **memhouse** | 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.** memhouse: 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 — still the heaviest in the category, but half the tax is paid.**
145
- AgentsView, deja-vu and ctx are single dependency-free binaries via Homebrew, Docker,
146
- `go install` or curl. We are Node and need a ClickHouse to point at.
147
- **Resolved 2026-08-16:** the native-dependency half is gone. `better-sqlite3` was
148
- replaced by `node:sqlite`, so `npm i -g memhouse` with no flags is now a complete,
149
- fully working install — no `--allow-scripts`, no build step, and no five-adapters-
150
- silently-read-nothing failure mode. What remains of the tax is the runtime (Node,
151
- not a static binary), the ClickHouse dependency, and the `EACCES`/`sudo` prefix
152
- triage, which was never about the flag and is not fixable from our side.
153
- - **Semantic search.** AgentsView (opt-in index), claude-mem (Chroma),
154
- claude-history (local embedding model). We are FTS-only. Contested rather than
155
- settled — deja-vu made the same choice and was criticised for it on HN.
156
- - **Secret redaction at ingest.** deja-vu redacts credential patterns on index *and*
157
- on sync export. Whether we do is *unverified* — and it matters more here than
158
- elsewhere, because Claude Code caches unredacted secrets in transcripts
159
- (anthropics/claude-code#43675) and we ship those rows to a shared server.
160
- - **Resume and write-back.** Agent Sessions copies resume commands for six CLIs and
161
- restores into the archive; claude-history resumes *and forks* worktree-aware. We
162
- read but do not hand the pilot back in.
163
- - **Price ceiling.** AgentsView gives the whole stack away under MIT. That caps what
164
- a self-hosted OSS competitor can charge for.
165
-
166
- ---
167
-
168
- ## Unclaimed ground
169
-
170
- Two positions nobody occupies, both reachable from where we already are.
171
-
172
- **1. Evidence and claims as two layers.** The sharpest architectural critique found
173
- anywhere in the survey, and no product in the field claims to do it: keep the capture
174
- log and the memory layer distinct. The capture log is chronological evidence; memory
175
- is a set of derived, revisable claims. Each claim cites the exact spans supporting
176
- it, records when it was inferred, and marks itself current, disputed or superseded —
177
- and deletion follows that lineage. This is available **only** to a system that keeps
178
- verbatim transcripts with provenance. Every extract-only competitor has discarded the
179
- evidence by the time the claim is written. We and MemPalace are the two systems
180
- positioned to build it. Neither has.
181
-
182
- **2. The 30-day deletion window.** Claude Code deletes JSONL transcripts after 30
183
- days. Contextify was built because of it; vibe-replay documents it; **nobody markets
184
- on it.** A durable server-side store is the strongest possible answer, and we are
185
- better positioned than any local-index tool. This is free ground.
186
-
187
- ---
188
-
189
- ## Three cautions
190
-
191
- **Do not compete on benchmark scores.** The benchmarks are broken. An independent
192
- LOCOMO audit found 99 score-corrupting errors in 1,540 questions (6.4%), and the
193
- standard LLM judge accepted 62.81% of adversarially-generated wrong-but-topical
194
- answers. Nine vendors claim mutually incompatible SOTA on it. MemPalace's claimed
195
- 100% was reverse-engineered publicly to 98.4%, achieved with `top-k=50` — which
196
- exceeds the session count. deja-vu's 84.9% hit@1 carries the same asterisk. Entering
197
- this contest means measuring the field against itself.
198
-
199
- **Stars are not traction, and are farmed in this category.** `mindverse/Second-Me`
200
- holds 15,648 stars and has been dead for ten months. MemPalace took 58k stars in four
201
- months while accumulating 2,183 issues, one titled *"in short: This sucks shit."*
202
- Screenpipe reportedly mails its stargazers.
203
-
204
- **The free incumbent sets the floor.** claude-mem is Apache-2.0, free, no cloud tier,
205
- no company, one dominant author. Any paid or heavier-install offering is measured
206
- against that baseline, not against a vendor's price list.
207
-
208
- ---
209
-
210
- ## Net position
211
-
212
- Not differentiated on parse-on-client, editor breadth, self-hosting, analytics, or
213
- agent-facing skills — all matched or beaten, most comprehensively by AgentsView
214
- (MIT, free, 50+ editors, 4,723 stars, six months old).
215
-
216
- Two things hold: **grant-enforced per-member isolation**, which nobody attempts, and
217
- **verbatim transcripts with provenance**, which is the prerequisite for the
218
- evidence/claims separation the field has identified but not built.
219
-
220
- The liabilities are zero distribution and the heaviest install in the category.
221
- Both are fixable; neither is fixed by adding another editor adapter.