Teach Claude a rule today.
Watch a session next week apply it — and show you
the message it came from.
Nine steps, about 10 minutes, and a few cents of model usage. The service runs in Docker; the only thing you install is the plugin.
docker compose version claude --version python3 -V step 1 No fake providers. The stack has an LLM_FAKE=1 mode for CI. It can
prove transport and exact message capture, but it cannot build the memory this test
checks. Leave it off and use a real key.
Steps 1–5 — stand up memory and prove it works
All of this happens before Claude Code is involved. That order is deliberate: when something is wrong here, no plugin, hook, or prompt can fix it.
- step 01 Get a model API key and put it in
.envThe shipped design calls OpenAI: a chat model for the memory passes and
text-embedding-3-smallfor every stored record. Create a key at platform.openai.com/api-keys. Add it asOPENAI_API_KEYto.envin the repository root. Compose reads that file automatically, and Git ignores it.your terminal$ git clone https://github.com/memseekai/memseek && cd memseek
Another provider? Point
examples/agent_memory_catalog/conf/models.yamlat any OpenAI-compatible endpoint that also offers embeddings, name its key variable inapi_key_env, and put that variable in.env. - step 02 Start the stack with one command
--waitreturns only once the API is healthy and the one-shot steps have exited0. First build: a few minutes. After that: seconds.your terminal$ docker compose up -d --build --wait $ docker compose logs setup --no-log-prefix workspace 'local' created; key written to /state/api_key published agent_memory@0.3.0 (20 files) from examples/agent_memory_catalog MCP interface ready — 7 tools: context, recall, standing_rules, replay_session, remember, record, answer
migrateandsetupare supposed to show as exited indocker compose ps -a: they apply the schema and publish the memory design, then have nothing left to do. Ifsetupstill shows as running, it is mid-publish — give it a few seconds. - step 03 Read the workspace key
The setup step writes it to a bind-mounted file instead of printing it into interleaved logs. This is the key the plugin will ask for.
your terminal$ cat .memseek/api_key
- step 04 Check the service answers
Liveness including the database, then the exact tool contract the plugin's MCP connection depends on — checked from inside the container, so Docker stays the only requirement.
your terminal$ curl -s http://127.0.0.1:8000/health {"ok":true,"db":true} $ docker compose exec \ -e MEMSEEK_URL=http://127.0.0.1:8000 \ -e MEMSEEK_API_KEY="$(cat .memseek/api_key)" \ api memseek mcp --check # expect: package agent_memory 0.3.0, seven tools, and # "streamable_http": "http://127.0.0.1:8000/mcp"
- step 05 Prove your model credentials work — before Claude is involved
This is the check that separates “my API key is wrong” from “the plugin is broken”, and it takes 30 seconds. Write one message over HTTP, then watch the worker do the real model work.
your terminal$ curl -sS -X POST http://127.0.0.1:8000/records \ -H "Authorization: Bearer $(cat .memseek/api_key)" \ -H 'Content-Type: application/json' \ -d '{"records":[{"collection":"messages","type":"message", "entity":"project:preflight", "text":"Every distributed-cache key must start with orbit:.", "content":{"text":"Every distributed-cache key must start with orbit:.", "role":"user","session_id":"preflight","ordinal":0}, "dedupe_key":"preflight:0"}]}' {"inserted":[{"index":0,"id":"4882d928-…","ready":false}],"duplicates":[]} $ docker compose logs -f worker # within ~30s, one line per stage: "processor":"embedding_v1","provider":"openai","status":"ok" "derivation":"l1_extract","status":"ok","output_count":1 "derivation":"scene_synthesis","status":"ok","output_count":1
That is the ladder forming from a single message: evidence embedded, a reusable memory extracted, a topic summary written.
ready:falsein the first response is expected — the record is stored, its embedding is pending. A"status":"error"line naming authentication or a model is your key or your model name, and it is much cheaper to see it here.your terminal# is the derived memory retrievable? $ curl -sS -X POST http://127.0.0.1:8000/views/memory_recall/query \ -H "Authorization: Bearer $(cat .memseek/api_key)" \ -H 'Content-Type: application/json' \ -d '{"entity":"project:preflight","task":"distributed cache key prefix"}' # then delete the throwaway entity so it cannot pollute the real test $ curl -sS -X POST http://127.0.0.1:8000/erase \ -H "Authorization: Bearer $(cat .memseek/api_key)" \ -H 'Content-Type: application/json' \ -d '{"entity":"project:preflight"}'
Steps 6–7 — install it, then try to catch it forgetting
Step 7 is the actual product test. Everything before it exists so that a failure there means something.
- step 06 Install the plugin from the checkout
The plugin is not on a marketplace yet — and it does not need to be. The repository you cloned is one: it carries
.claude-plugin/marketplace.json.--configsupplies the three values the interactive flow would ask for, so there is nothing to type into a prompt.in the repo you want Claude to remember$ claude plugin marketplace add ./ $ claude plugin install memseek-memory@memseek --scope local \ --config MEMSEEK_URL=http://127.0.0.1:8000 \ --config MEMSEEK_API_KEY="$(cat .memseek/api_key)" \ --config MEMSEEK_CAPTURE_MODE=conversation ✔ Successfully added marketplace: memseek (declared in user settings) ✔ Successfully installed plugin: memseek-memory@memseek (scope: local) $ claude plugin details memseek-memory Skills (5) memseek-explain, memseek-feedback, memseek-remember, memseek-search, memseek-status Hooks (5) SessionStart, UserPromptSubmit, Stop, PreCompact, SessionEnd MCP servers (1) memseek
Start a session in that repository. The plugin loads on startup:
your terminal$ claude Memseek connected for project:memseek:2f77b8026b767ade.
Value What it is MEMSEEK_URL http://127.0.0.1:8000— the base URL, no/mcp, no trailing slashMEMSEEK_API_KEY the workspace key from step 3; stored as a sensitive value, not written into settings.jsonMEMSEEK_CAPTURE_MODE conversation,explicit, oroff— all three keep recall on./, not.— a bare dot is rejected.--scope localkeeps the plugin to this project;--scope userputs it in every project. Installing copies the plugin at its declared version, so if you are editing its hooks or skills, runclaude --plugin-dir ./integrations/claude-codeinstead and it loads your working tree.Then confirm the host side:
claude code> /memseek-memory:memseek-status Memseek is ready. Service: http://127.0.0.1:8000 Project memory: project:memseek:2f77b8026b767ade Conversation capture: conversation Memory tools: 7/7 available Retry queue: 0 pending, 0 need inspection
Note the project memory name. It is derived from the repository, and it is what makes a later session find the same memory instead of a blank one.
- step 07 Teach one rule, restart, and ask cold
- 01 · say it
For this test project, every distributed-cache key must start with orbit:. Treat this as a priority-90 coding rule until I revoke it.
- 02 · watch it become memory
$ docker compose logs -f worker # "derivation":"l1_extract","status":"ok" — from your actual # conversation, with no memory tool called
- 03 · confirm it is retrievable Repeat every few seconds until the
> /memseek-memory:memseek-search distributed-cache key prefixorbit:rule comes back. Derivation is asynchronous. If it never appears, the worker or the model key is at fault — not the plugin. - 04 · quit claude code, reopen it in the same repo, and forbid tools An answer of
Do not call a memory tool. Based only on context supplied before this request, what prefix must distributed-cache keys use here? Cite the memory evidence.
orbit:with a citation proves the whole chain at once: captured, derived, project identity stable across a restart, relevant memory selected, brief delivered before Claude answered. - 05 · ask why it believes that Claude should separate the derived rule from the literal message you typed, with record ids. Memory you cannot audit is not the feature.
> /memseek-memory:memseek-explain
Step 3 passes but step 4 fails → memory is healthy, the automatic brief is the suspect. Step 3 fails → look at the worker first.
- 01 · say it
Go deeper, then delete everything
- Exact capture, in order
GET /timeline?entity=<project memory>returns your message and Claude's reply as separate rows. - Fail-open under outage
docker compose stop api, send a prompt: Claude keeps working and the write waits in a local queue. Start it again and flush. - Retention policySwitch capture to
explicitoroffand confirm ordinary chat stops producing records while recall keeps working. - Feedback lands on a real render
/memseek-memory:memseek-feedback task_success …reports an artifact-use id and zero queued writes.
# stop, keep the memory and the key $ docker compose down # delete everything this test created $ docker compose down -v && rm -rf .memseek
A fresh volume means a fresh key. down -v destroys the workspace,
so the next up mints a new key and the plugin's stored one stops
working. Update it in /plugin → memseek-memory@memseek and
start a new session.
# and the plugin itself $ claude plugin uninstall memseek-memory@memseek --scope local $ claude plugin marketplace remove memseek
When it does not work
| Symptom | What to do |
|---|---|
Marketplace file not found at …/marketplaces/memseekai-memseek/… | The plugin is not published to GitHub yet, so there is nothing to clone. Install from your checkout: claude plugin marketplace add ./. |
Plugin "memseek-memory" not found in marketplace "memseek" | The marketplace entry points at a copy with no plugin — usually a failed remote add. claude plugin marketplace remove memseek, then add ./ from the repository root. |
Invalid marketplace source format | A bare . is not accepted. Use ./ or an absolute path. |
| Plugin source edits have no effect | Install copies the plugin at its declared version. Use claude --plugin-dir ./integrations/claude-code while you are editing it. |
| Port 8000 already in use | Add MEMSEEK_PORT=8100 to .env, bring the stack up again, and give the plugin http://127.0.0.1:8100. |
Records stay ready: false | The embedding call is failing. docker compose logs worker — usually a missing or unfunded key in .env. |
Worker logs "status":"error" with a model name | Your account cannot call that model. Change the alias targets in examples/agent_memory_catalog/conf/models.yaml, then docker compose run --rm setup && docker compose restart api worker. |
/mcp does not list memseek | The URL must be the base — http://127.0.0.1:8000, with no /mcp and no trailing slash. |
| Search finds the rule, a new session does not | Storage and retrieval are fine; the automatic brief is the suspect. Compare the project memory name memseek-status reports in both sessions. |
.memseek/api_key is missing | A workspace key is disclosed once. docker compose down -v and start over. |
The repo carries the same procedure with every expected output in full, plus the capture-mode matrix and the complete troubleshooting table: docs/claude-code-plugin.md.
What you just tested is not a chat log.
The plugin stores your exact messages as evidence, derives small reusable rules and decisions from them, keeps a summary per area of work, and hands Claude a bounded brief for the task in front of it — with links back to what you actually said. It is one memory design declared in YAML, running on a Postgres you own.