Skip to main content

memory-ops

Use when OpenClaw memory or its embeddings are involved — embedding calls failing authorization or reporting an invalid token, vector search paused or returning nothing useful, an index-identity warning, a last-index timestamp far in the past, search still poor after the provider was fixed, choosing or changing an embedding provider, model or key, a reindex, or a state database that keeps growing and needs retention or compaction. This skill owns the subscription-session-versus-embedding-key distinction; chat-side credential and OAuth problems are provider-auth.

Source facts

Repository
Agents-Store/codex-plugins
Last source activity
November 1, 2026 at 02:46
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
4 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
memory-ops
description
Use when OpenClaw memory or its embeddings are involved — embedding calls failing authorization or reporting an invalid token, vector search paused or returning nothing useful, an index-identity warning, a last-index timestamp far in the past, search still poor after the provider was fixed, choosing or changing an embedding provider, model or key, a reindex, or a state database that keeps growing and needs retention or compaction. This skill owns the subscription-session-versus-embedding-key distinction; chat-side credential and OAuth problems are provider-auth.
# Memory operations ## How memory is put together - Three retrieval paths over one store: **full text**, **vectors**, and a hybrid that merges both. Full text needs no provider; vectors need an embedding provider and are the part that breaks. - The index lives in the **per-agent database** (`agents/<id>/agent/openclaw-agent.sqlite` under the state directory), beside that agent's sessions and transcripts — not in the shared state database. It is per agent and per instance, it is not shareable, and it is included in a state-directory archive — which is also why that archive grows with it. Because the database also holds canonical history, it is never deleted, nor are its `-wal` / `-shm` sidecars, to "reset" memory. - **Memory commands are per agent.** `memory status`, `index` and `reset` without `--agent` run for every configured agent; `search` and `forget` default to the default agent only. Say which agent you mean: `--agent <id>` on every call. - Text is **chunked** before embedding, and the chunking parameters are part of the index's identity (below), not a tuning knob you can change quietly. - Reads may be accelerated by a separate read-only process against the same store; it is a reader, so it cannot repair anything, and it does not clear a stuck state. - Current metrics — provider, model, last index time, database size — come from `${CLAUDE_PLUGIN_ROOT}/scripts/healthcheck.py <selector> --json`, never from memory. ## The one diagnostic idea worth carrying **An "invalid token" error on an embedding call is not an expired key. It is a session credential presented where an API key was required.** Subscription sign-in through a coding-CLI provider covers chat completions and **does not satisfy embedding requests** — this is documented behaviour, not a defect. The usual mechanism is that the embedding client inherits the OAuth profile configured for chat instead of a key of its own. Consequence for triage: an authorization failure on embeddings is almost never fixed by logging in again. Do not re-run a login to test it — a repeated OAuth refresh burns a single-use token and logs out another consumer. Read the embedding provider's configuration and ask a different question: *which credential is this call actually presenting, and is it a key at all?* (`fleet.memory.embeddings-unauthorized`; provider-by-provider in `references/embedding-providers.md`.) ## Index identity The index carries an identity derived from **provider + model + chunking + the key in use**. Change any one of them and the identity no longer matches what is stored: - vector search **pauses** with an identity warning; it does not silently return wrong hits; - reindexing is **explicit only** — nothing re-embeds by itself, no matter how long it waits; - because the key is part of the identity, **rotating an embedding key forces a reindex everywhere it changed**, including instances where the key was "just replaced" with an equivalent one. Plan a key change as a reindex programme, not as a config edit (`fleet.memory.index-identity-changed`). Read the warning with `memory status --agent <id> --deep`, rebuild with `memory index --force --agent <id>` (`memory status --index --agent <id>` rebuilds an incompatible index too, and implies the deep probe — it is not a plain read). A full rebuild is built in a temporary database and published atomically, and a failed rebuild leaves the published index intact — so a reindex is an R3 for its **provider cost and load**, not for a risk of corrupting the index. ## Fail-closed is a feature When a non-local embedding provider is configured explicitly, failures **fail closed**: no quiet downgrade to full-text. That is the property that makes the whole subsystem observable — if embeddings were failing and search silently degraded, nothing would ever tell you. So absence of errors is real evidence that the vector path works (`fleet.memory.fail-closed-silent`). The corollary: never "fix" a broken provider by removing it from the config. That converts a loud failure into a silent one, and search quality drops with nobody watching. ## Stuck on the fallback After a provider outage, search can stay on the fallback model **even once the provider is healthy again**. A reload does not clear it; **only a full restart of the gateway does**. Any instance that sat in a provider failure for a long stretch should be assumed stuck until a restart proves otherwise — the "fix worked but search is still bad" report is this, nearly every time (`fleet.memory.search-stuck-fallback`). ## Giving an instance its own embedding key 1. Snapshot the state directory first — this path ends in a reindex, which is R3. 2. Put a **per-instance** key in the secret store. A key shared across instances makes one revocation a fleet-wide outage and makes per-instance spend unattributable. 3. **Verify delivery by name, never by value.** Ask the container whether the environment name is populated and how long the value is; the value itself is never printed, logged, or read into context. A name that is referenced but not delivered is `fleet.secrets.delivery-short` — the feature is silently dead while the config looks correct. 4. Reference the secret **by name** in the config. A literal key in config is a leak the moment the config is backed up, diffed, or pasted. 5. **Full restart**, not a reload — see above. 6. **Reindex explicitly** (`memory index --force --agent <id>`, once per agent), one instance at a time, outside peak hours. Reindexing is the expensive part: it re-embeds the corpus, so it costs provider spend and competes with live traffic. ## Retention and size: use the supported tools The embedding cache is **bounded** — the oldest entries are pruned in batches against an existing cap, and a full rebuild trims it before publishing — but the database as a whole still grows with sessions, transcripts and the index, and nothing in memory retention removes canonical history (`fleet.memory.db-growth`). Start from `memory status --agent <id> --json`: database and WAL sizes, reusable (free) bytes, retained cache payload and per-source chunk payloads. These figures overlap — do not add them up, and a large file alone does not say which table is responsible. The supported tools, each an **R3** (a verified backup shown in the plan first, the gateway stopped where it says so): | Need | Command | What it does and does not do | |---|---|---| | remove memory derived from chosen sessions, participants or sources | `memory forget --agent <id> …` — **`--dry-run` first** | deletes **immediately** with no prompt; transcripts are retained; this, not reset, is the privacy tool | | discard the derived index and cache, then rebuild | `memory reset --agent <id> --yes`, then `memory index --agent <id>` | drops and recreates only memory-owned tables; sessions, transcripts and memory files are untouched; **does not shrink the file** | | give the space back | `doctor --session-sqlite compact --session-sqlite-agent <id>` for an agent database, `doctor --state-sqlite compact` for the shared one | checkpoints, compacts and verifies integrity; needs **temporary disk space** and the gateway and other writers stopped, and they stay stopped through reset and compaction so indexing cannot refill the cache | Order when both apply: verified backup → stop the gateway through its deployment owner → reset → compact → start → reindex → a smoke query that must return vector hits (not a health endpoint, which is green either way). If only free pages need reclaiming, skip the reset and keep the index. **Hand-editing the tables is no longer a path.** Deleting cache rows with a SQL client was the operator-owned procedure when nothing supported it; the commands above replace it, and a manual `DELETE` is now outside upstream's support and an R4. Never delete the database file or its sidecars. Before planning any of it, check that these verbs exist on this build (`--help`); if the gateway is down, the database verbs run in a one-off container over the stopped state directory (cold mode — `database` and `doctor` are the admitted verbs). ## Common mistakes - Reading a key value to diagnose an authorization failure. Presence, fingerprint, size and expiry answer every question the value could, and the value cannot be un-printed. - Re-running a login against an embeddings error — wrong credential class, and it burns a token. - Changing provider, model or chunking and expecting search to recover on its own. - Reloading instead of restarting after a provider is fixed. - Deleting rows, or the database file, by hand when `memory reset`, `memory forget` and the compaction verbs exist — the file also holds the agent's canonical history. - Running `memory forget` without `--dry-run` first: it deletes at once, with no prompt. - Compacting a running instance, or skipping the compaction and reporting freed space. - Calling a reindex "cheap" — it is provider spend plus load, one instance at a time.
View on GitHub