fleet-memory/hindsight-docs/docs-integrations/openclaw.md
Nicolò Boschi e22ae05f47
refactor(openclaw)!: read config from plugin config instead of process.env (#974)
* refactor(openclaw)!: read config from plugin config instead of process.env

The plugin loaded credentials and runtime settings from environment
variables (HINDSIGHT_API_LLM_*, HINDSIGHT_EMBED_API_*, HINDSIGHT_BANK_ID)
plus auto-detection of OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY
/ GROQ_API_KEY. That tripped OpenClaw's install-scanner env-harvesting
rule and bypassed the framework's first-class SecretRef resolution.
Switch to reading from the plugin config exclusively, with secrets
configured via 'openclaw config set ... --ref-source env|file|exec'.

Combined with the daemon lifecycle extraction in #949, this closes the
remaining install-scanner findings the 0.5.x plugin was hitting. The
plugin source now contains neither process.env nor child_process; the
former moved to plugin config (resolved by OpenClaw before the plugin
loads), and the latter lives in @vectorize-io/hindsight-all under
node_modules where the scanner's directory walker skips it. The plugin
can be installed without --dangerously-force-unsafe-install.

BREAKING CHANGE: drops the llmApiKeyEnv plugin config field along with
the HINDSIGHT_API_LLM_*, HINDSIGHT_EMBED_API_*, and HINDSIGHT_BANK_ID
environment variables. Users must now configure llmProvider and
llmApiKey explicitly via 'openclaw config set'. Migration guide is in
hindsight-docs/docs-integrations/openclaw.md and the integration
changelog.

* chore(openclaw): pin published versions of hindsight-all and hindsight-client

Phase 2 (#949) introduced @vectorize-io/hindsight-all and
@vectorize-io/hindsight-client as plugin dependencies using 'file:'
workspace paths. Those paths resolve inside the monorepo but break when
the published tarball is installed outside it — 'openclaw plugins
install @vectorize-io/hindsight-openclaw' failed with 'Cannot find
module @vectorize-io/hindsight-all' because npm could not resolve the
file: path from the extracted extension directory.

Replace both with semver ranges targeting the published versions:

  @vectorize-io/hindsight-all   ^0.1.0
  @vectorize-io/hindsight-client ^0.5.0

Verified end-to-end: 'openclaw plugins install <local-tarball>' now
succeeds without --dangerously-force-unsafe-install and without the
workspace-symlink hack. npm pulls both dependencies from the registry
into the extracted extension's node_modules, the plugin loads cleanly,
and 'openclaw plugins doctor' reports no issues.
2026-04-10 18:27:28 +02:00

17 KiB

sidebar_position title description
4 OpenClaw Persistent Memory with Hindsight | Plugin Integration Add persistent, automated memory to your OpenClaw agent with Hindsight. Local-first, open source — one plugin install replaces built-in memory with structured knowledge extraction and auto-recall.

OpenClaw

Local, long term memory for OpenClaw agents using Hindsight.

This plugin integrates hindsight-embed, 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 →

Quick Start

Step 1: Install the plugin

openclaw plugins install @vectorize-io/hindsight-openclaw

Step 2: Configure the LLM provider used for memory extraction

The plugin reads configuration from OpenClaw's plugin config — set it non-interactively with openclaw config set:

# Option A — OpenAI (set llmApiKey as a SecretRef so the value comes from
# the OPENAI_API_KEY environment variable at runtime instead of being
# stored in plaintext on disk)
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source env --ref-provider default --ref-id OPENAI_API_KEY

# Option B — Anthropic
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider anthropic
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source env --ref-provider default --ref-id ANTHROPIC_API_KEY

# Option C — Claude Code (no API key needed)
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider claude-code

# Option D — OpenAI Codex (no API key needed)
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai-codex

Step 3: Start OpenClaw

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.

Migrating from 0.5.x? See the Migration from 0.5.x section below for the env-var → SecretRef mapping.

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:

{
  "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")
  • llmProvider - LLM provider for memory extraction (openai, anthropic, gemini, groq, ollama, openai-codex, claude-code). Required unless hindsightApiUrl is set.
  • llmModel - LLM model used with llmProvider (provider default if omitted)
  • llmApiKey - API key for the LLM provider. Sensitive — set via openclaw config set ... --ref-source env --ref-id OPENAI_API_KEY to reference an env var.
  • llmBaseUrl - Optional base URL override for OpenAI-compatible providers (e.g. https://openrouter.ai/api/v1)
  • 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)
  • bankId - Static bank ID used when dynamicBankId is false.
  • bankIdPrefix - Optional prefix for bank IDs (e.g. "prod""prod-slack-C123" or "prod-shared-bank")
  • 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:

{
  "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. In static mode, the plugin uses bankId if set, otherwise the default openclaw bank name.

Retention Controls

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

{
  "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

Configure the memory-extraction LLM via OpenClaw's plugin config. API keys should be stored as SecretRef values so they're resolved from env vars, mounted files, or exec-style secret managers (Vault, etc.) at runtime instead of sitting in plaintext on disk.

Provider llmProvider API key
OpenAI openai required
Anthropic anthropic required
Gemini gemini required
Groq groq required
Ollama ollama not required (local)
Claude Code claude-code not required (uses Claude Code CLI)
OpenAI Codex openai-codex not required (uses Codex CLI auth)

Set provider + API key:

openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source env --ref-provider default --ref-id OPENAI_API_KEY

Override the model (optional — Hindsight picks a sensible default per provider):

openclaw config set plugins.entries.hindsight-openclaw.config.llmModel gpt-4o-mini

OpenAI-compatible providers (OpenRouter, Azure OpenAI, vLLM, ...):

openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
openclaw config set plugins.entries.hindsight-openclaw.config.llmBaseUrl https://openrouter.ai/api/v1
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source env --ref-provider default --ref-id OPENROUTER_API_KEY
openclaw config set plugins.entries.hindsight-openclaw.config.llmModel xiaomi/mimo-v2-flash

Use a file or exec source instead of env (for K8s secrets, Vault, etc.):

# File source (e.g. mounted Docker/K8s secret)
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source file --ref-provider mounted-json --ref-id /providers/openai/apiKey

# Exec source (e.g. HashiCorp Vault)
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source exec --ref-provider vault --ref-id openai/api-key

The corresponding secret provider needs to be configured under secrets.providers in your OpenClaw config — see openclaw config set --help for the --provider-source/--provider-path/--provider-command builder flags.

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:

{
  "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). Sensitive — set as a SecretRef:

    openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiToken \
        --ref-source env --ref-provider default --ref-id HINDSIGHT_API_TOKEN
    

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:

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:

cat ~/.hindsight/profiles/openclaw.env

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

Check Daemon Status

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

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

Query Memories

# 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

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

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

Daemon not starting

# 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 configured the LLM provider through openclaw config set (or use a provider that doesn't require a key):

# Option 1 — OpenAI (requires OPENAI_API_KEY in your env)
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source env --ref-provider default --ref-id OPENAI_API_KEY

# Option 2 — Anthropic
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider anthropic
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
    --ref-source env --ref-provider default --ref-id ANTHROPIC_API_KEY

# Option 3 — Claude Code (no API key needed)
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider claude-code

# Option 4 — OpenAI Codex (no API key needed)
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai-codex

# Verify the config is valid
openclaw config validate

# Inspect the current value
openclaw config get plugins.entries.hindsight-openclaw.config.llmProvider

If you used --ref-source env, double-check that the referenced env var (e.g. OPENAI_API_KEY) is exported in the shell that runs openclaw gateway.

Verify it's working

Check gateway logs for memory operations:

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

Migration from 0.5.x

0.6.0 removes all process-environment reads from the plugin. Configuration that previously came from shell env vars must now go through OpenClaw's plugin config (with SecretRef for credentials). The plugin no longer auto-detects providers from OPENAI_API_KEY / ANTHROPIC_API_KEY / etc. — you must set llmProvider explicitly.

Old (0.5.x) New (0.6.0)
OPENAI_API_KEY=… (auto-detected) openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id OPENAI_API_KEY
HINDSIGHT_API_LLM_PROVIDER=… openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider …
HINDSIGHT_API_LLM_MODEL=… openclaw config set plugins.entries.hindsight-openclaw.config.llmModel …
HINDSIGHT_API_LLM_API_KEY=… openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id …
HINDSIGHT_API_LLM_BASE_URL=… openclaw config set plugins.entries.hindsight-openclaw.config.llmBaseUrl …
HINDSIGHT_EMBED_API_URL=… openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiUrl …
HINDSIGHT_EMBED_API_TOKEN=… openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiToken --ref-source env --ref-id …
HINDSIGHT_BANK_ID=… openclaw config set plugins.entries.hindsight-openclaw.config.bankId …
llmApiKeyEnv: "MY_KEY" (plugin config) llmApiKey configured as a SecretRef with --ref-id MY_KEY

If your shell already exports OPENAI_API_KEY, the SecretRef config above resolves to the same value at startup — you don't need to change your shell setup, just point the plugin at the variable explicitly. Run openclaw config validate after migrating to confirm the new shape parses cleanly.