Lossless Context Management plugin for OpenClaw, based on the LCM paper from Voltropy. Replaces OpenClaw's built-in sliding-window compaction with a DAG-based summarization system that preserves every message while keeping active context within model token limits.
Two ways to learn: read the below, or check out this super cool animated visualization.
When a conversation grows beyond the model's context window, OpenClaw (just like all of the other agents) normally truncates older messages. LCM instead:
lcm_grep, lcm_describe, lcm_expand) so agents can search and recall details from compacted historyNothing is lost. Raw messages stay in the database. Summaries link back to their source messages. Agents can drill into any summary to recover the original detail.
It feels like talking to an agent that never forgets. Because it doesn't. In normal operation, you'll never need to think about compaction again.
The package installs an agent-oriented lcm shell CLI and includes a bundled lossless-claw skill plus plugin commands for supported OpenClaw chat/native command providers.
The shell CLI reads lcm.db without modifying conversation data. Its only write command sets one validated Lossless config value in openclaw.json:
lcm status
lcm conversations show --session-key 'agent:main:example'
lcm messages tail --conversation-id 42
lcm summaries list --conversation-id 42 --depth 0 --recency 7d
lcm config get freshTailCount
lcm config set freshTailCount 96
JSON is the default output. List commands use bounded keyset pagination. See Lossless Claw CLI for commands, filters, path precedence, output fields, config-write safety, and exit codes.
The native OpenClaw command surface provides in-session operations:
/lossless shows version, enablement/selection state, DB path and size, summary counts, and summary-health status/lossless backup creates a timestamped backup of the current LCM SQLite database/lossless doctor scans for broken or truncated summaries/lossless doctor maintenance reports active actionable compaction debt separately from inactive historical debt, grouped by reason, without writing/lossless doctor apply maintenance <conversation-id> confirm-inactive administratively closes one eligible inactive debt row after creating a SQLite backup/lossless doctor apply repairs broken summaries in the current conversation after the normal safety preflight/lossless doctor apply <conversation-id> confirm-offline repairs a specific conversation after its active channel path has been paused or moved away; targeted repair is restricted to authorized OpenClaw command senders and always requires the explicit offline confirmation/lossless doctor clean shows read-only high-confidence junk diagnostics for archived subagents and cron sessions under every configured OpenClaw agent id, plus NULL-key orphaned subagent runs/lossless status shows plugin, conversation, and maintenance state including deferred compaction debt/lcm is the shorter alias for /losslessSupported native command examples:
/lossless/lossless backup/lossless doctor/lossless doctor maintenance/lossless doctor apply maintenance 42 confirm-inactive/lossless doctor apply 42 confirm-offline/lossless doctor clean/lcmThe package does not register these OpenClaw root subcommands:
openclaw losslessopenclaw lcmopenclaw /losslessopenclaw /lcmThe bundled skill focuses on configuration, diagnostics, architecture, and recall-tool usage. Its reference set lives under skills/lossless-claw/references/.
Deferred compaction debt on an active conversation is actionable maintenance pressure. Debt on an archived or otherwise inactive conversation is historical: normal stable-session maintenance cannot select that conversation, so /lossless doctor maintenance reports it separately and shows a bounded set of recent examples. Closing historical debt requires the exact confirm-inactive token and a successful file-backed SQLite backup. The close records an operator-ignored resolution on the maintenance row only; it does not run compaction and does not delete or rewrite conversations, messages, summaries, or context items. If that conversation later receives a genuine new debt request, the prior administrative resolution is cleared and the row becomes pending again.
Lossless-claw also exposes an optional host-facing context-engine control contract for OpenClaw gateways that support context-engine capabilities and control dispatch. The contract is intentionally smaller than the native slash command surface:
status returns whether an LCM conversation is active and the current stored message count.doctor returns a bounded, sanitized warning list for summary-health issues.Programmatic control never returns transcript text, local database paths, backup paths, credentials, provider debug, or shell output.
This surface is capability-gated by the OpenClaw host. At the time of this change there is not yet a stable OpenClaw release with the required context-engine control endpoints; downstream users should treat it as unavailable unless their host advertises the matching capability, for example through the pending openclaw/openclaw#98060 contract or an equivalent downstream gateway.
lossless-claw-migrate-sessions is a one-time shell CLI for backfilling OpenClaw JSONL session files into lcm.db after lossless-claw was disabled, missing, or installed after sessions already existed. It is not a background replay loop and it does not run summarization.
Run it in dry-run mode first:
npx --package @martian-engineering/lossless-claw@latest lossless-claw-migrate-sessions --state-dir ~/.openclaw
Apply the import only after reviewing the dry-run output:
npx --package @martian-engineering/lossless-claw@latest lossless-claw-migrate-sessions --state-dir ~/.openclaw --apply
The command defaults to ${OPENCLAW_STATE_DIR:-~/.openclaw} and ${OPENCLAW_STATE_DIR:-~/.openclaw}/lcm.db. --apply creates a timestamped SQLite backup before writing when the database already exists. Use --file <path> or repeatable --sessions-dir <path> for targeted imports, --since <iso-date> or --limit <n> to narrow a batch, and --json for machine-readable output.
Compatibility:
lossless-clawrequires OpenClaw2026.7.2-beta.2or newer. That beta is the first published build with the branch-safe visible transcript projection used to bootstrap SQLite-backed sessions; stable2026.7.1does not provide it. If you cannot use a beta or upgrade OpenClaw, stay on alossless-clawrelease compatible with your installed OpenClaw version.
On OpenClaw hosts that advertise the durable context-engine turn contract,
LosslessClaw declares current-turn transcript fencing and commits each accepted
turn through an atomic idempotency ledger. Older supported hosts continue to use
the existing afterTurn compatibility path.
Upgrade compatibility: Lossless Claw 1.x accepts
transcriptGcEnabledandautoRotateSessionFilesso 0.15 configs continue to load. It ignores both settings and warns at startup. Remove them after upgrading; OpenClaw owns active transcript storage and session-file rotation.
Lossless Claw 1.0 stable releases use npm's latest channel. The beta
channel remains available for prerelease testing.
Use OpenClaw's plugin installer (recommended):
openclaw plugins install @martian-engineering/lossless-claw@latest
If you're running from a local OpenClaw checkout, use:
pnpm openclaw plugins install @martian-engineering/lossless-claw@latest
Use exact versions only for rollback or reproducible canary testing. OpenClaw records an exact install spec such as @martian-engineering/lossless-claw@0.12.0 as a pinned update track, so OpenClaw plugin update sync will keep that version until you move back to the stable track:
openclaw plugins update @martian-engineering/lossless-claw@latest
For local plugin development, build your working copy first, then link it instead of copying files:
cd /path/to/lossless-claw
pnpm build
openclaw plugins install --link /path/to/lossless-claw
# or from a local OpenClaw checkout:
# pnpm openclaw plugins install --link /path/to/lossless-claw
Re-run pnpm build after local source changes so the linked plugin's dist/ output stays current.
The install command records the plugin, enables it, and applies compatible slot selection (including contextEngine when applicable).
Note: If your OpenClaw config uses
plugins.allow, allowlist the plugin idlossless-clawplus any other active plugins you rely on. Do not add command tokens or aliases likelosslessor/lcmtoplugins.allow; that setting only accepts plugin ids. In some setups, narrowing the allowlist can prevent plugin-backed integrations from loading, even iflossless-clawitself is installed correctly. Restart the gateway after plugin config changes.
Ensure the context engine slot points at lossless-claw and explicitly allow its conversation prompt hook:
{
"plugins": {
"slots": {
"contextEngine": "lossless-claw"
},
"entries": {
"lossless-claw": {
"hooks": {
"allowConversationAccess": true
}
}
}
}
}
OpenClaw builds that protect before_prompt_build as a conversation-access hook
require this grant. Without it, the context engine still loads, but OpenClaw
blocks Lossless's static recall-policy prompt hook and logs the missing setting.
The grant belongs beside config, not inside it.
Restart OpenClaw after configuration changes.
LCM is configured through a combination of plugin config and environment variables. Environment variables take precedence for backward compatibility.
Add a lossless-claw entry under plugins.entries in your OpenClaw config:
{
"plugins": {
"entries": {
"lossless-claw": {
"enabled": true,
"hooks": {
"allowConversationAccess": true
},
"llm": {
"allowModelOverride": true,
"allowedModels": ["openai/gpt-5.4-mini"]
},
"config": {
"freshTailCount": 64,
"leafChunkTokens": 80000,
"newSessionRetainDepth": 2,
"contextThreshold": 0.75,
"contextThresholdOverrides": [
{
"name": "large-context-models",
"match": { "modelContextWindowMin": 900000 },
"contextThreshold": 0.15
},
{
"name": "telegram-sessions",
"match": { "sessionPattern": "agent:*:telegram:**" },
"contextThreshold": 0.3
}
],
"incrementalMaxDepth": 1,
"cacheAwareCompaction": {
"enabled": true,
"cacheTTLSeconds": 300
},
"ignoreSessionPatterns": [
"agent:*:cron:**",
"agent:*:**:active-memory:**",
"agent:*:dreaming-narrative-**"
],
"proactiveThresholdCompactionMode": "deferred",
"summaryModel": "openai/gpt-5.4-mini",
"expansionModel": "openai/gpt-5.4-mini",
"delegationTimeoutMs": 300000,
"summaryTimeoutMs": 60000,
"summaryCallWindowMs": 600000,
"summaryMaxCallsPerWindow": 24,
"summarySpendBackoffMs": 1800000
}
}
}
}
}
The ignoreSessionPatterns entries in this example are storage exclusions. Matching cron, active-memory, and OpenClaw memory-core dreaming narrative sessions do not create LCM conversation rows or store messages in LCM.
leafChunkTokens controls how many source tokens can accumulate in a leaf compaction chunk before summarization is triggered. The default is 20000, but quota-limited summary providers may benefit from a larger value to reduce compaction frequency. summaryModel and summaryProvider let you request a cheaper or faster compaction model through OpenClaw's api.runtime.llm.complete capability; OpenClaw still owns provider dispatch and auth. Explicit summary model requests require llm.allowModelOverride and matching llm.allowedModels policy entries for lossless-claw. expansionModel does the same for lcm_expand_query sub-agent calls (drilling into summaries to recover detail). delegationTimeoutMs controls how long lcm_expand_query waits for that delegated sub-agent to finish before returning a timeout error; it defaults to 120000 (120s). summaryTimeoutMs controls the per-call timeout for model-backed LCM summarization; it defaults to 60000 (60s). summaryMaxCallsPerWindow, summaryCallWindowMs, and summarySpendBackoffMs bound repeated non-auth summarization spend per session. When unset, the model settings still fall back to OpenClaw's configured default model/provider. See Expansion model override requirements for the required subagent trust policy when using expansionModel.
| Variable | Default | Description |
|---|---|---|
LCM_ENABLED | true | Enable/disable the plugin |
LCM_DATABASE_PATH | ~/.openclaw/lcm.db | Path to the SQLite database |
LCM_IGNORE_SESSION_PATTERNS | "" | Comma-separated glob patterns for session keys to exclude from LCM storage |
LCM_STATELESS_SESSION_PATTERNS | "" | Comma-separated glob patterns for session keys that may read from LCM but never write to it |
LCM_SKIP_STATELESS_SESSIONS | true | Enable stateless-session write skipping for matching session keys |
LCM_CONTEXT_THRESHOLD | 0.75 | Fraction of context window that triggers compaction (0.0–1.0) |
LCM_FRESH_TAIL_COUNT | 64 | Number of recent messages protected from compaction |
LCM_NEW_SESSION_RETAIN_DEPTH | 2 | Context retained after /new (-1 keeps all context, 2 keeps d2+) |
LCM_LEAF_MIN_FANOUT | 8 | Minimum raw messages per leaf summary |
LCM_CONDENSED_MIN_FANOUT | 4 | Minimum summaries per condensed node |
LCM_CONDENSED_MIN_FANOUT_HARD | 2 | Relaxed fanout for forced compaction sweeps |
LCM_INCREMENTAL_MAX_DEPTH | 1 | How deep incremental compaction goes (0 = leaf only, 1 = one condensed pass, -1 = unlimited) |
LCM_LEAF_CHUNK_TOKENS | 20000 | Max source tokens per leaf compaction chunk |
LCM_LEAF_TARGET_TOKENS | 2400 | Target token count for leaf summaries |
LCM_CONDENSED_TARGET_TOKENS | 2000 | Target token count for condensed summaries |
LCM_MAX_EXPAND_TOKENS | 4000 | Token cap for sub-agent expansion queries |
LCM_LARGE_FILE_TOKEN_THRESHOLD | 25000 | File blocks above this size are intercepted and stored separately |
LCM_LARGE_FILE_SUMMARY_PROVIDER | "" | Provider override for large-file summarization |
LCM_LARGE_FILE_SUMMARY_MODEL | "" | Model override for large-file summarization |
LCM_SUMMARY_MODEL | "" | Model override for compaction summarization; falls back to OpenClaw's default model when unset |
LCM_SUMMARY_PROVIDER | "" | Provider override for compaction summarization; falls back to OPENCLAW_PROVIDER or the provider embedded in the model ref |
LCM_SUMMARY_BASE_URL | (from OpenClaw / provider default) | Base URL override for summarization API calls |
LCM_EXPANSION_MODEL | (from OpenClaw) | Model override for lcm_expand_query sub-agent (e.g. openai/gpt-5.4-mini) |
LCM_EXPANSION_PROVIDER | (from OpenClaw) | Provider override for lcm_expand_query sub-agent |
LCM_DELEGATION_TIMEOUT_MS | 120000 | Max time to wait for delegated lcm_expand_query sub-agent completion |
LCM_SUMMARY_TIMEOUT_MS | 60000 | Max time to wait for a single model-backed LCM summarizer call |
LCM_SUMMARY_CALL_WINDOW_MS | 600000 | Rolling window used by the per-session summarization spend guard |
LCM_SUMMARY_MAX_CALLS_PER_WINDOW | 24 | Max model-backed summarization calls per session/window before spend backoff opens |
LCM_SUMMARY_SPEND_BACKOFF_MS | 1800000 | Cooldown after the summarization spend guard opens |
LCM_PRUNE_HEARTBEAT_OK | false | Retroactively delete HEARTBEAT_OK turn cycles from LCM storage |
LCM_PROACTIVE_THRESHOLD_COMPACTION_MODE | deferred | Choose whether proactive threshold compaction is deferred into maintenance debt or kept inline for legacy behavior |
LCM_CACHE_TTL_SECONDS | 300 | Cache TTL used by cache-aware deferred compaction when provider/runtime telemetry does not supply a more specific retention window |
Deferred proactive compaction is also the default. Set proactiveThresholdCompactionMode or LCM_PROACTIVE_THRESHOLD_COMPACTION_MODE to inline only if you need legacy foreground compaction behavior. In deferred mode, lossless-claw records one coalesced prompt-mutating debt item after the turn, leaves background maintain() to process only non-prompt-mutating work while Anthropic cache is still hot, and then consumes that debt pre-assembly once the cache is cold or the prompt is approaching overflow.
If you want lcm_expand_query to run on a dedicated model via expansionModel or LCM_EXPANSION_MODEL, OpenClaw must explicitly trust the plugin to request sub-agent model overrides.
For most setups, openai/gpt-5.4-mini is a better starting point than Anthropic Haiku because it is cheap, fast, and does not depend on Anthropic quota remaining.
Add a subagent policy under plugins.entries.lossless-claw and allowlist the canonical provider/model target you want the plugin to use:
{
"models": {
"openai/gpt-4.1-mini": {}
},
"plugins": {
"entries": {
"lossless-claw": {
"enabled": true,
"subagent": {
"allowModelOverride": true,
"allowedModels": ["openai/gpt-4.1-mini"]
},
"config": {
"expansionModel": "openai/gpt-4.1-mini"
}
}
}
}
}
subagent.allowModelOverride is required for OpenClaw to honor plugin-requested per-run provider/model overrides.subagent.allowedModels is optional but recommended. Use "*" only if you intentionally want to trust any target model.models map as shown above.config.expansionProvider and use a bare config.expansionModel.openclaw doctor --fix can add the required subagent policy for a configured expansionModel. If a host still rejects a stale or unavailable override, lcm_expand_query retries once without the override so recall does not fail hard.Plugin config equivalents:
ignoreSessionPatternsstatelessSessionPatternsskipStatelessSessionsnewSessionRetainDepthsummaryModelsummaryProviderdelegationTimeoutMssummaryTimeoutMsEnvironment variables still win over plugin config when both are set.
For compaction summarization, lossless-claw resolves the model in this order:
LCM_SUMMARY_MODEL / LCM_SUMMARY_PROVIDERsummaryModel / summaryProviderIf summaryModel already includes a provider prefix such as anthropic/claude-sonnet-4-20250514, summaryProvider is ignored for that choice. Otherwise, the provider falls back to the matching override, then OPENCLAW_PROVIDER, then the provider inferred by the caller.
Summary calls are dispatched through OpenClaw's runtime LLM layer, so auth profiles, OAuth refresh, API keys, base URLs, and provider-specific request preparation remain host-owned. Run openclaw doctor --fix after adding explicit summary model overrides if you want OpenClaw to add the matching plugins.entries.lossless-claw.llm policy.
LCM_FRESH_TAIL_COUNT=64
LCM_LEAF_CHUNK_TOKENS=20000
LCM_INCREMENTAL_MAX_DEPTH=1
LCM_CONTEXT_THRESHOLD=0.75
LCM_SUMMARY_MODEL=openai/gpt-5.4-mini
LCM_EXPANSION_MODEL=openai/gpt-5.4-mini
0 for leaf-only behavior, a larger positive integer for a deeper cap, or -1 for unlimited cascading.contextThreshold.Lossless-claw distinguishes OpenClaw's two session-reset commands:
/new keeps the active conversation row and all stored summaries, but prunes context_items so the next turn rebuilds context from retained summaries instead of the fresh tail./reset archives the active conversation row and creates a new active row for the same stable sessionKey, giving the next turn a clean LCM conversation while preserving prior history.Lossless-claw no longer rewrites active OpenClaw transcripts for GC or session rotation. SQLite-backed OpenClaw owns active transcript storage; Lossless keeps durable conversation, summary, and recall data in its own SQLite database. If you want an LCM database snapshot before maintenance, run /lossless backup.
newSessionRetainDepth (or LCM_NEW_SESSION_RETAIN_DEPTH) controls how much summary structure survives /new:
-1: keep all existing context items0: keep all summaries, drop only fresh-tail messages1: keep d1+ summaries2: keep d2+ summaries; recommended default3+: keep only deeper, more abstract summariesLossless-claw applies /new pruning through before_reset and uses session_end to catch transcript rollovers such as /reset, idle or daily session rotation, compaction session replacement, and deletions. User-facing confirmation text after /new or /reset must still be emitted by OpenClaw's command handlers.
Use ignoreSessionPatterns or LCM_IGNORE_SESSION_PATTERNS to keep low-value sessions completely out of LCM. Matching sessions do not create conversations, do not store messages, and do not participate in compaction or delegated expansion grants.
Cron scheduler keys (agent:<agent>:cron:<job>...) are isolated automatically when OpenClaw reuses the same sessionKey for a new runtime sessionId: lossless-claw archives the prior active run and creates a fresh LCM conversation for the new run. Leave cron sessions out of ignoreSessionPatterns when they need in-run LCM compaction.
Pattern rules:
* matches any characters except :** matches anything, including :Examples:
agent:*:cron:** excludes cron sessions for any agent when you want to bypass LCM entirelyagent:*:**:active-memory:** excludes active-memory sessions under nested session-key prefixes; the ** segment is intentionally broad because it spans colon-separated session-key segmentsagent:*:dreaming-narrative-** excludes OpenClaw memory-core dreaming narrative sessions; OpenClaw builds those keys with the dreaming-narrative- prefix (source)agent:main:subagent:** excludes all main-agent subagent sessionsagent:ops:** excludes every session under the ops agent idTreat these examples as storage exclusions. Matching sessions do not create LCM conversation rows or store messages in LCM, so use them only for lanes whose history can stay outside LCM.
Environment variable example:
LCM_IGNORE_SESSION_PATTERNS=agent:*:cron:**,agent:main:subagent:**
Plugin config example:
{
"plugins": {
"entries": {
"lossless-claw": {
"config": {
"ignoreSessionPatterns": [
"agent:*:cron:**",
"agent:main:subagent:**"
]
}
}
}
}
}
Use statelessSessionPatterns or LCM_STATELESS_SESSION_PATTERNS for sessions that should still be able to read from existing LCM context, but should never create or mutate LCM state themselves. This is useful for delegated or temporary sub-agent sessions that should benefit from retained context without polluting the database.
When skipStatelessSessions or LCM_SKIP_STATELESS_SESSIONS is enabled, matching sessions:
Pattern rules are the same as ignoreSessionPatterns, and matching is done against the full session key.
Environment variable example:
LCM_STATELESS_SESSION_PATTERNS=agent:*:subagent:**,agent:ops:subagent:**
LCM_SKIP_STATELESS_SESSIONS=true
Plugin config example:
{
"plugins": {
"entries": {
"lossless-claw": {
"config": {
"statelessSessionPatterns": [
"agent:*:subagent:**",
"agent:ops:subagent:**"
],
"skipStatelessSessions": true
}
}
}
}
}
LCM preserves history through compaction, but it does not change OpenClaw's core session reset policy. If sessions are resetting sooner than you want, increase OpenClaw's session.reset.idleMinutes or use a channel/type-specific override.
{
"session": {
"reset": {
"mode": "idle",
"idleMinutes": 10080
}
}
}
session.reset.mode: "idle" keeps a session alive until the idle window expires.session.reset.idleMinutes is the actual reset interval in minutes.idleMinutes; in source it is validated only as a positive integer.idleMinutes acts as a secondary guard and the session resets when either the daily boundary or the idle window is reached first.session.idleMinutes still works, but OpenClaw prefers session.reset.idleMinutes.Useful values:
1440 = 1 day10080 = 7 days43200 = 30 days525600 = 365 daysFor most long-lived LCM setups, a good starting point is:
{
"session": {
"reset": {
"mode": "idle",
"idleMinutes": 10080
}
}
}
# Build (bundles TypeScript to dist/index.js)
pnpm build
# Run tests
npx vitest
# Type check
npx tsc --noEmit
# Run a specific test file
npx vitest test/engine.test.ts
index.ts # Plugin entry point and registration
src/
engine.ts # LcmContextEngine — implements ContextEngine interface
assembler.ts # Context assembly (summaries + messages → model context)
compaction.ts # CompactionEngine — leaf passes, condensation, sweeps
summarize.ts # Depth-aware prompt generation and LLM summarization
retrieval.ts # RetrievalEngine — grep, describe, expand operations
expansion.ts # DAG expansion logic for lcm_expand_query
expansion-auth.ts # Delegation grants for sub-agent expansion
expansion-policy.ts # Depth/token policy for expansion
large-files.ts # File interception, storage, and exploration summaries
transcript-repair.ts # Tool-use/result pairing sanitization
types.ts # Core type definitions (dependency injection contracts)
openclaw-bridge.ts # Bridge utilities
db/
config.ts # LcmConfig resolution from env vars
connection.ts # SQLite connection management
migration.ts # Schema migrations
store/
conversation-store.ts # Message persistence and retrieval
summary-store.ts # Summary DAG persistence and context item management
fts5-sanitize.ts # FTS5 query sanitization
tools/
lcm-grep-tool.ts # lcm_grep tool implementation
lcm-describe-tool.ts # lcm_describe tool implementation
lcm-expand-tool.ts # lcm_expand tool (sub-agent only)
lcm-expand-query-tool.ts # lcm_expand_query tool (main agent wrapper)
lcm-conversation-scope.ts # Conversation scoping utilities
common.ts # Shared tool utilities
test/ # Vitest test suite
specs/ # Design specifications
openclaw.plugin.json # Plugin manifest with config schema and UI hints
tui/ # Interactive terminal UI (Go)
main.go # Entry point and bubbletea app
data.go # Data loading and SQLite queries
dissolve.go # Summary dissolution
repair.go # Corrupted summary repair
rewrite.go # Summary re-summarization
transplant.go # Cross-conversation DAG copy
prompts/ # Depth-aware prompt templates
.goreleaser.yml # GoReleaser config for TUI binary releases
This repository codifies LF line endings through .gitattributes so diffs stay
stable across macOS, Linux, and Windows development environments.
* text=auto eol=lf rule normalizes newly added text files.binary to avoid unsafe
newline conversion.Please report suspected vulnerabilities privately. See SECURITY.md for the supported disclosure process and response expectations.
MIT
(top 30 of 92)
TypeScript
88.2%
Go
10.1%
JavaScript
1.5%
Lossless Context Management plugin for OpenClaw, based on the LCM paper from Voltropy. Replaces OpenClaw's built-in sliding-window compaction with a DAG-based summarization system that preserves every message while keeping active context within model token limits.
Two ways to learn: read the below, or check out this super cool animated visualization.
When a conversation grows beyond the model's context window, OpenClaw (just like all of the other agents) normally truncates older messages. LCM instead:
lcm_grep, lcm_describe, lcm_expand) so agents can search and recall details from compacted historyNothing is lost. Raw messages stay in the database. Summaries link back to their source messages. Agents can drill into any summary to recover the original detail.
It feels like talking to an agent that never forgets. Because it doesn't. In normal operation, you'll never need to think about compaction again.
The package installs an agent-oriented lcm shell CLI and includes a bundled lossless-claw skill plus plugin commands for supported OpenClaw chat/native command providers.
The shell CLI reads lcm.db without modifying conversation data. Its only write command sets one validated Lossless config value in openclaw.json:
lcm status
lcm conversations show --session-key 'agent:main:example'
lcm messages tail --conversation-id 42
lcm summaries list --conversation-id 42 --depth 0 --recency 7d
lcm config get freshTailCount
lcm config set freshTailCount 96
JSON is the default output. List commands use bounded keyset pagination. See Lossless Claw CLI for commands, filters, path precedence, output fields, config-write safety, and exit codes.
The native OpenClaw command surface provides in-session operations:
/lossless shows version, enablement/selection state, DB path and size, summary counts, and summary-health status/lossless backup creates a timestamped backup of the current LCM SQLite database/lossless doctor scans for broken or truncated summaries/lossless doctor maintenance reports active actionable compaction debt separately from inactive historical debt, grouped by reason, without writing/lossless doctor apply maintenance <conversation-id> confirm-inactive administratively closes one eligible inactive debt row after creating a SQLite backup/lossless doctor apply repairs broken summaries in the current conversation after the normal safety preflight/lossless doctor apply <conversation-id> confirm-offline repairs a specific conversation after its active channel path has been paused or moved away; targeted repair is restricted to authorized OpenClaw command senders and always requires the explicit offline confirmation/lossless doctor clean shows read-only high-confidence junk diagnostics for archived subagents and cron sessions under every configured OpenClaw agent id, plus NULL-key orphaned subagent runs/lossless status shows plugin, conversation, and maintenance state including deferred compaction debt/lcm is the shorter alias for /losslessSupported native command examples:
/lossless/lossless backup/lossless doctor/lossless doctor maintenance/lossless doctor apply maintenance 42 confirm-inactive/lossless doctor apply 42 confirm-offline/lossless doctor clean/lcmThe package does not register these OpenClaw root subcommands:
openclaw losslessopenclaw lcmopenclaw /losslessopenclaw /lcmThe bundled skill focuses on configuration, diagnostics, architecture, and recall-tool usage. Its reference set lives under skills/lossless-claw/references/.
Deferred compaction debt on an active conversation is actionable maintenance pressure. Debt on an archived or otherwise inactive conversation is historical: normal stable-session maintenance cannot select that conversation, so /lossless doctor maintenance reports it separately and shows a bounded set of recent examples. Closing historical debt requires the exact confirm-inactive token and a successful file-backed SQLite backup. The close records an operator-ignored resolution on the maintenance row only; it does not run compaction and does not delete or rewrite conversations, messages, summaries, or context items. If that conversation later receives a genuine new debt request, the prior administrative resolution is cleared and the row becomes pending again.
Lossless-claw also exposes an optional host-facing context-engine control contract for OpenClaw gateways that support context-engine capabilities and control dispatch. The contract is intentionally smaller than the native slash command surface:
status returns whether an LCM conversation is active and the current stored message count.doctor returns a bounded, sanitized warning list for summary-health issues.Programmatic control never returns transcript text, local database paths, backup paths, credentials, provider debug, or shell output.
This surface is capability-gated by the OpenClaw host. At the time of this change there is not yet a stable OpenClaw release with the required context-engine control endpoints; downstream users should treat it as unavailable unless their host advertises the matching capability, for example through the pending openclaw/openclaw#98060 contract or an equivalent downstream gateway.
lossless-claw-migrate-sessions is a one-time shell CLI for backfilling OpenClaw JSONL session files into lcm.db after lossless-claw was disabled, missing, or installed after sessions already existed. It is not a background replay loop and it does not run summarization.
Run it in dry-run mode first:
npx --package @martian-engineering/lossless-claw@latest lossless-claw-migrate-sessions --state-dir ~/.openclaw
Apply the import only after reviewing the dry-run output:
npx --package @martian-engineering/lossless-claw@latest lossless-claw-migrate-sessions --state-dir ~/.openclaw --apply
The command defaults to ${OPENCLAW_STATE_DIR:-~/.openclaw} and ${OPENCLAW_STATE_DIR:-~/.openclaw}/lcm.db. --apply creates a timestamped SQLite backup before writing when the database already exists. Use --file <path> or repeatable --sessions-dir <path> for targeted imports, --since <iso-date> or --limit <n> to narrow a batch, and --json for machine-readable output.
Compatibility:
lossless-clawrequires OpenClaw2026.7.2-beta.2or newer. That beta is the first published build with the branch-safe visible transcript projection used to bootstrap SQLite-backed sessions; stable2026.7.1does not provide it. If you cannot use a beta or upgrade OpenClaw, stay on alossless-clawrelease compatible with your installed OpenClaw version.
On OpenClaw hosts that advertise the durable context-engine turn contract,
LosslessClaw declares current-turn transcript fencing and commits each accepted
turn through an atomic idempotency ledger. Older supported hosts continue to use
the existing afterTurn compatibility path.
Upgrade compatibility: Lossless Claw 1.x accepts
transcriptGcEnabledandautoRotateSessionFilesso 0.15 configs continue to load. It ignores both settings and warns at startup. Remove them after upgrading; OpenClaw owns active transcript storage and session-file rotation.
Lossless Claw 1.0 stable releases use npm's latest channel. The beta
channel remains available for prerelease testing.
Use OpenClaw's plugin installer (recommended):
openclaw plugins install @martian-engineering/lossless-claw@latest
If you're running from a local OpenClaw checkout, use:
pnpm openclaw plugins install @martian-engineering/lossless-claw@latest
Use exact versions only for rollback or reproducible canary testing. OpenClaw records an exact install spec such as @martian-engineering/lossless-claw@0.12.0 as a pinned update track, so OpenClaw plugin update sync will keep that version until you move back to the stable track:
openclaw plugins update @martian-engineering/lossless-claw@latest
For local plugin development, build your working copy first, then link it instead of copying files:
cd /path/to/lossless-claw
pnpm build
openclaw plugins install --link /path/to/lossless-claw
# or from a local OpenClaw checkout:
# pnpm openclaw plugins install --link /path/to/lossless-claw
Re-run pnpm build after local source changes so the linked plugin's dist/ output stays current.
The install command records the plugin, enables it, and applies compatible slot selection (including contextEngine when applicable).
Note: If your OpenClaw config uses
plugins.allow, allowlist the plugin idlossless-clawplus any other active plugins you rely on. Do not add command tokens or aliases likelosslessor/lcmtoplugins.allow; that setting only accepts plugin ids. In some setups, narrowing the allowlist can prevent plugin-backed integrations from loading, even iflossless-clawitself is installed correctly. Restart the gateway after plugin config changes.
Ensure the context engine slot points at lossless-claw and explicitly allow its conversation prompt hook:
{
"plugins": {
"slots": {
"contextEngine": "lossless-claw"
},
"entries": {
"lossless-claw": {
"hooks": {
"allowConversationAccess": true
}
}
}
}
}
OpenClaw builds that protect before_prompt_build as a conversation-access hook
require this grant. Without it, the context engine still loads, but OpenClaw
blocks Lossless's static recall-policy prompt hook and logs the missing setting.
The grant belongs beside config, not inside it.
Restart OpenClaw after configuration changes.
LCM is configured through a combination of plugin config and environment variables. Environment variables take precedence for backward compatibility.
Add a lossless-claw entry under plugins.entries in your OpenClaw config:
{
"plugins": {
"entries": {
"lossless-claw": {
"enabled": true,
"hooks": {
"allowConversationAccess": true
},
"llm": {
"allowModelOverride": true,
"allowedModels": ["openai/gpt-5.4-mini"]
},
"config": {
"freshTailCount": 64,
"leafChunkTokens": 80000,
"newSessionRetainDepth": 2,
"contextThreshold": 0.75,
"contextThresholdOverrides": [
{
"name": "large-context-models",
"match": { "modelContextWindowMin": 900000 },
"contextThreshold": 0.15
},
{
"name": "telegram-sessions",
"match": { "sessionPattern": "agent:*:telegram:**" },
"contextThreshold": 0.3
}
],
"incrementalMaxDepth": 1,
"cacheAwareCompaction": {
"enabled": true,
"cacheTTLSeconds": 300
},
"ignoreSessionPatterns": [
"agent:*:cron:**",
"agent:*:**:active-memory:**",
"agent:*:dreaming-narrative-**"
],
"proactiveThresholdCompactionMode": "deferred",
"summaryModel": "openai/gpt-5.4-mini",
"expansionModel": "openai/gpt-5.4-mini",
"delegationTimeoutMs": 300000,
"summaryTimeoutMs": 60000,
"summaryCallWindowMs": 600000,
"summaryMaxCallsPerWindow": 24,
"summarySpendBackoffMs": 1800000
}
}
}
}
}
The ignoreSessionPatterns entries in this example are storage exclusions. Matching cron, active-memory, and OpenClaw memory-core dreaming narrative sessions do not create LCM conversation rows or store messages in LCM.
leafChunkTokens controls how many source tokens can accumulate in a leaf compaction chunk before summarization is triggered. The default is 20000, but quota-limited summary providers may benefit from a larger value to reduce compaction frequency. summaryModel and summaryProvider let you request a cheaper or faster compaction model through OpenClaw's api.runtime.llm.complete capability; OpenClaw still owns provider dispatch and auth. Explicit summary model requests require llm.allowModelOverride and matching llm.allowedModels policy entries for lossless-claw. expansionModel does the same for lcm_expand_query sub-agent calls (drilling into summaries to recover detail). delegationTimeoutMs controls how long lcm_expand_query waits for that delegated sub-agent to finish before returning a timeout error; it defaults to 120000 (120s). summaryTimeoutMs controls the per-call timeout for model-backed LCM summarization; it defaults to 60000 (60s). summaryMaxCallsPerWindow, summaryCallWindowMs, and summarySpendBackoffMs bound repeated non-auth summarization spend per session. When unset, the model settings still fall back to OpenClaw's configured default model/provider. See Expansion model override requirements for the required subagent trust policy when using expansionModel.
| Variable | Default | Description |
|---|---|---|
LCM_ENABLED | true | Enable/disable the plugin |
LCM_DATABASE_PATH | ~/.openclaw/lcm.db | Path to the SQLite database |
LCM_IGNORE_SESSION_PATTERNS | "" | Comma-separated glob patterns for session keys to exclude from LCM storage |
LCM_STATELESS_SESSION_PATTERNS | "" | Comma-separated glob patterns for session keys that may read from LCM but never write to it |
LCM_SKIP_STATELESS_SESSIONS | true | Enable stateless-session write skipping for matching session keys |
LCM_CONTEXT_THRESHOLD | 0.75 | Fraction of context window that triggers compaction (0.0–1.0) |
LCM_FRESH_TAIL_COUNT | 64 | Number of recent messages protected from compaction |
LCM_NEW_SESSION_RETAIN_DEPTH | 2 | Context retained after /new (-1 keeps all context, 2 keeps d2+) |
LCM_LEAF_MIN_FANOUT | 8 | Minimum raw messages per leaf summary |
LCM_CONDENSED_MIN_FANOUT | 4 | Minimum summaries per condensed node |
LCM_CONDENSED_MIN_FANOUT_HARD | 2 | Relaxed fanout for forced compaction sweeps |
LCM_INCREMENTAL_MAX_DEPTH | 1 | How deep incremental compaction goes (0 = leaf only, 1 = one condensed pass, -1 = unlimited) |
LCM_LEAF_CHUNK_TOKENS | 20000 | Max source tokens per leaf compaction chunk |
LCM_LEAF_TARGET_TOKENS | 2400 | Target token count for leaf summaries |
LCM_CONDENSED_TARGET_TOKENS | 2000 | Target token count for condensed summaries |
LCM_MAX_EXPAND_TOKENS | 4000 | Token cap for sub-agent expansion queries |
LCM_LARGE_FILE_TOKEN_THRESHOLD | 25000 | File blocks above this size are intercepted and stored separately |
LCM_LARGE_FILE_SUMMARY_PROVIDER | "" | Provider override for large-file summarization |
LCM_LARGE_FILE_SUMMARY_MODEL | "" | Model override for large-file summarization |
LCM_SUMMARY_MODEL | "" | Model override for compaction summarization; falls back to OpenClaw's default model when unset |
LCM_SUMMARY_PROVIDER | "" | Provider override for compaction summarization; falls back to OPENCLAW_PROVIDER or the provider embedded in the model ref |
LCM_SUMMARY_BASE_URL | (from OpenClaw / provider default) | Base URL override for summarization API calls |
LCM_EXPANSION_MODEL | (from OpenClaw) | Model override for lcm_expand_query sub-agent (e.g. openai/gpt-5.4-mini) |
LCM_EXPANSION_PROVIDER | (from OpenClaw) | Provider override for lcm_expand_query sub-agent |
LCM_DELEGATION_TIMEOUT_MS | 120000 | Max time to wait for delegated lcm_expand_query sub-agent completion |
LCM_SUMMARY_TIMEOUT_MS | 60000 | Max time to wait for a single model-backed LCM summarizer call |
LCM_SUMMARY_CALL_WINDOW_MS | 600000 | Rolling window used by the per-session summarization spend guard |
LCM_SUMMARY_MAX_CALLS_PER_WINDOW | 24 | Max model-backed summarization calls per session/window before spend backoff opens |
LCM_SUMMARY_SPEND_BACKOFF_MS | 1800000 | Cooldown after the summarization spend guard opens |
LCM_PRUNE_HEARTBEAT_OK | false | Retroactively delete HEARTBEAT_OK turn cycles from LCM storage |
LCM_PROACTIVE_THRESHOLD_COMPACTION_MODE | deferred | Choose whether proactive threshold compaction is deferred into maintenance debt or kept inline for legacy behavior |
LCM_CACHE_TTL_SECONDS | 300 | Cache TTL used by cache-aware deferred compaction when provider/runtime telemetry does not supply a more specific retention window |
Deferred proactive compaction is also the default. Set proactiveThresholdCompactionMode or LCM_PROACTIVE_THRESHOLD_COMPACTION_MODE to inline only if you need legacy foreground compaction behavior. In deferred mode, lossless-claw records one coalesced prompt-mutating debt item after the turn, leaves background maintain() to process only non-prompt-mutating work while Anthropic cache is still hot, and then consumes that debt pre-assembly once the cache is cold or the prompt is approaching overflow.
If you want lcm_expand_query to run on a dedicated model via expansionModel or LCM_EXPANSION_MODEL, OpenClaw must explicitly trust the plugin to request sub-agent model overrides.
For most setups, openai/gpt-5.4-mini is a better starting point than Anthropic Haiku because it is cheap, fast, and does not depend on Anthropic quota remaining.
Add a subagent policy under plugins.entries.lossless-claw and allowlist the canonical provider/model target you want the plugin to use:
{
"models": {
"openai/gpt-4.1-mini": {}
},
"plugins": {
"entries": {
"lossless-claw": {
"enabled": true,
"subagent": {
"allowModelOverride": true,
"allowedModels": ["openai/gpt-4.1-mini"]
},
"config": {
"expansionModel": "openai/gpt-4.1-mini"
}
}
}
}
}
subagent.allowModelOverride is required for OpenClaw to honor plugin-requested per-run provider/model overrides.subagent.allowedModels is optional but recommended. Use "*" only if you intentionally want to trust any target model.models map as shown above.config.expansionProvider and use a bare config.expansionModel.openclaw doctor --fix can add the required subagent policy for a configured expansionModel. If a host still rejects a stale or unavailable override, lcm_expand_query retries once without the override so recall does not fail hard.Plugin config equivalents:
ignoreSessionPatternsstatelessSessionPatternsskipStatelessSessionsnewSessionRetainDepthsummaryModelsummaryProviderdelegationTimeoutMssummaryTimeoutMsEnvironment variables still win over plugin config when both are set.
For compaction summarization, lossless-claw resolves the model in this order:
LCM_SUMMARY_MODEL / LCM_SUMMARY_PROVIDERsummaryModel / summaryProviderIf summaryModel already includes a provider prefix such as anthropic/claude-sonnet-4-20250514, summaryProvider is ignored for that choice. Otherwise, the provider falls back to the matching override, then OPENCLAW_PROVIDER, then the provider inferred by the caller.
Summary calls are dispatched through OpenClaw's runtime LLM layer, so auth profiles, OAuth refresh, API keys, base URLs, and provider-specific request preparation remain host-owned. Run openclaw doctor --fix after adding explicit summary model overrides if you want OpenClaw to add the matching plugins.entries.lossless-claw.llm policy.
LCM_FRESH_TAIL_COUNT=64
LCM_LEAF_CHUNK_TOKENS=20000
LCM_INCREMENTAL_MAX_DEPTH=1
LCM_CONTEXT_THRESHOLD=0.75
LCM_SUMMARY_MODEL=openai/gpt-5.4-mini
LCM_EXPANSION_MODEL=openai/gpt-5.4-mini
0 for leaf-only behavior, a larger positive integer for a deeper cap, or -1 for unlimited cascading.contextThreshold.Lossless-claw distinguishes OpenClaw's two session-reset commands:
/new keeps the active conversation row and all stored summaries, but prunes context_items so the next turn rebuilds context from retained summaries instead of the fresh tail./reset archives the active conversation row and creates a new active row for the same stable sessionKey, giving the next turn a clean LCM conversation while preserving prior history.Lossless-claw no longer rewrites active OpenClaw transcripts for GC or session rotation. SQLite-backed OpenClaw owns active transcript storage; Lossless keeps durable conversation, summary, and recall data in its own SQLite database. If you want an LCM database snapshot before maintenance, run /lossless backup.
newSessionRetainDepth (or LCM_NEW_SESSION_RETAIN_DEPTH) controls how much summary structure survives /new:
-1: keep all existing context items0: keep all summaries, drop only fresh-tail messages1: keep d1+ summaries2: keep d2+ summaries; recommended default3+: keep only deeper, more abstract summariesLossless-claw applies /new pruning through before_reset and uses session_end to catch transcript rollovers such as /reset, idle or daily session rotation, compaction session replacement, and deletions. User-facing confirmation text after /new or /reset must still be emitted by OpenClaw's command handlers.
Use ignoreSessionPatterns or LCM_IGNORE_SESSION_PATTERNS to keep low-value sessions completely out of LCM. Matching sessions do not create conversations, do not store messages, and do not participate in compaction or delegated expansion grants.
Cron scheduler keys (agent:<agent>:cron:<job>...) are isolated automatically when OpenClaw reuses the same sessionKey for a new runtime sessionId: lossless-claw archives the prior active run and creates a fresh LCM conversation for the new run. Leave cron sessions out of ignoreSessionPatterns when they need in-run LCM compaction.
Pattern rules:
* matches any characters except :** matches anything, including :Examples:
agent:*:cron:** excludes cron sessions for any agent when you want to bypass LCM entirelyagent:*:**:active-memory:** excludes active-memory sessions under nested session-key prefixes; the ** segment is intentionally broad because it spans colon-separated session-key segmentsagent:*:dreaming-narrative-** excludes OpenClaw memory-core dreaming narrative sessions; OpenClaw builds those keys with the dreaming-narrative- prefix (source)agent:main:subagent:** excludes all main-agent subagent sessionsagent:ops:** excludes every session under the ops agent idTreat these examples as storage exclusions. Matching sessions do not create LCM conversation rows or store messages in LCM, so use them only for lanes whose history can stay outside LCM.
Environment variable example:
LCM_IGNORE_SESSION_PATTERNS=agent:*:cron:**,agent:main:subagent:**
Plugin config example:
{
"plugins": {
"entries": {
"lossless-claw": {
"config": {
"ignoreSessionPatterns": [
"agent:*:cron:**",
"agent:main:subagent:**"
]
}
}
}
}
}
Use statelessSessionPatterns or LCM_STATELESS_SESSION_PATTERNS for sessions that should still be able to read from existing LCM context, but should never create or mutate LCM state themselves. This is useful for delegated or temporary sub-agent sessions that should benefit from retained context without polluting the database.
When skipStatelessSessions or LCM_SKIP_STATELESS_SESSIONS is enabled, matching sessions:
Pattern rules are the same as ignoreSessionPatterns, and matching is done against the full session key.
Environment variable example:
LCM_STATELESS_SESSION_PATTERNS=agent:*:subagent:**,agent:ops:subagent:**
LCM_SKIP_STATELESS_SESSIONS=true
Plugin config example:
{
"plugins": {
"entries": {
"lossless-claw": {
"config": {
"statelessSessionPatterns": [
"agent:*:subagent:**",
"agent:ops:subagent:**"
],
"skipStatelessSessions": true
}
}
}
}
}
LCM preserves history through compaction, but it does not change OpenClaw's core session reset policy. If sessions are resetting sooner than you want, increase OpenClaw's session.reset.idleMinutes or use a channel/type-specific override.
{
"session": {
"reset": {
"mode": "idle",
"idleMinutes": 10080
}
}
}
session.reset.mode: "idle" keeps a session alive until the idle window expires.session.reset.idleMinutes is the actual reset interval in minutes.idleMinutes; in source it is validated only as a positive integer.idleMinutes acts as a secondary guard and the session resets when either the daily boundary or the idle window is reached first.session.idleMinutes still works, but OpenClaw prefers session.reset.idleMinutes.Useful values:
1440 = 1 day10080 = 7 days43200 = 30 days525600 = 365 daysFor most long-lived LCM setups, a good starting point is:
{
"session": {
"reset": {
"mode": "idle",
"idleMinutes": 10080
}
}
}
# Build (bundles TypeScript to dist/index.js)
pnpm build
# Run tests
npx vitest
# Type check
npx tsc --noEmit
# Run a specific test file
npx vitest test/engine.test.ts
index.ts # Plugin entry point and registration
src/
engine.ts # LcmContextEngine — implements ContextEngine interface
assembler.ts # Context assembly (summaries + messages → model context)
compaction.ts # CompactionEngine — leaf passes, condensation, sweeps
summarize.ts # Depth-aware prompt generation and LLM summarization
retrieval.ts # RetrievalEngine — grep, describe, expand operations
expansion.ts # DAG expansion logic for lcm_expand_query
expansion-auth.ts # Delegation grants for sub-agent expansion
expansion-policy.ts # Depth/token policy for expansion
large-files.ts # File interception, storage, and exploration summaries
transcript-repair.ts # Tool-use/result pairing sanitization
types.ts # Core type definitions (dependency injection contracts)
openclaw-bridge.ts # Bridge utilities
db/
config.ts # LcmConfig resolution from env vars
connection.ts # SQLite connection management
migration.ts # Schema migrations
store/
conversation-store.ts # Message persistence and retrieval
summary-store.ts # Summary DAG persistence and context item management
fts5-sanitize.ts # FTS5 query sanitization
tools/
lcm-grep-tool.ts # lcm_grep tool implementation
lcm-describe-tool.ts # lcm_describe tool implementation
lcm-expand-tool.ts # lcm_expand tool (sub-agent only)
lcm-expand-query-tool.ts # lcm_expand_query tool (main agent wrapper)
lcm-conversation-scope.ts # Conversation scoping utilities
common.ts # Shared tool utilities
test/ # Vitest test suite
specs/ # Design specifications
openclaw.plugin.json # Plugin manifest with config schema and UI hints
tui/ # Interactive terminal UI (Go)
main.go # Entry point and bubbletea app
data.go # Data loading and SQLite queries
dissolve.go # Summary dissolution
repair.go # Corrupted summary repair
rewrite.go # Summary re-summarization
transplant.go # Cross-conversation DAG copy
prompts/ # Depth-aware prompt templates
.goreleaser.yml # GoReleaser config for TUI binary releases
This repository codifies LF line endings through .gitattributes so diffs stay
stable across macOS, Linux, and Windows development environments.
* text=auto eol=lf rule normalizes newly added text files.binary to avoid unsafe
newline conversion.Please report suspected vulnerabilities privately. See SECURITY.md for the supported disclosure process and response expectations.
MIT
(top 30 of 92)
TypeScript
88.2%
Go
10.1%
JavaScript
1.5%