v0.12.7 · 17 editor adapters · MIT

Your agents forget.
The house remembers.

Every coding-agent session on every machine you install it on — Claude Code, Codex, Cursor, Gemini CLI, Devin, Zed and a dozen more — parsed on your machine and shipped to one typed ClickHouse store you own. Then your next agent can read what the last one already worked out.

$ npm install -g memhouse

then memhouse onboard — discover, configure, ship, start.
no flags, no build step, nothing native. needs Node 24+.

17
editor adapters
JSONL and SQLite-backed
3
rooms per credential
one set per member, or per agent
1
command to install
dual-mode: human or agent
0
clouds to trust
your ClickHouse, your rules

One shipper · seventeen adapters · whatever you switched to last month

localhost:4640 — memhouse dashboard
The memhouse dashboard: sessions per editor, token and cost tiles, a coding-activity heatmap and per-editor monthly trends

// shown in dark mode — the dashboard ships both themes, like this page. It is agentlytics' UI, unforked: memhouse serves the same bundle over its own typed store

01  /  The problem

Your history already exists. It's just unusable.

Every agent you run already writes down what it did — into its own directory, in its own format, on whichever laptop you happened to use. Which means the answer you worked out three weeks ago is on disk and out of reach: not to you, and definitely not to the agent that is about to re-derive it.

Session files as they shipExport + index (RAG)memhouse
Where it lives A dozen app directories, per machine A vector store you now operate One ClickHouse you already trust
Coverage Whatever one editor wrote Whatever exports cleanly to text 17 adapters, JSONL and SQLite-backed editors
Shape of the data Raw JSONL, or an app's private SQLite Chunks and embeddings Typed rows: messages, sessions, tool calls
Answering a question grep, if you remember which folder Approximate recall, no exact filters SQL and full-text — exact, filterable, joinable
A second machine A second pile of files Re-export and re-index it Install there too, same credential — it ships into your rooms, tagged with a stable host
Sharing with a teammate Paste a transcript Copy the whole index, or nothing One GRANT — theirs stays theirs
Not a chat-log warehouse. memhouse parses before anyone asks and writes the result down, so what lands in the house is already structured: who said it, in which session, in which project, with which model, at what cost, calling which tools. The query does no archaeology.

02  /  Alternatives

Four ways to give an agent a memory

Agent memory is a crowded field, and the projects in it do not disagree about the goal — they disagree about where you tap the stream. That choice decides everything downstream: what gets captured, whether your existing history counts, and who your prompts pass through on the way to the model.

Nothing
the files as they ship
Proxy at the model boundary Memory framework
vector / graph store
memhouse
Where it taps in Nowhere — each app writes its own files In front of the LLM API; you point agents at it SDK calls you add to your own app Reads the session files each editor already writes
Your history from before you installed it On disk, unread Gone — only new traffic is seen Gone, unless you write an importer Ingested — that is the whole point
What it can see Everything, unusably The model conversation Whatever you remembered to pass it Tool calls, timing, project, model, cost — what actually ran
Where your prompts travel Nowhere Through the proxy, then upstream To an embedding API, usually Nowhere — parsing is local, rows go to your ClickHouse
Infrastructure it adds None Several services to run and keep up A vector DB, often a graph DB too One ClickHouse — or the one you already run
Who enforces isolation The filesystem Application code, over an app-level store Application code, over an app-level store The database — GRANT and currentUser(), not a service you have to trust
Cost of coverage One integration catches every agent One integration, but only your own app 17 adapters to maintain — deliberately paid
Where the proxy approach genuinely wins. One integration point catches every agent, because every agent talks to a model API — while adapters are one per editor, forever, and they break when an editor changes its on-disk layout. memhouse pays that maintenance on purpose, for the two things a proxy structurally cannot do: read the history already sitting on your disk, and stay out of the path between you and your model. If you would rather not run a man-in-the-middle on every prompt you send, that is the trade. The repo grades the whole field bet by bet in COMPETITION.md.

03  /  How it works

Three moving parts. One of them writes.

memhouse is a house — a ClickHouse database — plus one resident: the shipper. Everything else in the system only reads, which is why there is so little of it.

STEP 01

Parse on the client

The shipper runs all 17 adapters locally — JSONL transcripts and the private SQLite databases Cursor, Zed, Goose, OpenCode and Antigravity keep — and emits typed rows. Nothing raw leaves the disk.

STEP 02

Ship into typed rooms

messages, sessions, tool_calls as real columns, plus one extra JSON escape hatch so no adapter field is ever lost. Incremental by default; a re-ship of a grown session replaces the stale rows instead of duplicating them.

STEP 03

Ask — human or agent

A dashboard for eyes, memhouse search for terms, plain SQL for everything else, and a skills payload so an agent queries its own past sessions before it claims it doesn't know.

04  /  Who it's for

One person with six agents. Or six people with sixty.

Same install, same rooms. The only difference is who holds a grant.

Solo builders

One place your whole agent history lives

You switch editors. You switch machines. You do not switch memory — point each machine at the same house with the same credential and every session lands in the same three rooms, each row tagged with the machine it came from. "How did I fix that" is then one query, not an archaeology dig through four app directories on two laptops.

  • All of it, not the last one. The editor you abandoned in March still ships.
  • Costs you can actually see. Spend, model mix and tool usage across every agent at once.
  • Runs on your laptop. memhouse deploy --local stands up a loopback-bound ClickHouse in one command.
Teams

One house, everyone's memory

A team's house is a database — team_a.messages, team_a.sessions, team_a.tool_calls — and every housemate's shipper writes into the same tables with their own credential. The server stamps user_id on every row; the install fingerprint stamps host.

  • Or no DBA at all. memhouse invite alice mints the user, the database and the grants, and writes a portable env file — the admin credential is never stored, and Alice runs one memhouse install --env to be a full owner of her own house.
  • The whole team in one dashboard, no configuration — and WHERE user_id = 'alice' is one person.
  • The boundary is the database. Groups that should not see each other get separate houses; a house's ALL reaches nothing outside it.
  • Read-only shares, without a new account. memhouse share opens a SELECT-only window into your house for a housemate who should see it, not own it.

Every row says where it came from

Provenance is two columns, and neither can be faked by a client. user_id is MATERIALIZED currentUser() — computed by the server during the insert, with async inserts pinned off on the user so the stamp cannot be skipped. host is a fingerprint minted once per install, so two laptops with the same hostname stay two machines and renaming one does not split its history.

  • One person: WHERE user_id = 'alice'. One machine: WHERE host = 'macbook-4127a95b'. The whole house: no filter.
  • Housemates are collaborators. The model is trust inside the house — grants can be narrowed later if a team wants, but separation between groups is a separate house, not machinery inside one.
  • Your own history survives a re-ship. Rows carry origin; the shipper's clear binds it, and imported history is never its to delete.
The line that actually matters. Attribution comes from the credential, not from the client. A crew running under one shared credential is one user_id however it labels itself — a client-supplied tag is a label, not provenance. Give each person (or each agent) their own credential and the server does the rest.
# the fast way — mints user + database + grants, no admin credential stored
$ memhouse invite alice --url https://ch.example.com:8443 \
    --admin-user root --admin-password *****
 alice.env written — hand it to alice, she runs:
    memhouse install --env alice.env

# or the statements a DBA already knows, by hand
$ CREATE DATABASE team_a;
$ CREATE USER alice IDENTIFIED BY '…';
$ GRANT ALL ON team_a.* TO alice;   # repeat per housemate

# everyone ships into the same rooms; the server says who wrote what
$ SELECT user_id, host, count() FROM team_a.messages
$ GROUP BY user_id, host;
  alice  macbook-4127a95b   64258
  bob    thinkpad-0fc96a7c  64258

05  /  What you get

Memory that behaves like a database

Because it is one.

Typed common schema

Physical columns for what other tools derive at query time, a tool_calls table most don't have at all, and one extra JSON field per table so unnormalized adapter data is never dropped.

Full-text search built in

memhouse search <terms> across every session you have ever had, on any machine, in any editor — ClickHouse text indexes, not a grep over files that may already be rotated away.

Go back into the session

memhouse resume <session-id> prints the command that reopens that conversation in the editor it came from, working directory included — Claude Code and Codex both scope their session lists by it. It prints rather than runs: a resume from the wrong directory does not fail, it quietly starts a new session, and the transcript you were after is still gone.

A credential per person, a database per group

Everyone in a house writes into the same three rooms, and the server stamps every row with who wrote it — attribution no client can fake. Groups that should not see each other get separate houses; a house's ALL reaches nothing outside its own database.

Two laptops, one memory

Every machine you own ships into the same rooms, and each install stamps its rows with a fingerprint written once — so WHERE host = … tells the desktop from the laptop. It is random rather than derived from the hostname, because two machines that both answer to MacBook-Pro would otherwise share one identity, and renaming a machine would cut its history in half.

Agent-native, not agent-adjacent

Every command is dual-mode: interactive for humans, --yes / flags / --json for agents. An agent can install its own memory and its own skills, unattended.

Costs, models, tools

A cost engine over per-model token sums, and a dashboard showing sessions, spend, model mix, peak hours and tool usage across all your agents at once.

Survives a reboot

memhouse service install writes a real user service — systemd --user on Linux, a launchd agent on macOS — and takes over from the pidfile daemons.

Upgrades itself, and says so

memhouse update does the two thirds a bare npm i -g leaves undone: it re-passes the native-binding flag, restarts the daemons, and checks whether your house is missing a column the new shipper needs. The daemons also notice on their own — each compares the installed version against the one it booted with and hands over, exiting under systemd or launchd so the supervisor restarts it, re-executing itself when nothing is supervising. A shipper here once ran for a day and a half out of a directory that had been moved.

06  /  Where the memory lives

Your ClickHouse, your rules

memhouse does not embed a database and does not run a cloud you have to trust. Point it at a ClickHouse — or let it stand one up for you.

PathWhat it runsWho it's for
deploy --local Stock ClickHouse in docker or podman, bound to loopback. Since 0.4.2 onboard offers it when discover has just proved there is nothing to point at, instead of demanding a URL you do not have. It labels what it creates and refuses to touch a container or volume it did not create, so a name collision costs you an error rather than somebody else's data. One machine — or several members later.
kernel install An agency house on an ultimagent kernel: house, owner, credential, and members provisioned with grants on their own rooms. A team, provisioned centrally.
your own Any reachable ClickHouse — a server you run, ClickHouse Cloud, whatever you already pay for. You already have one.

The shipper never deletes what it can't rebuild

A re-ship that comes back shorter used to replace the old rows — collapse a longer parse down to a shorter one, permanently. Rows now carry an epoch: unchanged sessions stay on the epoch they were on, a session that changed writes under a new one, and the old epoch is kept, not overwritten. Reads default to the current epoch; nothing is gone.

  • Schema outgrows a running house. memhouse migrate runs whatever this house still needs — copy, atomic swap, nothing deleted — and --dry-run shows the plan first.
  • Moving server? memhouse relocate --to <url> copies the whole house server-to-server and repoints the install; the shipper does not re-ingest, and the source is left untouched until you say otherwise.
# see what a migration would do before it runs
$ memhouse migrate --dry-run
  sessions: schema 2 → 3, adds `origin`, `epoch`
  plan: copy → atomic swap → keep sessions_pre_epoch

$ memhouse migrate --yes
 house record: schema 3, no migration pending

# moving to a new ClickHouse — copy, then repoint
$ memhouse relocate --to https://new.example.com:8443 --yes

07  /  The CLI

One binary, no dashboard tour required

Config resolves flags > MEMHOUSE_* env > ~/.memhouse/env > defaults.

# install
$ npm install -g memhouse

# no ClickHouse yet? onboard offers to stand one up
$ memhouse deploy --local

# the wizard: discover → configure → ship → start
$ memhouse onboard
 17 adapters · 9 with sessions on this machine
 sessions shipped · dashboard on http://localhost:4640

# then, any time
$ memhouse search clickhouse ttl
$ memhouse stats
$ memhouse status --json
$ memhouse doctor

Want to look before it writes anything?

discover is a read-only preflight: which editors it found, how many sessions are sitting on this disk, and which ClickHouses it can reach. It writes nothing.

$ npx -y memhouse discover
  • Incremental. A pass skips every session that hasn't grown or changed; a full re-ship stays safe.
  • Idempotent. Re-shipping a known session clears its old message and tool rows first, so a shrunken re-parse can't leave a stale tail behind.
  • Degrades one adapter at a time. A missing SQLite binding used to make discover report zero editors — one absent native module threw before any adapter ran. Since 0.4.3 the eleven adapters that need no native code work regardless, and the five that do are named as skipped.
  • Honest about failure. doctor diagnoses the whole pipeline, and both it and discover say out loud when the binding is missing rather than leaving you to infer it from a low number.

08  /  For agents

The next agent starts where the last one stopped

A house full of past sessions is only worth it if the next session can read it. memhouse ships the delivery kit that makes that the default behaviour rather than a thing you remember to do.

"Did we ever solve this before?" — asked before the answer is re-derived, not after.

  • Nine skills. /mem:ask answers from memory, /mem:search and /mem:sessions find and browse, /mem:sql runs read-only analytics, /mem:status and /mem:users report on the house, and /mem:invite / /mem:share bring in or read from a housemate — an agent can onboard a teammate without an admin at the keyboard.
  • A plugin. memhouse plugins install claude drops them into every Claude Code config directory on the machine — ~/.claude, whatever CLAUDE_CONFIG_DIR points at, and each playbook under ~/.claude-playbooks/ — all selected by default, because a skill installed into only one of them is missing from the instance you actually work in, and a missing skill never announces itself. onboard offers this at the end.
  • A prompt snippet. memhouse prompt prints the system-prompt block that tells an agent to search memory before claiming ignorance.
  • An install prompt, rendered for this machine. memhouse prompt --install probes for a house, a container engine and an existing config, then states the one route that applies — including "already installed, do not reinstall" and "configured but the house does not answer, diagnose before repointing". An agent gets an instruction, not a decision tree to walk and a branch to pick wrong.
  • The skills only read. Agents query; only the shipper writes — and every row an agent reads carries user_id and host, so "whose session was this" is a WHERE clause, not a guess.
# give an agent its own memory, unattended
$ memhouse install --yes \
    --url https://ch.example.com:8443 \
    --user alice --password ***** --db mem
 rooms ready: sessions, messages, tool_calls in mem
 verified as alice

$ memhouse plugins install claude
 skills installed: ask · hello · invite · search · sessions · share · sql · status · users

$ memhouse prompt >> CLAUDE.md

# or hand an agent the install itself
$ memhouse prompt --install

Start remembering

One command to see what every agent on your machines has actually been doing — and to let the next one read it.

$ npm install -g memhouse

09  /  Questions

Before you install it

Does anything leave my machine?

Only what you point it at. Parsing happens locally, and the shipper writes typed rows to the ClickHouse you configure — which can be a container on the same laptop (memhouse deploy --local, bound to loopback). There is no memhouse cloud and no phone-home.

Do I need any flags, or a compiler?

No. npm install -g memhouse with nothing after it is the complete install, and nothing in it compiles.

It was not always so. Five adapters — Cursor, Goose, OpenCode, Zed and Antigravity — read sessions out of SQLite files, and that used to mean better-sqlite3, whose native binding is built by an npm install script. npm 12 blocks install scripts by default, so the install needed --allow-scripts=better-sqlite3 — a flag npm never remembered, that had to be re-typed on every upgrade, and whose omission cost you those five editors with no error at all. Up to 0.4.3 it was worse still: the missing module threw at import time, before any adapter ran, so discover reported zero editors on a machine that had plenty.

SQLite now comes from node:sqlite, which is part of Node itself and stable in 24 — hence the Node 24 floor. There is no binding to build, no flag to forget, and no way for an adapter to go dark for want of one.

I already have a memhouse house — is upgrading safe?

Upgrade with memhouse update, and read the refusal it prints. 0.4.4 fixed a data-loss bug that matters if you ever imported history into your house: a ship pass clears and re-inserts a session's rows so a shorter re-parse cannot leave a stale tail, and that clear was scoped to the session alone — so it removed rows the adapters never wrote and cannot rewrite. Measured on a real house of 135,307 imported messages, one pass took a source from 126,098 rows to 98,150, and would have continued a pass at a time.

Rooms now carry an origin column, and it is in the sorting key — guarding only the delete leaves ReplacingMergeTree to collapse an imported row against a shipped one sharing the same key, which is the same loss reached through the merge. ORDER BY cannot be altered in place, so a house built earlier needs its rooms rebuilt; the shipper refuses to write into one and prints the steps, and it checks on every pass rather than at schema time. A house with no imported rows can simply be re-shipped from scratch.

What if the install fails with EACCES?

Check ls -ld "$(npm prefix -g)" — the prefix root is what decides, not the path and not the failing file. Owned by root: a system-managed Node, so re-run with sudo. Owned by you (Homebrew, fnm, nvm, volta): the prefix is yours and the root-owned file npm tripped on is a stray from an earlier sudo npm — another sudo just adds more. Fix that one path with chown instead.

How is this different from RAG over my transcripts?

memhouse doesn't chunk and embed — it parses. What lands in the house is typed rows you can filter, aggregate and join: by project, by model, by editor, by cost, by tool call. Full-text search is a ClickHouse text index over those rows, so a query is exact rather than approximate, and the same data also answers "what did I spend on Opus last month".

Can a team share memory?

Sharing is the design, not a feature. A team's house is one database; every housemate's shipper writes into the same tables, the server stamps who, the fingerprint stamps which machine, and the dashboard shows the whole house with no configuration. Groups that should not see each other run separate houses — the database is the boundary.

Which editors, exactly?

Seventeen adapters, covering: Claude Code, Codex, Cursor, Cursor Agent, VS Code, VS Code Insiders, GitHub Copilot (CLI and JetBrains), Gemini CLI, Devin, Devin Next, Zed, Goose, OpenCode, Kiro, Antigravity, Codebuff, Command Code and GSD Workflow.

Where does this come from?

The adapters, dashboard and cost engine are built on agentlytics by Fatih Kadir Akın (MIT); the repo's history carries the full lineage. memhouse adds the typed store, per-member rooms, the shipper and the agent delivery kit. It is part of the Ultimagent constellation, where it installs as an agency.