Connect OpenClaw
This page is for your own OpenClaw install β the one you installed from npm, not the Companion OpenClaw app from the Hub app store.
Nothing here requires a Companion build. The packaged app installs stock OpenClaw from npm; the only difference is that it arrives pre-wired.
Before you start
You need two API keys and the addresses of both servers.
<hub-url> and <memory-url> below are your two serversβ base URLs β everything before /api/mcp.
Neither has a port you can assume, so take both from the Hub dashboard if you are unsure:
Hub,
Memory.
OpenClaw can do this itself. Everything on this page β the MCP servers and
first-class memory β is also published as an agent-readable skill. Ask it to
set itself up from https://docs.ci.computer/connect/SKILL.md, or install
the skillΒ so it is there next
time. You still supply the two keys. See Or let your agent do
it.
Add the servers
Add Companion Hub
Prefer the CLI. openclaw mcp add probes the server before saving, so a wrong URL or key fails
immediately instead of at first use:
openclaw mcp add ci-hub --url "<hub-url>/api/mcp" --transport streamable-http --header "Authorization=Bearer <hub-key>"Add Companion Memory
openclaw mcp add ci-memory --url "<memory-url>/api/mcp" --transport streamable-http --header "Authorization=Bearer <memory-key>"One line each, deliberately: a trailing \ continues a command in bash, but in
PowerShell and cmd it is just another argument β pasted there, the first line
runs without its --url and every later line fails as an unknown command.
Confirm both registered
openclaw mcp probeThis reports each server with the number of tools it advertises. Read the counts, not just the
names β a server listed with 0 tools is connected and useless, and that is the failure this step
exists to catch.
The same underlying problem can also surface as a line beginning ! rather than a tool count, when
the server answers tools/list with -32601 Method not found instead of an empty list. Treat either
shape as the same finding.
Editing the config by hand
openclaw mcp add writes ~/.openclaw/openclaw.json. You can edit it directly instead:
{
"mcp": {
"servers": {
"ci-hub": {
"url": "<hub-url>/api/mcp",
"transport": "streamable-http",
"headers": { "Authorization": "Bearer ${HUB_MCP_API_KEY}" }
},
"ci-memory": {
"url": "<memory-url>/api/mcp",
"transport": "streamable-http",
"headers": { "Authorization": "Bearer ${CI_MEMORY_API_KEY}" }
}
}
}
}Prefer the ${ENV_VAR} form over pasting keys directly, so the credential
never lands in a config file that might be backed up or committed. The name
must be upper-case (A-Z, 0-9, _, not starting with a digit).
Export it everywhere OpenClaw runs, not just in your shell. Substitution
happens when the config is loaded, so a variable set in your terminal but not
in the service environment is unset at load time. OpenClaw does not fail
loudly: it logs missing env var "β¦" - feature using this value will be unavailable, leaves the literal ${VAR} in place, and starts normally. The
server then sends Authorization: Bearer ${CI_MEMORY_API_KEY} verbatim and
gets a 401 β so this arrives looking like a bad key rather than a missing
one. Check the startup log before you go replacing credentials.
Setting the variable where the gateway can see it
The ${VAR} syntax itself is platform-neutral β OpenClaw substitutes it when the config loads. What
differs is how you put the variable somewhere the gateway process inherits it.
macOS / Linux / WSL2
# This shell only:
export CI_MEMORY_API_KEY='<memory-key>'
# Persist it: add that line to ~/.zshrc, ~/.bashrc, or the systemd unit's
# Environment= / EnvironmentFile= if the gateway runs as a service.The transport field must be streamable-http. OpenClaw is the client that names this field
transport; Hermes omits it and Claude Code calls it type. Copying a working entry between clients
without translating that field is a common failure.
After a hand edit, a running OpenClaw has to be told to pick it up:
openclaw mcp reloadreload only affects the process it runs in. It disposes the cached MCP
runtimes held by that CLI invocation β which is the right command when
OpenClaw is embedded in the same process, and a no-op when it is not. If you
run OpenClaw as a service or a separate gateway, that process keeps its
old config and you must restart it β openclaw daemon restart. The command
reports success either way, because a fresh CLI process genuinely has nothing
cached to dispose.
This is easy to miss, because openclaw mcp probe is also a separate process that reads the file and
dials the server itself β it will report success while the running agent is still on the old config.
Verify
Ask your agent to list what it can do, or check directly:
openclaw mcp probeExpect both servers listed with a non-zero tool count. If ci-memory shows zero, the key is missing
the Intents scope β see the scope trap.
Read the ! lines too. A server that errors during the probe β including one answering
-32601 Method not found, the other symptom of a missing Intents scope β is reported as a
diagnostic rather than listed with a count, so scanning only for 0 tools misses it.
Removing a server
Revoking a key does not remove the entry that used it, and a stale entry fails on every start:
openclaw mcp unset ci-memoryDo this whenever you rotate or revoke a key, or the client keeps trying the old credential.
OPENCLAW_DATA_DIR does not isolate openclaw mcp add β OpenClaw does
not read that variable at all, so the command writes to the real
~/.openclaw/openclaw.json. To isolate a scripted test, use one of the
mechanisms OpenClaw does support: the --profile <name> flag, or the
OPENCLAW_CONFIG_PATH / OPENCLAW_STATE_DIR environment variables.
First-class memory
Everything above gives your agent memory it can call. What it does not give you is memory that
accumulates on its own β passive turn capture and bootstrap context injected at the start of a
session. That comes from a memory-slot provider, OpenClawβs plugins.slots.memory, which is a
different mechanism from MCP entirely.
The provider is published as @companionintelligence/openclaw-memory. You do not need MCP
configured to use it β the two are independent, and you can do this instead of the sections above
if passive memory is all you want.
There are two ways to install it. They produce the same configuration.
The official way
Install the plugin
openclaw plugins install npm:@companionintelligence/openclaw-memory@2026.8.3If this fails, check your Node version before anything else. OpenClaw
refuses to run at all on a Node outside its supported range and says so β
Node.js >=22.22.3 <23, >=24.15.0 <25, or >=25.9.0 is required β which reads
like a plugin problem when it appears here. It is not; upgrade Node, or if you
use a version manager check that the version on your PATH is the one you
think it is. Verified working on native Windows against the pinned OpenClaw
release once Node is in range.
Fill in what the installer does not
This is the step people miss. plugins install registers the plugin and stops there β it does
not select it as your memory provider, and none of the rest of this block is written for you. Edit
~/.openclaw/openclaw.json:
Install before you edit, not after. slots.memory naming a plugin that is
not installed yet makes the whole config invalid β plugin not found: companionintelligence β and OpenClaw then refuses to run plugins install,
so you cannot fix it by carrying on. If you have already done it in that
order, remove the plugins block, install, then put it back.
{
"plugins": {
"slots": { "memory": "companionintelligence" },
"entries": {
"companionintelligence": {
"enabled": true,
"hooks": { "allowConversationAccess": true },
"config": {
"url": "<memory-url>",
"token": "<memory-key>"
}
}
}
},
"tools": { "alsoAllow": ["memory_store"] },
"hooks": {
"internal": { "entries": { "session-memory": { "enabled": false } } }
}
}Every line earns its place:
| Key | Why |
|---|---|
slots.memory | Selects the provider. Without it the plugin is installed and inert |
hooks.allowConversationAccess | OpenClaw only delivers conversation hooks to a plugin that opts in. Without it you get the tools and nothing accumulates β the entire point of this section |
tools.alsoAllow | If a tools profile or allowlist narrows your tool set, the built-in group:memory group covers search and get only, so memory_store has to be named. On an unrestricted config it is harmless |
session-memory disabled | OpenClawβs bundled hook keeps a parallel local memory β session summaries written to workspace files on /new and /reset β that this provider does not manage and expects not to compete with |
Add to tools.alsoAllow, and never introduce tools.allow. alsoAllow
extends the default set; allow replaces it with an exclusive allowlist,
so creating it denies every tool not named in it and breaks unrelated things
on your machine.
The key for token needs different scopes than an MCP key. This provider
talks REST, not MCP, so the key must carry the Memory scope (plus
Intents for the intent tools) at capability Read & write β the
dialogβs default. A key minted for the MCP sections above (MCP + Intents)
is refused on every capture call, and the plugin never breaks your session
over a failed write, so the result is memory that silently never accumulates
while every check on this page passes. One key with Memory, Intents and
MCP covers both setups. See Get Your API Keys.
url is the Companion Memory base URL β the same <memory-url> used above,
without /api/mcp. It is written once and never re-resolved, so this agent
is configured for exactly one network position. A laptop that reaches your Hub
over a VPN at home and not at all from a cafΓ© needs the address that works from
wherever it actually runs. See Find your address
first for the routes
and how to read each one off the dashboard.
Restart and verify
Configuration is read at startup, so the gateway has to come back before any of this takes effect:
openclaw daemon restartThat is the command when the gateway runs as an installed service β launchd on macOS, systemd on
Linux, a Scheduled Task named OpenClaw Gateway on native Windows. openclaw daemon status tells
you whether yours is one, naming the service manager and the unit or task it found. If you instead
start the gateway yourself in a terminal, stop that process and start it again β daemon restart
manages the service and will not touch a gateway you are running by hand.
Then:
openclaw plugins inspect companionintelligence --runtime --jsonLook inside the plugin object for "status": "loaded" and
"activationReason": "selected memory slot". toolNames should include memory_store.
Know what each check proves. plugins inspect is a separate process that
reads the config from disk and loads the plugin itself β the same trap this
page describes for openclaw mcp probe β so it reports loaded whether or
not the running gateway has restarted, and it never dials the server, so a
typo in url or an unreachable address still loads cleanly. The check that
exercises the running gateway and the connection is /ci-memory in a live
session.
The proof that passive capture is actually on: have a short conversation, then look for the turn in the Companion Memory dashboard β or start a fresh session and ask about something from the last one. Nothing in that flow calls a memory tool by hand, which is the point.
The cihub connect way
If you are working on the Hub host itself, one command does the install and the configuration:
cihub connect openclaw --memory-url "<memory-url>" --memory-key "<memory-key>"It probes the server before touching anything, installs the pinned plugin version, writes every key
in the table above, and backs up your config first. Add --dry-run to see exactly what it would do
and write nothing. You still restart the gateway afterwards β openclaw daemon restart β as the
commandβs output reminds you.
The pre-flight probe checks the key as well as the address β it calls an endpoint that requires the
Memory scope, so a key that would fail silently at capture time is refused up front, with nothing
written.
It configures the machine it runs on. If your agent lives on your laptop and the Hub is an appliance across the room, use the official way on the laptop β that split is the design, not a gap.
Optionally add --hub-url and --hub-key and it will register the Hub MCP server too, replacing
the openclaw mcp add ci-hub step near the top of this page.
When memory does not accumulate
The command refused with βthe memory slot is held by β¦β. Another provider is selected, and the
configuration this page writes would take the slot from it. That selection was a deliberate choice
you or a previous setup made, so cihub connect refuses to overwrite it without --force. (Plain
openclaw plugins install does not touch the slot either way β which is why step 2 exists.)
Setup succeeded, tools appear, nothing is captured. Two usual causes, both silent. First, the
key: wrong, or missing the Memory scope, or minted Read-only β the plugin swallows failed
writes rather than break your session, and no check on this page can catch a bad key, so re-check
the key before anything else. Second, hooks.allowConversationAccess: it must be true on the
pluginβs own entry β not at the top level.
Session summaries still pile up in workspace memory/*.md files. The bundled session-memory
hook is still enabled, keeping its parallel local memory alongside this provider.
Changes did nothing. A running gateway keeps its old config. openclaw mcp reload does not help
here β it disposes MCP runtimes in the process that runs it, and this is not MCP. Restart the
gateway with openclaw daemon restart, or by stopping and starting it yourself if you do not run it
as a service.