@harness-memory/openclaw
v0.9.0
Published
OpenClaw native memory plugin backed by harness-memory (SQLite + FTS5, atom/tree/raw recall).
Readme
harnessmemory — OpenClaw native memory plugin
kind: "memory"plugin that occupiesplugins.slots.memoryexclusively. Backed byharness-memory(SQLite + FTS5). Spawns a Python subprocess (harnessmemory-bridge) for the heavy lifting; the TypeScript shell only handles OpenClaw lifecycle + tool wiring.
Status
| Wave | Scope | Status |
|---|---|---|
| A | TS shell, promptBuilder, flushPlanResolver, JSON-RPC bridge client, memory_search/memory_get tools, agent_end capture hook, harnessmemory CLI forwarder | ✅ Implemented (feature/v0.2, 2026-06-04) |
| B | Real-environment dogfood + harnessmemory setup openclaw CLI | ✅ Implemented (feature/v0.2, 2026-06-04) |
| C | host_files watcher (D51-C real-file index), e2e mock test harness | ✅ Implemented (feature/v0.2, 2026-06-04) |
Install
Requires OpenClaw
>= 2026.4.11(perpackage.json#openclaw.install.minHostVersion), Node.js 18+, and Python 3.11+.
# 1. Install the Python bridge as an isolated tool.
# Prefer uv/pipx over bare pip: the system Python's sqlite3 often
# lacks FTS5, which the bridge requires; uv ships one that has it.
uv tool install 'harness-memory[cli]' # or: pipx install 'harness-memory[cli]'
# Verify the bridge — expect {"ok": true, "fts5": true, ...}
harnessmemory-bridge --probe
# 2. Install the OpenClaw plugin from npm.
npm install @harness-memory/openclaw
# or via OpenClaw's plugin manager:
openclaw plugins install @harness-memory/openclaw
# 3. One-shot setup: probes the bridge (FTS5 check), writes
# plugins.slots.memory + entries config into ~/.openclaw/openclaw.json,
# creates the SQLite dir, runs a capture→search smoke test, and
# restarts the gateway. The plugin is NOT active until this runs.
openclaw harnessmemory setup
# Verify.
openclaw harnessmemory statusSee ../INSTALL.md for setup flags (--namespace,
--db-path, --profile, --dry-run) and troubleshooting (PATH,
missing FTS5, empty search results).
Install from source (development)
Plugin directories must NOT be symlinks (host inspection rejects them).
# 1. Install harness-memory in the python env that OpenClaw uses.
pip install 'harness-memory[cli]' # or `uv pip install ...`
# 2. Build the plugin TS shell.
cd plugins/openclaw/harnessmemory
npm install
npm run build
# 3. Copy (don't symlink) into OpenClaw's extensions dir.
cp -r . ~/.openclaw/extensions/harnessmemory
# 4. Activate the slot.
openclaw config set plugins.slots.memory harnessmemoryOr run scripts/deploy-openclaw.sh,
which does all of the above idempotently (venv, build, config, doctor).
Configuration
All options live under plugins.entries.harnessmemory.config in openclaw.json.
Schema is enforced by OpenClaw at install time (manifest configSchema).
⚠️
hooks.allowConversationAccess: trueis required (sibling ofconfig, not inside it). OpenClaw ≥2026.4.29 gates conversation hooks (agent_end,llm_input, …) behind this per-plugin opt-in; without it the host silently never deliversagent_end, so auto-capture stores nothing while everything else looks healthy. Bothsetupflows write it automatically.
{
"plugins": {
"slots": { "memory": "harnessmemory" },
"entries": {
"harnessmemory": {
"enabled": true,
"hooks": { "allowConversationAccess": true },
"config": {
"profile": "balanced",
"mode": "self-hosted",
"namespace": "openclaw__a3f2c891",
"host_files_root": "~/.openclaw/workspace",
"host_files_allow": ["topics/*.md", "projects/*.md"],
"bridge": {
"python": "python3",
"log_level": "info",
"spawn_timeout_ms": 5000
},
"recall": {
"mode": "tool_hint"
},
"capture": {
"agent_end_hook": true,
"host_files_watcher": true,
"min_message_chars": 50
},
"compaction": {
"enabled": true,
"soft_threshold_tokens": 4000
}
}
}
}
}
}Scenario profiles
profile selects a scenario preset. Available profiles are balanced (default), low_latency, proactive, privacy, archive, and eval. Profile defaults are applied first; explicit config values such as recall.mode or capture.host_files_watcher override the profile.
When capture.host_files_watcher=true, host_files_root defaults to the OpenClaw workspace (~/.openclaw/workspace, or ~/.openclaw/workspace-<OPENCLAW_PROFILE> for named profiles). The watcher indexes MEMORY.md, USER.md, DREAMS.md, daily memory/YYYY-MM-DD*.md files, plus allowlisted topical Markdown such as topics/*.md and projects/*.md. It does not scan arbitrary **/*.md by default.
See ../../../docs/openclaw-harnessmemory-config-reference.md for the complete configuration reference, and ../../../docs/openclaw-memory-config-profiles.md for profile design diagrams and scenario guidance.
Recall prompt modes
recall.mode controls what promptBuilder injects into the model context:
| Mode | Behaviour |
|---|---|
| off | Omit the HarnessMemory prompt section entirely. Tools remain registered, but the model receives no memory hint. |
| tool_hint | Default. Inject a short ## Memory Recall section that tells the model when to call memory_search / memory_get; no memories are preloaded. |
| hybrid | Opt-in compatibility mode for future auto-recall. In OpenClaw v2026.5.28 the promptBuilder contract is synchronous and exposes only availableTools / citationsMode, so this currently falls back to explicit tool guidance rather than querying the bridge. |
Use tool_hint for the safest default. Switch to off for low-token debugging, and reserve hybrid for hosts that later expose query context in promptBuilder.
Chat slash command
/harnessmemory is registered at runtime via api.registerCommand (the same
surface memory-core's /dreaming uses) — the manifest commandAliases entry
only covers CLI routing and does not make a chat command work:
/harnessmemory status
/harnessmemory search <query>
/harnessmemory show <path> [from] [lines]
/harnessmemory reindexOn hosts that predate the registerCommand surface the registration is
skipped (logged at info); tools and CLI keep working.
Native OpenClaw CLI
HarnessMemory registers native OpenClaw subcommands for day-to-day inspection:
openclaw harnessmemory status
openclaw harnessmemory search "Hermes adapter"
openclaw harnessmemory show raw/2026-06-04/evt_xxx.md --from 1 --lines 20
openclaw harnessmemory reindex| Command | Purpose |
|---|---|
| status | Show namespace, profile/recall mode, raw/atom/entity counts, and host_files index status. |
| search <query> | Call the plugin's memory_search tool from the terminal. Supports --max and --corpus. |
| show <path> | Call memory_get and print the rendered excerpt. Supports --from and --lines. |
| reindex | Force a host_files scan for MEMORY.md, USER.md, DREAMS.md, memory/YYYY-MM-DD*.md, and allowlisted topical Markdown. |
| admin [args...] | Forward advanced maintenance commands to python -m harness_memory.adapters.cli. |
Decision lock state (locked 2026-06-04)
| ID | Decision |
|---|---|
| D51-C | memory_get path projection: SQLite is truth (atom/<id>.md, page/<entity>.md, raw/<date>/<id>.md are virtual) + host-written real files (memory/<date>.md, MEMORY.md, USER.md, DREAMS.md, and allowlisted topical Markdown) are also indexed via 30s stat poll (Wave C). |
| D52-C | Auto-capture: agent_end hook → filtered Memory.add_raw_batch() write (raw layer) plus host silent-turn writes to memory/*.md indexed by Wave C watcher. Both default true, independently togglable. |
| D53-推迟 | Cloud / multi-backend (mode: "platform") deferred to M6. |
Architecture
OpenClaw host
├── promptBuilder ─────► src/prompt-section.ts (sync, static)
├── flushPlanResolver ─► src/flush-plan.ts (sync, static)
├── memory_search tool ─► src/index.ts → BridgeClient.call("memory_search")
├── memory_get tool ────► src/index.ts → BridgeClient.call("memory_get")
└── agent_end hook ────► src/index.ts → BridgeClient.call("capture")
│ stdin/stdout JSON-RPC
▼
harnessmemory-bridge (Python: harness_memory.adapters.bridge.server)
│
▼
harness-memory SQLite store
~/.harnessmemory/<namespace>/memory.sqliteThe TypeScript layer is intentionally thin (~600 LoC):
- prompt section + flush plan are static templates (no IO),
- tools are 6-line shims around the bridge,
- the bridge client is a single
BridgeClientclass.
All data plane work — atom/raw FTS recall, atom/page rendering, capture
heuristics — lives in harness-memory. This keeps the OpenClaw
installation surface tiny and lets the same Python core serve future
hosts (Hermes / ACE) by swapping just the TS shell.
Cross-references
- Decision doc:
../../../docs/openclaw-native-plugin-contract.md - Python bridge:
../../../src/harness_memory/adapters/bridge/
