Blog / How-to guides

Persistent memory for OpenClaw, on your own machine

25 October 2026 · Semurg · 5 min read · Markdown

openclawmcpagentsmemoryhow-to

Tested with OpenClaw 2026.10.7: OpenClaw's own MCP client connected to the node and listed every memory tool it serves. The agents page shows the release it last ran on.

OpenClaw starts each session without what it learned in the last one. This guide adds a memory it asks instead of forgets: a Semurg node on your own machine, which OpenClaw reaches over MCP after one registry command. Facts stay on your disk, come back cited to where they were said, and are shared with every other agent on the node that uses the same scope.

OpenClaw keeps one MCP server entry that holds a reference to your token; it reaches your node, which keeps the memory in the scope you named on your own disk; a later session or another agent on the same scope reads it back, cited.OpenClawOne MCP server entryYour scope, on yournodeA later session, oranother agenttoken from its environmentmemory toolsthe same facts, cited

What you need

  • An Intel or AMD x86_64 machine with Ubuntu 24.04, on Linux directly or on Windows through WSL2. One node is free, with no licence key.
  • OpenClaw on the same machine. Its installer needs curl, git, ca-certificates, tar and xz-utils; we test both in a fresh ubuntu:24.04 container.

Step one: install a node

On Ubuntu 24.04 (x86_64), with sudo:

bash
curl -fsSL https://one.semurg.io/install | sudo bash

The install page lists what the installer needs and what it changes. The installer ends by printing your API token, and the node keeps a copy. Put it in a file only you can read, and have every new terminal load it:

bash
mkdir -p ~/.config/semurg
(umask 077; sudo grep '^SEMURG_API_TOKEN=' /etc/semurg/semurg.env | cut -d= -f2- > ~/.config/semurg/token)
echo 'export SEMURG_API_TOKEN="$(cat ~/.config/semurg/token)"' >> ~/.bashrc
export SEMURG_API_TOKEN="$(cat ~/.config/semurg/token)"

Step two: install OpenClaw

OpenClaw installs itself with its own installer, the line the agents page shows. The MCP commands below work without its onboarding and without a running gateway.

bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard

Step three: connect

Register the node and probe it, exactly as the agents page shows. The single quotes matter: they keep ${SEMURG_API_TOKEN} as a reference, so OpenClaw stores the reference, never the token, and fills it in from its environment each time it connects.

bash
openclaw mcp set semurg '{"url":"http://127.0.0.1:4000/v1/mcp","transport":"streamable-http","headers":{"Authorization":"Bearer ${SEMURG_API_TOKEN}","X-Semurg-Scope":"default"}}'
openclaw mcp doctor semurg --probe

Change default to a scope of your own per project: agents that use the same scope share what they learn.

Step four: check it, then use it

The probe in step three makes a live connection, which needs no model. To see the tools by name, ask for the probe's JSON:

bash
openclaw mcp probe semurg --json

It names each memory tool, semurg__memory_status, semurg__memory_remember and so on. OpenClaw then offers them to its model like its other tools, so you can ask in plain words: "remember that we chose Postgres for billing because of the audit log", and in a later session, "what did we decide about billing?". We have tested the connection, not a conversation with a model.

To see from outside OpenClaw which of your scopes now hold facts, ask the node directly:

bash
curl -sS http://127.0.0.1:4000/v1/memory/status \
  -H "Authorization: Bearer $SEMURG_API_TOKEN"

The memory tools in OpenClaw

OpenClaw names each tool after the server, semurg__ followed by the tool's own name:

  • memory_status: reports whether shared memory is on for this node and which of your scopes hold facts.
  • memory_remember: stores entities, the relationships between them and the passages they came from, or plain text, with an optional source label and date.
  • memory_recall: recalls what is stored about one named entity, its own facts first, each item cited.
  • memory_relate: adds one typed relationship between two entities in a scope, creating an end that is not stored yet.
  • memory_context: answers a question in plain words with cited items and a verdict on whether the store covers it.
  • memory_document: takes a whole document (PDF with a text layer, Word, HTML or plain text) and stores it as cited passages in a scope.
  • memory_forget: deletes one thing per call: an entity and everything that names it, one fact, one document, every document under a source label, or the whole scope. It is unreachable at once and not yet wiped from the disk.
  • memory_export: reads everything a scope holds, one page per call: send each reply's next back as cursor until it is empty. The records are the entities, the facts with their dated sources and whether each is current or ended, and each stored document once; a forgotten passage is never exported.
  • memory_import: stores the records memory_export produced into any scope, through the same writes memory_remember makes. A page sent twice stores nothing twice, and the reply names every record it skipped.

Every answer says its state: answered, nothing_stored (nothing stored matched, so the agent should say it does not know) or could_not_judge.

Troubleshooting

  • The connection is refused: SEMURG_API_TOKEN must be set in the environment of every OpenClaw process, the command line and any gateway or background service alike. A service started outside your shell does not read ~/.bashrc.
  • openclaw mcp doctor warns about a literal sensitive value: for the ${SEMURG_API_TOKEN} reference that warning is a false alarm, because the stored entry holds no token.
  • Read the probe's tool names, not its exit status: in our tests openclaw mcp probe exited with success even when the connection failed, and without --json it prints only a count.
  • openclaw: command not found: where the installer puts the command is not documented. Look in ~/.local/bin, /usr/local/bin, ~/.npm-global/bin and ~/.openclaw/bin, and add that folder to your path.

Use 127.0.0.1 rather than localhost: on Ubuntu localhost can resolve to the IPv6 address first, and the node listens on IPv4 loopback only.

Next

Related