Skip to main content

Overview

The OpenClaw plugin gives persistent memory to agents running on the OpenClaw 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. System prompt context injection — Injects the observation timeline into each agent’s system prompt via the before_prompt_build hook, keeping MEMORY.md free for agent-curated memory
  3. Observation feed — Streams new observations to messaging channels (Telegram, Discord, Slack, and more) 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.

Installation

Run this one-liner to install everything automatically:
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:
# 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:
{
  "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.

How It Works

OpenClaw Gateway

  ├── before_agent_start ───→ Init session
  ├── before_prompt_build ──→ Inject context into system prompt
  ├── tool_result_persist ──→ Record observation
  ├── agent_end ────────────→ Summarize + Complete session
  └── gateway_start ────────→ Reset session tracking + context cache


         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 ──→ System prompt context
           └── GET  /stream ─────────────→ SSE → Messaging channels

Event Lifecycle

1

Agent starts (before_agent_start)

When an OpenClaw agent starts, the plugin initializes a session by sending the user prompt to POST /api/sessions/init so the worker can create a new session and start processing.
2

Context injected (before_prompt_build)

Before each LLM call, the plugin fetches the observation timeline from the worker’s /api/context/inject endpoint and returns it as appendSystemContext. This injects cross-session context directly into the agent’s system prompt without writing any files.The context is cached for 60 seconds to avoid re-fetching on every LLM turn within a session.
3

Tool use recorded (tool_result_persist)

Every time the agent uses a tool (Read, Write, Bash, etc.), the plugin sends the observation to POST /api/sessions/observations with the tool name, input, and truncated response (max 1,000 chars). This is fire-and-forget — it does not block the agent from continuing work.Tools prefixed with memory_ are skipped to avoid recursive recording.
4

Agent finishes (agent_end)

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.
5

Gateway restarts (gateway_start)

Clears all session tracking (session IDs, context cache) so agents get fresh state after a gateway restart.

System Prompt Context Injection

The plugin injects cross-session observation context into each agent’s system prompt via OpenClaw’s before_prompt_build hook. The content comes from the worker’s GET /api/context/inject?projects=<project> endpoint, which generates a formatted markdown timeline from the SQLite database. This approach keeps MEMORY.md under the agent’s control for curated long-term memory (decisions, preferences, durable facts), while the observation timeline is delivered through the system prompt where it belongs.
Context is cached for 60 seconds per project to avoid re-fetching on every LLM turn. The cache is cleared on gateway restart. Use syncMemoryFileExclude to opt specific agents out of context injection entirely.

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: telegramTarget ID: Your Telegram chat ID (numeric). To find it:
  1. Message @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)
"observationFeed": {
  "enabled": true,
  "channel": "telegram",
  "to": "123456789"
}
You can also supply a dedicated botToken to send directly via the Telegram Bot API, bypassing the OpenClaw channel runtime:
"observationFeed": {
  "enabled": true,
  "channel": "telegram",
  "to": "123456789",
  "botToken": "YOUR_BOT_TOKEN"
}
Channel type: discordTarget 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
"observationFeed": {
  "enabled": true,
  "channel": "discord",
  "to": "1234567890123456789"
}
Channel type: slackTarget 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
"observationFeed": {
  "enabled": true,
  "channel": "slack",
  "to": "C01ABC2DEFG"
}
Channel type: signalTarget ID: The Signal phone number or group ID configured in your OpenClaw gateway.
"observationFeed": {
  "enabled": true,
  "channel": "signal",
  "to": "+1234567890"
}
Channel type: whatsappTarget ID: The WhatsApp phone number or group JID configured in your OpenClaw gateway.
"observationFeed": {
  "enabled": true,
  "channel": "whatsapp",
  "to": "+1234567890"
}
Channel type: lineTarget ID: The LINE user ID or group ID from the LINE Developer Console.
"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:
{
  "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 is not registered, you will see Unknown channel type: <channel> 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 will 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 is a 1–2 second delay between tool use and the observation message appearing in your channel.

Troubleshooting the Feed

SymptomCauseFix
Connection: disconnectedWorker not running or wrong portCheck workerPort config, run npm run worker:status
Connection: reconnectingWorker was running but connection droppedThe plugin auto-reconnects with backoff — wait up to 30s
Unknown channel type in logsChannel plugin not loaded on gatewayVerify your OpenClaw gateway has the channel plugin configured
No messages appearingFeed connected but no observations being createdCheck that agents are running and the worker is processing observations
Observation feed disabled in logsenabled is false or missingSet observationFeed.enabled to true
Observation feed misconfigured in logsMissing channel or toBoth channel and to are required

Configuration

project
string
default:"openclaw"
Project name for scoping observations in the memory database. All observations from this gateway will be stored under this project name. OpenClaw agent projects are automatically scoped as openclaw-<agentId> when the context has an agentId.
syncMemoryFile
boolean
default:true
Inject observation context into the agent system prompt via the before_prompt_build hook. When true, agents receive cross-session context automatically. Set to false to disable context injection entirely (observations are still recorded).
syncMemoryFileExclude
string[]
default:[]
Agent IDs excluded from automatic context injection. Useful for agents that curate their own memory and do not need the observation timeline (e.g., ["snarf", "debugger"]). Observations are still recorded for excluded agents — only the context injection is skipped.
workerPort
number
default:37777
Port for the claude-mem worker service. Override if your worker runs on a non-default port.
observationFeed.enabled
boolean
default:false
Enable live observation streaming to messaging channels.
observationFeed.channel
string
Channel type: telegram, discord, signal, slack, whatsapp, line, imessage
observationFeed.to
string
Target chat/user/channel ID to send observations to.
observationFeed.botToken
string
Optional Telegram bot token for direct Telegram API delivery, bypassing the OpenClaw channel runtime. Only applies when channel is telegram.
observationFeed.emojis
object
Customize the emoji labels that prefix observation messages. Optional sub-fields:
  • primary — Emoji for OpenClaw gateway sessions (default: 🦞)
  • claudeCode — Emoji for Claude Code sessions (default: ⌨️)
  • claudeCodeLabel — Label suffix for Claude Code sessions (default: Claude Code Session)
  • default — Fallback emoji for unknown project types (default: 🦀)
  • agents — Record mapping specific agent IDs to custom emojis (e.g., {"snarf": "🤖"})

Commands

/claude_mem_feed

Show or toggle the observation feed status. Run from any OpenClaw chat.
/claude_mem_feed        # Show current status
/claude_mem_feed on     # Request enable (update config to persist)
/claude_mem_feed off    # Request disable (update config to persist)
Example response:
Claude-Mem Observation Feed
Enabled: yes
Channel: telegram
Target: 123456789
Connection: connected

/claude_mem_status

Check worker health and session status.
/claude_mem_status
Returns worker status, port, active session count, and observation feed connection state. Example response:
Claude-Mem Worker Status
Status: ok
Port: 37777
Active sessions: 2
Observation feed: connected
Search the claude-mem observation database from chat.
/claude-mem-search <query> [limit]
/claude-mem-search authentication 5

/claude-mem-recent

Show recent context snapshot for a project.
/claude-mem-recent [project] [limit]
/claude-mem-recent my-project 3

/claude-mem-timeline

Find the best matching memory and show nearby timeline events.
/claude-mem-timeline <query> [depthBefore] [depthAfter]
/claude-mem-timeline "retry logic" 5 5

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 in the format openclaw-<sessionKey>-<timestamp>. The plugin maintains a sessionIds map from OpenClaw session keys to content session IDs.

Context Cache

A TTL cache (60 seconds) keyed by project name stores the last fetched context injection response. This prevents re-fetching on every LLM turn within a session. Both the session map and context cache are cleared on gateway_start.

Fire-and-Forget HTTP

Tool observations (tool_result_persist) and session completions are sent without awaiting a response, so they never delay the agent. Session init and summarize await their responses to ensure ordering.

SSE Reconnection

The observation feed service uses a persistent loop with exponential backoff — starting at 1 second and capping at 30 seconds — to automatically reconnect if the worker restarts or the stream drops.

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)

Build docs developers (and LLMs) love