What it adds
You can reach Kemory from any host without this plugin — a config-file entry gives you the same kemory_* tools, and Connect a local client covers that path. What it does not give you is any reason for the model to reach for them. A tool sits unused unless something prompts it, and prompting is the whole of what the plugin contributes.
- A standing instruction that ships with the plugin — nothing to paste into
CLAUDE.md, nothing to keep in sync per project. - Prompt recall — every substantive prompt is searched against your vault and the matches arrive before the agent answers, without it deciding to look.
- Context injection — your namespace summaries load at session start, so a session begins informed rather than blind.
- Rate reminder — the agent rates the memories it actually used, so retrieval keeps improving.
- Store nudge — opt-in. When a turn reached a decision and stored nothing, the turn does not just end.
- Session capture — opt-in. A bounded, redacted digest of what the session was about, stored as it goes.
/kemory:status— one command that says what is and is not working.
It works against hosted Kemory and against the open-source Community Edition — one variable, KEMORY_URL, moves the whole plugin.
Hosts and surfaces
The plugin is one tree with a manifest per host, so a second host is a manifest rather than a fork. ${CLAUDE_PLUGIN_ROOT} in the hook and MCP entries is what the hosts resolve, not a Claude-only spelling — the hooks, skills, commands and scripts underneath are shared.
| Host | Manifest | Status |
|---|---|---|
| Claude Code | .claude-plugin/plugin.json | Ships today. The host it installs and is tested on, and the one every command on this page is written for |
| Grok Build | .grok-plugin/plugin.json | Same manifest, same version. The catalog entry is in review |
A release check fails if the two manifests drift: nothing at runtime reads both, so a version bump applied to one and not the other would ship a plugin that disagrees with itself, and the host reading the stale manifest would never see the update — every marketplace gates on the version string, not the commit.
Which Claude surface you are on
Read this before the install commands. Claude Code and Claude Desktop are different products, and only one of them has plugins at all. The row that trips people is the middle one: the plugin works there, the command to manage it does not.
| Surface | Plugin: tools + hooks | /plugin | How to install |
|---|---|---|---|
| Claude Code — terminal | yes | yes | /plugin install kemory@kemory, then /reload-plugins |
| Claude Code — Desktop app, IDE extensions | yes | no | claude plugin install kemory@kemory in a shell, then restart the app fully |
| Claude Desktop — the chat app | no plugins, no hooks | — | kemory mcp install --host claude-desktop, or the Kemory connector |
The Desktop app and the IDE extensions read the same ~/.claude/plugins as the terminal, which is why installing from a shell is enough for them.
Claude Desktop is a different application with no plugin system: it takes MCP servers through its own config, so you get the memory tools there and none of the hooks. Claude Code on the web cannot install plugins either, and claude.ai chat has no hooks — use the Kemory connector on both.
The hooks are bash scripts calling curl and python3, so on Windows they need Git Bash or WSL. That combination is untested, so Windows is not claimed for the hooks even though the CLI runs on it natively.
Install
On Claude Code, in a terminal:
/plugin marketplace add SeKondBrainAILabs/kemory-plugin
/plugin install kemory@kemory
/reload-plugins
/reload-plugins is not optional. /plugin install says so in its own output, and until it runs the plugin's commands do not exist yet. Skipping it is the single most common way to land on Unknown command: /kemory:login after a perfectly good install.
Nothing is downloaded beyond the plugin itself: the bundled MCP entry launches a script inside the plugin, so there is no binary to install and nothing to put on PATH.
Sign in
/kemory:login
It prints one link. Open it, approve in the browser, and the credential is written for you — nothing to install, nothing to paste. It is an RFC 8628 device authorization grant against the same public client the CLI uses, so the user code is already in the URL.
It signs you in the same way kemory login does and writes the same file, ~/.kemory/credentials-<env> — so if you install the CLI later it finds you already signed in.
Restart Claude Code fully afterwards. Closing the window is not enough, and context injection begins with your next session because the hook that performs it runs at session start.
Already reach Kemory another way?
| You have | Do this |
|---|---|
The Kemory CLI, signed in with kemory login | Nothing at all — that is the same credential /kemory:login writes, and both halves read it. kemory connect is only needed for other MCP hosts. |
| The claude.ai Kemory connector | Tools already work; disable the bundled entry under /mcp so you are not running two. The hooks still need export KEMORY_API_KEY="..." — the connector's OAuth token lives inside Claude and a shell script cannot read it. |
| A self-hosted or Community Edition instance | export KEMORY_URL=http://... alongside KEMORY_API_KEY. One URL moves the whole plugin. |
| A headless machine — CI, a container, no browser | export KEMORY_API_KEY="kemory_...". It is a long-lived secret, so prefer /kemory:login anywhere a browser exists. |
Confirm it works
/kemory:status
One command, three blocks, and it is the first thing to run whenever something looks wrong.
| Block | What it answers |
|---|---|
| HOOKS | Whether a credential resolves at all, and whether the API accepts it — the two checks that have to pass. |
| TOOLS | Whether the bundled MCP server will start, which credential it will serve with, whether another server on this machine already covers the same Kemory, and the installed plugin version. |
| SETTINGS | How capture and context injection are configured, and how many sessions have been captured so far. |
/mcp then shows which Kemory server Claude Code is actually talking to. There is one case /kemory:status cannot see and says so rather than reporting a reassuring zero: a claude.ai connector lives inside Claude and is invisible from a shell.
Staying current
Plugins do not update themselves. What you installed is a snapshot, and hooks are where this plugin's behaviour lives — an install left alone keeps running the set that was current the day you ran it, however much has been fixed since.
/plugin update kemory@kemory
It refreshes the marketplace on its way through, so this is the whole command. Restart Claude Code afterwards to load the new hooks — the update itself does not apply them. /kemory:status prints the version you are on, and the changelog says what moved.
The repository was renamed from claude-kemory to kemory-plugin when a second host appeared. GitHub redirects the old path, so an existing /plugin marketplace add keeps working — but kemory-plugin is the name to use from here.
The hooks
Seven hooks, none of which need remembering. Five are on by default; the two that could surprise you ship off.
| Hook | Event | What it does | Leaves your machine | Default |
|---|---|---|---|---|
| context injection | SessionStart | Injects your namespace summaries; warns once if Kemory is not set up yet | Your credential; reads summaries back | on |
| prompt recall | UserPromptSubmit | Searches your vault with the prompt you typed and injects what matches | The text of your prompt | on |
| recall approval | PreToolUse | Auto-approves Kemory read-only tools so memory stops interrupting you. Writes still ask, every time | Nothing | on |
| rate reminder | PostToolUse | Prompts the agent to rate the memories it actually used. Fires only when the response is rateable — a recall_id or a non-empty result list | Nothing | on |
| consolidate reminder | SessionStart after compaction | Prompts the agent to store facts that would otherwise survive only as a summary | Nothing | on |
| store nudge | Stop | When the turn settled something durable and no Kemory write happened, asks for it before the turn ends | Nothing | off |
| session capture | Stop, SessionEnd | Stores a redacted digest of your own prompts: last 12 turns, 8000 characters | Your prompts, redacted | off |
Prompt recall
This is the difference between an instruction and a mechanism. Telling an agent to "recall when the topic shifts" relies on it noticing the shift; searching every prompt does not.
The query is redacted before it leaves your machine, using the same rules as capture. Prompts under 12 characters and those starting with /, ! or # are skipped, so slash commands are never sent. A memory injected once is not injected again in the same session.
Because this path uses POST /api/v1/memories/search, which returns memory ids rather than an invocation id, hook-injected memories carry no recall_id. The agent is told to rate them by memory_id; they will not appear in recall coverage metrics, which join on recall ids.
The store nudge
Every other hook feeds the model and hopes; a standing instruction asks and hopes. This is the only mechanism in the plugin that makes a write actually happen — when a turn stated a conclusion and nothing was stored, it says so before the turn ends.
The phrases it looks for are deliberately narrow: each one states a conclusion rather than merely discussing a topic. "We could use Redis" is not a decision; "we'll use Redis" is. It reads the transcript on your machine and sends nothing.
It is off by default anyway — a hook that continues a turn is disruptive when it is wrong, so it ships off until the false-positive rate has been measured on real sessions. KEMORY_STORE_NUDGE_SIGNALS adds your own |-separated regexes to the built-in set.
Session capture
Capture is off unless you set it explicitly, because it uploads conversation content to your Kemory instance.
What is captured: your own turns only — assistant replies and tool output are skipped — capped at the last N turns and 8000 characters, with common secret patterns redacted. Digests are written to POST /api/v1/memories tagged session-capture and carry the session_id, so the server-side Reflector can consolidate them into semantic summaries.
SessionEnd fires on exit, /clear and resume, so the same turns can be offered more than once. The hook stores a hash of each digest under ~/.kemory/.captured/<session_id> and skips a write whose content it has already stored, so repeats do not accumulate duplicate memories. The hash is recorded only after the write succeeds.
Why compaction is handled at SessionStart
The consolidate reminder deliberately does not use PreCompact: that event rejects additionalContext, and fires as compaction begins, so the model gets no turn in which to act. SessionStart with source=compact fires on the other side of it, where there is still something to do.
Missing credentials, an unreachable server, or a malformed transcript all exit cleanly and never block a session. Every network call is capped at 3–6 seconds so a dead network cannot stall a session. The hooks whose output is actually read — SessionStart, UserPromptSubmit, PreToolUse — run synchronously, because an async hook's stdout is discarded and that would silently kill context injection and read-only auto-approval while still appearing to run. Capture writes and has no output anyone reads, so it runs async.
The cost of failing open is that a broken setup looks like an idle one. A quiet session is a setup problem, not a healthy one — see Troubleshooting.
Skills and commands
| Ships as | What it is for |
|---|---|
/kemory:login | Browser sign-in. One link, approve, credential written for you. |
/kemory:status | Whether credentials resolve, whether the API accepts them, which server will serve the tools, and how capture and injection are configured. |
kemory skill | How to recall, rate, store and phrase memories so semantic search can find them again. |
kemory-setup skill | Walks the agent through connecting Kemory when something is not working. |
The kemory skill is the standing instruction from Optimise your AIs, already written and kept current — with the plugin installed you do not need to paste it into CLAUDE.md yourself.
If you pasted that instruction into CLAUDE.md before the plugin shipped one, you can delete it; the plugin says so once a week until you do. Keeping both is not harmful, but the pasted copy asks the agent to open each session with kemory_list_namespaces and a recall, which the prompt-recall hook has already done by then.
The bundled instruction is injected on every session, including a brand-new vault and a session whose context call failed. It is short on purpose: recall and the write prompt are hooks now, so it says only what no hook can — what Kemory is, and the standard for writing to it.
Credentials
The bundled MCP entry launches a script that resolves a credential through the same function the hooks use, then serves: kemory mcp serve when the credential came from a browser login, and a bundled stdio-to-HTTP bridge when it came from the environment. So one entry covers every way of reaching Kemory, and the tools cannot end up authenticated differently from the hooks or pointed at a different host.
Resolution order is KEMORY_API_KEY, then KEMORY_TOKEN, then the stored browser login in ~/.kemory/credentials-<env>, against KEMORY_URL — defaulting to hosted Kemory. Any one of them turns on both halves. Stored tokens are refreshed automatically when they expire; if a refresh fails, /kemory:status says so rather than leaving the hooks quietly rejected.
With no credential the bundled server exits with that reason on stderr rather than starting. A server that starts and exposes nothing reads as connected in /mcp while every memory tool is missing, which is worse than a visible failure.
Two credentials, not one
The MCP tools and the hooks authenticate separately. This is the single most common source of confusion:
| You have | Tools | Hooks |
|---|---|---|
KEMORY_API_KEY in your environment | yes | yes |
/kemory:login or kemory login, nothing exported | yes | yes |
| Connector or remote MCP, nothing else | yes | no |
| A key inside an MCP config file | yes | no — the hooks never read MCP config |
That last row is worth stating twice: a key in .mcp.json or ~/.claude.json authenticates the tools and is invisible to the hooks. That is how you end up with working kemory_* tools and no context injection. /kemory:status detects the case and tells you; export the same key as KEMORY_API_KEY to turn the hooks on.
The plugin never writes credentials anywhere, never logs them, and refuses to send them to a URL that is not http:// or https://.
Run one server,
not two
Three routes each register an MCP server for Claude Code — a pasted pair-claim prompt, kemory mcp install, and this plugin — and they stack silently. Any two of them leave every tool duplicated in each request, with /mcp listing both without saying they are the same server twice.
So the bundled entry stands down when this machine already has a server for the same Kemory. It is the one that gives way: an entry in a host config was put there deliberately, and this one arrives with the plugin. The cost is only the duplicate — the hooks read credentials directly, so recall, context injection, rating and capture all keep working while the server stands aside, and the message says so, because "your tools moved" and "your memory stopped working" are very different sentences.
Loudly, never silently: it exits with the reason, names the offending entry and the file it is in, and gives the way back. KEMORY_ALLOW_DUPLICATE=1 runs both anyway.
kemory mcp install pins the environment in its arguments precisely so production and staging can coexist as separate servers, so two entries pointing at different hosts are deliberate multi-environment work and are left alone. Each entry is resolved the way the thing that runs it would: an HTTP entry by its own URL, a kemory [--env X] mcp serve entry through the host in ~/.kemory/credentials-X. An entry whose endpoint cannot be worked out is skipped, never guessed at — failing to stand down costs duplicated tools, standing down wrongly costs you your tools entirely.
If you use the claude.ai connector, disable the bundled entry under /mcp; that is the one case the launcher cannot detect from a shell.
Configuration
Set these in the env block of ~/.claude/settings.json, or export them in your shell. Remember the rule above: an environment variable reaches both halves, a key in a config file reaches only the tools.
Credentials and target
| Variable | Default | Meaning |
|---|---|---|
KEMORY_API_KEY | — | API key from the dashboard, sent as X-API-Key. Authenticates both the bundled tools and the hooks |
KEMORY_TOKEN | — | Bearer token, sent as Authorization: Bearer |
KEMORY_URL | https://api.kemory.s9n.ai | Override only for a self-hosted or Community Edition instance. No trailing slash, no path |
KEMORY_ENV | prod | Which credentials file to read |
KEMORY_ALLOW_DUPLICATE | 0 | 1 starts the bundled server even when another one already serves the same Kemory |
Context injection
| Variable | Default | Meaning |
|---|---|---|
KEMORY_CONTEXT | 1 | 0 disables session-start injection |
KEMORY_CONTEXT_DEPTH | l3 | Summary depth requested — l3, or l4 for a synthesised cross-namespace briefing |
KEMORY_CONTEXT_MAX_CHARS | 4000 | Injection budget; summaries beyond it are dropped with a note (floor 500) |
KEMORY_CONTEXT_NAMESPACES | all | Comma-separated allowlist, e.g. user:preferences,shared |
KEMORY_CONTEXT_TIMEOUT | 6 | Seconds to wait for the API before giving up |
KEMORY_QUIET_SETUP | 0 | 1 suppresses the "not configured yet" notice |
If Kemory is not configured, the hook prints one short setup notice and then stays quiet for 24 hours rather than nagging every session.
Prompt recall
| Variable | Default | Meaning |
|---|---|---|
KEMORY_PROMPT_RECALL | 1 | 0 stops the per-prompt vault search, and with it the only default-on transmission of your prompt text |
KEMORY_PROMPT_RECALL_LIMIT | 5 | Maximum memories injected per prompt |
KEMORY_PROMPT_RECALL_MIN_RELEVANCE | 0.55 | Raw-cosine relevance floor — not the blended min_score |
KEMORY_PROMPT_RECALL_ITEM_CHARS | 600 | Per-memory truncation in the injected block |
KEMORY_PROMPT_RECALL_NAMESPACE | all | Restrict recall to one namespace |
KEMORY_PROMPT_RECALL_TIMEOUT | 3 | Seconds to wait for the API |
Store nudge and session capture
| Variable | Default | Meaning |
|---|---|---|
KEMORY_STORE_NUDGE | 0 | 1 asks for a write when a turn settled something and stored nothing |
KEMORY_STORE_NUDGE_SIGNALS | — | Extra |-separated regexes that mark a turn as worth storing, added to the built-in set |
KEMORY_AUTO_CAPTURE | 0 | 1 enables the redacted session digest |
KEMORY_CAPTURE_NAMESPACE | shared | Namespace digests are written to |
KEMORY_CAPTURE_MAX_TURNS | 12 | Maximum user turns in a single stored memory |
KEMORY_CAPTURE_MIN_NEW_TURNS | 3 | New turns required before a mid-session Stop stores anything; SessionEnd flushes any remainder |
KEMORY_CAPTURE_SOURCE | claude-code | Value recorded in the memory's metadata.source |
What leaves
your machine
Two hooks transmit anything at all.
- Prompt recall is on by default and sends the text of each prompt to your Kemory instance as a search query. It skips prompts under 12 characters and anything starting with
/,!or#, so slash commands are never sent. - Session capture is off unless you set it, because it uploads your own turns.
Context injection sends only your credential. The recall-approval, rate-reminder and store-nudge hooks make no network calls at all. Separately, when a stored login has expired the hooks refresh it against the identity provider named in the credential file.
export KEMORY_PROMPT_RECALL=0 # stop sending prompt text
export KEMORY_AUTO_CAPTURE=1 # turn capture on (off by default)
export KEMORY_STORE_NUDGE=1 # turn the store nudge on (off by default)
Redaction
One set of rules, shared by both hooks that send text. It strips credential shapes — bearer tokens, api_key= and password= style assignments, sk-, gh*_, AWS access key ids, Slack xox* tokens, JWTs and PEM private-key headers — replacing each with [REDACTED]. A keyword only triggers when it is followed by an actual assignment and a value long enough to be a credential, so ordinary prose about tokens and secrets survives intact.
This is pattern-matching, not a guarantee. A novel or unusual secret format can pass through. Treat it as a safety net; if you work with sensitive material, leave capture off.
Local files
~/.kemory/.captured/ and ~/.kemory/.nudged/ hold per-session hashes used to avoid storing or asking twice; ~/.kemory/.setup-hint and ~/.kemory/.paste-hint hold timestamps that throttle one-off notices. None contains conversation content.
At session start the plugin also reads ~/.claude/CLAUDE.md and a CLAUDE.md in the current directory, looking only for a hand-pasted copy of the Kemory instruction so it can tell you the plugin now ships one. The file contents are never sent anywhere, never stored, and never edited.
Whatever the plugin injects becomes part of your Claude Code conversation, so it reaches Anthropic on the same terms as anything else you type there.
Storage and deletion
What you send is stored as memories in your own vault, scoped to your organisation and user. Encryption at rest is opt-in per account and off until you enable it. Memories persist until you remove them — there is no automatic expiry unless you set a TTL when storing.
Removal comes at two levels, and the difference matters:
| Action | What it does |
|---|---|
kemory_delete_memory, kemory_forget | Soft delete. The memory stops being active and stops coming back in recall, but the row remains. |
DELETE /api/v1/user/memory-data | Irreversible erasure. Every memory for your user in that organisation, everything derived from them — session summaries, session digests, the consolidated namespace summary — and your memory encryption key along with it. The response tells you which of the two you got. |
If your vault was encrypted, destroying that key makes any ciphertext surviving in a backup permanently unrecoverable; if it was never encrypted, that call is an ordinary hard delete.
Who else can see it
Memories default to user-private and are isolated per organisation; nothing crosses to another organisation. You can widen a memory to team or org-public yourself — see Scoping and sharing.
The hosted service builds the namespace summaries that context injection reads by sending memory content to an LLM sub-processor. Embeddings are computed with a local model and do not leave the service. On a self-hosted instance both are whatever you configured, and the plugin itself adds no sub-processor. The sub-processor list is the authoritative record and covers the whole platform, not just this plugin.
The service itself is governed by the SeKondBrain Privacy Policy.
Troubleshooting
The hooks fail quiet by design, so a broken setup looks like an idle one. Run /kemory:status first — it names which check failed, and the table below acts on what it says.
| What you see | What it means | What to do |
|---|---|---|
Unknown command: /kemory:login | The plugin is installed but not loaded yet — not a failed install | Run /reload-plugins |
/plugin "isn't available in this environment" | You are in the Claude Code Desktop app or an IDE extension | claude plugin install kemory@kemory in a shell, then restart the app fully |
No kemory_* tools at all | The bundled server did not start — usually no credential, or it stood down for a duplicate | /kemory:status names which; then /kemory:login, or remove the other entry |
| Tools work, nothing at session start | The credential is in an MCP config file, which the hooks never read | export KEMORY_API_KEY="..." in your shell, then restart fully |
| Two copies of every tool | Two servers for the same Kemory | Disable the bundled entry under /mcp, or remove the config-file entry |
401 on every call | The stored login expired or was revoked, or the key was reissued | /kemory:login, or mint a new key |
| Installed, signed in, still quiet | Claude Code was not restarted, or this is the session the credential arrived in | Quit completely and reopen — injection starts with the next session |
| Recall returns nothing useful | The relevance floor is above what your vault matches | Lower KEMORY_PROMPT_RECALL_MIN_RELEVANCE, or raise KEMORY_PROMPT_RECALL_LIMIT |
Unknown tool on an s9nmem_* name | A standing instruction or rules file written before the August 2026 rename | Change those names to kemory_*; reconnecting will not fix it |
A hook that quietly does nothing is not evidence of a healthy setup. If /kemory:status is green on every line and sessions still start blind, check /mcp to see which server Claude Code is actually talking to.
Source and contributing
Apache-2.0, and the whole client lives in one tree:
plugin/
├── .claude-plugin/plugin.json
├── .grok-plugin/plugin.json
├── .mcp.json bundled MCP entry → scripts/mcp.sh
├── hooks/hooks.json
├── commands/ /kemory:login, /kemory:status
├── skills/ kemory, kemory-setup
└── scripts/ one script per hook, plus lib and redact
Three ground rules govern a change: a hook must never block or fail a session and exits 0 on every error path; the plugin must no-op safely with no credential and no server; and anything that sends data anywhere must be opt-in and documented. One deliberate exception to the second — the MCP launcher exits non-zero with a reason when it finds no credential, because a silent no-op there produces a server that looks connected and serves nothing.
./scripts/check.sh
Validates every manifest, shell syntax, executable bits, plugin source paths, hook script references, that the two host manifests have not drifted, and that capture stays off by default. CI runs the same script plus shellcheck.
| Repository | SeKondBrainAILabs/kemory-plugin |
| Changelog | CHANGELOG.md |
| Server, MCP tools and CLI | SeKondBrainAILabs/kemory-community |
This repository holds client-side integrations only. Server behaviour, MCP tool definitions and the CLI live in the community repository — and the Community Edition guide covers running the whole stack yourself.
Support
| Dashboard | kemory.sekondbrain.ai |
| Support | support@sekondbrain.ai |
| Privacy and data questions | privacy@sekondbrain.ai |
| Vulnerabilities | security@sekondbrain.ai — reported privately, acknowledged within 3 business days |
The output of /kemory:status is the most useful thing to include in a support request: it says which step broke without exposing your memories or your credentials.