# @remnic/plugin-openclaw

OpenClaw plugin for Remnic memory and context. The package bundles the OpenClaw adapter plus the Remnic core runtime so it can run without a separate Remnic service; the adapter registers OpenClaw hooks/tools and delegates memory behavior to [`@remnic/core`](https://www.npmjs.com/package/@remnic/core).

Part of [Remnic](https://github.com/joshuaswarren/remnic), open-source memory and context for user-aware agents.

## Install

```bash
openclaw plugins install clawhub:@remnic/plugin-openclaw
```

Or ask your OpenClaw agent:

> Install the @remnic/plugin-openclaw ClawHub plugin and configure it as my memory system.

## Configure

Add the plugin to your `openclaw.json`:

```jsonc
{
  "plugins": {
    "allow": ["openclaw-remnic"],
    "slots": { "memory": "openclaw-remnic" },
    "entries": {
      "openclaw-remnic": {
        "package": "@remnic/plugin-openclaw",
        "hooks": {
          "allowConversationAccess": true
        }
      }
    }
  }
}
```

Then restart the gateway:

```bash
launchctl kickstart -k gui/501/ai.openclaw.gateway
```

## Compatibility Policy

Remnic supports OpenClaw releases from at least the previous 60 days. As of
June 26, 2026, that means releases back to April 27, 2026.
The package metadata keeps the installer compatibility floor at the single
`>=2026.4.1` shape OpenClaw setup expects because that older floor is still
more permissive than the active 60-day requirement.

`openclaw.compat.pluginApi` and `peerDependencies.openclaw` are evaluated by
**different resolvers**, so they are intentionally not identical (issue #1450):

- **`openclaw.compat.pluginApi` → `>=2026.4.1`.** OpenClaw's installer checker
  (`clawhub.ts`) splits the range on whitespace and AND-evaluates every token,
  and it normalizes away the host's prerelease suffix when the target is a plain
  version. So a single `>=2026.4.1` comparator accepts every stable **and**
  prerelease host from that point forward (including stable `2026.6.1`). A
  `||`-joined OR list silently fails that checker — OpenClaw reads the `||` as a
  literal token — and is the bug behind #1450, so it must stay a single
  comparator.
- **`peerDependencies.openclaw` → explicit `>=2026.4.1 || …prerelease hosts…`.**
  This field is resolved by npm/node-semver, which *does* support `||` but
  excludes prereleases from a bare `>=` range. The explicit list keeps reviewed
  prerelease hosts installable under strict peer-dependency resolution.

The adapter separately records `2026.6.11-beta.1` as the latest reviewed
OpenClaw npm-published target. Stable hosts through `2026.6.10` are covered by
the `>=2026.4.1` floor, while newly reviewed prereleases through
`2026.6.11-beta.1` stay explicit in the peer range for strict npm
peer-dependency resolution.

When adding newer OpenClaw manifest surfaces, keep older-compatible metadata in
place for hosts inside that 60-day window unless an upstream breaking change is
documented and unavoidable.

## Benchmarking The OpenClaw Chain

The benchmark CLI can now exercise the real OpenClaw-backed answer path instead
of only the stripped retrieval harness. Use the `openclaw-chain` runtime
profile to load the Remnic plugin config from `openclaw.json`, route answer
generation through the configured gateway chain, and optionally attach a
provider-backed judge:

```bash
remnic bench run longmemeval \
  --runtime-profile openclaw-chain \
  --openclaw-config ~/.openclaw/openclaw.json \
  --gateway-agent-id memory-primary

remnic bench run longmemeval \
  --runtime-profile openclaw-chain \
  --openclaw-config ~/.openclaw/openclaw.json \
  --gateway-agent-id memory-primary \
  --judge-provider openai \
  --judge-model gpt-5.4-mini
```

To compare the stripped harness, direct Remnic runtime, and OpenClaw chain in a
single pass, run a profile matrix:

```bash
remnic bench run longmemeval \
  --matrix baseline,real,openclaw-chain \
  --openclaw-config ~/.openclaw/openclaw.json \
  --remnic-config ~/.config/remnic/config.json
```

Each stored result records its `runtimeProfile`, provider metadata, and the
resolved Remnic config so benchmark comparisons can distinguish retrieval-only
runs from real runtime and OpenClaw chain runs.

## What it does

This plugin hooks into the OpenClaw gateway lifecycle:

- **`gateway_start`** -- initializes the Remnic memory engine
- **`before_agent_start`** / **`before_prompt_build`** -- adds relevant memories to the agent context through OpenClaw's memory context builders
- **`agent_end`** -- buffers the conversation turn for extraction
- **`before_compaction`** / **`after_compaction`** -- saves checkpoints and triggers session reset on context compaction
- **`before_reset`** -- bounded flush of the in-flight buffer before OpenClaw discards a session
- **`api.registerCommand()`** -- exposes Remnic slash-command descriptors to the command palette
- **`session_start`** / **`session_end`** -- session lifecycle tracking
- **`before_tool_call`** / **`after_tool_call`** -- tool usage observation for analytics
- **`llm_output`** -- LLM token usage tracking
- **`subagent_spawned`** / **`subagent_ended`** -- subagent lifecycle observation (replaced the deprecated `subagent_spawning` hook in issue #1550; core handles thread-bound subagent bindings)
- **Tools** -- registers `memory_search`, `memory_get`, `memory_stats`, and other agent tools
- **Commands** -- provides CLI commands for memory management

All memory processing uses [`@remnic/core`](https://www.npmjs.com/package/@remnic/core). Memory files stay on your local filesystem as plain markdown files. When the plugin is configured to use OpenAI, an OpenAI-compatible endpoint, or provider credentials resolved from OpenClaw runtime auth, conversation and memory excerpts may be sent to that configured model provider for extraction, consolidation, summarization, embeddings, active recall, or benchmark judging. Use `modelSource: "gateway"` and route the gateway agent to local or otherwise approved models when those operations should stay on your own OpenClaw/local model path.

Credential and model-provider behavior is explicit:

- `modelSource: "gateway"` is the recommended OpenClaw mode and uses OpenClaw gateway agents instead of a Remnic-owned API key.
- Plugin/provider modes may read configured model credentials from the OpenClaw auth resolver, OpenClaw's materialized provider config at `~/.openclaw/agents/main/agent/models.json`, or provider-specific environment variables such as `<PROVIDER>_API_KEY` and `<PROVIDER>_TOKEN`.
- Do not set `openaiApiKey` or provider environment variables for Remnic if you want all LLM-backed memory work routed through the gateway.

The npm package also declares this surface in `package.json` under
`openclaw.environment` so ClawHub and other registries can show the optional
provider env vars, config path, and external-model routing behavior before
installation.

## Privacy Boundary

OpenClaw hook runtime metadata such as authorization headers, API keys, provider
credential objects, and bearer tokens is operational metadata. Remnic does not
persist those fields to transcripts, extraction buffers, recall audit entries,
logs, or memory content.

User-authored message text is different: Remnic is a memory plugin, so message
content can be stored, extracted, summarized, embedded, or recalled according to
the configured memory policy. Do not paste secrets into chat when you do not
want them treated as conversation content.

## Plugin Inspection

Run the OpenClaw plugin inspector with:

```bash
npm run plugin:inspect
npm run plugin:inspect:runtime
```

The inspector gate covers the static OpenClaw adapter manifest, hook, tool, and
service surfaces. Some registrations are intentionally casted or dynamically
guarded in the adapter, including `registerMemoryCapability`, `registerCli`,
and `registerCommand`; keep runtime capture coverage for those surfaces in a
separate adapter test slice.

Run the deterministic OpenClaw adapter scenario suite with:

```bash
npm run test:openclaw-scenarios
```

The suite covers the registered memory tools and lifecycle hooks without live
OpenClaw, LLM credentials, or network calls.

Run the OpenClaw hook privacy suite with:

```bash
npm run test:openclaw-privacy
```

The suite guards against runtime auth metadata leaking into persisted memory,
transcript, recall-audit, or debug-log surfaces.

## SDK Surface Drift Check

The adapter keeps a conservative OpenClaw SDK surface snapshot at
`openclaw-sdk-surface.expected.json`. Run
`npm run check:openclaw-sdk-surface` after changing OpenClaw dependencies or
with `-- --package-root <path>` to check a local OpenClaw checkout. When an
upstream SDK change is intentional, review the adapter impact first, then
refresh the snapshot with `npm run check:openclaw-sdk-surface -- --write`.
CI jobs that provision OpenClaw should use
`npm run check:openclaw-sdk-surface:required` or pass
`-- --require --package-root <path>` so a missing SDK fails instead of skipping.

Last compatibility sweep: June 26, 2026, adding newly published prerelease
hosts through `openclaw@2026.6.11-beta.1` to the reviewed peer range. The
latest reviewed stable npm build is `openclaw@2026.6.10`; the latest reviewed
prerelease is `openclaw@2026.6.11-beta.1`. No Remnic adapter runtime change
was required — see `docs/plugins/openclaw.md` for the full sweep notes. Earlier
sweeps: the SDK surface check passed against
`openclaw@2026.5.3`, `openclaw@2026.5.3-1`, `openclaw@2026.5.4-beta.1`,
`openclaw@2026.5.4-beta.2`, `openclaw@2026.5.4-beta.3`,
`openclaw@2026.5.4`, `openclaw@2026.5.5`, `openclaw@2026.5.6`,
`openclaw@2026.5.16-beta.2`, `openclaw@2026.5.16-beta.3`, and
`openclaw@2026.5.16-beta.4`. The May 19 sweep also checked the source SDK
surface for `openclaw@2026.5.19-beta.1`, which covers the intervening
`2026.5.16-beta.6`, `2026.5.16-beta.7`, and `2026.5.18-beta.1` release line
for the Remnic adapter surfaces. The May 31 sweep checked source tags
`v2026.5.31-alpha.1` through `v2026.5.31-beta.3` and the issue window from
#1203 through #1245, excluding unrelated issue #1211. The June 2 sweep reviewed
Remnic issues #1258, #1259, #1266, and #1271 against OpenClaw tags
`v2026.5.31-beta.4`, `v2026.6.1-alpha.1`, `v2026.6.1-alpha.2`,
`v2026.6.1-alpha.3`, `v2026.6.1-beta.1`, `v2026.6.1-beta.2`,
`v2026.6.2-alpha.1`, and `v2026.6.2-alpha.2`. The existing SDK snapshot still
matched (`14 registrars, 22 hooks, 2 manifest contracts`) for each tag.
`v2026.6.2-alpha.1` and `v2026.6.2-alpha.2` exist as upstream source tags, but
as of June 2, 2026 they are not GitHub release pages or published npm packages.
The June 3 sweep reviewed issue #1312 against `v2026.6.1-beta.3` and
`v2026.6.3-alpha.1`; `v2026.6.3-alpha.1` exists as upstream source but was not
a GitHub release page at review time.

OpenClaw 2026.5.16 package-entry discovery prefers explicit built runtime
entries for installed packages. The published Remnic adapter declares
`openclaw.runtimeExtensions: ["./dist/index.js"]` alongside the existing
extension entry, and its package install metadata advertises
`openclaw.install.clawhubSpec: "clawhub:@remnic/plugin-openclaw"`,
`openclaw.install.npmSpec: "@remnic/plugin-openclaw"`, and
`openclaw.install.defaultChoice: "clawhub"`. That keeps OpenClaw setup,
repair, and update flows ClawHub-first while preserving npm as the fallback.
OpenClaw 2026.5.30-beta.1 may resolve bare package names npm-first during the
launch cutover, so operator docs should keep the explicit `clawhub:` prefix for
deterministic installs.

The manifest declares `activation.onStartup: false`, exposes the optional
plugin-mode OpenAI key through `providerAuthChoices`, and mirrors the
`OPENAI_API_KEY` env signal through `setup.providers[].envVars` for current
OpenClaw auth/status discovery. It keeps `providerAuthEnvVars.openai` mirrored
for older OpenClaw pre-runtime auth probes; current OpenClaw does not warn
because the env var is also present on `setup.providers[].envVars`.
Memory-slot selection is carried by `kind: "memory"` plus the normal
`plugins.slots.memory` config, and the legacy `supports` block remains for
OpenClaw 2026.4 / early 2026.5 slot and lifecycle routing. Privacy and
provider-data disclosures live in docs and package metadata instead of the
unsupported top-level `securityDisclosure` manifest field.

Earlier 2026.5.16 sweeps confirmed that Remnic still relies on host-owned
gateway restart/reload behavior after plugin install changes, uses
`gateway_stop` instead of the deprecated `deactivate` cleanup alias, and stays
on host-owned gateway/provider routing by default. Current OpenClaw setup/auth
surfaces read env-var status from `setup.providers[].envVars`, so Remnic mirrors
the optional plugin-mode OpenAI key there without adding top-level provider
ownership metadata.

OpenClaw 2026.5.16-beta.6 added `defineToolPlugin` and the authoring CLI for
simple typed tool-only plugins. Remnic intentionally stays on `definePluginEntry`
because the adapter owns mixed memory-slot hooks, lifecycle handlers, slash
command metadata, public artifacts, and runtime tools rather than only static
tools.

OpenClaw 2026.5.20-beta.2 through the reviewed `2026.6.3-alpha.1` source tag
keep the Remnic-required plugin install, ClawHub fallback, manifest contract,
hook, memory-slot, gateway LLM, and plugin security-scan surfaces compatible.
OpenClaw 2026.5.31-beta.4 added optional `plugin-sdk/chat-channel-ids` and
`plugin-sdk/memory-core-host-embedding-registry` subpaths, and
`2026.6.2-alpha.1`/`2026.6.2-alpha.2` add quoted-reply metadata fields to
inbound and `before_dispatch` hook contexts. Remnic consumes those optional
surfaces only through compatibility gates:

- `hostEmbeddingProviderEnabled` (default `true`) lets Remnic prefer
  OpenClaw memory/generic embedding providers for semantic fallback and
  embedded vector backends when the host SDK exposes them. Provider creation
  failures fall back to Remnic's existing embedding path.
- `openclawMessageReceivedCaptureEnabled` (default `true`) captures inbound
  `message_received` content into transcripts when the host emits that hook.
- `openclawReplyMetadataCaptureEnabled` (default `true`) stores bounded
  `messageId`, `threadId`, `replyToId`, `replyToBody`, and `replyToSender`
  transcript metadata.
- `openclawReplyMetadataExtractionHintsEnabled` (default `false`) prepends
  bounded quoted-reply context to user turns before extraction.
- `openclawChannelEnvelopeCleaningEnabled` (default `true`) uses OpenClaw's
  canonical channel envelope prefixes when the SDK subpath exists, with the
  legacy OpenClaw-only cleaner preserved for older hosts.

That sweep recorded `2026.6.2-alpha.2` as the reviewed OpenClaw source-tag
target and kept the stable `>=2026.4.1` installer floor plus reviewed
prerelease peer/plugin-API hosts eligible.

OpenClaw `2026.6.3-alpha.1` adds no required Remnic memory-adapter behavior.
The upstream diff from `v2026.6.2-alpha.2` confirms optional provider/exec/CLI
surfaces: `resolve_exec_env`, CLI backend `ownsNativeCompaction`, and
`ProviderNormalizeTransportContext.modelId`. Remnic does not register an exec
environment hook, does not provide a CLI backend, and does not implement
provider transport normalization, so these remain optional upstream surfaces
for future gated features. OpenClaw `2026.6.1-beta.3` was also reviewed as a
current prerelease host and did not change plugin docs or `src/plugins` from
`v2026.6.1-beta.2`. The package metadata records `2026.6.3-alpha.1` as the
reviewed target while explicitly accepting both prerelease tags and keeping
`openclaw.install.minHostVersion` at `>=2026.4.1` for older supported hosts.

OpenClaw 2026.5.31-beta.3 adds explicit command/callback semantics for
message-presentation controls. Remnic's current memory commands are text-first
and do not emit channel control buttons or selects, so no runtime adapter change
is required.

Native memory registrars are tracked separately in
[`docs/plugins/openclaw-native-memory-registrars.md`](../../docs/plugins/openclaw-native-memory-registrars.md).
That spike explains why Remnic currently uses `registerMemoryCapability()` as
the primary integration point instead of OpenClaw embedding, corpus supplement,
or compaction-provider registrars.

## Slot Selection

Remnic is an exclusive memory-slot plugin. When `plugins.slots.memory` points
to another plugin, Remnic now validates that mismatch and either errors or
loads passively depending on `slotBehavior`:

```jsonc
{
  "plugins": {
    "entries": {
      "openclaw-remnic": {
        "config": {
          "slotBehavior": {
            "requireExclusiveMemorySlot": true,
            "onSlotMismatch": "error"
          }
        }
      }
    }
  }
}
```

Passive mode keeps the tool/service surface available but skips context-building
and extraction hooks so two memory plugins do not race each other.

## Supported OpenClaw Memory Features

Remnic supports the following OpenClaw memory integration points:

### Memory Context Sections

| Feature | Status | Since |
|---------|--------|-------|
| `before_agent_start` hook (legacy) | Supported | 2025.x |
| `before_prompt_build` hook (new SDK) | Supported | 2026.3.22 |
| `registerMemoryPromptSection()` (structured builder) | Supported | 2026.3.22 |
| `registerMemoryCapability()` (unified capability) | Supported | 2026.4.5 |
| `registerMemoryRuntime()` (split runtime surface) | Supported | 2026.4.x |
| `registerMemoryFlushPlan()` (split flush-plan surface) | Supported | 2026.4.x |
| `registerMemoryCorpusSupplement()` (read-only corpus supplement) | Supported | 2026.4.x |

On current OpenClaw SDKs, Remnic registers both the unified memory capability
and the compatible split surfaces. That lets OpenClaw consume Remnic through
the active memory runtime, the explicit flush-plan resolver, and additive
corpus search/read APIs without changing Remnic's ownership of storage,
retrieval, extraction, and QMD behavior.

### Public Artifacts (memory-wiki bridge)

| Feature | Status | Since |
|---------|--------|-------|
| `publicArtifacts.listArtifacts()` | Supported | 2026.4.5 |

When `registerMemoryCapability` is available, Remnic registers a `publicArtifacts` provider that exposes wiki-safe memory files:

- **facts/** -- extracted knowledge (dated subdirectories)
- **entities/** -- entity knowledge graph
- **corrections/** -- fact corrections
- **artifacts/** -- structured artifacts
- **profile.md** -- agent identity summary

Private runtime state (state/, questions/, transcripts/, archive/, buffers) is never exposed.

With this feature, `openclaw wiki status` reports Remnic artifacts, and `memory-wiki` bridge mode can discover and ingest them.

The corpus supplement exposes read-only search/get access to Remnic memories as
the `remnic` corpus under a service-scoped supplement ID. It does not expose
private plugin state, transcript buffers, auth metadata, or artifact paths.

### Session Lifecycle

| Feature | Status | Since |
|---------|--------|-------|
| `session_start` / `session_end` hooks | Supported | 2026.3.22 |
| `before_compaction` / `after_compaction` hooks | Supported | 2026.3.22 |
| `before_reset` hook | Supported | 2026.4.10 |
| `api.registerCommand()` runtime discovery | Supported | 2026.5.16 |
| `api.resetSession()` (compaction reset) | Supported | 2026.3.22 |
| Checkpoint saves before compaction | Supported | 2026.3.22 |

Reset handling is configurable:

```jsonc
{
  "plugins": {
    "entries": {
      "openclaw-remnic": {
        "config": {
          "flushOnResetEnabled": true,
          "beforeResetTimeoutMs": 2000,
          "initGateTimeoutMs": 30000
        }
      }
    }
  }
}
```

The reset path clears per-session context caches and workspace preference state.
If `flushOnResetEnabled` is true, Remnic also attempts a bounded extraction
flush before the reset completes.

`initGateTimeoutMs` controls Remnic's cold-start init wait during recall and is
registered as the `before_prompt_build` hook timeout on OpenClaw versions with
per-hook timeout support. Raise it if first-turn recall is timing out during
slow startup; older OpenClaw versions ignore the extra hook option safely.

Session-scoped recall controls are exposed through OpenClaw's
`api.registerCommand()` surface when it is available:

- `remnic off` / `remnic on`
- `remnic status`
- `remnic clear`
- `remnic stats`
- `remnic flush`

When verbose mode is enabled, Remnic prints its recall decision header inline
and can optionally persist JSONL recall transcripts under
`<memoryDir>/state/plugins/openclaw-remnic/transcripts/`.

### Observation Hooks

| Feature | Status | Since |
|---------|--------|-------|
| `before_tool_call` / `after_tool_call` | Supported | 2026.3.22 |
| `llm_output` (token tracking) | Supported | 2026.3.22 |
| `subagent_spawned` / `subagent_ended` | Supported (replaced `subagent_spawning`) | 2026.3.22 |

### Dreaming

OpenClaw's dreaming feature (background memory consolidation) is handled by OpenClaw's built-in `memory-core` extension. Remnic implements its own consolidation pipeline (extraction, deduplication, graph maintenance, hourly summaries) that runs independently of OpenClaw's dreaming system. The two systems are complementary -- Remnic's consolidation handles the heavy memory extraction, while OpenClaw's dreaming (if enabled alongside Remnic) can further organize knowledge.

The plugin manifest now accepts the OpenClaw `dreaming` config block directly
so newer runtimes do not reject the config at validation time, and the OpenClaw
adapter now adds recent diary entries as `## Recent Dreams (Remnic)` when
the journal contains entries. The adapter also imports `DREAMS.md` entries into
Remnic storage as `memoryKind: "dream"` with stable provenance so file-watch
replays stay idempotent:

```jsonc
{
  "plugins": {
    "entries": {
      "openclaw-remnic": {
        "config": {
          "dreaming": {
            "enabled": false,
            "journalPath": "DREAMS.md",
            "maxEntries": 500,
            "injectRecentCount": 3,
            "minIntervalMinutes": 120,
            "narrativeModel": "gpt-5.5",
            "narrativePromptStyle": "reflective",
            "watchFile": true
          }
        }
      }
    }
  }
}
```

When Remnic's consolidation pass produces a reflective multi-session summary and
the interval gate is satisfied, the OpenClaw adapter appends a new dream entry
back to `DREAMS.md` through the shared writer using the OpenAI Responses API.

The shared `@remnic/core` surface parsers also understand `HEARTBEAT.md`. The
OpenClaw adapter imports those entries as `memoryKind: "procedural"`, gates
normal recall during heartbeat-triggered runs, adds the active heartbeat plus
`## Previous Runs`, and skips episodic buffering for heartbeat turns by default.
Detection can use explicit runtime metadata, a documented heuristic fallback, or
`auto` to prefer runtime metadata and fall back when needed. All of that logic
stays in the OpenClaw adapter; standalone/core remains host-agnostic.

## Codex Compatibility

Remnic now advertises and parses a dedicated `codexCompat` block for bundled
Codex-provider safety work:

```jsonc
{
  "plugins": {
    "entries": {
      "openclaw-remnic": {
        "config": {
          "codexCompat": {
            "enabled": false,
            "threadIdBufferKeying": true,
            "compactionFlushMode": "auto",
            "fingerprintDedup": true
          }
        }
      }
    }
  }
}
```

`codexCompat.enabled` defaults to `false`, so operators only opt into bundled
Codex thread buffering and compaction behavior when they explicitly enable it.

This governs Remnic's own buffering and extraction behavior only. Remnic still
uses its own extraction auth path; OpenClaw's bundled Codex provider auth does
not replace Remnic's extraction credentials.

### Bridge Mode

| Feature | Status |
|---------|--------|
| Embedded mode (in-process EMO + HTTP :4318) | Supported |
| Delegate mode (connects to running daemon) | Supported |
| Auto-detection (daemon running = delegate) | Supported |

## Standalone usage

If you're not using OpenClaw, use [`@remnic/cli`](https://www.npmjs.com/package/@remnic/cli) or [`@remnic/server`](https://www.npmjs.com/package/@remnic/server) instead.

## License

MIT
