memhouse 0.0.1 → 0.3.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 (97) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +72 -3
  3. package/bin/memhouse.js +559 -0
  4. package/cache.js +850 -0
  5. package/ch-ingest.js +329 -0
  6. package/ch-schema.js +152 -0
  7. package/clickhouse.js +87 -0
  8. package/editors/adapter-errors.js +52 -0
  9. package/editors/antigravity.js +1048 -0
  10. package/editors/base.js +321 -0
  11. package/editors/claude.js +386 -0
  12. package/editors/codebuff.js +338 -0
  13. package/editors/codex.js +537 -0
  14. package/editors/commandcode.js +166 -0
  15. package/editors/copilot-jetbrains.js +207 -0
  16. package/editors/copilot.js +260 -0
  17. package/editors/cursor-agent.js +202 -0
  18. package/editors/cursor.js +498 -0
  19. package/editors/gemini.js +231 -0
  20. package/editors/goose.js +386 -0
  21. package/editors/gsd.js +366 -0
  22. package/editors/index.js +274 -0
  23. package/editors/kiro.js +315 -0
  24. package/editors/opencode.js +432 -0
  25. package/editors/vscode.js +413 -0
  26. package/editors/windsurf.js +634 -0
  27. package/editors/zed.js +229 -0
  28. package/index.js +424 -2
  29. package/mcp-server.js +294 -0
  30. package/mem-house/DESIGN.md +119 -0
  31. package/mem-house/delivery/AGENT-INSTALL.md +87 -0
  32. package/mem-house/delivery/PROMPT.md +42 -0
  33. package/mem-house/delivery/install.sh +181 -0
  34. package/mem-house/delivery/kernel-install.md +83 -0
  35. package/mem-house/delivery/plugin/.claude-plugin/plugin.json +8 -0
  36. package/mem-house/delivery/skills/memhouse-search/SKILL.md +104 -0
  37. package/mem-house/delivery/skills/memhouse-sessions/SKILL.md +94 -0
  38. package/mem-house/delivery/skills/memhouse-sql/SKILL.md +115 -0
  39. package/mem-house/rls.sql +17 -0
  40. package/mem-house/schema.sql +145 -0
  41. package/mem-house/server/queries.js +878 -0
  42. package/mem-house/server/server.js +228 -0
  43. package/mem-house/shipper/ship.js +461 -0
  44. package/misc/syntax-check.js +38 -0
  45. package/package.json +59 -7
  46. package/pricing.js +88 -0
  47. package/pricing.json +992 -0
  48. package/public/assets/index-CCPh7a2Z.js +75 -0
  49. package/public/assets/index-DV6ONi_F.css +2 -0
  50. package/public/index.html +16 -0
  51. package/relay-client.js +306 -0
  52. package/relay-server.js +577 -0
  53. package/server.js +860 -0
  54. package/share-image.js +367 -0
  55. package/ui/eslint.config.js +29 -0
  56. package/ui/index.html +15 -0
  57. package/ui/package-lock.json +4229 -0
  58. package/ui/package.json +38 -0
  59. package/ui/src/App.jsx +364 -0
  60. package/ui/src/components/ActivityHeatmap.jsx +206 -0
  61. package/ui/src/components/AiAuditCard.jsx +254 -0
  62. package/ui/src/components/AnimatedLoader.jsx +14 -0
  63. package/ui/src/components/AnimatedLogo.jsx +96 -0
  64. package/ui/src/components/ChatSidebar.jsx +226 -0
  65. package/ui/src/components/DateRangePicker.jsx +104 -0
  66. package/ui/src/components/EditorDot.jsx +11 -0
  67. package/ui/src/components/EditorIcon.jsx +117 -0
  68. package/ui/src/components/KpiCard.jsx +9 -0
  69. package/ui/src/components/LiveFeed.jsx +128 -0
  70. package/ui/src/components/LoginScreen.jsx +81 -0
  71. package/ui/src/components/MessageRenderer.jsx +148 -0
  72. package/ui/src/components/PageHeader.jsx +11 -0
  73. package/ui/src/components/SectionTitle.jsx +3 -0
  74. package/ui/src/components/ShareModal.jsx +305 -0
  75. package/ui/src/components/TokenTimeline.jsx +258 -0
  76. package/ui/src/hooks/useLive.jsx +15 -0
  77. package/ui/src/index.css +83 -0
  78. package/ui/src/lib/api.js +343 -0
  79. package/ui/src/lib/constants.js +88 -0
  80. package/ui/src/lib/theme.jsx +23 -0
  81. package/ui/src/main.jsx +16 -0
  82. package/ui/src/pages/Artifacts.jsx +575 -0
  83. package/ui/src/pages/Compare.jsx +232 -0
  84. package/ui/src/pages/CostAnalysis.jsx +354 -0
  85. package/ui/src/pages/Dashboard.jsx +529 -0
  86. package/ui/src/pages/DeepAnalysis.jsx +495 -0
  87. package/ui/src/pages/GSD.jsx +726 -0
  88. package/ui/src/pages/MCPs.jsx +744 -0
  89. package/ui/src/pages/ProjectDetail.jsx +325 -0
  90. package/ui/src/pages/Projects.jsx +249 -0
  91. package/ui/src/pages/RelayDashboard.jsx +590 -0
  92. package/ui/src/pages/RelayUserDetail.jsx +466 -0
  93. package/ui/src/pages/Sessions.jsx +535 -0
  94. package/ui/src/pages/Settings.jsx +241 -0
  95. package/ui/src/pages/SqlViewer.jsx +370 -0
  96. package/ui/src/pages/Subscriptions.jsx +411 -0
  97. package/ui/vite.config.js +18 -0
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env bash
2
+ # mem-house standalone installer.
3
+ #
4
+ # Checks node >= 20 and a reachable ClickHouse, writes ~/.memhouse/env
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
7
+ # dashboard and set up continuous shipping (`--loop`).
8
+ #
9
+ # Usage:
10
+ # ./install.sh # interactive (prompts for missing values)
11
+ # ./install.sh --url http://localhost:8123 --user memhouse_root --password 'pw' --db memhouse
12
+ # ./install.sh --yes # non-interactive, defaults / env / existing env file
13
+ #
14
+ # Flags:
15
+ # --url URL ClickHouse HTTP(S) endpoint (default http://localhost:8123)
16
+ # --user USER ClickHouse user (default memhouse_root; 'default' works for a local CH)
17
+ # --password PW credential (default empty)
18
+ # --db DB the house (database) (default memhouse)
19
+ # --port PORT dashboard/API port (default 4640)
20
+ # --yes never prompt; take flags > current env > ~/.memhouse/env > defaults
21
+ # --no-ship stop after writing env + ensure-schema (skip the first ship)
22
+ #
23
+ # Defaults resolve in order: flag > MEMHOUSE_* already in the environment >
24
+ # existing ~/.memhouse/env > built-in default. Runs from any cwd — the repo is
25
+ # resolved from this script's own location (mem-house/delivery/ -> repo root).
26
+ set -euo pipefail
27
+
28
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
+ REPO_ROOT="$(cd "$HERE/../.." && pwd)"
30
+ SHIP="$REPO_ROOT/mem-house/shipper/ship.js"
31
+ SERVER="$REPO_ROOT/mem-house/server/server.js"
32
+ ENV_DIR="$HOME/.memhouse"
33
+ ENV_FILE="$ENV_DIR/env"
34
+
35
+ die() { echo "install.sh: $*" >&2; exit 1; }
36
+ info() { echo "== $*"; }
37
+
38
+ # ---------- 0. defaults: existing env file, then environment ----------------
39
+ if [ -f "$ENV_FILE" ]; then
40
+ # shellcheck disable=SC1090
41
+ set -a; . "$ENV_FILE"; set +a
42
+ fi
43
+ CH_URL="${MEMHOUSE_URL:-http://localhost:8123}"
44
+ CH_USER="${MEMHOUSE_USER:-memhouse_root}"
45
+ CH_PASSWORD="${MEMHOUSE_PASSWORD:-}"
46
+ CH_DB="${MEMHOUSE_DB:-memhouse}"
47
+ DASH_PORT="${MEMHOUSE_PORT:-4640}"
48
+
49
+ ASSUME_YES=0
50
+ NO_SHIP=0
51
+ URL_SET=0; USER_SET=0; PASS_SET=0; DB_SET=0
52
+
53
+ while [ $# -gt 0 ]; do
54
+ case "$1" in
55
+ --url) CH_URL="${2:?--url needs a value}"; URL_SET=1; shift 2;;
56
+ --user) CH_USER="${2:?--user needs a value}"; USER_SET=1; shift 2;;
57
+ --password) CH_PASSWORD="${2:?--password needs a value}"; PASS_SET=1; shift 2;;
58
+ --db) CH_DB="${2:?--db needs a value}"; DB_SET=1; shift 2;;
59
+ --port) DASH_PORT="${2:?--port needs a value}"; shift 2;;
60
+ --yes|-y) ASSUME_YES=1; shift;;
61
+ --no-ship) NO_SHIP=1; shift;;
62
+ -h|--help) sed -n '2,25p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0;;
63
+ *) die "unknown flag: $1 (try --help)";;
64
+ esac
65
+ done
66
+
67
+ # ---------- 1. node >= 20 ---------------------------------------------------
68
+ command -v node >/dev/null 2>&1 || die "node not found (need node >= 20; https://nodejs.org)"
69
+ NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]')"
70
+ [ "$NODE_MAJOR" -ge 20 ] 2>/dev/null || die "node >= 20 required (found $(node -v))"
71
+ info "node $(node -v) ok"
72
+
73
+ [ -f "$SHIP" ] || die "shipper not found at $SHIP (incomplete checkout?)"
74
+
75
+ # ---------- 2. repo dependencies -------------------------------------------
76
+ if [ ! -d "$REPO_ROOT/node_modules" ]; then
77
+ info "installing npm dependencies (first run)"
78
+ (cd "$REPO_ROOT" && npm install --no-audit --no-fund)
79
+ fi
80
+
81
+ # ---------- 3. gather connection values -------------------------------------
82
+ prompt() { # prompt <question> <current> -> stdout
83
+ local ans
84
+ read -r -p "$1 [$2]: " ans
85
+ echo "${ans:-$2}"
86
+ }
87
+ if [ "$ASSUME_YES" -eq 0 ] && [ -t 0 ]; then
88
+ [ "$URL_SET" -eq 1 ] || CH_URL="$(prompt "ClickHouse URL" "$CH_URL")"
89
+ [ "$USER_SET" -eq 1 ] || CH_USER="$(prompt "ClickHouse user" "$CH_USER")"
90
+ if [ "$PASS_SET" -eq 0 ]; then
91
+ read -r -s -p "ClickHouse password [keep current/empty]: " ans; echo
92
+ [ -n "$ans" ] && CH_PASSWORD="$ans"
93
+ fi
94
+ [ "$DB_SET" -eq 1 ] || CH_DB="$(prompt "House (database)" "$CH_DB")"
95
+ fi
96
+
97
+ # ---------- 4. ClickHouse reachable? ----------------------------------------
98
+ info "checking ClickHouse at $CH_URL (user $CH_USER)"
99
+ ONE="$(curl -sS --connect-timeout 5 --fail-with-body \
100
+ --user "$CH_USER:$CH_PASSWORD" \
101
+ --data-binary "SELECT 1" "$CH_URL")" \
102
+ || die "ClickHouse not reachable at $CH_URL with those credentials"
103
+ [ "$ONE" = "1" ] || die "unexpected reply from $CH_URL: $ONE"
104
+ info "ClickHouse ok"
105
+
106
+ # Ensure the house exists before ensure-schema (schema.sql is unqualified and the
107
+ # shipper binds to MEMHOUSE_DB — on a virgin standalone server the database must
108
+ # be created first). On a kernel realm the house is already provisioned; if the
109
+ # user lacks CREATE DATABASE but the house is reachable, that's fine too.
110
+ case "$CH_DB" in
111
+ (*[!A-Za-z0-9_]*|'') die "invalid database name '$CH_DB' — use letters, digits, underscore" ;;
112
+ esac
113
+ if ! curl -fsS --max-time 20 --user "$CH_USER:$CH_PASSWORD" \
114
+ --data-binary "CREATE DATABASE IF NOT EXISTS $CH_DB" "$CH_URL" >/dev/null 2>&1; then
115
+ curl -fsS --max-time 20 --user "$CH_USER:$CH_PASSWORD" \
116
+ --data-binary "SELECT 1" "$CH_URL/?database=$CH_DB" >/dev/null 2>&1 \
117
+ || die "house '$CH_DB' does not exist and cannot be created as $CH_USER"
118
+ fi
119
+ info "house '$CH_DB' ready"
120
+
121
+ # ---------- 5. write ~/.memhouse/env ----------------------------------------
122
+ mkdir -p "$ENV_DIR"; chmod 700 "$ENV_DIR"
123
+ # Values are single-quoted (embedded ' escaped) — this file is sourced by shells
124
+ # (docs/skills use `. ~/.memhouse/env`), so unquoted metacharacters in a password
125
+ # would corrupt the value or execute on source.
126
+ shq() { printf "%s" "$1" | sed "s/'/'\\\\''/g"; }
127
+ cat > "$ENV_FILE" <<EOF
128
+ # mem-house connection (written by install.sh $(date +%Y-%m-%d-%H_%M)). NEVER commit.
129
+ MEMHOUSE_URL='$(shq "$CH_URL")'
130
+ MEMHOUSE_USER='$(shq "$CH_USER")'
131
+ MEMHOUSE_PASSWORD='$(shq "$CH_PASSWORD")'
132
+ MEMHOUSE_DB='$(shq "$CH_DB")'
133
+ MEMHOUSE_PORT='$(shq "$DASH_PORT")'
134
+ EOF
135
+ chmod 600 "$ENV_FILE"
136
+ info "wrote $ENV_FILE"
137
+
138
+ export MEMHOUSE_URL="$CH_URL" MEMHOUSE_USER="$CH_USER" \
139
+ MEMHOUSE_PASSWORD="$CH_PASSWORD" MEMHOUSE_DB="$CH_DB" \
140
+ MEMHOUSE_PORT="$DASH_PORT"
141
+
142
+ # ---------- 6. schema + first ship ------------------------------------------
143
+ info "applying house schema (ship.js --ensure-schema)"
144
+ node "$SHIP" --ensure-schema \
145
+ || die "ensure-schema failed. If $CH_USER cannot CREATE DATABASE, create '$CH_DB' first (or, on a kernel realm, provision the agency: see delivery/kernel-install.md), then re-run."
146
+
147
+ if [ "$NO_SHIP" -eq 0 ]; then
148
+ info "first ship (this parses local editor sessions and may take a while)"
149
+ node "$SHIP"
150
+ else
151
+ info "skipping first ship (--no-ship)"
152
+ fi
153
+
154
+ # ---------- 7. next steps ----------------------------------------------------
155
+ cat <<EOF
156
+
157
+ mem-house installed.
158
+
159
+ env file $ENV_FILE
160
+ house $CH_DB @ $CH_URL
161
+
162
+ Next steps:
163
+
164
+ # dashboard (agentlytics UI over the house) -> http://localhost:$DASH_PORT
165
+ node "$SERVER"
166
+
167
+ # keep shipping continuously (re-ships incrementally; Ctrl-C to stop)
168
+ node "$SHIP" --loop
169
+ # background it:
170
+ nohup node "$SHIP" --loop >> "$ENV_DIR/ship.log" 2>&1 &
171
+
172
+ # agent skills (search/sessions/sql from inside Claude Code):
173
+ node "$REPO_ROOT/bin/memhouse.js" plugins install claude
174
+ # -> installs memhouse-search / memhouse-sessions / memhouse-sql into
175
+ # \${CLAUDE_CONFIG_DIR:-\$HOME/.claude}/skills (loads next session)
176
+
177
+ Verify anytime:
178
+ set -a; . "$ENV_FILE"; set +a
179
+ curl -sS --user "\$MEMHOUSE_USER:\$MEMHOUSE_PASSWORD" --data-binary \\
180
+ "SELECT count() FROM sessions" "\$MEMHOUSE_URL/?database=\$MEMHOUSE_DB&final=1"
181
+ EOF
@@ -0,0 +1,83 @@
1
+ # mem-house — install as a kernel agency
2
+
3
+ How to run mem-house as an **agency** on an ultimagent kernel — a ClickHouse server
4
+ (a **town**) promoted into a realm — instead of a plain ClickHouse. Same flow proven
5
+ for the agentlytics agency (`agency/AGENCY.md`); the agency/house name here is
6
+ **`memhouse`** (CH identifiers can't carry a dash). What lands is a **house** (the
7
+ `memhouse` database) with a **resident** (the shipper — `kind = "worker"`,
8
+ `on = "loop"`) — that pairing is the agency. Residents write; routines read, and the
9
+ `sessions_v` view is a routine. Terms: `../../TERMINOLOGY.md`.
10
+
11
+ This is an operator runbook, so it speaks machine vocabulary throughout — ClickHouse,
12
+ `GRANT`, row policies. That is correct for this audience.
13
+
14
+ ## 1. Provision (operator, one-time — from the kernel checkout)
15
+
16
+ ```bash
17
+ python3 executor/executor.py provision memhouse
18
+ ```
19
+
20
+ Submits `install-agency{name:'memhouse'}`; the mayor — the human owner — approves;
21
+ the executor (running as the ego, the `kernel` user) creates database `memhouse`
22
+ (the house), owner `memhouse_root`
23
+ (`realm_user` profile), and owner grants. It returns a one-time **credential** —
24
+ rotate on first connect (`issue-credential{user:'memhouse_root'}`).
25
+
26
+ ## 2. Owner sets up the house
27
+
28
+ ```bash
29
+ npm install -g memhouse --allow-scripts=better-sqlite3
30
+ memhouse install --yes \
31
+ --url https://<kernel-host>:8443 \
32
+ --user memhouse_root \
33
+ --password <credential-from-provision> \
34
+ --db memhouse
35
+ ```
36
+
37
+ That writes `~/.memhouse/env`, applies the schema, and runs the first ship.
38
+ `memhouse start` then keeps it fresh on a 300s loop.
39
+
40
+ Keep `--allow-scripts=better-sqlite3`: without it npm 12 leaves `better-sqlite3`
41
+ with no native binding and the five SQLite-backed adapters ship nothing, silently.
42
+ `memhouse discover` names any adapter it had to skip.
43
+
44
+ The kernel never runs or reads any of this — it is content-blind; the shipper is
45
+ the agency's own resident, a deterministic `worker` on a loop (no LLM, not an
46
+ injection surface). It is the only thing here that writes without being asked.
47
+
48
+ ## 3. Members (multi-user)
49
+
50
+ For each person joining, split across the two authorities:
51
+
52
+ ```bash
53
+ # The EGO (the `kernel` user) mints the identity; the mayor approves:
54
+ python3 executor/executor.py submit register-member '{"handle":"alice"}'
55
+ python3 executor/executor.py approve <call_id> && python3 executor/executor.py drain
56
+
57
+ # OWNER grants house access (memhouse_root has grant-option on memhouse.*):
58
+ # GRANT INSERT, SELECT ON memhouse.* TO alice
59
+ ```
60
+
61
+ Each member then runs the shipper with **their own** credential
62
+ (`MEMHOUSE_USER=alice`) — the house stamps `user_id='alice'` on their rows,
63
+ un-spoofably (`MATERIALIZED currentUser()`, `async_insert=0`).
64
+
65
+ ## 4. Visibility: own-only vs team pool
66
+
67
+ - **Own-only** (memory-house's model — each member sees only their own rows): the
68
+ **ego (the `kernel` user) or the mayor** applies `mem-house/rls.sql` (three row
69
+ policies bound to the `member` role). The owner cannot — `CREATE ROW POLICY` needs
70
+ ACCESS MANAGEMENT, which the kernel withholds from agency owners by design.
71
+ - **Team pool** (everyone sees everything): apply no policy; the owner GRANTs from
72
+ step 3 are the whole model.
73
+
74
+ Pick one; do not mix on the same role.
75
+
76
+ ## 5. Verify
77
+
78
+ ```bash
79
+ memhouse stats # per-source counts as the owner
80
+ # as a member (own-only): counts reflect only that member's rows
81
+ curl -s -u "alice:<pw>" "$MEMHOUSE_URL/?database=memhouse" \
82
+ --data-binary "SELECT count() FROM sessions_v SETTINGS final=1"
83
+ ```
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "memhouse",
3
+ "description": "Conversation memory for AI agents over the memhouse typed ClickHouse store: search, browse, and analyze every past session across all 17 supported editors and machines. Skills install as /memhouse:search, /memhouse:sessions, and /memhouse:sql.",
4
+ "version": "0.3.0",
5
+ "author": { "name": "Ramazan Polat" },
6
+ "homepage": "https://github.com/agent-realm/memhouse",
7
+ "keywords": ["memory", "clickhouse", "search", "sessions", "analytics", "agentlytics"]
8
+ }
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: memhouse-search
3
+ description: Full-text search across ALL shipped agent conversations — every session from all 17 supported editors (Claude Code, Codex, Cursor, VS Code, Zed, OpenCode, Gemini CLI, …), every project, every machine — stored in the memhouse ClickHouse. Use whenever the user refers to something from the past that isn't in the current context, e.g. "what did I say about X", "find that conversation about Y", "when did I work on Z", "did I ever try W", "the chat where we discussed it", "remind me how I did it". Reach for this before saying you don't know about prior work.
4
+ user-invocable: true
5
+ argument-hint: "<search terms> [in <project>] [last <N> days] [from <editor>]"
6
+ allowed-tools: Bash(set -a*), Bash(. *), Bash(curl*)
7
+ ---
8
+
9
+ # memhouse-search — search conversation memory
10
+
11
+ Search the full message history in the memhouse house (`messages` + `sessions`
12
+ tables on ClickHouse).
13
+
14
+ ## Connection
15
+
16
+ Credentials come from `~/.memhouse/env` (or already-exported `MEMHOUSE_*` vars).
17
+ Every query runs over ClickHouse HTTP with `final=1` (ReplacingMergeTree keeps
18
+ stale row versions until merges; `final=1` collapses to latest-wins — always
19
+ include it on reads):
20
+
21
+ ```bash
22
+ set -a; [ -f ~/.memhouse/env ] && . ~/.memhouse/env; set +a
23
+ curl -sS --fail-with-body --user "${MEMHOUSE_USER:-memhouse_root}:${MEMHOUSE_PASSWORD:-}" \
24
+ --data-binary @- "${MEMHOUSE_URL:-http://localhost:8123}/?database=${MEMHOUSE_DB:-memhouse}&final=1" <<'SQL'
25
+ <the query>
26
+ FORMAT PrettyCompact
27
+ SQL
28
+ ```
29
+
30
+ `FORMAT PrettyCompact` for display; `FORMAT JSONEachRow` when you want to parse
31
+ the rows yourself.
32
+
33
+ ## How to search (the FTS columns)
34
+
35
+ `messages` carries two MATERIALIZED lowercase copies of `text`, each with a
36
+ text index — search those, display `text`:
37
+
38
+ - `text_ngram` (ngram index) → substring match: `text_ngram LIKE '%term%'`
39
+ - `text_word` (word index) → whole-token match: `hasToken(text_word, 'term')`
40
+
41
+ **Search terms MUST be lowercased** (the columns are `lower(text)`); escape
42
+ single quotes in user terms as `\'`. Multiple words → AND of clauses; a quoted
43
+ phrase → one `LIKE` clause for the whole phrase.
44
+
45
+ ### Example 1 — substring search with session names
46
+
47
+ ```sql
48
+ SELECT m.ts, m.source, m.project, m.role, m.session_id,
49
+ s.name AS session,
50
+ substring(m.text, 1, 300) AS snippet
51
+ FROM messages AS m
52
+ LEFT JOIN sessions AS s USING (session_id)
53
+ WHERE m.text_ngram LIKE '%postgres%' AND m.text_ngram LIKE '%migration%'
54
+ ORDER BY m.ts DESC
55
+ LIMIT 30
56
+ FORMAT PrettyCompact
57
+ ```
58
+
59
+ ### Example 2 — word match, scoped by editor and time
60
+
61
+ ```sql
62
+ SELECT ts, project, session_id, substring(text, 1, 200) AS snippet
63
+ FROM messages
64
+ WHERE hasToken(text_word, 'rls')
65
+ AND source = 'claude-code'
66
+ AND ts > now() - INTERVAL 14 DAY
67
+ ORDER BY ts DESC
68
+ LIMIT 20
69
+ FORMAT PrettyCompact
70
+ ```
71
+
72
+ ### Example 3 — which sessions mention it most (then drill in)
73
+
74
+ ```sql
75
+ SELECT m.session_id, any(s.name) AS session, any(m.project) AS project,
76
+ count() AS hits, max(m.ts) AS last_hit
77
+ FROM messages AS m
78
+ LEFT JOIN sessions AS s USING (session_id)
79
+ WHERE m.text_ngram LIKE '%clickhouse cache%'
80
+ GROUP BY m.session_id
81
+ ORDER BY hits DESC
82
+ LIMIT 10
83
+ FORMAT PrettyCompact
84
+ ```
85
+
86
+ ## Qualifiers
87
+
88
+ - `in <project>` → `AND m.project ILIKE '%<project>%'`
89
+ - `last N days` → `AND m.ts > now() - INTERVAL N DAY`
90
+ - `from <editor>` → `AND m.source = '<id>'` (ids: `claude-code`, `codex`,
91
+ `cursor`, `cursor-agent`, `vscode`, `zed`, `opencode`, `gemini-cli`,
92
+ `windsurf`, `antigravity`, `copilot-cli`, `goose`, `kiro`, …)
93
+ - Skip subagent noise → `AND NOT m.is_subagent`
94
+ - Only user/assistant text lives in `messages`; tool invocations are in
95
+ `tool_calls` (`tool_name`, `args`) — search `args ILIKE '%term%'` there only
96
+ if the user explicitly wants tool calls searched.
97
+
98
+ ## Output
99
+
100
+ Summarize hits grouped by session (name, source, project, date, 1–2 best
101
+ snippets each) and give the total hit count. Offer to pull the full transcript
102
+ of the best session (`SELECT role, text FROM messages WHERE session_id = '…'
103
+ ORDER BY seq`). If zero hits, retry with broader/fewer terms and report the
104
+ corpus size (`SELECT count() FROM messages`).
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: memhouse-sessions
3
+ description: List recent agent sessions from memhouse conversation memory — names, projects, editors, hosts, times, message and token counts across all 17 supported editors. Use for "what was I working on", "show my recent sessions", "sessions from last week", "what did I do in project X", "list my cursor sessions", or to orient before drilling into one session.
4
+ user-invocable: true
5
+ argument-hint: "[N] [project <name>] [from <editor>] [today|week|month]"
6
+ allowed-tools: Bash(set -a*), Bash(. *), Bash(curl*)
7
+ ---
8
+
9
+ # memhouse-sessions — browse session history
10
+
11
+ List/filter sessions from the `sessions_v` rollup view (session metadata +
12
+ message aggregates) in the memhouse house.
13
+
14
+ ## When to use
15
+
16
+ - The user wants an overview of recent activity rather than a specific quote.
17
+ - As a first step before digging into one session, when they don't have an
18
+ id/name yet.
19
+
20
+ ## Connection
21
+
22
+ Credentials from `~/.memhouse/env` (or exported `MEMHOUSE_*`). Always read with
23
+ `final=1` (collapses ReplacingMergeTree duplicates to latest-wins):
24
+
25
+ ```bash
26
+ set -a; [ -f ~/.memhouse/env ] && . ~/.memhouse/env; set +a
27
+ curl -sS --fail-with-body --user "${MEMHOUSE_USER:-memhouse_root}:${MEMHOUSE_PASSWORD:-}" \
28
+ --data-binary @- "${MEMHOUSE_URL:-http://localhost:8123}/?database=${MEMHOUSE_DB:-memhouse}&final=1" <<'SQL'
29
+ <the query>
30
+ FORMAT PrettyCompact
31
+ SQL
32
+ ```
33
+
34
+ ## Default listing
35
+
36
+ ```sql
37
+ SELECT session_id, name, source, host, project,
38
+ started, ended, total_msgs, user_msgs, assistant_msgs,
39
+ output_tokens,
40
+ substring(first_prompt, 1, 80) AS first_prompt
41
+ FROM sessions_v
42
+ ORDER BY ended DESC
43
+ LIMIT 20
44
+ FORMAT PrettyCompact
45
+ ```
46
+
47
+ - Default `LIMIT 20`; `[N]` overrides.
48
+ - `today` / `week` / `month` → `WHERE ended > now() - INTERVAL 1 DAY`
49
+ (`7 DAY` / `30 DAY`).
50
+ - `project <name>` → `WHERE project ILIKE '%<name>%'`.
51
+ - `from <editor>` → `WHERE source = '<id>'` (`claude-code`, `codex`, `cursor`,
52
+ `vscode`, `zed`, `opencode`, `gemini-cli`, `windsurf`, …).
53
+ - Unnamed sessions (`name = ''`): fall back to `first_prompt` as the label.
54
+
55
+ ## More cuts
56
+
57
+ Per-editor rollup ("where has my work been happening?"):
58
+
59
+ ```sql
60
+ SELECT source, count() AS sessions, sum(total_msgs) AS msgs,
61
+ sum(output_tokens) AS out_tokens, max(ended) AS last_activity
62
+ FROM sessions_v
63
+ GROUP BY source
64
+ ORDER BY sessions DESC
65
+ FORMAT PrettyCompact
66
+ ```
67
+
68
+ Busiest projects this month:
69
+
70
+ ```sql
71
+ SELECT project, count() AS sessions, sum(assistant_msgs) AS assistant_msgs
72
+ FROM sessions_v
73
+ WHERE ended > now() - INTERVAL 30 DAY AND project != ''
74
+ GROUP BY project
75
+ ORDER BY sessions DESC
76
+ LIMIT 15
77
+ FORMAT PrettyCompact
78
+ ```
79
+
80
+ ## Examples
81
+
82
+ | User says | What you do |
83
+ |---|---|
84
+ | "what was I working on yesterday?" | `WHERE ended > now() - INTERVAL 1 DAY` |
85
+ | "show my last 10 sessions in agentlytics" | `LIMIT 10 … WHERE project ILIKE '%agentlytics%'` |
86
+ | "list my cursor sessions this month" | `WHERE source = 'cursor' AND ended > now() - INTERVAL 30 DAY` |
87
+ | "which machine did I do the schema work on?" | search via memhouse-search, or filter `host` here |
88
+
89
+ ## Output
90
+
91
+ A compact table: when, name (or first prompt), source, host, project, msgs,
92
+ tokens. Offer to pull a full transcript next
93
+ (`SELECT role, text FROM messages WHERE session_id = '…' ORDER BY seq`) or to
94
+ run memhouse-search for a specific quote.
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: memhouse-sql
3
+ description: Run free-form read-only SQL against memhouse conversation memory (typed sessions/messages/tool_calls tables + the sessions_v view on ClickHouse). Use for ad-hoc analytics the other memhouse skills don't cover — token spend, model/editor usage, tool rankings, activity heatmaps, busiest days/projects, cache-hit ratios, or any custom question over conversation data.
4
+ user-invocable: true
5
+ argument-hint: "<question or SQL>"
6
+ allowed-tools: Bash(set -a*), Bash(. *), Bash(curl*)
7
+ ---
8
+
9
+ # memhouse-sql — ad-hoc analytics
10
+
11
+ If the user gives SQL, run it (append `FORMAT PrettyCompact` if no FORMAT
12
+ given). If they give a question, write the SQL yourself from the schema below.
13
+
14
+ **Read-only rule:** the shipper (`ship.js`) is the only writer. Never INSERT/
15
+ ALTER/DROP from here — member credentials typically hold only
16
+ `INSERT, SELECT ON memhouse.*`, and on shared instances own-only row policies
17
+ scope reads to your rows.
18
+
19
+ ## Connection
20
+
21
+ Credentials from `~/.memhouse/env` (or exported `MEMHOUSE_*`). Always read with
22
+ `final=1` — every table is `ReplacingMergeTree(ingested_at)`, so without it you
23
+ can double-count stale row versions:
24
+
25
+ ```bash
26
+ set -a; [ -f ~/.memhouse/env ] && . ~/.memhouse/env; set +a
27
+ curl -sS --fail-with-body --user "${MEMHOUSE_USER:-memhouse_root}:${MEMHOUSE_PASSWORD:-}" \
28
+ --data-binary @- "${MEMHOUSE_URL:-http://localhost:8123}/?database=${MEMHOUSE_DB:-memhouse}&final=1" <<'SQL'
29
+ <the query>
30
+ FORMAT PrettyCompact
31
+ SQL
32
+ ```
33
+
34
+ `FORMAT PrettyCompact` for display, `FORMAT JSONEachRow` to parse.
35
+
36
+ ## Schema (the house)
37
+
38
+ | Object | Kind | Columns |
39
+ |---|---|---|
40
+ | `sessions` | table, 1 row/session | `session_id, source, host, name, mode, folder, project, git_branch, created_at, last_updated_at, message_count, path, extra JSON, user_id, ingested_at` |
41
+ | `messages` | table, 1 row/message | `session_id, seq, source, host, ts, role, model, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, text, project, folder, is_subagent, extra JSON, line_hash, user_id, ingested_at` + FTS columns `text_ngram`/`text_word` (lowercased; see memhouse-search) |
42
+ | `tool_calls` | table, 1 row/tool call | `session_id, seq, idx, source, host, tool_name, args, ts, project, folder, user_id, ingested_at` |
43
+ | `sessions_v` | view, rollup | `session_id, source, host, name, mode, folder, project, git_branch, user_id, created_at, last_updated_at, started, ended, duration_sec, total_msgs, user_msgs, assistant_msgs, subagent_msgs, models, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, user_chars, assistant_chars, first_prompt` |
44
+
45
+ Notes: `source` = editor id (`claude-code`, `codex`, `cursor`, `cursor-agent`,
46
+ `vscode`, `zed`, `opencode`, `gemini-cli`, `windsurf`, `antigravity`, …);
47
+ `seq` = message index within its session (0-based); `tool_calls.idx` = call
48
+ index within the session; `user_id` is server-stamped (`currentUser()`);
49
+ `models` in `sessions_v` is an `Array(String)`. Exclude `''` and
50
+ `'<synthetic>'` from model aggregates.
51
+
52
+ ## Examples
53
+
54
+ Token spend by model:
55
+
56
+ ```sql
57
+ SELECT model, sum(input_tokens) AS in_tok, sum(output_tokens) AS out_tok,
58
+ sum(cache_read_tokens) AS cache_read
59
+ FROM messages
60
+ WHERE model NOT IN ('', '<synthetic>')
61
+ GROUP BY model
62
+ ORDER BY out_tok DESC
63
+ FORMAT PrettyCompact
64
+ ```
65
+
66
+ Which tools do I use most (memhouse exclusive — memory-house has no tool table):
67
+
68
+ ```sql
69
+ SELECT tool_name, count() AS calls, uniqExact(session_id) AS sessions
70
+ FROM tool_calls
71
+ GROUP BY tool_name
72
+ ORDER BY calls DESC
73
+ LIMIT 20
74
+ FORMAT PrettyCompact
75
+ ```
76
+
77
+ Busiest days, last two weeks:
78
+
79
+ ```sql
80
+ SELECT toDate(ts) AS day, uniqExact(session_id) AS sessions, count() AS msgs
81
+ FROM messages
82
+ WHERE ts > now() - INTERVAL 14 DAY
83
+ GROUP BY day
84
+ ORDER BY day DESC
85
+ FORMAT PrettyCompact
86
+ ```
87
+
88
+ Activity by editor this week / subagent share:
89
+
90
+ ```sql
91
+ SELECT source, count() AS msgs, countIf(is_subagent) AS subagent_msgs
92
+ FROM messages
93
+ WHERE ts > now() - INTERVAL 7 DAY
94
+ GROUP BY source
95
+ ORDER BY msgs DESC
96
+ FORMAT PrettyCompact
97
+ ```
98
+
99
+ Longest sessions by wall-clock:
100
+
101
+ ```sql
102
+ SELECT name, project, source, duration_sec, total_msgs, output_tokens
103
+ FROM sessions_v
104
+ ORDER BY duration_sec DESC
105
+ LIMIT 10
106
+ FORMAT PrettyCompact
107
+ ```
108
+
109
+ ## Output
110
+
111
+ Run the query, present the result as a compact table, and add one or two lines
112
+ of interpretation. Offer a natural follow-up cut (by source, by project, by
113
+ host, by token volume) when relevant. Dollar costs are computed by the
114
+ dashboard server from pricing.js — token sums here are the raw material, not
115
+ dollars.
@@ -0,0 +1,17 @@
1
+ -- mem-house — own-only row-level security (the sharing model's isolation half).
2
+ --
3
+ -- Applied by the KERNEL (or the mayor, who has ACCESS MANAGEMENT) — the agency owner
4
+ -- cannot CREATE ROW POLICY by design. Binds to the kernel's `member` role, so every
5
+ -- registered member sees only their own rows; the owner (not a member) sees the whole
6
+ -- house. For a shared team pool instead, apply NO policy — just the owner's GRANTs.
7
+ --
8
+ -- Substitute `memhouse` if the operator named the house differently. Policies bind to
9
+ -- physical tables; views (sessions_v) inherit the querying user's policy via messages/
10
+ -- sessions.
11
+
12
+ CREATE ROW POLICY IF NOT EXISTS own_sessions ON memhouse.sessions
13
+ FOR SELECT USING user_id = currentUser() TO member;
14
+ CREATE ROW POLICY IF NOT EXISTS own_messages ON memhouse.messages
15
+ FOR SELECT USING user_id = currentUser() TO member;
16
+ CREATE ROW POLICY IF NOT EXISTS own_tool_calls ON memhouse.tool_calls
17
+ FOR SELECT USING user_id = currentUser() TO member;