memhouse 0.15.0 → 0.17.0

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.
@@ -1,121 +0,0 @@
1
- ---
2
- name: hello
3
- description: Introduce memhouse — what it is, what it remembers, and how to use it from here. Use when the user asks "what is memhouse", "what can my memory do", "how do I use this", invokes /mem:hello, or seems new to the memory system. Also the right first answer when another /mem skill fails because nothing is configured yet.
4
- user-invocable: true
5
- argument-hint: ""
6
- allowed-tools: Bash
7
- ---
8
-
9
- # /mem:hello — welcome to your memory
10
-
11
- **Invoking this skill IS the request. Give the introduction immediately — grounded in
12
- this machine's actual state, not hypotheticals. Nothing to clarify first.**
13
-
14
- ## First: find out what state this machine is in
15
-
16
- RUN this yourself with the Bash tool — do not print it for the user to run, and do not
17
- show the env values it sources. Read its output, then write the introduction using the
18
- ACTUAL numbers it returns (interpolate them; never emit the literal "N sessions").
19
-
20
- ```bash
21
- MH_ENV="${MEMHOUSE_HOME:-$HOME/.memhouse}/env"
22
- _u=${MEMHOUSE_URL-}; _s=${MEMHOUSE_USER-}; _p=${MEMHOUSE_PASSWORD-}; _d=${MEMHOUSE_DB-}
23
- set -a; [ -f "$MH_ENV" ] && . "$MH_ENV"; set +a
24
- [ -n "$_u" ] && MEMHOUSE_URL=$_u; [ -n "$_s" ] && MEMHOUSE_USER=$_s
25
- [ -n "$_p" ] && MEMHOUSE_PASSWORD=$_p; [ -n "$_d" ] && MEMHOUSE_DB=$_d
26
- if [ -n "${MEMHOUSE_URL:-}" ] && [ -n "${MEMHOUSE_USER:-}" ]; then
27
- curl -sS -m 5 --user "$MEMHOUSE_USER:${MEMHOUSE_PASSWORD:-}" \
28
- --data-binary "SELECT uniqExact(session_id), count(), formatDateTime(min(ts),'%Y-%m-%d') FROM messages" \
29
- "$MEMHOUSE_URL/?database=${MEMHOUSE_DB:-$MEMHOUSE_USER}&final=1&readonly=1" 2>&1
30
- else
31
- echo "NOT_CONFIGURED"
32
- fi
33
- ```
34
-
35
- (Do not print the env values, and do not narrate that you are withholding them — just use them.)
36
-
37
- ## What memhouse is — the overview (give this in every state, before the tour)
38
-
39
- One paragraph, grounded not sold: **memhouse is your personal, permanent archive of every
40
- AI coding session.** A background shipper reads the session files your editors write —
41
- Claude Code, Codex, Cursor, VS Code, Zed, OpenCode, Gemini CLI and 10 more, 17 in all —
42
- and ships them into a ClickHouse database you own, called a **house**. YOU choose that
43
- ClickHouse: a local one on your laptop, one on your own VM, or any ClickHouse server you
44
- control — managed or remote. memhouse itself is not a hosted service and phones nothing
45
- home; your sessions go only to the house you point it at, and it runs no LLM in its write
46
- or read path — it stores rows, the agent reading them (this chat) does the thinking. It
47
- outlives the transcripts on disk: editors compact and delete their local session files
48
- after weeks, so for anything older than ~30 days the house is the only place it still
49
- exists. One archive spans every editor, every project, every machine you ship from.
50
-
51
- What it gives you, in one breath: **ask** your own history a question and get a cited
52
- answer, **search** for the session you half-remember, **query** the raw data for numbers,
53
- browse a **dashboard**, and **invite** other people onto your ClickHouse so memories can be
54
- **shared** read-only. The tour below names each.
55
-
56
- ## Then introduce it — three states, three openings
57
-
58
- **Configured and answering** — open with the numbers: "Your memory holds N sessions
59
- (M messages) going back to <date> — every conversation you've had with coding agents
60
- (Claude Code, Codex, Cursor, Gemini CLI and 13 more), across all your machines. It
61
- outlives the transcripts on disk: editors delete their session files after weeks; this
62
- doesn't." Then the tour below.
63
-
64
- **Not configured** — say what memhouse IS (one paragraph: a personal, permanent archive
65
- of every AI coding session, stored in a ClickHouse "house" you own), then how to start:
66
- `memhouse onboard` (wizard) or `memhouse install --env <file>` if someone invited them
67
- (the file came from `/mem:invite` on the inviter's side).
68
-
69
- **Configured but unreachable** — say which URL refused, point at `memhouse doctor`,
70
- stop. Never guess another endpoint.
71
-
72
- ## The tour (keep it to one screen)
73
-
74
- What you can DO from this chat:
75
-
76
- - `/mem:ask <question>` — answer from your past work, with citations ("how did I fix X
77
- last time?")
78
- - `/mem:search <terms>` — find the session ("that conversation about Y")
79
- - `/mem:sessions` — browse and filter what's stored
80
- - `/mem:sql <question or SQL>` — ad-hoc analytics (tokens, costs, rankings)
81
- - `/mem:status` — is it healthy, how much is stored, which machines ship into it
82
-
83
- The first three overlap — same words work in each — so give the reader the rule that
84
- separates them: **want a session → search. Want an answer → ask. Want a number → sql.**
85
- `ask` runs a `search` first, then reads the turns it finds and writes you a cited answer;
86
- `search` stops at the ranked list of sessions; `sql` counts and aggregates the columns
87
- rather than hunting text.
88
-
89
- And around other people — **inviting comes before sharing**:
90
-
91
- - `/mem:invite <name>` — mint a friend's account + their own house on your ClickHouse,
92
- hand them one env file; they install with it and have their own memory
93
- - `/mem:share <name>` — once they exist, open a read-only window into YOUR memory
94
- (`/mem:share revoke <name>` closes it); `/mem:users` shows who's around
95
- - **Read a friend's shared memory** — once they've shared theirs with you, name their
96
- house right in the question: `/mem:ask <question> in <their-house>`, or
97
- `/mem:search <terms> in <their-house>` / `/mem:sql … on <their-house>`. It reads THEIR
98
- house read-only, with your own credentials; `/mem:users` lists the houses shared with
99
- you. (A house is a whole ClickHouse database — sharing grants read on it, not on single
100
- sessions.)
101
-
102
- Also worth naming: `memhouse start` serves a dashboard at http://localhost:4640 for
103
- browsing and analytics outside the chat, and everything here is read-only for agents —
104
- only the shipper writes.
105
-
106
- **Freshness check** — quietly compare the installed client to the latest release; mention
107
- it ONLY if there's a real gap (don't clutter the welcome otherwise):
108
-
109
- ```bash
110
- INSTALLED=$(memhouse version 2>/dev/null | head -1 | tr -d '[:space:]')
111
- LATEST=$(curl -sS -m 5 https://registry.npmjs.org/memhouse/latest 2>/dev/null | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')
112
- echo "installed=${INSTALLED:-unknown} latest=${LATEST:-unknown}"
113
- ```
114
-
115
- If the installed version is a MINOR or MAJOR behind (or many patches), add one line:
116
- "heads-up — you're on 0.A.B, 0.C.D is out; `memhouse update` upgrades it and refreshes
117
- these `/mem:*` skills." A patch or two behind isn't worth mentioning here. Never run the
118
- update yourself.
119
-
120
- End by offering one concrete action: a search for something they mentioned recently, or
121
- `/mem:status` if they seem unsure it's working. One offer, not a menu.
@@ -1,130 +0,0 @@
1
- ---
2
- name: invite
3
- description: Invite another person onto this memhouse ClickHouse — mint their user and their own house (database) with the right grants, producing the one env file their install needs. Use when the user says "invite X", "add X to memhouse", "get my friend set up". Inviting comes BEFORE sharing — /mem:share can only grant a user who exists.
4
- user-invocable: true
5
- argument-hint: "<name> [into <db>]"
6
- allowed-tools: Bash
7
- ---
8
-
9
- # /mem:invite — mint a member and hand them one file
10
-
11
- This runs the `memhouse invite` CLI and nothing else. Inviting mints a ClickHouse user
12
- and a house, which takes an ADMIN credential — and an admin password must never enter
13
- this conversation, because memhouse ships the transcript into the house it just
14
- provisioned. The CLI is the only safe path: the admin password is passed to one process
15
- and never echoed. **Do not hand-run `CREATE USER` / `GRANT` with an admin password
16
- substituted into a command — that burns the credential into the transcript on disk.**
17
-
18
- ## Do this
19
-
20
- 1. Confirm the `memhouse` binary is present: `command -v memhouse`. If it is not, tell
21
- the user to install it first (`npm install -g memhouse`) — there is no in-skill
22
- fallback, on purpose (see above).
23
-
24
- 2. Gather ONLY two things by asking:
25
- - the invitee's **name** (validate `[A-Za-z][A-Za-z0-9_]*`; refuse otherwise)
26
- - the **URL the invitee will reach the house at** — NOT localhost (that is the
27
- invitee's own machine). A LAN IP, hostname, or tunnel.
28
-
29
- Do NOT ask for an admin user or password yet — the next step usually needs neither.
30
- Only ask about a **shared house** if the user brings one up; default is the invitee's
31
- own house (omit --db; never pass `--db default` for "the default house").
32
-
33
- 3. TRY IT BARE FIRST — run this via the Bash tool, from the directory the file should
34
- land in (step 4). `memhouse invite` uses the caller's OWN configured credential when
35
- it can manage users, which is the common case for whoever set the house up, so no
36
- admin is needed:
37
-
38
- ```
39
- memhouse invite <name> --url <url> [--db <shared-house>]
40
- ```
41
-
42
- If it prints `invite written: …`, go to step 4 — you are done, and no admin secret
43
- ever touched this conversation.
44
-
45
- Otherwise read WHICH refusal came back; they need different answers.
46
-
47
- **"cannot reach `<url>` …"** — nothing to do with privileges. The address is wrong,
48
- or the house is bound to loopback (`memhouse deploy --local` binds to 127.0.0.1 on
49
- purpose, so no LAN address reaches it and no invitee could either). Ask the user for
50
- the address the invitee will actually use; do not retry with a guess.
51
-
52
- **"`<user>` is a MEMBER of this ClickHouse, not an administrator"** — inviting needs
53
- CREATE USER and CREATE DATABASE, which a member deliberately does not hold. Two cases,
54
- and you must ask which one applies rather than assuming:
55
-
56
- - **They run the ClickHouse.** They have the admin credential; memhouse never stores
57
- it. Do NOT take that password in chat — memhouse archives this transcript. Hand them
58
- the line to run THEMSELVES, and leave `--admin-password` OFF so it is prompted for,
59
- keeping it out of both the process list and shell history:
60
-
61
- ```
62
- memhouse invite <name> --url <url> [--db <shared-house>] --admin-user <admin>
63
- ```
64
-
65
- **You cannot run that line yourself.** The prompt needs a TTY and your Bash tool has
66
- none, so it refuses with "no TTY to prompt on" — and the fix is NOT to add
67
- `--admin-password`, which would put the credential in this transcript. The user runs
68
- it in their own terminal; you wait for them to say it is done.
69
-
70
- - **Somebody else runs it.** They cannot invite, and no flag changes that. Print the
71
- statements for whoever administers the server — this contacts nothing and needs no
72
- credential:
73
-
74
- ```
75
- memhouse invite <name> --url <url> [--db <shared-house>] --print-sql
76
- ```
77
-
78
- The output ends with the four `MEMHOUSE_*` lines the invitee needs. Those lines are
79
- a credential: tell the user to send them over a trusted channel, and **never print
80
- them into the conversation yourself**.
81
-
82
- **If it refuses with "house `<db>` already exists and holds N messages", STOP.** That
83
- house is somebody's memory, and inviting into it would hand the invitee someone else's
84
- sessions. Do not pass `--adopt` on your own initiative — report the row count and the
85
- writer count to the user and let them choose: a different handle, a different `--db`,
86
- or `--adopt` if sharing that house is genuinely what they want.
87
-
88
- 4. **Put the file where the user can attach it.** The CLI writes `invite-<name>.env`
89
- into the CURRENT directory, and the user has to send it by hand — so run the command
90
- from their downloads directory (on macOS and most Linux desktops `~/Downloads`), or
91
- move it there afterwards. Never leave it in a git repo: it is a password, and
92
- `invite-*.env` is only gitignored in this repo, not in whatever checkout the user
93
- happened to be standing in.
94
-
95
- Confirm it is there and still mode `600`, and say the full path. **Never print the
96
- file's contents** — the password inside would land in a transcript memhouse ships.
97
-
98
- 5. **Say whether the house was fresh.** Run
99
- `memhouse stats` or query `SELECT count() FROM <db>.messages` and tell the user
100
- plainly: a brand-new house reads 0. This is a second line of defence behind step 3's
101
- refusal, and it is how the user learns the invitee is starting clean.
102
-
103
- 6. **Write the message the user will send.** They are about to hand over a file plus an
104
- explanation, so compose it for them rather than making them write it. Put it in a
105
- fenced block they can copy whole, and cover:
106
- - what memhouse is, in a sentence or two — the invitee may never have heard of it
107
- - that the attached `invite-<name>.env` IS a password: don't forward it, don't paste
108
- it into chat
109
- - `npm install -g memhouse` (Node 24+, no flags, nothing compiles), then
110
- `memhouse install --env invite-<name>.env`
111
- - that install OFFERS to change the password to one only they know, then deletes the
112
- file — so they should say yes, because the inviter knows the current one
113
- - `memhouse onboard` to start shipping, `memhouse status` to check it worked
114
- - that their house is theirs alone; the inviter cannot read it unless they run
115
- `/mem:share <inviter>`
116
-
117
- If the invitee is REPLACING an existing setup (they were shipping under another
118
- credential), add `memhouse ship --full` after the install — a plain incremental pass
119
- skips sessions the new house has no record of, so their history would not follow them.
120
-
121
- Then: once installed, sharing works both ways — `/mem:share <name>`.
122
-
123
- ## Never
124
-
125
- Never create a ClickHouse user by running raw SQL with an admin password you were given
126
- in chat. Never invent an admin credential. Never suggest granting beyond what `memhouse
127
- invite` does. If the binary is absent, stop and say so — do not improvise the SQL.
128
-
129
- Never print the invite file's contents, and never pass `--adopt` unless the user asked
130
- for it after being told what is already in that house.
@@ -1,186 +0,0 @@
1
- ---
2
- name: 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". Searches your own house by default, or a friend's house shared with you when they name it ("find X in yigit's memory"). 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
7
- ---
8
-
9
- # /mem:search — search conversation memory
10
-
11
- Search the full message history in the memhouse house. Every room is named for your
12
- ClickHouse user — `messages`, `sessions` — see **Room names** below.
13
-
14
- ## Connection
15
-
16
- **Never print this file or the variables in it.** No `cat "$MH_ENV"`, no `env | grep
17
- MEMHOUSE`, no `set -x` around these commands. Anything you print becomes part of a
18
- transcript that memhouse itself ships into the house.
19
-
20
- Credentials resolve as **flags > exported `MEMHOUSE_*` > `$MEMHOUSE_HOME/env`**
21
- (default `~/.memhouse/env`) — the same order the `memhouse` CLI uses. Every query
22
- runs over ClickHouse HTTP with `final=1` and `join_use_nulls=1` (ReplacingMergeTree
23
- keeps stale row versions until merges; `final=1` collapses to latest-wins — always
24
- include it on reads):
25
-
26
- ```bash
27
- # Config lives at $MEMHOUSE_HOME/env (default ~/.memhouse/env). Exported MEMHOUSE_*
28
- # vars WIN over the file — snapshot them, source, then put them back. Sourcing alone
29
- # lets a stale file silently override the house you were pointed at.
30
- MH_ENV="${MEMHOUSE_HOME:-$HOME/.memhouse}/env"
31
- _u=${MEMHOUSE_URL-}; _s=${MEMHOUSE_USER-}; _p=${MEMHOUSE_PASSWORD-}; _d=${MEMHOUSE_DB-}
32
- set -a; [ -f "$MH_ENV" ] && . "$MH_ENV"; set +a
33
- [ -n "$_u" ] && MEMHOUSE_URL=$_u; [ -n "$_s" ] && MEMHOUSE_USER=$_s
34
- [ -n "$_p" ] && MEMHOUSE_PASSWORD=$_p; [ -n "$_d" ] && MEMHOUSE_DB=$_d
35
- # No default URL. localhost:8123 as memhouse_root is a REAL house on many machines,
36
- # usually the pilot's own — guessing it reads someone else's memory and looks like it
37
- # worked. If there is no config, say so and stop.
38
- if [ -z "${MEMHOUSE_URL:-}" ] || [ -z "${MEMHOUSE_USER:-}" ]; then
39
- # An explicit test, not ${VAR:?msg}: zsh does not expand the message, so under the
40
- # shell Claude Code actually uses the refusal read "nothing in $MH_ENV" literally.
41
- echo "no memhouse house configured — nothing in $MH_ENV and no MEMHOUSE_URL/MEMHOUSE_USER set." >&2
42
- echo "Run: memhouse install" >&2
43
- exit 1
44
- fi
45
-
46
- # --user, not a -K config file. The config-file parser treats `"` and `\` specially, so a
47
- # password containing either authenticates fine from the CLI and fails from every skill
48
- # with "password is incorrect" — measured. The argv exposure -K was meant to avoid is not
49
- # observable here either: curl blanks the --user argument before `ps` can read it (0 hits
50
- # in 50 samples). What actually leaks a credential is PRINTING it, which the rule above
51
- # covers.
52
- curl -sS --fail-with-body --user "$MEMHOUSE_USER:${MEMHOUSE_PASSWORD:-}" \
53
- --data-binary @- "$MEMHOUSE_URL/?database=${MEMHOUSE_DB:-$MEMHOUSE_USER}&final=1&join_use_nulls=1&readonly=1" <<'SQL'
54
- <the query>
55
- FORMAT PrettyCompact
56
- SQL
57
- ```
58
-
59
- `FORMAT PrettyCompact` for display; `FORMAT JSONEachRow` when you want to parse
60
- the rows yourself.
61
-
62
- ## Room names — plain, shared tables
63
-
64
- The house's rooms are three plain tables: `messages`, `sessions`, `tool_calls` — resolved
65
- by the connection's database (`MEMHOUSE_DB`), not by who is asking. Everyone in the house
66
- writes into the same tables; `user_id` (stamped by the server) says whose row it is and
67
- `host` says which machine shipped it. Search the whole house by default; add
68
- `AND user_id = '<name>'` only when the user asks for one person's sessions.
69
-
70
- **Keep the SQL heredoc quoted (`<<'SQL'`).** This skill once told the agent to substitute
71
- a shell variable into the table names, which cannot expand inside a quoted heredoc — so
72
- the agent unquotes it, and then the SEARCH TERMS expand too. Both instances driving this
73
- skill did exactly that, unprompted, on the first attempt. Measured consequences, from
74
- `system.query_log`:
75
-
76
- - a term containing `$home` became the empty string, so `LIKE '%%'` matched **every row**
77
- and reported hits with exit 0 — silently wrong, not an error;
78
- - a term containing a backtick **executed the command inside it**.
79
-
80
- A user's search term is arbitrary text. With the heredoc quoted, neither can happen.
81
-
82
- **There is no `sessions_v` object.** The session rollup is a saved query over those same
83
- rooms — `memhouse sessions-query` prints it for whoever you are connected as, ready to
84
- paste into a `FROM (...) AS c` position.
85
-
86
- **The rollup is self-contained.** As of 0.4.5 the printed text carries its own `FINAL` on
87
- both rooms and a trailing `SETTINGS join_use_nulls = 1`, so it is correct wherever you
88
- paste it. `final=1` on the connection still matters for reads of the rooms THEMSELVES,
89
- which carry no FINAL of their own.
90
-
91
-
92
- ## How to search (the FTS columns)
93
-
94
- `messages` carries two MATERIALIZED lowercase copies of `text`, each with a
95
- text index — search those, display `text`:
96
-
97
- - `text_ngram` (ngram index) → substring match: `text_ngram LIKE '%term%'`
98
- - `text_word` (word index) → whole-token match: `hasToken(text_word, 'term')`
99
-
100
- **Search terms MUST be lowercased** (the columns are `lower(text)`); escape
101
- single quotes in user terms as `\'`. Multiple words → AND of clauses; a quoted
102
- phrase → one `LIKE` clause for the whole phrase.
103
-
104
- ### Example 1 — substring search with session names
105
-
106
- ```sql
107
- SELECT m.ts, m.source, m.project, m.role, m.session_id,
108
- s.name AS session,
109
- substring(m.text, 1, 300) AS snippet
110
- FROM messages AS m
111
- LEFT JOIN sessions AS s USING (session_id, user_id)
112
- WHERE m.text_ngram LIKE '%postgres%' AND m.text_ngram LIKE '%migration%'
113
- ORDER BY m.ts DESC
114
- LIMIT 30
115
- FORMAT PrettyCompact
116
- ```
117
-
118
- ### Example 2 — word match, scoped by editor and time
119
-
120
- ```sql
121
- SELECT ts, project, session_id, substring(text, 1, 200) AS snippet
122
- FROM messages
123
- WHERE hasToken(text_word, 'rls')
124
- AND source = 'claude-code'
125
- AND ts > now() - INTERVAL 14 DAY
126
- ORDER BY ts DESC
127
- LIMIT 20
128
- FORMAT PrettyCompact
129
- ```
130
-
131
- ### Example 3 — which sessions mention it most (then drill in)
132
-
133
- ```sql
134
- SELECT m.session_id, m.user_id, any(s.name) AS session, any(m.project) AS project,
135
- count() AS hits, max(m.ts) AS last_hit
136
- FROM messages AS m
137
- LEFT JOIN sessions AS s USING (session_id, user_id)
138
- WHERE m.text_ngram LIKE '%clickhouse cache%'
139
- GROUP BY m.session_id, m.user_id
140
- ORDER BY hits DESC
141
- LIMIT 10
142
- FORMAT PrettyCompact
143
- ```
144
-
145
- ## Reading another person's house (shared with you)
146
-
147
- Every house is its own ClickHouse database on the same server; a share is a read-only
148
- GRANT on that database. To read a friend's memory you keep YOUR credentials and point the
149
- connection at THEIR house — the rooms (`messages`, `sessions`, `tool_calls`) resolve by
150
- the connection's `database`, so one change redirects every query in this skill.
151
-
152
- 1. **Resolve the target house.** `SHOW DATABASES` lists what your credential may read; the
153
- names that are not `system` / `information_schema` / `default` and not your own
154
- `$MEMHOUSE_DB` are houses shared with you. If the user names one — "yigit's memory",
155
- "in yigit", "house yigit", "from yigit" — set `HOUSE=yigit`; otherwise leave
156
- `HOUSE=$MEMHOUSE_DB`.
157
- 2. **Point the connection at it:** in the recipe above, replace
158
- `database=${MEMHOUSE_DB:-$MEMHOUSE_USER}` with `database=<HOUSE>`. Leave the table names bare —
159
- they resolve to that house. Nothing else in the query changes.
160
- 3. **A house wins over `in <project>`.** A name that matches a readable house is a HOUSE,
161
- not a project filter — otherwise "in yigit" silently filters YOUR house's project
162
- column and returns nothing. If a real project in your own house shares the name, keep
163
- the possessive ("<name>'s memory") or say "project <name>" to force the project reading.
164
- 4. **Read-only, thin by design.** If the SELECT is refused, that house was not shared with
165
- you (or the share was revoked) — say so; never guess another database.
166
-
167
- ## Qualifiers
168
-
169
- - `in <project>` → `AND m.project ILIKE '%<project>%'` — but a name matching a readable
170
- house is a HOUSE (see above), not a project.
171
- - `last N days` → `AND m.ts > now() - INTERVAL N DAY`
172
- - `from <editor>` → `AND m.source = '<id>'` (ids: `claude-code`, `codex`,
173
- `cursor`, `cursor-agent`, `vscode`, `zed`, `opencode`, `gemini-cli`,
174
- `windsurf`, `antigravity`, `copilot-cli`, `goose`, `kiro`, …)
175
- - Skip subagent noise → `AND NOT m.is_subagent`
176
- - Only user/assistant text lives in `messages`; tool invocations are in
177
- `tool_calls` (`tool_name`, `args`) — search `args ILIKE '%term%'` there
178
- only if the user explicitly wants tool calls searched.
179
-
180
- ## Output
181
-
182
- Summarize hits grouped by session (name, source, project, date, 1–2 best
183
- snippets each) and give the total hit count. Offer to pull the full transcript
184
- of the best session (`SELECT role, text FROM messages WHERE session_id = '…'
185
- ORDER BY seq`). If zero hits, retry with broader/fewer terms and report the
186
- corpus size (`SELECT count() FROM messages`).
@@ -1,164 +0,0 @@
1
- ---
2
- name: 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
7
- ---
8
-
9
- # /mem:sessions — browse session history
10
-
11
- List/filter sessions from the session rollup — a saved query over your own rooms, not an
12
- object; `memhouse sessions-query` prints it (session metadata +
13
- message aggregates) in the memhouse house.
14
-
15
- ## When to use
16
-
17
- - The user wants an overview of recent activity rather than a specific quote.
18
- - As a first step before digging into one session, when they don't have an
19
- id/name yet.
20
-
21
- ## Connection
22
-
23
- **Never print this file or the variables in it.** No `cat "$MH_ENV"`, no `env | grep
24
- MEMHOUSE`, no `set -x` around these commands. Anything you print becomes part of a
25
- transcript that memhouse itself ships into the house.
26
-
27
- Credentials resolve as **flags > exported `MEMHOUSE_*` > `$MEMHOUSE_HOME/env`**
28
- (default `~/.memhouse/env`) — the same order the `memhouse` CLI uses. Every query
29
- runs over ClickHouse HTTP with `final=1` and `join_use_nulls=1` (ReplacingMergeTree
30
- keeps stale row versions until merges; `final=1` collapses to latest-wins — always
31
- include it on reads):
32
-
33
- ```bash
34
- # Config lives at $MEMHOUSE_HOME/env (default ~/.memhouse/env). Exported MEMHOUSE_*
35
- # vars WIN over the file — snapshot them, source, then put them back. Sourcing alone
36
- # lets a stale file silently override the house you were pointed at.
37
- MH_ENV="${MEMHOUSE_HOME:-$HOME/.memhouse}/env"
38
- _u=${MEMHOUSE_URL-}; _s=${MEMHOUSE_USER-}; _p=${MEMHOUSE_PASSWORD-}; _d=${MEMHOUSE_DB-}
39
- set -a; [ -f "$MH_ENV" ] && . "$MH_ENV"; set +a
40
- [ -n "$_u" ] && MEMHOUSE_URL=$_u; [ -n "$_s" ] && MEMHOUSE_USER=$_s
41
- [ -n "$_p" ] && MEMHOUSE_PASSWORD=$_p; [ -n "$_d" ] && MEMHOUSE_DB=$_d
42
- # No default URL. localhost:8123 as memhouse_root is a REAL house on many machines,
43
- # usually the pilot's own — guessing it reads someone else's memory and looks like it
44
- # worked. If there is no config, say so and stop.
45
- if [ -z "${MEMHOUSE_URL:-}" ] || [ -z "${MEMHOUSE_USER:-}" ]; then
46
- # An explicit test, not ${VAR:?msg}: zsh does not expand the message, so under the
47
- # shell Claude Code actually uses the refusal read "nothing in $MH_ENV" literally.
48
- echo "no memhouse house configured — nothing in $MH_ENV and no MEMHOUSE_URL/MEMHOUSE_USER set." >&2
49
- echo "Run: memhouse install" >&2
50
- exit 1
51
- fi
52
-
53
- # --user, not a -K config file. The config-file parser treats `"` and `\` specially, so a
54
- # password containing either authenticates fine from the CLI and fails from every skill
55
- # with "password is incorrect" — measured. The argv exposure -K was meant to avoid is not
56
- # observable here either: curl blanks the --user argument before `ps` can read it (0 hits
57
- # in 50 samples). What actually leaks a credential is PRINTING it, which the rule above
58
- # covers.
59
- curl -sS --fail-with-body --user "$MEMHOUSE_USER:${MEMHOUSE_PASSWORD:-}" \
60
- --data-binary @- "$MEMHOUSE_URL/?database=${MEMHOUSE_DB:-$MEMHOUSE_USER}&final=1&join_use_nulls=1&readonly=1" <<'SQL'
61
- <the query>
62
- FORMAT PrettyCompact
63
- SQL
64
- ```
65
-
66
- ## Room names — plain, shared tables
67
-
68
- The house's rooms are three plain tables: `messages`, `sessions`, `tool_calls` — resolved
69
- by the connection's database (`MEMHOUSE_DB`), not by who is asking. Everyone in the house
70
- writes into the same tables; `user_id` (stamped by the server) says whose row it is and
71
- `host` says which machine shipped it. Search the whole house by default; add
72
- `AND user_id = '<name>'` only when the user asks for one person's sessions.
73
-
74
- **Keep the SQL heredoc quoted (`<<'SQL'`).** This skill once told the agent to substitute
75
- a shell variable into the table names, which cannot expand inside a quoted heredoc — so
76
- the agent unquotes it, and then the SEARCH TERMS expand too. Both instances driving this
77
- skill did exactly that, unprompted, on the first attempt. Measured consequences, from
78
- `system.query_log`:
79
-
80
- - a term containing `$home` became the empty string, so `LIKE '%%'` matched **every row**
81
- and reported hits with exit 0 — silently wrong, not an error;
82
- - a term containing a backtick **executed the command inside it**.
83
-
84
- A user's search term is arbitrary text. With the heredoc quoted, neither can happen.
85
-
86
- **There is no `sessions_v` object.** The session rollup is a saved query over those same
87
- rooms — `memhouse sessions-query` prints it for whoever you are connected as, ready to
88
- paste into a `FROM (...) AS c` position.
89
-
90
- **The rollup is self-contained.** As of 0.4.5 the printed text carries its own `FINAL` on
91
- both rooms and a trailing `SETTINGS join_use_nulls = 1`, so it is correct wherever you
92
- paste it. Both matter: without `FINAL` every message is counted once per undeleted
93
- ReplacingMergeTree version (2x right after a ship, 3x a few ships later — measured, and it
94
- grows); without `join_use_nulls` a session with no messages reports `total_msgs = 1`
95
- rather than 0.
96
-
97
- **If the `memhouse` binary is not on PATH**, you cannot print the rollup — the skills are
98
- installable on their own. Query the rooms directly instead: `sessions` for metadata
99
- and `messages` for counts, each read `FINAL`, joined on `session_id` and `user_id`.
100
- Prefer the binary when it is there; a rollup you assemble by hand and one printed by a
101
- DIFFERENT memhouse version are the two ways this goes quietly wrong.
102
-
103
-
104
- ## Default listing
105
-
106
- ```sql
107
- SELECT session_id, name, source, host, project,
108
- started, ended, total_msgs, user_msgs, assistant_msgs,
109
- output_tokens,
110
- substring(first_prompt, 1, 80) AS first_prompt
111
- FROM (the rollup from `memhouse sessions-query`)
112
- ORDER BY ended DESC
113
- LIMIT 20
114
- FORMAT PrettyCompact
115
- ```
116
-
117
- - Default `LIMIT 20`; `[N]` overrides.
118
- - `today` / `week` / `month` → `WHERE ended > now() - INTERVAL 1 DAY`
119
- (`7 DAY` / `30 DAY`).
120
- - `project <name>` → `WHERE project ILIKE '%<name>%'`.
121
- - `from <editor>` → `WHERE source = '<id>'` (`claude-code`, `codex`, `cursor`,
122
- `vscode`, `zed`, `opencode`, `gemini-cli`, `windsurf`, …).
123
- - Unnamed sessions (`name = ''`): fall back to `first_prompt` as the label.
124
-
125
- ## More cuts
126
-
127
- Per-editor rollup ("where has my work been happening?"):
128
-
129
- ```sql
130
- SELECT source, count() AS sessions, sum(total_msgs) AS msgs,
131
- sum(output_tokens) AS out_tokens, max(ended) AS last_activity
132
- FROM (the rollup from `memhouse sessions-query`)
133
- GROUP BY source
134
- ORDER BY sessions DESC
135
- FORMAT PrettyCompact
136
- ```
137
-
138
- Busiest projects this month:
139
-
140
- ```sql
141
- SELECT project, count() AS sessions, sum(assistant_msgs) AS assistant_msgs
142
- FROM (the rollup from `memhouse sessions-query`)
143
- WHERE ended > now() - INTERVAL 30 DAY AND project != ''
144
- GROUP BY project
145
- ORDER BY sessions DESC
146
- LIMIT 15
147
- FORMAT PrettyCompact
148
- ```
149
-
150
- ## Examples
151
-
152
- | User says | What you do |
153
- |---|---|
154
- | "what was I working on yesterday?" | `WHERE ended > now() - INTERVAL 1 DAY` |
155
- | "show my last 10 sessions in agentlytics" | `LIMIT 10 … WHERE project ILIKE '%agentlytics%'` |
156
- | "list my cursor sessions this month" | `WHERE source = 'cursor' AND ended > now() - INTERVAL 30 DAY` |
157
- | "which machine did I do the schema work on?" | search via /mem:search, or filter `host` here |
158
-
159
- ## Output
160
-
161
- A compact table: when, name (or first prompt), source, host, project, msgs,
162
- tokens. Offer to pull a full transcript next
163
- (`SELECT role, text FROM messages WHERE session_id = '…' ORDER BY seq`) or to
164
- run /mem:search for a specific quote.