---
sidebar_position: 4
---

# OpenClaw

Local, long term memory for [OpenClaw](https://openclaw.ai) agents using [Hindsight](https://vectorize.io/hindsight).

This plugin integrates [hindsight-embed](https://vectorize.io/hindsight/cli), a standalone daemon that bundles Hindsight's memory engine (API + PostgreSQL) into a single command. Everything runs locally on your machine, reuses the LLM you're already paying for, and costs nothing extra.

[View Changelog →](../../changelog/integrations/openclaw.md)

## Quick Start

**Step 1: Set up LLM for memory extraction**

Choose one provider and set its API key:

```bash
# Option A: OpenAI
export OPENAI_API_KEY="sk-your-key"

# Option B: Anthropic
export ANTHROPIC_API_KEY="your-key"

# Option C: Gemini
export GEMINI_API_KEY="your-key"

# Option D: Groq
export GROQ_API_KEY="your-key"

# Option E: Claude Code (no API key needed)
export HINDSIGHT_API_LLM_PROVIDER=claude-code

# Option F: OpenAI Codex (no API key needed)
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
```

**Step 2: Install the plugin**

```bash
openclaw plugins install @vectorize-io/hindsight-openclaw
```

**Step 3: Start OpenClaw**

```bash
openclaw gateway
```

The plugin will automatically:
- Start a local Hindsight daemon (port 9077)
- Capture conversations after each turn
- Inject relevant memories before agent responses

**Important:** The LLM you configure above is **only for memory extraction** (background processing). Your main OpenClaw agent can use any model you configure separately.

## How It Works

**Auto-Capture:** Every conversation is automatically stored after each turn. Facts, entities, and relationships are extracted in the background.

**Auto-Recall:** Before each agent response, relevant memories are automatically injected into the context (up to 1024 tokens). The agent uses past context without needing to call tools.

**Feedback Loop Prevention:** The plugin automatically strips injected memory tags (`<hindsight_memories>`) before storing conversations. This prevents recalled memories from being re-extracted as new facts, which would cause exponential memory growth and duplicate entries.

Traditional memory systems give agents a `search_memory` tool - but models don't use it consistently. Auto-recall solves this by injecting memories automatically before every turn.

## Configuration

### Plugin Settings

Optional settings in `~/.openclaw/openclaw.json`:

```json
{
  "plugins": {
    "entries": {
      "hindsight-openclaw": {
        "enabled": true,
        "config": {
          "apiPort": 9077,
          "daemonIdleTimeout": 0,
          "embedVersion": "latest"
        }
      }
    }
  }
}
```

**Options:**
- `apiPort` - Port for the openclaw profile daemon (default: `9077`)
- `daemonIdleTimeout` - Seconds before daemon shuts down from inactivity (default: `0` = never)
- `embedVersion` - hindsight-embed version (default: `"latest"`)
- `bankMission` - Agent identity/purpose stored on the memory bank. Helps the memory engine understand context for better fact extraction during retain. Set once per bank on first use — not a recall prompt.
- `dynamicBankId` - Enable per-context memory banks (default: `true`)
- `bankIdPrefix` - Optional prefix for bank IDs (e.g. `"prod"` → `"prod-slack-C123"`)
- `dynamicBankGranularity` - Fields used to derive bank ID: `agent`, `channel`, `user`, `provider` (default: `["agent", "channel", "user"]`)
- `excludeProviders` - Message providers to skip for recall/retain (e.g. `["slack"]`, `["telegram"]`, `["discord"]`)
- `autoRecall` - Auto-inject memories before each turn (default: `true`). Set to `false` when the agent has its own recall tool.
- `autoRetain` - Auto-retain conversations after each turn (default: `true`)
- `retainRoles` - Which message roles to retain (default: `["user", "assistant"]`). Options: `user`, `assistant`, `system`, `tool`
- `recallBudget` - Recall effort: `"low"`, `"mid"`, or `"high"` (default: `"mid"`). Higher budgets use more retrieval strategies for better results.
- `recallMaxTokens` - Max tokens for recall response (default: `1024`). Controls how much memory context is injected per turn.
- `recallTopK` - Max number of memories to inject per turn (default: unlimited).
- `recallTypes` - Memory types to recall (default: `["world", "experience"]`). Options: `world`, `experience`, `observation`.
- `recallContextTurns` - Number of prior user turns to include in the recall query (default: `1`).
- `recallMaxQueryChars` - Max characters for the composed recall query (default: `800`).
- `recallPromptPreamble` - Custom preamble text placed above recalled memories. Overrides the built-in guidance text.
- `recallInjectionPosition` - Where to inject recalled memories: `"prepend"` (default), `"append"`, or `"user"`. Use `"append"` to preserve prompt caching with large static system prompts. Use `"user"` to inject before the user message instead of in the system prompt.
- `recallRoles` - Which message roles to include when composing the contextual recall query (default: `["user", "assistant"]`).
- `retainEveryNTurns` - Retain every Nth turn (default: `1` = every turn). Values > 1 enable chunked retention.
- `retainOverlapTurns` - Extra prior turns included when chunked retention fires (default: `0`).
- `debug` - Enable debug logging (default: `false`).

### Memory Isolation

The plugin creates separate memory banks based on conversation context. By default, banks are derived from the `agent`, `channel`, and `user` fields — so each unique combination gets its own isolated memory store.

You can customize which fields are used for bank segmentation with `dynamicBankGranularity`:

```json
{
  "plugins": {
    "entries": {
      "hindsight-openclaw": {
        "enabled": true,
        "config": {
          "dynamicBankGranularity": ["provider", "user"]
        }
      }
    }
  }
}
```

In this example, memories are isolated per provider + user, meaning the same user shares memories across all channels within a provider.

Available isolation fields:
- `agent` - The agent/bot identity
- `channel` - The channel or conversation ID
- `user` - The user interacting with the agent
- `provider` - The message provider (e.g. Slack, Discord)

Use `bankIdPrefix` to namespace bank IDs across environments (e.g. `"prod"`, `"staging"`). Set `dynamicBankId` to `false` to use a single shared bank for all conversations.

### Retention Controls

By default, the plugin retains `user` and `assistant` messages after each turn. You can customize this behavior:

```json
{
  "plugins": {
    "entries": {
      "hindsight-openclaw": {
        "enabled": true,
        "config": {
          "autoRetain": true,
          "retainRoles": ["user", "assistant", "system"]
        }
      }
    }
  }
}
```

- `autoRetain` - Set to `false` to disable automatic retention entirely (useful if you handle retention yourself)
- `retainRoles` - Controls which message roles are included in the retained transcript. Only messages from the last user message onward are retained each turn, preventing duplicate storage.

### LLM Configuration

The plugin auto-detects your LLM provider from these environment variables:

| Provider | Env Var | Notes |
|----------|---------|-------|
| OpenAI | `OPENAI_API_KEY` | |
| Anthropic | `ANTHROPIC_API_KEY` | |
| Gemini | `GEMINI_API_KEY` | |
| Groq | `GROQ_API_KEY` | |
| Claude Code | `HINDSIGHT_API_LLM_PROVIDER=claude-code` | No API key needed |
| OpenAI Codex | `HINDSIGHT_API_LLM_PROVIDER=openai-codex` | No API key needed |

The model is selected automatically by the Hindsight API. To override, set `HINDSIGHT_API_LLM_MODEL`.

**Override with explicit config:**

```bash
export HINDSIGHT_API_LLM_PROVIDER=openai
export HINDSIGHT_API_LLM_API_KEY=sk-your-key

# Optional: custom base URL (OpenRouter, Azure, vLLM, etc.)
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
```

**Example: Free OpenRouter model**

```bash
export HINDSIGHT_API_LLM_PROVIDER=openai
export HINDSIGHT_API_LLM_MODEL=xiaomi/mimo-v2-flash  # FREE!
export HINDSIGHT_API_LLM_API_KEY=sk-or-v1-your-openrouter-key
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
```

### External API (Advanced)

Connect to a remote Hindsight API server instead of running a local daemon. This is useful for:

- **Shared memory** across multiple OpenClaw instances
- **Production deployments** with centralized memory storage
- **Team environments** where agents share knowledge

#### Plugin Configuration

Configure in `~/.openclaw/openclaw.json`:

```json
{
  "plugins": {
    "entries": {
      "hindsight-openclaw": {
        "enabled": true,
        "config": {
          "hindsightApiUrl": "https://your-hindsight-server.com",
          "hindsightApiToken": "your-api-token"
        }
      }
    }
  }
}
```

**Options:**
- `hindsightApiUrl` - Full URL to external Hindsight API (e.g., `https://mcp.hindsight.example.com`)
- `hindsightApiToken` - API token for authentication (optional, only if API requires auth)

#### Environment Variables (Alternative)

You can also configure via environment variables:

```bash
export HINDSIGHT_EMBED_API_URL=https://your-hindsight-server.com
export HINDSIGHT_EMBED_API_TOKEN=your-api-token  # Optional

openclaw gateway
```

**Note:** Plugin config takes precedence over environment variables.

#### Behavior

When external API mode is enabled:
- **No local daemon** is started (no hindsight-embed process)
- **Health check** runs on startup to verify API connectivity
- **All memory operations** (retain, recall, reflect) go to the external API
- **Faster startup** since no local PostgreSQL or embedding models are needed

#### Verification

Check OpenClaw logs for external API mode:

```bash
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight

# Should see on startup:
# [Hindsight] External API mode enabled: https://your-hindsight-server.com
# [Hindsight] External API health check passed
```

If you see daemon startup messages instead, verify your configuration is correct.

## Inspecting Memories

### Check Configuration

View the daemon config that was written by the plugin:

```bash
cat ~/.hindsight/profiles/openclaw.env
```

This shows the LLM provider, model, port, and other settings the daemon is using.

### Check Daemon Status

```bash
# Check if daemon is running
uvx hindsight-embed@latest -p openclaw daemon status

# View daemon logs
tail -f ~/.hindsight/profiles/openclaw.log
```

### Query Memories

```bash
# Search memories
uvx hindsight-embed@latest -p openclaw memory recall openclaw "user preferences"

# View recent memories
uvx hindsight-embed@latest -p openclaw memory list openclaw --limit 10

# Open web UI (uses openclaw profile's daemon)
uvx hindsight-embed@latest -p openclaw ui
```

## Troubleshooting

### Plugin not loading

```bash
openclaw plugins list | grep hindsight
# Should show: ✓ enabled │ Hindsight Memory │ ...

# Reinstall if needed
openclaw plugins install @vectorize-io/hindsight-openclaw
```

### Daemon not starting

```bash
# Check daemon status (note: -p openclaw uses the openclaw profile)
uvx hindsight-embed@latest -p openclaw daemon status

# View logs for errors
tail -f ~/.hindsight/profiles/openclaw.log

# Check configuration
cat ~/.hindsight/profiles/openclaw.env

# List all profiles
uvx hindsight-embed@latest profile list
```

### No API key error

Make sure you've set one of the provider API keys (or use a provider that doesn't require one):

```bash
# Option 1: OpenAI
export OPENAI_API_KEY="sk-your-key"

# Option 2: Anthropic
export ANTHROPIC_API_KEY="your-key"

# Option 3: Claude Code (no API key needed)
export HINDSIGHT_API_LLM_PROVIDER=claude-code

# Option 4: OpenAI Codex (no API key needed)
export HINDSIGHT_API_LLM_PROVIDER=openai-codex

# Verify it's set
echo $OPENAI_API_KEY
# or
echo $HINDSIGHT_API_LLM_PROVIDER
```

### Verify it's working

Check gateway logs for memory operations:

```bash
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight

# Should see on startup:
# [Hindsight] ✓ Using provider: openai, model: gpt-4o-mini
# or
# [Hindsight] ✓ Using provider: claude-code, model: claude-sonnet-4-20250514

# Should see after conversations:
# [Hindsight] Retained X messages for session ...
# [Hindsight] Auto-recall: Injecting X memories
```
