--- title: OpenClaw Integration description: Persistent memory for OpenClaw agents — observation recording, MEMORY.md live sync, and real-time observation feeds icon: dragon --- ## Overview The OpenClaw plugin gives claude-mem persistent memory to agents running on the [OpenClaw](https://openclaw.ai) gateway. It handles three things: 1. **Observation recording** — Captures tool usage from OpenClaw's embedded runner and sends it to the claude-mem worker for AI processing 2. **MEMORY.md live sync** — Writes a continuously-updated timeline to each agent's workspace so agents always have context from previous sessions 3. **Observation feed** — Streams new observations to messaging channels (Telegram, Discord, Slack, etc.) in real-time via SSE OpenClaw's embedded runner (`pi-embedded`) calls the Anthropic API directly without spawning a `claude` process, so claude-mem's standard hooks never fire. This plugin bridges that gap by using OpenClaw's event system to capture the same data. ## How It Works ```plaintext OpenClaw Gateway │ ├── before_agent_start ──→ Sync MEMORY.md + Init session ├── tool_result_persist ──→ Record observation + Re-sync MEMORY.md ├── agent_end ────────────→ Summarize + Complete session └── gateway_start ────────→ Reset session tracking │ ▼ Claude-Mem Worker (localhost:37777) ├── POST /api/sessions/init ├── POST /api/sessions/observations ├── POST /api/sessions/summarize ├── POST /api/sessions/complete ├── GET /api/context/inject ──→ MEMORY.md content └── GET /stream ─────────────→ SSE → Messaging channels ``` ### Event Lifecycle When an OpenClaw agent starts, the plugin does two things: 1. **Syncs MEMORY.md** — Fetches the latest timeline from the worker's `/api/context/inject` endpoint and writes it to `MEMORY.md` in the agent's workspace directory. This gives the agent context from all previous sessions before it starts working. 2. **Initializes a session** — Sends the user prompt to `POST /api/sessions/init` so the worker can create a new session and start processing. Short prompts (under 10 characters) skip session init but still sync MEMORY.md. Every time the agent uses a tool (Read, Write, Bash, etc.), the plugin: 1. **Sends the observation** to `POST /api/sessions/observations` with the tool name, input, and truncated response (max 1000 chars) 2. **Re-syncs MEMORY.md** with the latest timeline from the worker Both operations are fire-and-forget — they don't block the agent from continuing work. The MEMORY.md file gets progressively richer as the session continues. Tools prefixed with `memory_` are skipped to avoid recursive recording. When the agent completes, the plugin extracts the last assistant message and sends it to `POST /api/sessions/summarize`, then calls `POST /api/sessions/complete` to close the session. Both are fire-and-forget. Clears all session tracking (session IDs, workspace directory mappings) so agents get fresh state after a gateway restart. ### MEMORY.md Live Sync The plugin writes a `MEMORY.md` file to each agent's workspace directory containing the full timeline of observations and summaries from previous sessions. This file is updated: - On every `before_agent_start` event (agent gets fresh context before starting) - On every `tool_result_persist` event (context stays current during the session) The content comes from the worker's `GET /api/context/inject?projects=` endpoint, which generates a formatted markdown timeline from the SQLite database. MEMORY.md updates are fire-and-forget. They run in the background without blocking the agent. The file reflects whatever the worker has processed so far — it doesn't wait for the current observation to be fully processed before writing. ### Observation Feed (SSE → Messaging) The plugin runs a background service that connects to the worker's SSE stream (`GET /stream`) and forwards `new_observation` events to a configured messaging channel. This lets you monitor what your agents are learning in real-time from Telegram, Discord, Slack, or any supported OpenClaw channel. The SSE connection uses exponential backoff (1s → 30s) for automatic reconnection. ## Setting Up the Observation Feed The observation feed sends a formatted message to your OpenClaw channel every time claude-mem creates a new observation. Each message includes the observation title and subtitle so you can follow along as your agents work. Messages look like this in your channel: ``` 🧠 Claude-Mem Observation **Implemented retry logic for API client** Added exponential backoff with configurable max retries to handle transient failures ``` ### Step 1: Choose your channel The observation feed works with any channel that your OpenClaw gateway has configured. You need two pieces of information: - **Channel type** — The name of the channel plugin registered with OpenClaw (e.g., `telegram`, `discord`, `slack`, `signal`, `whatsapp`, `line`) - **Target ID** — The chat ID, channel ID, or user ID where messages should be sent **Channel type:** `telegram` **Target ID:** Your Telegram chat ID (numeric). To find it: 1. Message [@userinfobot](https://t.me/userinfobot) on Telegram 2. It will reply with your chat ID (e.g., `123456789`) 3. For group chats, the ID is negative (e.g., `-1001234567890`) ```json "observationFeed": { "enabled": true, "channel": "telegram", "to": "123456789" } ``` **Channel type:** `discord` **Target ID:** The Discord channel ID. To find it: 1. Enable Developer Mode in Discord (Settings → Advanced → Developer Mode) 2. Right-click the channel → Copy Channel ID ```json "observationFeed": { "enabled": true, "channel": "discord", "to": "1234567890123456789" } ``` **Channel type:** `slack` **Target ID:** The Slack channel ID (not the channel name). To find it: 1. Open the channel in Slack 2. Click the channel name at the top 3. Scroll to the bottom of the channel details — the ID looks like `C01ABC2DEFG` ```json "observationFeed": { "enabled": true, "channel": "slack", "to": "C01ABC2DEFG" } ``` **Channel type:** `signal` **Target ID:** The Signal phone number or group ID configured in your OpenClaw gateway. ```json "observationFeed": { "enabled": true, "channel": "signal", "to": "+1234567890" } ``` **Channel type:** `whatsapp` **Target ID:** The WhatsApp phone number or group JID configured in your OpenClaw gateway. ```json "observationFeed": { "enabled": true, "channel": "whatsapp", "to": "+1234567890" } ``` **Channel type:** `line` **Target ID:** The LINE user ID or group ID from the LINE Developer Console. ```json "observationFeed": { "enabled": true, "channel": "line", "to": "U1234567890abcdef" } ``` ### Step 2: Add the config to your gateway Add the `observationFeed` block to your claude-mem plugin config in your OpenClaw gateway configuration: ```json { "plugins": { "claude-mem": { "enabled": true, "config": { "project": "my-project", "observationFeed": { "enabled": true, "channel": "telegram", "to": "123456789" } } } } } ``` The `channel` value must match a channel plugin that is already configured and running on your OpenClaw gateway. If the channel isn't registered, you'll see `Unknown channel type: ` in the logs. ### Step 3: Verify the connection After starting the gateway, check that the feed is connected: 1. **Check the logs** — You should see: ``` [claude-mem] Observation feed starting — channel: telegram, target: 123456789 [claude-mem] Connecting to SSE stream at http://localhost:37777/stream [claude-mem] Connected to SSE stream ``` 2. **Use the status command** — Run `/claude_mem_feed` in any OpenClaw chat to see: ``` Claude-Mem Observation Feed Enabled: yes Channel: telegram Target: 123456789 Connection: connected ``` 3. **Trigger a test** — Have an agent do some work. When the worker processes the tool usage into an observation, you'll receive a message in your configured channel. The feed only sends `new_observation` events — not raw tool usage. Observations are generated asynchronously by the worker's AI agent, so there's a 1-2 second delay between tool use and the observation message appearing in your channel. ### Troubleshooting the Feed | Symptom | Cause | Fix | |---------|-------|-----| | `Connection: disconnected` | Worker not running or wrong port | Check `workerPort` config, run `npm run worker:status` | | `Connection: reconnecting` | Worker was running but connection dropped | The plugin auto-reconnects with backoff — wait up to 30s | | `Unknown channel type` in logs | Channel plugin not loaded on gateway | Verify your OpenClaw gateway has the channel plugin configured | | No messages appearing | Feed connected but no observations being created | Check that agents are running and the worker is processing observations | | `Observation feed disabled` in logs | `enabled` is `false` or missing | Set `observationFeed.enabled` to `true` | | `Observation feed misconfigured` in logs | Missing `channel` or `to` | Both `channel` and `to` are required | ## Installation Run this one-liner to install everything automatically: ```bash curl -fsSL https://install.cmem.ai/openclaw.sh | bash ``` The installer handles dependency checks (Bun, uv), plugin installation, memory slot configuration, AI provider setup, worker startup, and optional observation feed configuration. You can also pre-select options: ```bash # With a specific AI provider curl -fsSL https://install.cmem.ai/openclaw.sh | bash -s -- --provider=gemini --api-key=YOUR_KEY # Fully unattended (defaults to Claude Max Plan) curl -fsSL https://install.cmem.ai/openclaw.sh | bash -s -- --non-interactive # Upgrade existing installation curl -fsSL https://install.cmem.ai/openclaw.sh | bash -s -- --upgrade ``` ### Manual Configuration Add `claude-mem` to your OpenClaw gateway's plugin configuration: ```json { "plugins": { "claude-mem": { "enabled": true, "config": { "project": "my-project", "syncMemoryFile": true, "workerPort": 37777, "observationFeed": { "enabled": true, "channel": "telegram", "to": "your-chat-id" } } } } } ``` The claude-mem worker service must be running on the same machine as the OpenClaw gateway. The plugin communicates with it via HTTP on `localhost:37777`. ## Configuration Project name for scoping observations in the memory database. All observations from this gateway will be stored under this project name. Enable automatic MEMORY.md sync to agent workspaces. Set to `false` if you don't want the plugin writing files to workspace directories. Port for the claude-mem worker service. Override if your worker runs on a non-default port. Enable live observation streaming to messaging channels. Channel type: `telegram`, `discord`, `signal`, `slack`, `whatsapp`, `line` Target chat/user/channel ID to send observations to. ## Commands ### /claude_mem_feed Show or toggle the observation feed status. ``` /claude_mem_feed # Show current status /claude_mem_feed on # Request enable /claude_mem_feed off # Request disable ``` ### /claude_mem_status Check worker health and session status. ``` /claude_mem_status ``` Returns worker status, port, active session count, and observation feed connection state. ## Architecture The plugin uses HTTP calls to the already-running claude-mem worker service rather than spawning subprocesses. This means: - No `bun` dependency required on the gateway - No process spawn overhead per event - Uses the same worker API that Claude Code hooks use - All operations are non-blocking (fire-and-forget where possible) ### Session Tracking Each OpenClaw agent session gets a unique `contentSessionId` (format: `openclaw--`) that maps to a claude-mem session in the worker. The plugin tracks: - `sessionIds` — Maps OpenClaw session keys to content session IDs - `workspaceDirsBySessionKey` — Maps session keys to workspace directories so `tool_result_persist` events can sync MEMORY.md even when the event context doesn't include `workspaceDir` Both maps are cleared on `gateway_start`. ## Requirements - Claude-mem worker service running on `localhost:37777` (or configured port) - OpenClaw gateway with plugin support - Network access between gateway and worker (localhost only)