Claude Code plugin
Always-on memory for Claude Code — injects relevant context at every prompt and captures significant work automatically.
Claude Code plugin
The MemHQ plugin gives Claude Code a memory that persists across sessions. It runs entirely through Claude Code's hooks pipeline and does two things:
- Injects relevant memories at session start and before every prompt, so Claude knows what you decided last week.
- Captures significant work automatically — commits, deploys, config
edits, completed todos — with no
/remembercommand to forget.
The plugin and the MCP server are complementary, not
alternatives. The MCP server gives Claude three tools it calls on
purpose (memhq_add, memhq_search, memhq_ask). The plugin is the
always-on background sync that runs whether or not Claude thinks to
reach for a tool. Most people run both.
Install
The plugin is not on the Claude Code marketplace yet, so install it by symlinking the package into your local plugins directory:
mkdir -p ~/.claude/plugins
ln -s /absolute/path/to/memhq/packages/plugin-claude-code ~/.claude/plugins/memhqSet your project API key in the shell Claude Code launches from — usually
your login shell rc, not a project .env:
export MEMHQ_API_KEY="mem_..."Restart Claude Code. The hooks resolve through ${CLAUDE_PLUGIN_ROOT}, so
the symlink works with no further wiring.
Configuration
Everything is environment variables.
| Variable | Default | Purpose |
|---|---|---|
MEMHQ_API_KEY | required | Project API key, starts with mem_. |
MEMHQ_API_URL | https://api.memhq.ai | API base URL. Point at http://localhost:3000 for local dev. |
MEMHQ_USER_ID | (see below) | Explicit identity override. |
MEMHQ_USER_ID_FROM_KEY | 0 | Set 1 to derive the identity from the API key. |
MEMHQ_ENABLED | true | Set false to disable every hook without uninstalling. |
MEMHQ_SESSION_START_LIMIT | 10 | Memories injected at session start. |
MEMHQ_PROMPT_SEARCH_LIMIT | 5 | Memories injected per prompt. |
MEMHQ_MIN_PROMPT_CHARS | 40 | Prompts shorter than this skip the search entirely. |
MEMHQ_LOG | /tmp/memhq-hook.out | Debug log path. |
MEMHQ_URL is still read as a legacy fallback for MEMHQ_API_URL, but
prefer the latter — it matches the variable the SDKs and MCP server use.
Identity
Memories are stored against a user_id, which decides whose graph they
land in. The plugin resolves it in this order:
- Explicit —
MEMHQ_USER_ID=alice, used verbatim. Best when you want one identity across every machine you work on. - Derived from the key —
MEMHQ_USER_ID_FROM_KEY=1computessha256(MEMHQ_API_KEY)[:16], so identity follows the key rather than the machine. - Per-machine default —
claude-code-$(hostname -s), matching the MCP server's default.
Pick one and keep it stable. Changing identity mid-stream doesn't lose anything, but new memories land in a different graph than the old ones, so recall quietly gets worse.
What gets captured
| Hook | Fires | Behaviour |
|---|---|---|
SessionStart | New session | Searches for memories matching the project, injects them as markdown. |
UserPromptSubmit | Every prompt | Searches using the prompt as the query, injects up to 5 matches. |
PostToolUse (Bash) | After a shell command | Captures git commit/push/merge/rebase/tag, docker compose up/down, kubectl apply, terraform apply, and npm/pnpm/pip publish. |
PostToolUse (Edit/Write) | After a file edit | Captures edits to Dockerfile, docker-compose*, pyproject*, requirements*, CLAUDE.md, .env*, tsconfig*, package.json. |
PostToolUse (TodoWrite) | After a todo update | Captures the first 3 newly-completed todos. |
PostCompact | After compaction | Stores the compaction summary so the context survives being compacted away. |
Stop | Session ends | Stores the final assistant message. |
The capture lists are deliberately narrow. A hook that stored every Bash command would bury the signal — the filter targets actions that change the state of a system, because those are the ones you ask about later.
Failure behaviour
Every hook exits 0 no matter what, and every HTTP call is capped with
--max-time 8. A network outage, an expired key, or a MemHQ incident
slows a hook down at worst; it can never block or fail your Claude Code
session. The cost of that guarantee is that failures are silent, which is
what the log is for.
Troubleshooting
The plugin writes one line per HTTP call:
tail -f /tmp/memhq-hook.outskip /v1/memhq/...: MEMHQ_API_KEY unset — the key isn't visible to
the shell Claude Code launched from. Export it in your login shell rc and
restart Claude Code; a project-local .env won't be picked up.
HTTP 401 or 403 — the key doesn't match the API URL you're pointing at, most often a local key against production or vice versa.
Nothing injected on a prompt — either the prompt is shorter than
MEMHQ_MIN_PROMPT_CHARS (40 by default), or nothing matches yet. Memory
compounds; the first few sessions in a project genuinely have nothing to
recall.
Requirements
POSIX bash, jq, and curl. No Node, no Python. macOS ships all three;
on Linux install jq from your package manager.