diff --git a/hindsight-docs/docs-integrations/openclaw.md b/hindsight-docs/docs-integrations/openclaw.md
index 5613a693..1e596656 100644
--- a/hindsight-docs/docs-integrations/openclaw.md
+++ b/hindsight-docs/docs-integrations/openclaw.md
@@ -14,36 +14,37 @@ This plugin integrates [hindsight-embed](https://vectorize.io/hindsight/cli), a
## 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**
+**Step 1: Install the plugin**
```bash
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`:
+
+```bash
+# 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**
```bash
@@ -57,6 +58,8 @@ The plugin will automatically:
**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](#migration-from-05x) 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.
@@ -94,9 +97,13 @@ Optional settings in `~/.openclaw/openclaw.json`:
- `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`. Can also be set with `HINDSIGHT_BANK_ID`.
+- `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"]`)
@@ -145,7 +152,7 @@ Available isolation fields:
- `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`, then `HINDSIGHT_BANK_ID`, then the default `openclaw` bank name.
+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
@@ -172,38 +179,61 @@ By default, the plugin retains `user` and `assistant` messages after each turn.
### LLM Configuration
-The plugin auto-detects your LLM provider from these environment variables:
+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 | 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 |
+| 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) |
-The model is selected automatically by the Hindsight API. To override, set `HINDSIGHT_API_LLM_MODEL`.
-
-**Override with explicit config:**
+**Set provider + API key:**
```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
+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
```
-**Example: Free OpenRouter model**
+**Override the model (optional — Hindsight picks a sensible default per provider):**
```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
+openclaw config set plugins.entries.hindsight-openclaw.config.llmModel gpt-4o-mini
```
+**OpenAI-compatible providers (OpenRouter, Azure OpenAI, vLLM, ...):**
+
+```bash
+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.):**
+
+```bash
+# 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:
@@ -234,20 +264,12 @@ Configure in `~/.openclaw/openclaw.json`:
**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)
+- `hindsightApiToken` - API token for authentication (optional). **Sensitive** — set as a SecretRef:
-#### 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.
+ ```bash
+ openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiToken \
+ --ref-source env --ref-provider default --ref-id HINDSIGHT_API_TOKEN
+ ```
#### Behavior
@@ -336,27 +358,36 @@ 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):
+Make sure you've configured the LLM provider through `openclaw config set`
+(or use a provider that doesn't require a key):
```bash
-# Option 1: OpenAI
-export OPENAI_API_KEY="sk-your-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
-export ANTHROPIC_API_KEY="your-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)
-export HINDSIGHT_API_LLM_PROVIDER=claude-code
+# 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)
-export HINDSIGHT_API_LLM_PROVIDER=openai-codex
+# Option 4 — OpenAI Codex (no API key needed)
+openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai-codex
-# Verify it's set
-echo $OPENAI_API_KEY
-# or
-echo $HINDSIGHT_API_LLM_PROVIDER
+# 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:
@@ -373,3 +404,29 @@ tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
# [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.
diff --git a/hindsight-docs/src/pages/changelog/integrations/openclaw.md b/hindsight-docs/src/pages/changelog/integrations/openclaw.md
index 85ae0fbf..4915c2bc 100644
--- a/hindsight-docs/src/pages/changelog/integrations/openclaw.md
+++ b/hindsight-docs/src/pages/changelog/integrations/openclaw.md
@@ -8,6 +8,21 @@ import PageHero from '@site/src/components/PageHero';
[← OpenClaw integration](/sdks/integrations/openclaw)
+## 0.6.0 (Unreleased)
+
+**Breaking Changes**
+
+- The plugin no longer reads any configuration from process environment variables. All settings — including the LLM provider, model, API key, base URL, external Hindsight API URL/token, and bank ID — must now be set through OpenClaw's plugin config (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config. `). API keys and other secrets should be configured as `SecretRef` values via `--ref-source env|file|exec` so they're resolved from your secret store at runtime instead of being stored in plaintext on disk.
+- Removed the `llmApiKeyEnv` plugin config field. Use the new `llmApiKey` field configured as a SecretRef instead (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id OPENAI_API_KEY`).
+- Removed automatic LLM provider detection from `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` / `GROQ_API_KEY`. Set `llmProvider` and `llmApiKey` explicitly via `openclaw config set`.
+- Removed support for the `HINDSIGHT_API_LLM_PROVIDER`, `HINDSIGHT_API_LLM_MODEL`, `HINDSIGHT_API_LLM_API_KEY`, `HINDSIGHT_API_LLM_BASE_URL`, `HINDSIGHT_EMBED_API_URL`, `HINDSIGHT_EMBED_API_TOKEN`, and `HINDSIGHT_BANK_ID` environment variables. The same values now live in plugin config — see the [migration guide](/sdks/integrations/openclaw#migration-from-05x).
+
+**Features**
+
+- Added the `llmApiKey` plugin config field, marked as a sensitive field so OpenClaw resolves it as a `SecretRef` from env, file, or exec sources.
+- Added the `llmBaseUrl` plugin config field for OpenAI-compatible endpoint overrides (OpenRouter, Azure OpenAI, vLLM, etc.).
+- Marked `hindsightApiToken` as a sensitive field — it can now be configured as a `SecretRef` the same way as `llmApiKey`.
+
## [0.5.1](https://github.com/vectorize-io/hindsight/tree/integrations/openclaw/v0.5.1)
**Bug Fixes**
diff --git a/hindsight-integrations/openclaw/README.md b/hindsight-integrations/openclaw/README.md
index 564b45b4..d7c3f9cb 100644
--- a/hindsight-integrations/openclaw/README.md
+++ b/hindsight-integrations/openclaw/README.md
@@ -5,25 +5,56 @@ Biomimetic long-term memory for [OpenClaw](https://openclaw.ai) using [Hindsight
## Quick Start
```bash
-# 1. Configure your LLM provider for memory extraction
-# Option A: OpenAI
-export OPENAI_API_KEY="sk-your-key"
-
-# Option B: Claude Code (no API key needed)
-export HINDSIGHT_API_LLM_PROVIDER=claude-code
-
-# Option C: OpenAI Codex (no API key needed)
-export HINDSIGHT_API_LLM_PROVIDER=openai-codex
-
-# 2. Install and enable the plugin
+# 1. Install the plugin
openclaw plugins install @vectorize-io/hindsight-openclaw
+# 2. Configure the LLM provider used for memory extraction.
+
+# Option A — OpenAI (or any OpenAI-compatible provider)
+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 — Claude Code (no API key needed)
+openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider claude-code
+
+# Option C — OpenAI Codex (no API key needed)
+openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai-codex
+
# 3. Start OpenClaw
openclaw gateway
```
That's it! The plugin will automatically start capturing and recalling memories.
+`llmApiKey` is marked sensitive — `openclaw config set ... --ref-source env` writes a
+SecretRef that resolves the value from your `OPENAI_API_KEY` environment variable at
+runtime, so the key is never stored in plaintext on disk. `--ref-source file` and
+`--ref-source exec` are also supported for mounted-secret and Vault-style setups.
+
+## Migrating 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). Concrete mappings:
+
+| 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 — no 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.
+
## Features
- **Auto-capture** and **auto-recall** of memories each turn, injected into system prompt space so recalled memories stay out of the visible chat transcript
@@ -43,11 +74,12 @@ Optional settings in `~/.openclaw/openclaw.json` under `plugins.entries.hindsigh
| `embedVersion` | `"latest"` | hindsight-embed version |
| `embedPackagePath` | — | Local path to `hindsight-embed` package for development |
| `bankMission` | — | Agent identity/purpose stored on the memory bank. Helps the engine understand context for better fact extraction. Set once per bank — not a recall prompt. |
-| `llmProvider` | auto-detect | LLM provider override for memory extraction (`openai`, `anthropic`, `gemini`, `groq`, `ollama`, `openai-codex`, `claude-code`) |
-| `llmModel` | provider default | LLM model override used with `llmProvider` |
-| `llmApiKeyEnv` | provider standard env var | Custom env var name for the provider API key |
+| `llmProvider` | — | LLM provider for memory extraction (`openai`, `anthropic`, `gemini`, `groq`, `ollama`, `openai-codex`, `claude-code`). Required unless `hindsightApiUrl` is set. |
+| `llmModel` | provider default | LLM model used with `llmProvider` |
+| `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 (or `--ref-source file`/`exec` for mounted-secret/Vault sources). |
+| `llmBaseUrl` | — | Optional base URL override for OpenAI-compatible providers (e.g. `https://openrouter.ai/api/v1`) |
| `dynamicBankId` | `true` | Enable per-context memory banks |
-| `bankId` | — | Static bank ID used when `dynamicBankId` is `false`. Can also be set with `HINDSIGHT_BANK_ID`. |
+| `bankId` | — | Static bank ID used when `dynamicBankId` is `false`. |
| `bankIdPrefix` | — | Prefix for bank IDs (e.g. `"prod"`) |
| `retainTags` | `[]` | Tags applied to every retained document, useful for cross-agent/source labeling (e.g. `source_system:openclaw`, `agent:agentname`) |
| `retainSource` | `"openclaw"` | `source` value written into retained document metadata |
@@ -67,7 +99,7 @@ Optional settings in `~/.openclaw/openclaw.json` under `plugins.entries.hindsigh
| `recallMaxQueryChars` | `800` | Maximum character length for the composed recall query before calling recall. |
| `recallPromptPreamble` | built-in string | Prompt text placed above recalled memories in the injected `` system-context block. |
| `hindsightApiUrl` | — | External Hindsight API URL (skips local daemon) |
-| `hindsightApiToken` | — | Auth token for external API |
+| `hindsightApiToken` | — | Auth token for external API. **Sensitive** — set via `openclaw config set ... --ref-source env --ref-id HINDSIGHT_API_TOKEN`. |
| `ignoreSessionPatterns` | `[]` | Session key glob patterns to skip entirely — no recall, no retain (e.g. `["agent:*:cron:**"]`) |
| `statelessSessionPatterns` | `[]` | Session key glob patterns for read-only sessions — retain is always skipped; recall is skipped when `skipStatelessSessions` is `true` (e.g. `["agent:*:subagent:**", "agent:*:heartbeat:**"]`) |
| `skipStatelessSessions` | `true` | When `true`, sessions matching `statelessSessionPatterns` also skip recall. Set to `false` to allow recall but still skip retain. |
diff --git a/hindsight-integrations/openclaw/openclaw.plugin.json b/hindsight-integrations/openclaw/openclaw.plugin.json
index 33878bb1..9361acb2 100644
--- a/hindsight-integrations/openclaw/openclaw.plugin.json
+++ b/hindsight-integrations/openclaw/openclaw.plugin.json
@@ -2,6 +2,14 @@
"id": "hindsight-openclaw",
"name": "Hindsight Memory",
"kind": "memory",
+ "configContracts": {
+ "secretInputs": {
+ "paths": [
+ { "path": "llmApiKey", "expected": "string" },
+ { "path": "hindsightApiToken", "expected": "string" }
+ ]
+ }
+ },
"configSchema": {
"type": "object",
"properties": {
@@ -27,7 +35,7 @@
},
"llmProvider": {
"type": "string",
- "description": "LLM provider for Hindsight memory (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama', 'openai-codex', 'claude-code'). Takes priority over auto-detection but not over HINDSIGHT_API_LLM_PROVIDER env var.",
+ "description": "LLM provider for Hindsight memory (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama', 'openai-codex', 'claude-code').",
"enum": [
"openai",
"anthropic",
@@ -42,9 +50,13 @@
"type": "string",
"description": "LLM model to use (e.g. 'gpt-4o-mini', 'claude-3-5-haiku-20241022'). Used with llmProvider."
},
- "llmApiKeyEnv": {
+ "llmApiKey": {
+ "type": ["string", "object"],
+ "description": "API key for the LLM provider used by the Hindsight memory daemon. Set via 'openclaw config set ... --ref-source env --ref-id OPENAI_API_KEY' to reference an env var without storing plaintext."
+ },
+ "llmBaseUrl": {
"type": "string",
- "description": "Name of the env var holding the API key (e.g. 'MY_CUSTOM_KEY'). If not set, uses the standard env var for the chosen provider."
+ "description": "Optional base URL override for OpenAI-compatible providers (e.g. 'https://openrouter.ai/api/v1')."
},
"embedPackagePath": {
"type": "string",
@@ -60,7 +72,7 @@
"description": "External Hindsight API URL (e.g. 'https://mcp.hindsight.devcraft.team'). When set, skips local daemon and connects directly to this API."
},
"hindsightApiToken": {
- "type": "string",
+ "type": ["string", "object"],
"description": "API token for external Hindsight API authentication. Required if the external API has authentication enabled."
},
"dynamicBankId": {
@@ -70,7 +82,7 @@
},
"bankId": {
"type": "string",
- "description": "Static bank ID used when dynamicBankId is false. Can also be provided via HINDSIGHT_BANK_ID."
+ "description": "Static bank ID used when dynamicBankId is false."
},
"bankIdPrefix": {
"type": "string",
@@ -290,9 +302,14 @@
"label": "LLM Model",
"placeholder": "e.g. gpt-4o-mini, claude-3-5-haiku-20241022"
},
- "llmApiKeyEnv": {
- "label": "API Key Env Var",
- "placeholder": "e.g. MY_CUSTOM_API_KEY (optional)"
+ "llmApiKey": {
+ "label": "LLM API Key",
+ "placeholder": "API key for the chosen LLM provider",
+ "sensitive": true
+ },
+ "llmBaseUrl": {
+ "label": "LLM Base URL",
+ "placeholder": "e.g. https://openrouter.ai/api/v1 (optional)"
},
"embedPackagePath": {
"label": "Local Package Path (Dev)",
@@ -308,7 +325,8 @@
},
"hindsightApiToken": {
"label": "External API Token",
- "placeholder": "API token if external API requires authentication"
+ "placeholder": "API token if external API requires authentication",
+ "sensitive": true
},
"dynamicBankId": {
"label": "Dynamic Bank IDs",
diff --git a/hindsight-integrations/openclaw/package.json b/hindsight-integrations/openclaw/package.json
index 6aa2c241..e8b05e60 100644
--- a/hindsight-integrations/openclaw/package.json
+++ b/hindsight-integrations/openclaw/package.json
@@ -44,8 +44,8 @@
"prepublishOnly": "npm run clean && npm run build"
},
"dependencies": {
- "@vectorize-io/hindsight-client": "file:../../hindsight-clients/typescript",
- "@vectorize-io/hindsight-all": "file:../../hindsight-all-npm"
+ "@vectorize-io/hindsight-client": "^0.5.0",
+ "@vectorize-io/hindsight-all": "^0.1.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
diff --git a/hindsight-integrations/openclaw/src/backfill.ts b/hindsight-integrations/openclaw/src/backfill.ts
index 6bdf2cce..0ccfe16e 100644
--- a/hindsight-integrations/openclaw/src/backfill.ts
+++ b/hindsight-integrations/openclaw/src/backfill.ts
@@ -173,12 +173,9 @@ function parseArgs(argv: string[]): ParsedArgs {
function inferApiSettings(pluginConfig: PluginConfig, explicitApiUrl?: string, explicitApiToken?: string): { apiUrl: string; apiToken?: string } {
const apiUrl = explicitApiUrl
- || process.env.HINDSIGHT_EMBED_API_URL
|| pluginConfig.hindsightApiUrl
|| `http://127.0.0.1:${pluginConfig.apiPort || 9077}`;
- const apiToken = explicitApiToken
- || process.env.HINDSIGHT_EMBED_API_TOKEN
- || pluginConfig.hindsightApiToken;
+ const apiToken = explicitApiToken || pluginConfig.hindsightApiToken;
return { apiUrl, apiToken: apiToken || undefined };
}
diff --git a/hindsight-integrations/openclaw/src/index.ts b/hindsight-integrations/openclaw/src/index.ts
index 5f370f63..dc39f4b4 100644
--- a/hindsight-integrations/openclaw/src/index.ts
+++ b/hindsight-integrations/openclaw/src/index.ts
@@ -245,12 +245,6 @@ async function lazyReinit(configOverride?: PluginConfig): Promise {
try {
await checkExternalApiHealth(externalApi.apiUrl, externalApi.apiToken);
- // Health check passed — set up env vars and create client
- process.env.HINDSIGHT_EMBED_API_URL = externalApi.apiUrl;
- if (externalApi.apiToken) {
- process.env.HINDSIGHT_EMBED_API_TOKEN = externalApi.apiToken;
- }
-
const llmConfig = detectLLMConfig(config);
clientOptions = buildClientOptions(llmConfig, config, externalApi);
banksWithMissionSet.clear();
@@ -667,16 +661,8 @@ export function formatMemories(results: MemoryResult[]): string {
}
-// Provider detection from standard env vars
-const PROVIDER_DETECTION = [
- { name: 'openai', keyEnv: 'OPENAI_API_KEY' },
- { name: 'anthropic', keyEnv: 'ANTHROPIC_API_KEY' },
- { name: 'gemini', keyEnv: 'GEMINI_API_KEY' },
- { name: 'groq', keyEnv: 'GROQ_API_KEY' },
- { name: 'ollama', keyEnv: '' },
- { name: 'openai-codex', keyEnv: '' },
- { name: 'claude-code', keyEnv: '' },
-];
+// Providers that authenticate via OAuth or run locally — no API key needed.
+const NO_KEY_REQUIRED_PROVIDERS = new Set(['ollama', 'openai-codex', 'claude-code']);
export function detectLLMConfig(pluginConfig?: PluginConfig): {
provider?: string;
@@ -685,88 +671,7 @@ export function detectLLMConfig(pluginConfig?: PluginConfig): {
baseUrl?: string;
source: string;
} {
- // Override values from HINDSIGHT_API_LLM_* env vars (highest priority)
- const overrideProvider = process.env.HINDSIGHT_API_LLM_PROVIDER;
- const overrideModel = process.env.HINDSIGHT_API_LLM_MODEL;
- const overrideKey = process.env.HINDSIGHT_API_LLM_API_KEY;
- const overrideBaseUrl = process.env.HINDSIGHT_API_LLM_BASE_URL;
-
- // Priority 1: If provider is explicitly set via env var, use that
- if (overrideProvider) {
- // Providers that don't require an API key (use OAuth or local models)
- const noKeyRequired = ['ollama', 'openai-codex', 'claude-code'];
- if (!overrideKey && !noKeyRequired.includes(overrideProvider)) {
- throw new Error(
- `HINDSIGHT_API_LLM_PROVIDER is set to "${overrideProvider}" but HINDSIGHT_API_LLM_API_KEY is not set.\n` +
- `Please set: export HINDSIGHT_API_LLM_API_KEY=your-api-key`
- );
- }
-
- return {
- provider: overrideProvider,
- apiKey: overrideKey || '',
- model: overrideModel,
- baseUrl: overrideBaseUrl,
- source: 'HINDSIGHT_API_LLM_PROVIDER override',
- };
- }
-
- // Priority 2: Plugin config llmProvider/llmModel
- if (pluginConfig?.llmProvider) {
- const providerInfo = PROVIDER_DETECTION.find(p => p.name === pluginConfig.llmProvider);
-
- // Resolve API key: llmApiKeyEnv > provider's standard keyEnv
- let apiKey = '';
- if (pluginConfig.llmApiKeyEnv) {
- apiKey = process.env[pluginConfig.llmApiKeyEnv] || '';
- } else if (providerInfo?.keyEnv) {
- apiKey = process.env[providerInfo.keyEnv] || '';
- }
-
- // Providers that don't require an API key (use OAuth or local models)
- const noKeyRequired = ['ollama', 'openai-codex', 'claude-code'];
- if (!apiKey && !noKeyRequired.includes(pluginConfig.llmProvider)) {
- const keySource = pluginConfig.llmApiKeyEnv || providerInfo?.keyEnv || 'unknown';
- throw new Error(
- `Plugin config llmProvider is set to "${pluginConfig.llmProvider}" but no API key found.\n` +
- `Expected env var: ${keySource}\n` +
- `Set the env var or use llmApiKeyEnv in plugin config to specify a custom env var name.`
- );
- }
-
- return {
- provider: pluginConfig.llmProvider,
- apiKey,
- model: pluginConfig.llmModel || overrideModel,
- baseUrl: overrideBaseUrl,
- source: 'plugin config',
- };
- }
-
- // Priority 3: Auto-detect from standard provider env vars
- for (const providerInfo of PROVIDER_DETECTION) {
- const apiKey = providerInfo.keyEnv ? process.env[providerInfo.keyEnv] : '';
-
- // Skip providers that don't use API keys in auto-detection (must be explicitly requested)
- const noKeyRequired = ['ollama', 'openai-codex', 'claude-code'];
- if (noKeyRequired.includes(providerInfo.name)) {
- continue;
- }
-
- if (apiKey) {
- return {
- provider: providerInfo.name,
- apiKey,
- model: overrideModel,
- baseUrl: overrideBaseUrl,
- source: `auto-detected from ${providerInfo.keyEnv}`,
- };
- }
- }
-
- // No configuration found - show helpful error
-
- // Allow empty LLM config if using external Hindsight API (server handles LLM)
+ // External API mode: the daemon handles LLM credentials, plugin doesn't need them.
const externalApiCheck = detectExternalApi(pluginConfig);
if (externalApiCheck.apiUrl) {
return {
@@ -778,37 +683,51 @@ export function detectLLMConfig(pluginConfig?: PluginConfig): {
};
}
- throw new Error(
- `No LLM configuration found for Hindsight memory plugin.\n\n` +
- `Option 1: Set a standard provider API key (auto-detect):\n` +
- ` export OPENAI_API_KEY=sk-your-key\n` +
- ` export ANTHROPIC_API_KEY=your-key\n` +
- ` export GEMINI_API_KEY=your-key\n` +
- ` export GROQ_API_KEY=your-key\n\n` +
- `Option 2: Use Codex or Claude Code (no API key needed):\n` +
- ` export HINDSIGHT_API_LLM_PROVIDER=openai-codex # Requires 'codex auth login'\n` +
- ` export HINDSIGHT_API_LLM_PROVIDER=claude-code # Requires Claude Code CLI\n\n` +
- `Option 3: Set llmProvider in openclaw.json plugin config:\n` +
- ` "llmProvider": "openai"\n\n` +
- `Option 4: Override with Hindsight-specific env vars:\n` +
- ` export HINDSIGHT_API_LLM_PROVIDER=openai\n` +
- ` export HINDSIGHT_API_LLM_API_KEY=sk-your-key\n` +
- ` export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1 # Optional\n\n` +
- `The model will be selected automatically by Hindsight. To override: export HINDSIGHT_API_LLM_MODEL=your-model`
- );
+ const provider = pluginConfig?.llmProvider;
+ if (!provider) {
+ throw new Error(
+ `No LLM provider configured for the Hindsight memory plugin.\n\n` +
+ `Set the provider via 'openclaw config set':\n` +
+ ` openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai\n\n` +
+ `For providers that need an API key, configure it as a SecretRef so the value\n` +
+ `is read from an env var (or file/exec source) at runtime instead of stored in plain text:\n` +
+ ` openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \\\n` +
+ ` --ref-source env --ref-provider default --ref-id OPENAI_API_KEY\n\n` +
+ `Providers that don't need an API key: ${[...NO_KEY_REQUIRED_PROVIDERS].join(', ')}.\n` +
+ `Or point the plugin at an external Hindsight API by setting hindsightApiUrl instead.`
+ );
+ }
+
+ const apiKey = pluginConfig?.llmApiKey ?? '';
+ if (!apiKey && !NO_KEY_REQUIRED_PROVIDERS.has(provider)) {
+ throw new Error(
+ `llmProvider is set to "${provider}" but llmApiKey is empty.\n\n` +
+ `Configure it via 'openclaw config set' as a SecretRef:\n` +
+ ` openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \\\n` +
+ ` --ref-source env --ref-provider default --ref-id OPENAI_API_KEY`
+ );
+ }
+
+ return {
+ provider,
+ apiKey,
+ model: pluginConfig?.llmModel,
+ baseUrl: pluginConfig?.llmBaseUrl,
+ source: 'plugin config',
+ };
}
/**
- * Detect external Hindsight API configuration.
- * Priority: env vars > plugin config
+ * Detect external Hindsight API configuration from plugin config.
*/
export function detectExternalApi(pluginConfig?: PluginConfig): {
apiUrl: string | null;
apiToken: string | null;
} {
- const apiUrl = process.env.HINDSIGHT_EMBED_API_URL || pluginConfig?.hindsightApiUrl || null;
- const apiToken = process.env.HINDSIGHT_EMBED_API_TOKEN || pluginConfig?.hindsightApiToken || null;
- return { apiUrl, apiToken };
+ return {
+ apiUrl: pluginConfig?.hindsightApiUrl ?? null,
+ apiToken: pluginConfig?.hindsightApiToken ?? null,
+ };
}
/**
@@ -867,9 +786,6 @@ async function checkExternalApiHealth(apiUrl: string, apiToken?: string | null):
function getPluginConfig(api: MoltbotPluginAPI): PluginConfig {
const config = api.config.plugins?.entries?.['hindsight-openclaw']?.config || {};
const defaultMission = 'You are an AI assistant helping users across multiple communication channels (Telegram, Slack, Discord, etc.). Remember user preferences, instructions, and important context from conversations to provide personalized assistance.';
- const envBankId = typeof process.env.HINDSIGHT_BANK_ID === 'string' && process.env.HINDSIGHT_BANK_ID.trim().length > 0
- ? process.env.HINDSIGHT_BANK_ID.trim()
- : undefined;
return {
bankMission: config.bankMission || defaultMission,
@@ -879,13 +795,14 @@ function getPluginConfig(api: MoltbotPluginAPI): PluginConfig {
embedPackagePath: config.embedPackagePath,
llmProvider: config.llmProvider,
llmModel: config.llmModel,
- llmApiKeyEnv: config.llmApiKeyEnv,
+ llmApiKey: config.llmApiKey,
+ llmBaseUrl: config.llmBaseUrl,
hindsightApiUrl: config.hindsightApiUrl,
hindsightApiToken: config.hindsightApiToken,
apiPort: config.apiPort || 9077,
// Dynamic bank ID options (default: enabled)
dynamicBankId: config.dynamicBankId !== false,
- bankId: envBankId || (typeof config.bankId === 'string' && config.bankId.trim().length > 0 ? config.bankId.trim() : undefined),
+ bankId: typeof config.bankId === 'string' && config.bankId.trim().length > 0 ? config.bankId.trim() : undefined,
bankIdPrefix: config.bankIdPrefix,
retainTags: Array.isArray(config.retainTags) ? config.retainTags.filter((tag): tag is string => typeof tag === 'string') : undefined,
retainSource: typeof config.retainSource === 'string' && config.retainSource.trim().length > 0 ? config.retainSource.trim() : undefined,
@@ -1013,10 +930,7 @@ export default function (api: MoltbotPluginAPI) {
log.warn(`could not initialize retain queue: ${error}`);
}
- // Set env vars so CLI commands (uvx hindsight-embed) use external API
- process.env.HINDSIGHT_EMBED_API_URL = externalApi.apiUrl;
if (externalApi.apiToken) {
- process.env.HINDSIGHT_EMBED_API_TOKEN = externalApi.apiToken;
debug('[Hindsight] API token configured');
}
} else {
@@ -1176,10 +1090,6 @@ export default function (api: MoltbotPluginAPI) {
if (externalApi.apiUrl) {
// External API mode
usingExternalApi = true;
- process.env.HINDSIGHT_EMBED_API_URL = externalApi.apiUrl;
- if (externalApi.apiToken) {
- process.env.HINDSIGHT_EMBED_API_TOKEN = externalApi.apiToken;
- }
await checkExternalApiHealth(externalApi.apiUrl, externalApi.apiToken);
diff --git a/hindsight-integrations/openclaw/src/types.ts b/hindsight-integrations/openclaw/src/types.ts
index 56f8058a..4806023d 100644
--- a/hindsight-integrations/openclaw/src/types.ts
+++ b/hindsight-integrations/openclaw/src/types.ts
@@ -55,14 +55,15 @@ export interface PluginConfig {
daemonIdleTimeout?: number; // Seconds before daemon shuts down (0 = never)
embedVersion?: string; // hindsight-embed version (default: "latest")
embedPackagePath?: string; // Local path to hindsight package (e.g. '/path/to/hindsight')
- llmProvider?: string; // LLM provider override (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama')
- llmModel?: string; // LLM model override (e.g. 'gpt-4o-mini', 'claude-3-5-haiku-20241022')
- llmApiKeyEnv?: string; // Env var name holding the API key (e.g. 'MY_CUSTOM_KEY')
+ llmProvider?: string; // LLM provider (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama', 'openai-codex', 'claude-code')
+ llmModel?: string; // LLM model (e.g. 'gpt-4o-mini', 'claude-3-5-haiku-20241022')
+ llmApiKey?: string; // LLM provider API key. Configure via SecretRef: openclaw config set ... --ref-source env --ref-id OPENAI_API_KEY
+ llmBaseUrl?: string; // Optional base URL override for OpenAI-compatible providers (e.g. OpenRouter)
apiPort?: number; // Port for openclaw profile daemon (default: 9077)
hindsightApiUrl?: string; // External Hindsight API URL (skips local daemon when set)
- hindsightApiToken?: string; // API token for external Hindsight API authentication
+ hindsightApiToken?: string; // API token for external Hindsight API. Configure via SecretRef.
dynamicBankId?: boolean; // Enable per-channel memory banks (default: true)
- bankId?: string; // Static bank ID used when dynamicBankId is false. Can also be set via HINDSIGHT_BANK_ID.
+ bankId?: string; // Static bank ID used when dynamicBankId is false.
bankIdPrefix?: string; // Prefix for bank IDs (e.g. 'prod' -> 'prod-slack-C123')
retainTags?: string[]; // Tags applied to all retained documents (e.g. ['source_system:openclaw', 'agent:agentname'])
retainSource?: string; // Source written into retained document metadata (default: 'openclaw')
diff --git a/hindsight-integrations/openclaw/tests/hooks.integration.test.ts b/hindsight-integrations/openclaw/tests/hooks.integration.test.ts
index 61eb5a5d..8cf20871 100644
--- a/hindsight-integrations/openclaw/tests/hooks.integration.test.ts
+++ b/hindsight-integrations/openclaw/tests/hooks.integration.test.ts
@@ -148,18 +148,15 @@ beforeAll(async () => {
// Reset module registry so we get a fresh module with clean state.
vi.resetModules();
- // Provide LLM config — used by plugin init even in HTTP mode.
- process.env.HINDSIGHT_API_LLM_PROVIDER = 'openai';
- process.env.HINDSIGHT_API_LLM_API_KEY = 'test-key-hooks';
- // Point the plugin at the running test API.
- process.env.HINDSIGHT_EMBED_API_URL = HINDSIGHT_API_URL;
-
const mod = await import('../src/index.js');
const { HindsightClient } = await import('@vectorize-io/hindsight-client');
const pluginFn = mod.default;
const getClient = mod.getClient;
+ // Plugin runs in external API mode (talks to the running test API), so no LLM
+ // credentials are needed in the plugin config — the daemon handles them.
const handle = createMockApi({
+ hindsightApiUrl: HINDSIGHT_API_URL,
dynamicBankId: true,
excludeProviders: ['slack'],
retainEveryNTurns: 1, // retain every turn so individual tests aren't affected by chunking
@@ -188,9 +185,6 @@ beforeAll(async () => {
afterAll(async () => {
vi.restoreAllMocks();
- delete process.env.HINDSIGHT_API_LLM_PROVIDER;
- delete process.env.HINDSIGHT_API_LLM_API_KEY;
- delete process.env.HINDSIGHT_EMBED_API_URL;
if (stopServicesFn) await stopServicesFn().catch(() => {});
}, 15_000);
diff --git a/skills/hindsight-docs/references/changelog/integrations/openclaw.md b/skills/hindsight-docs/references/changelog/integrations/openclaw.md
index ae96519e..233dc0a8 100644
--- a/skills/hindsight-docs/references/changelog/integrations/openclaw.md
+++ b/skills/hindsight-docs/references/changelog/integrations/openclaw.md
@@ -8,6 +8,21 @@ import PageHero from '@site/src/components/PageHero';
← OpenClaw integration
+## 0.6.0 (Unreleased)
+
+**Breaking Changes**
+
+- The plugin no longer reads any configuration from process environment variables. All settings — including the LLM provider, model, API key, base URL, external Hindsight API URL/token, and bank ID — must now be set through OpenClaw's plugin config (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config. `). API keys and other secrets should be configured as `SecretRef` values via `--ref-source env|file|exec` so they're resolved from your secret store at runtime instead of being stored in plaintext on disk.
+- Removed the `llmApiKeyEnv` plugin config field. Use the new `llmApiKey` field configured as a SecretRef instead (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id OPENAI_API_KEY`).
+- Removed automatic LLM provider detection from `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` / `GROQ_API_KEY`. Set `llmProvider` and `llmApiKey` explicitly via `openclaw config set`.
+- Removed support for the `HINDSIGHT_API_LLM_PROVIDER`, `HINDSIGHT_API_LLM_MODEL`, `HINDSIGHT_API_LLM_API_KEY`, `HINDSIGHT_API_LLM_BASE_URL`, `HINDSIGHT_EMBED_API_URL`, `HINDSIGHT_EMBED_API_TOKEN`, and `HINDSIGHT_BANK_ID` environment variables. The same values now live in plugin config — see the migration guide.
+
+**Features**
+
+- Added the `llmApiKey` plugin config field, marked as a sensitive field so OpenClaw resolves it as a `SecretRef` from env, file, or exec sources.
+- Added the `llmBaseUrl` plugin config field for OpenAI-compatible endpoint overrides (OpenRouter, Azure OpenAI, vLLM, etc.).
+- Marked `hindsightApiToken` as a sensitive field — it can now be configured as a `SecretRef` the same way as `llmApiKey`.
+
## [0.5.1](https://github.com/vectorize-io/hindsight/tree/integrations/openclaw/v0.5.1)
**Bug Fixes**