返回 Skills
martian-engineering/lossless-claw· MIT 内容可用

lossless-claw

Configure, diagnose, and use lossless-claw effectively in OpenClaw, with emphasis on key settings, summary health, and recall-tool usage.

安装

与 skills.sh 相同的 Command / Prompt 安装方式


name: lossless-claw description: Configure, diagnose, and use lossless-claw effectively in OpenClaw, with emphasis on key settings, summary health, and recall-tool usage.

Lossless Claw

Use this skill when the task is about operating, tuning, or debugging the lossless-claw OpenClaw plugin.

Start here:

  1. Confirm whether the user needs configuration help, diagnostics, recall-tool guidance, or session-lifecycle guidance.
  2. If they need a quick health check, tell them to run /lossless (/lcm is the shorter alias).
  3. If they are debugging lossless-claw behavior or failures, check the independent Lossless log before the shared OpenClaw gateway log.
  4. If they suspect summary corruption or truncation, use /lossless doctor.
  5. If they want high-confidence junk/session cleanup guidance, use /lossless doctor clean before recommending any deletes.
  6. If they ask how /new, /reset, or /lossless rotate interacts with LCM, read the session-lifecycle reference before answering.
  7. If they ask how to import old or past OpenClaw conversation data into Lossless, read the session-lifecycle reference before answering.
  8. Load the relevant reference file instead of improvising details from memory.

Reference map:

  • Configuration (complete config surface on current main): references/config.md
  • Internal model and data flow: references/architecture.md
  • Diagnostics and summary-health workflow: references/diagnostics.md
  • Recall tools and when to use them: references/recall-tools.md
  • /new, /reset, /lossless rotate, and past-session import behavior with current lossless-claw session mapping: references/session-lifecycle.md

Working rules:

  • Prioritize explaining why a setting matters, not just what it does.
  • Prefer the native plugin command surface for MVP workflows (/lossless, with /lcm as alias).
  • Do not assume the Go TUI is installed.
  • Do not recommend advanced rewrite/backfill/transplant/dissolve flows unless the user explicitly asks for non-MVP internals. If the user specifically asks to import old or past OpenClaw conversation data into Lossless, recommend the packaged session migration CLI instead of TUI backfill/surgery flows.
  • For exact evidence retrieval from compacted history, guide the user toward recall tools instead of guessing from summaries.
  • When users compare /lossless to /status, explain that they report different layers: /lossless shows LCM-side frontier/summary metrics, while /status shows the last assembled runtime prompt snapshot.

附带文件

references/architecture.md
# Architecture

`lossless-claw` stores full conversation history in SQLite and uses summaries to keep active context within model limits.

## Core flow

1. Messages are persisted into the LCM database.
2. Older messages are compacted into leaf summaries.
3. Leaf summaries can be condensed into higher-depth summaries.
4. Context assembly mixes summaries with the fresh raw tail.
5. Recall tools let agents drill back into compacted material when precision matters.

## Mental model

Think of LCM as two layers:

- durable storage of the full conversation record
- a summary DAG used to present compacted context efficiently

The summary DAG is not the source of truth. Raw messages remain the ground truth.

## Why summary quality matters

Bad summaries do not stay local:

- poor leaf summaries degrade condensed summaries
- poor condensed summaries degrade future recall
- aggressive truncation reduces the precision of downstream answers

That is why configuration choices around compaction thresholds and summary model quality matter operationally.

## What `/lossless` tells you

The MVP command surface focuses on operational facts:

- package version
- whether the plugin is enabled and selected
- database path and size
- summary counts
- total summarized source-token coverage when available
- broken or truncated summary presence

## What `/lossless doctor` tells you

The `/lossless doctor` scan is diagnostic only.

It looks for known summary-health markers that indicate:

- deterministic fallback summaries
- truncated summary artifacts near the end of stored content

This gives users one place to answer the question “is my summary graph healthy?” without introducing a broader mutation surface.

`/lossless doctor apply` is the separate backup-first mutation surface for repairing detected summaries. Current-conversation repair keeps the normal large/hot safety preflight. Targeting another conversation by id requires `/lossless doctor apply <conversation-id> confirm-offline` after the target's active channel path has been isolated.

## What `/lossless doctor clean` tells you

The cleaners flow is also diagnostic first.

It reports high-confidence junk patterns that are structurally safe to review as standalone cleanup candidates, including:

- archived subagent sessions
- cron sessions
- NULL-key orphaned subagent context conversations

This keeps cleanup discovery separate from summary-health diagnostics while still using the same native command surface.
references/config.md
# Configuration

This reference covers the current `lossless-claw` config surface on `main`, based on `openclaw.plugin.json`, [`docs/configuration.md`](../../../docs/configuration.md), and the runtime defaults in [`src/db/config.ts`](../../../src/db/config.ts).

`lossless-claw` is most effective when the operator understands which settings change compaction behavior and why.

## First checks

- Ensure the plugin is installed and enabled.
- Ensure the context-engine slot points at `lossless-claw` when you want it to own compaction.
- Run `/lossless` (`/lcm` alias) to confirm the plugin is active and see the live DB path.

## High-impact settings

These are the settings most operators should understand first.

### `contextThreshold`

Controls how full the model context can get before LCM compacts older material.

- Lower values compact earlier.
- Higher values compact later.

Why it matters:

- Too low increases summarization cost and churn.
- Too high risks hitting the model window with large tool output or long replies.

Good default:

- `0.75`

### `contextThresholdOverrides`

Optional ordered rules that choose a different compaction threshold, and optionally a different fresh-tail count or leaf chunk size, for matching runtime contexts.

Supported match fields:

- `model`: exact runtime model id, such as `openai/gpt-5.5`
- `modelContextWindowMin`: match models/windows at or above this token count
- `modelContextWindowMax`: match models/windows at or below this token count
- `sessionPattern`: session-key glob, using the same `*` and `**` semantics as ignored/stateless sessions

Rules are AND-matched: if a rule includes both `model` and `sessionPattern`, both must match. If multiple rules match, Lossless picks the highest-specificity rule, then the earliest rule in the array for ties. If no rule matches, it falls back to global `contextThreshold`, `freshTailCount`, and `leafChunkTokens`. If a matching rule includes `freshTailCount`, Lossless uses that value for assembly and threshold compaction. If it includes `leafChunkTokens`, Lossless uses that value for matching threshold sweeps.

Context-window matchers require explicit model context-window metadata from the OpenClaw host. Lossless does not infer those matches from the active token budget. Use exact `model` or `sessionPattern` rules when an override must affect assemble-time `freshTailCount` on all currently supported OpenClaw hosts.

Example:

```json
{
  "contextThreshold": 0.75,
  "contextThresholdOverrides": [
    {
      "name": "large-context-models",
      "match": { "modelContextWindowMin": 900000 },
      "contextThreshold": 0.15,
      "freshTailCount": 16,
      "leafChunkTokens": 12000
    },
    {
      "name": "telegram-sessions",
      "match": { "sessionPattern": "agent:*:telegram:**" },
      "contextThreshold": 0.3
    }
  ]
}
```

Debugging:

- threshold-selection logs include the selected threshold, source, rule index/name, token budget, threshold tokens, fresh-tail count, model, context-window value, and match reason
- there is no env-var override for `contextThresholdOverrides`; use plugin config for structured rules

### `freshTailCount`

Keeps the newest messages raw instead of compacting them.

Why it matters:

- Higher values preserve near-term conversational nuance.
- Lower values free context budget sooner.

Good starting range:

- `32` to `64`

### `freshTailMaxTokens`

Optional token cap for the protected fresh tail.

Why it matters:

- Prevents a few huge tool results from making the "fresh" suffix effectively uncompactable.
- Still preserves the newest message even if that single message exceeds the cap.

Good starting range:

- Leave unset unless large tool outputs are forcing avoidable cost or overflow.
- Start around `12000` to `32000` when you want a softer, size-aware fresh tail.

### `promptAwareEviction`

Controls whether budget-constrained assembly keeps older context by prompt relevance or pure chronology.

Why it matters:

- when enabled, lossless-claw can keep an older but on-topic summary instead of a newer irrelevant one
- this can improve retrieval quality when the assembled context is tight
- it also makes the preserved prompt prefix less stable, which can reduce prefix-based prompt-cache hit rates

Good default:

- `false`
- enable it only when topical older-context recall under tight budgets matters more than prompt-cache stability

### `stubLargeToolPayloads`

Controls whether older, evictable tool-result rows that were backfilled into the `large_files` store are assembled as compact `[LCM Tool Output: file_xxx ...]` stubs instead of full inline payloads.

Why it matters:

- it reuses the existing `large_files` drilldown path for old tool output without changing the fresh tail
- it can recover substantially more historical context at the same token budget in tool-heavy sessions
- it should stay off until the operator has run `scripts/lcm-blob-migrate.mjs` for the target database

Good default:

- `false`
- enable it only after migration and live validation

### `leafChunkTokens`

Caps how much raw material gets summarized into one leaf summary.

Why it matters:

- Larger chunks reduce summarization frequency.
- Smaller chunks create more summaries and more DAG fragmentation.
- The default is 20000 tokens.

Use this when:

- Your summarizer is rate-limited or expensive.
- You want fewer but broader leaf summaries.

### `cacheAwareCompaction`

Deprecated compatibility object. Lossless still accepts and reports these settings, but automatic compaction no longer uses prompt-cache hot/cold state.

Why it matters:

- Existing OpenClaw configs continue to load without schema errors.
- Operators can see that the settings are deprecated instead of silently losing familiar keys.
- Prompt-cache telemetry remains useful for diagnostics, but it no longer gates compaction.

Good defaults:

- Leave existing values in place during migration.
- Do not tune these settings to affect automatic compaction; use `contextThreshold`, `leafChunkTokens`, and fanout instead.

Operationally:

- threshold debt does not wait for cache TTL
- cold-cache catch-up passes have been removed
- cache-aware raw-history pressure no longer triggers automatic maintenance

### `dynamicLeafChunkTokens`

Deprecated compatibility object. Automatic compaction now uses `leafChunkTokens` directly.

Why it matters:

- Existing config stays accepted.
- The resolved default still appears in status/config output.
- It no longer changes automatic compaction chunk size.

Good defaults:

- `enabled: true`
- `max: 2 * leafChunkTokens`

With the default `leafChunkTokens=20000`, that means:

- `dynamicLeafChunkTokens.max = 40000`

### `sweepMaxDepth`

Controls how far routine threshold full-sweep condensation tries to cascade after leaf compaction.

Why it matters:

- `0` keeps only leaf summaries moving automatically.
- `1` is a practical default for long-running sessions.
- `-1` allows unlimited cascading, which can be useful for very long histories but is more aggressive.
- This is a preferred depth, not an absolute cap. Pressure sweeps may go deeper when summarized context remains too large.

### `summaryPrefixTargetTokens`

Optional target for summarized-prefix tokens after a full sweep.

Why it matters:

- Gives Lossless an escape hatch when too many summaries at the preferred depth still leave the prompt near full.
- When unset, Lossless derives a target from `contextThreshold`, the active token budget, and `leafChunkTokens`.
- Sweeps first exhaust eligible raw-message leaf chunks, then honor `sweepMaxDepth`; pressure condensation can go deeper only when summary-prefix pressure remains.

### `maxSweepIterations`

Hard cap on summarizer passes within a single full sweep. Default `12`.

Why it matters:

- A large conversation can otherwise drive an unbounded number of leaf/condensed passes in one sweep.
- On hitting the cap the sweep stops cleanly and returns the partial result; the next sweep resumes the remaining work.
- Bounds how long a sweep can run on the turn-critical path (the `assemble()` deferred-debt drain).

### `sweepDeadlineMs`

Wall-clock budget for a single full sweep, in milliseconds. Default `120000`.

Why it matters:

- A slow or rate-limited summarizer can burn a full `summaryTimeoutMs` per pass; without a deadline, many passes compound into tens of minutes.
- When the deadline is exceeded the sweep stops before starting another pass and returns the partial result.
- Pairs with `maxSweepIterations`: whichever limit is reached first stops the sweep.

### `compactUntilUnderDeadlineMs`

Wall-clock budget for a whole `compactUntilUnder` (overflow recovery) operation, in milliseconds. Default `300000`.

Why it matters:

- `compactUntilUnder` runs up to `maxRounds` sweeps, and each sweep re-arms its own `sweepDeadlineMs`; without an operation-wide budget the worst case is `maxRounds × sweepDeadlineMs` (~20 minutes at the defaults).
- The deadline is shared into each round's sweep — a sweep stops at whichever deadline is sooner — and is also checked before starting the next round.
- On hitting it, `compactUntilUnder` returns the consistent partial result; the default leaves room for a few full-deadline sweeps while capping the worst case well below 20 minutes.

### `incrementalMaxDepth`

Deprecated alias for `sweepMaxDepth`.

Why it matters:

- Existing OpenClaw configs continue to load.
- New config should use `sweepMaxDepth`.
- If both aliases are set in the same source, `sweepMaxDepth` wins.

### `summaryModel` and `summaryProvider`

Override the model used for compaction summarization.

Why they matter:

- Summary quality compounds upward in the DAG.
- Cheaper models can reduce cost, but weak summaries create weak recalled context later.

Guidance:

- Pick a cheaper model only if it remains reliably structured and faithful.
- `summaryProvider` only matters when `summaryModel` is a bare model name rather than a canonical provider/model ref.
- Summary calls go through OpenClaw's `api.runtime.llm.complete`; Lossless does not resolve provider credentials directly.
- Explicit summary model overrides require `plugins.entries.lossless-claw.llm.allowModelOverride` plus matching `allowedModels` entries, or `openclaw doctor --fix` to add them.

### `expansionModel` and `expansionProvider`

Override the model used by delegated recall flows such as `lcm_expand_query`.

Why they matter:

- This lets recall-heavy work use a different cost/latency profile than normal compaction.
- These are recall-path settings, not compaction-path settings.

## Complete config surface

## Core enablement and storage

### `enabled`

Boolean on/off switch for the plugin entry.

Use this when:

- you need the plugin installed but temporarily disabled
- you want to distinguish “installed” from “selected and active”

### `dbPath`

Overrides the SQLite DB location.

Why it matters:

- useful for custom deployments, testing, or isolating environments
- wrong path selection is a common reason operators think LCM is empty or not growing
- the default resolves to `${OPENCLAW_STATE_DIR}/lcm.db` (falls back to `~/.openclaw/lcm.db`)
- the `lcm` shell CLI also accepts `LCM_OPENCLAW_DIR` as a CLI-only state-directory override before `OPENCLAW_STATE_DIR`

### `databasePath`

Preferred alias of `dbPath`.

Why it matters:

- this is the documented key new config should use
- `dbPath` is still accepted for compatibility

### `largeFilesDir`

Directory for persisting large-file text payloads externalised from the transcript.

Why it matters:

- defaults to `${OPENCLAW_STATE_DIR}/lcm-files`; on multi-profile hosts each profile stores files in its own state directory automatically
- override with `LCM_LARGE_FILES_DIR` or set `largeFilesDir` in plugin config when you want an explicit path
### `largeFileThresholdTokens`

Threshold for externalizing oversized tool/file payloads out of the main transcript into large-file storage.

Why it matters:

- lower values externalize more aggressively
- higher values keep more payload inline but can bloat storage and compaction inputs

### `transcriptGcEnabled`

Controls whether `maintain()` rewrites transcript entries for already-externalized tool results.

Why it matters:

- keep this off unless you want transcript GC to mutate the live session file during maintenance
- the default is `false`

### `enableSummaryThinking`

Controls whether the summarization model receives a low reasoning budget.

Why it matters:

- when `true` (default), summarization calls request `reasoningIfSupported: "low"`, allowing the model to think before producing summaries — this is the current default behavior
- when `false`, no explicit reasoning budget is requested, which can reduce cost and keep summarization output more concise when reasoning is not needed for faithful summaries
- set to `false` when you want to minimize token spend on reasoning during compaction, especially with reasoning-capable models

Env override:

- `LCM_ENABLE_SUMMARY_THINKING`

### `proactiveThresholdCompactionMode`

Controls whether proactive threshold compaction is deferred into maintenance debt or kept inline for legacy behavior.

Why it matters:

- `deferred` is the default and avoids foreground turn stalls by recording one coalesced maintenance row per conversation
- `deferred` also stores provider/model/cache telemetry so Anthropic-family sessions can avoid rewriting a still-hot prompt cache
- `inline` preserves the legacy foreground compaction path for hosts that do not yet support deferred execution
- `/lossless status` (`/lcm status` alias) surfaces pending/running/last-failure maintenance state so operators can see when compaction is queued
- after-turn background drain and host-approved `maintain()` consume routine threshold debt; `assemble()` only drains pending threshold debt synchronously as an emergency safeguard when the live prompt estimate is already over budget

### `autoRotateSessionFiles`

Automatically rotates oversized LCM-managed session JSONL files.

Defaults:

- `enabled: true`
- `createBackups: false`
- `sizeBytes: 2097152`
- `startup: "rotate"`
- `runtime: "rotate"`

Why it matters:

- prevents very large OpenClaw session JSONL files from choking fallback/gateway startup while LCM owns the durable context
- runtime rotation only creates or replaces the rolling `rotate-latest` DB backup when `createBackups` is `true`; manual `/lossless rotate` always keeps its backup-backed behavior
- runtime JSONL rewrites run from `afterTurn()` after the host turn completes; `maintain()` skips rotation and leaves it to `afterTurn()` or startup because background maintenance can overlap an embedded model call
- startup scans OpenClaw's current indexed session stores for configured agents, intersects those candidates with active LCM bootstrap state, and creates one pre-rotation DB backup for the startup batch only when `createBackups` is `true`
- only runs for active, writable LCM conversations; ignored sessions, stateless sessions, sessions outside the indexed startup candidate set, and sessions without active LCM state are skipped
- the preserved transcript tail follows the normal rotate behavior controlled by `freshTailCount`

Operational logging:

- every decision is logged with the prefix `[lcm] auto-rotate:`
- startup emits one compact `action=summary` line with `scanned`, `eligible`, `rotated`, `warned`, `skipped`, `durationMs`, and `bytesRemoved`
- rotate logs include `phase`, `action`, `sessionId`, `sessionKey`, `sessionFile`, `sizeBytes`, `thresholdBytes`, `durationMs`, `backupPath`, `bytesRemoved`, `preservedTailMessageCount`, and `checkpointSize`
- real warning logs include the same available context plus `reason` or `error`; quiet startup skips such as missing files, missing bootstrap mappings, and below-threshold files are counted in the summary instead of logged per candidate

### `independentLogFile`

Writes lossless-claw JSONL logs to an independent plugin-owned file in addition to OpenClaw's runtime logger.

Defaults:

- `enabled: true`
- `file: /tmp/openclaw/lossless-claw-YYYY-MM-DD.log`
- `maxFileBytes: 104857600`

Why it matters:

- keeps high-volume `[lcm]` operational traces separate from the shared OpenClaw gateway log
- still sends startup banners and warning/error lines through OpenClaw's runtime logger, so gateway-level startup and failure diagnostics remain visible
- a dated `lossless-claw-YYYY-MM-DD.log` path rolls over daily, stale dated files are pruned after 3 days, and oversized files rotate through `.1.log` to `.5.log`

Env overrides:

- `LCM_LOG_FILE_ENABLED`
- `LCM_LOG_FILE`
- `LCM_LOG_MAX_FILE_BYTES`

## Compaction timing and shape

### `contextThreshold`

See high-impact settings above.

### `freshTailCount`

See high-impact settings above.

### `freshTailMaxTokens`

See high-impact settings above.

### `promptAwareEviction`

Boolean toggle for prompt-sensitive selection inside the evictable prefix during assembly.

Why it matters:

- only applies when the older evictable prefix does not fit the token budget
- the protected fresh tail is unaffected
- `true` keeps the most relevant older items for the current prompt
- `false` falls back to pure chronological retention for the older prefix

Env override:

- `LCM_PROMPT_AWARE_EVICTION_ENABLED`

### `stubLargeToolPayloads`

Boolean toggle for assemble-time stub substitution of migrated tool-result payloads outside the protected fresh tail.

Why it matters:

- only affects rows whose `messages.large_content` sidecar points at a `file_xxx` record
- the fresh tail is still emitted verbatim
- drilldown uses `lcm_describe(id=file_xxx, expandFile=true)`
- `scripts/lcm-blob-migrate.mjs` defaults to the same storage root as runtime LCM: `LCM_LARGE_FILES_DIR` or `${OPENCLAW_STATE_DIR}/lcm-files`

Env override:

- `LCM_STUB_LARGE_TOOL_PAYLOADS`

### `leafChunkTokens`

See high-impact settings above.

### `leafMinFanout`

Minimum number of leaf items required before creating a leaf compaction grouping.

Why it matters:

- higher values avoid tiny leaf summaries
- lower values compact sooner but can create overly granular summaries

### `condensedMinFanout`

Preferred minimum fanout for condensed summaries during normal condensation.

Why it matters:

- controls how eagerly summaries get grouped upward
- affects DAG breadth and readability of higher-level summaries

### `condensedMinFanoutHard`

Hard lower bound for condensed fanout decisions.

Why it matters:

- acts as the guardrail when normal fanout preferences cannot be met cleanly
- mostly useful for advanced tuning or pathological summary-tree shapes

### `sweepMaxDepth`

See high-impact settings above.

Env override:

- `LCM_SWEEP_MAX_DEPTH`

### `summaryPrefixTargetTokens`

See high-impact settings above.

Env override:

- `LCM_SUMMARY_PREFIX_TARGET_TOKENS`

### `maxSweepIterations`

See high-impact settings above.

Env override:

- `LCM_MAX_SWEEP_ITERATIONS`

### `sweepDeadlineMs`

See high-impact settings above.

Env override:

- `LCM_SWEEP_DEADLINE_MS`

### `compactUntilUnderDeadlineMs`

See high-impact settings above.

Env override:

- `LCM_COMPACT_UNTIL_UNDER_DEADLINE_MS`

### `incrementalMaxDepth`

Deprecated alias for `sweepMaxDepth`.

Env override:

- `LCM_INCREMENTAL_MAX_DEPTH`

### `bootstrapMaxTokens`

Maximum raw parent-history tokens imported when a brand-new LCM conversation bootstraps.

Why it matters:

- keeps first-time bootstrap from flooding the conversation with too much old transcript material
- defaults to `max(6000, floor(leafChunkTokens * 0.3))`
- only affects the first import path, not ordinary steady-state turns

## Session-selection controls

### `ignoreSessionPatterns`

Glob-style session-key patterns that should never enter LCM.

Why it matters:

- keeps low-value automation or noisy sessions out of the DB
- useful for excluding certain agent lanes or ephemeral traffic entirely
- cron scheduler keys are already isolated per runtime run, so ignore them only when they should bypass LCM compaction
- matching sessions do not create LCM conversation rows or store messages in LCM
- `agent:*:**:active-memory:**` is intentionally broad for active-memory keys because `**` spans colon-separated session-key segments
- `agent:*:dreaming-narrative-**` matches OpenClaw memory-core keys built with the `dreaming-narrative-` prefix ([source](https://github.com/openclaw/openclaw/blob/b81666ca6af25c86cc099983a4358cdc5ea9ced8/extensions/memory-core/src/dreaming-narrative.ts))
- ignored-session `/compact` calls use OpenClaw's built-in runtime compaction delegate when the host exposes it; older hosts keep the previous safe skip behavior

Example:

```json
[
  "agent:*:cron:**",
  "agent:*:**:active-memory:**",
  "agent:*:dreaming-narrative-**"
]
```

### `statelessSessionPatterns`

Patterns for sessions that may read from LCM but should not write to it.

Why it matters:

- useful for sub-agents and ephemeral workers
- prevents recall helpers from polluting the main history

### `skipStatelessSessions`

Boolean that changes how stateless matches are treated.

Why it matters:

- when enabled, matching stateless sessions skip LCM persistence entirely
- use carefully, because it affects whether those sessions behave as readers only or are effectively bypassed for writes

### `hostFallbackMode`

Controls the installation-wide `agent-run` host requirement.

- `error` is the default and requires the full context-engine lifecycle
- `capture-only` accepts hosts that provide bootstrap, after-turn ingestion, and maintenance
- generic CLI runs in capture-only mode persist transcripts and keep recall tools, but do not receive Lossless prompt assembly or host-triggered Lossless compaction
- backend-native compaction remains host-owned; explicit Lossless compaction requires `fallbackProviders`
- fully capable native hosts still execute the full lifecycle, and Lossless retains compaction ownership for those runs
- subagent forks continue to require `thread-bootstrap-projection`

Env override:

- `LCM_HOST_FALLBACK_MODE`

## Recall-path and delegation controls

### `expansionModel`

See high-impact settings above.

### `expansionProvider`

See high-impact settings above.

### `delegationTimeoutMs`

Maximum wall-clock budget for delegated recall work across one `lcm_expand_query` call. Cross-conversation buckets share this deadline, and the tool keeps 30 seconds of RPC headroom for cancellation, cleanup, and result delivery.

Why it matters:

- lower values fail faster under slow sub-agent paths
- higher values give the bounded recall request more time to finish

### `maxAssemblyTokenBudget`

Hard ceiling for assembled LCM token budget.

Why it matters:

- useful when the runtime model window is smaller than the surrounding system assumes
- can prevent oversized assembly on smaller-context models

## Anti-replay flood guard

The ingest path runs `assertNoReplayTimestampFlood` to refuse batches that look like webhook-style replay attacks (many replay-like user messages or many identical internal messages at the same `created_at`). Because SQLite `datetime('now')` is second-granularity, legitimate idempotent bursts from sub-agents can also trip the guard if it is single-threshold. The role-aware thresholds below split the budget by message origin.

### `replayFloodThresholdExternal`

Max replay-like messages allowed in a single SQLite-second for `role=user` before the guard refuses the batch. Defaults to `3`.

Why it matters:

- preserves replay defense for third-partyly-rebroadcastable input
- lower values are stricter but risk rejecting legitimate dedup retries from upstream channels

### `replayFloodThresholdInternal`

Max identical messages allowed in a single SQLite-second for `role=tool/assistant/system` before the guard refuses the batch. Defaults to `32`.

Why it matters:

- absorbs legitimate same-second idempotent tool returns (for example, sub-agents emitting many `{"status":"ok"}` results)
- still bounded so a pathological loop cannot ingest unboundedly under the same timestamp
- raise it if you operate cron sub-agents that emit very tight bursts; lower it if you want stricter sanity protection

## Nested objects

### `cacheAwareCompaction`

#### `cacheAwareCompaction.enabled`

Deprecated compatibility setting. It remains accepted by config loading but no longer changes automatic compaction behavior.

#### `cacheAwareCompaction.cacheTTLSeconds`

Deprecated compatibility setting. Threshold debt no longer waits for a prompt-cache TTL.

Why it matters:

- existing configs continue to load
- prompt-cache telemetry remains diagnostic only

Default:

- `300`

#### `cacheAwareCompaction.maxColdCacheCatchupPasses`

Deprecated compatibility setting. Automatic cold-cache catch-up passes were removed.

#### `cacheAwareCompaction.hotCachePressureFactor`

Deprecated compatibility setting. Hot-cache raw-history pressure no longer drives automatic compaction.

Why it matters:

- use `contextThreshold`, `leafChunkTokens`, and fanout for active compaction tuning

Default:

- `4`

#### `cacheAwareCompaction.hotCacheBudgetHeadroomRatio`

Deprecated compatibility setting. Hot-cache budget headroom no longer defers automatic threshold compaction.

Why it matters:

- threshold debt runs when the context threshold is crossed

Default:

- `0.2`

#### `cacheAwareCompaction.coldCacheObservationThreshold`

Deprecated compatibility setting. Cold-cache streaks may still be observable telemetry, but they no longer trigger catch-up compaction.

Why it matters:

- cache state is not reliable enough to drive prompt-mutating compaction

Default:

- `3`

#### `cacheAwareCompaction.criticalBudgetPressureRatio`

Deprecated compatibility setting. `contextThreshold` is now the only automatic compaction threshold.

Why it matters:

- the hot-cache delay gate has been removed
- overflow recovery still uses explicit budget-targeted compaction

Default:

- `0.90`

Env override:

- `LCM_CRITICAL_BUDGET_PRESSURE_RATIO`

### `dynamicLeafChunkTokens`

#### `dynamicLeafChunkTokens.enabled`

Deprecated compatibility setting. Automatic compaction uses `leafChunkTokens` directly.

Default:

- `true`

#### `dynamicLeafChunkTokens.max`

Deprecated compatibility setting. The resolved value is still accepted and visible, but no longer changes automatic compaction.

Default:

- `max(leafChunkTokens, floor(leafChunkTokens * 2))`

## Summary quality and prompt controls

### `summaryMaxOverageFactor`

Maximum allowed overage factor before an oversized summary is truncated/downgraded.

Why it matters:

- guards against runaway summaries that are much larger than their target budget
- useful when summary models are verbose or unstable

### `fallbackMaxTokens`

| | |
| --- | --- |
| Type | `integer` |
| Default | `512` |
| Minimum | `64` |
| Env | `LCM_FALLBACK_MAX_TOKENS` |

Maximum token budget for deterministic fallback summaries when the LLM summarizer is unavailable.

Why it matters:

- when the LLM summarizer fails (auth errors, timeout, empty output), Lossless falls back to a purely local truncation-based summary
- this fallback is bounded by `fallbackMaxTokens` so it cannot balloon the context
- values below `64` are ignored so the required fallback marker can fit inside the configured budget
- lower values produce more aggressive truncation; higher values preserve more source text at the cost of larger fallback summaries
- the default `512` is conservative; raise it if you prefer richer fallback summaries over more aggressive truncation

### `summaryMaxCallsPerWindow`, `summaryCallWindowMs`, and `summarySpendBackoffMs`

Bounds model-backed compaction and large-file summarization calls per session.

Defaults:

- `summaryMaxCallsPerWindow`: `24`
- `summaryCallWindowMs`: `600000`
- `summarySpendBackoffMs`: `1800000`

Env overrides:

- `LCM_SUMMARY_MAX_CALLS_PER_WINDOW`
- `LCM_SUMMARY_CALL_WINDOW_MS`
- `LCM_SUMMARY_SPEND_BACKOFF_MS`

Why they matter:

- prevents non-auth provider failures, ineffective compaction, or repeated deferred debt from spending unbounded summarization calls
- keeps provider-auth failures on the separate auth circuit breaker path
- direct deterministic fallbacks remain available when model-backed large-file summaries are throttled

### `customInstructions`

Natural-language instructions injected into summarization prompts.

Why it matters:

- lets operators steer formatting or emphasis without patching code
- should be used sparingly; low-quality instructions can degrade summary quality system-wide

### `stripInjectedContextTags`

| | |
| --- | --- |
| Type | `string[]` |
| Default | `["active_memory_plugin", "relevant-memories", "relevant_memories", "hindsight_memories"]` |
| Env | `LCM_STRIP_INJECTED_CONTEXT_TAGS` (comma-separated) |

XML tag names whose blocks are stripped from message content before compaction summarization.

Why it matters:

- Memory and context plugins (active-memory, memory-lancedb, hindsight-openclaw) prepend XML-tagged blocks to user messages via the `prependContext` hook.  These blocks are ephemeral retrieval context — they helped the model on that specific turn but are not part of the actual conversation.
- Without stripping, the summarizer treats injected memories as real conversation content, permanently corrupting compacted summaries with auto-retrieved context that the user never said.
- The default list covers well-known OpenClaw memory plugin tags.  Add custom tag names if you use plugins that inject context via other tags.
- Set to `[]` (or empty env string) to disable stripping.

Design note: stripping happens at compaction time, not at message ingestion.  The raw message stored in the LCM database still contains the original injected blocks, so `lcm_expand` and `lcm_grep` can still surface the full context the model saw on any given turn.  Only the summarizer input is cleaned.

## Practical operator workflow

1. Install and enable the plugin.
2. Set the context-engine slot to `lossless-claw`.
3. Start with conservative defaults.
4. Run `/lossless` after startup to confirm path, size, and summary health.
5. If threshold sweeps happen too often, tune `contextThreshold`, `leafChunkTokens`, `summaryPrefixTargetTokens`, and fanout before adding new mechanisms.
6. If threshold sweeps happen too often, try a larger `leafChunkTokens` value such as 30000 before adding new mechanisms.
7. If recall feels weak, revisit `freshTailCount`, `leafChunkTokens`, and summarizer model quality before changing anything else.
8. Touch advanced knobs like fanout, large-file thresholds, custom instructions, and assembly caps only after a concrete symptom appears.

## Reading the status output

`/lossless` is the right command for LCM-local metrics.

Useful interpretation notes:

- `LCM frontier tokens` is the current LCM frontier token count in the live LCM state.
- `compression ratio` is shown as a rounded `1:N`, which is easier to read than a tiny percentage for heavily compacted conversations.
- `/status` may still show a different context number because it reflects the runtime prompt that was actually assembled and sent on the last turn.

## Keep this reference aligned

This file should stay consistent with:

- [`docs/configuration.md`](../../../docs/configuration.md)
- [`openclaw.plugin.json`](../../../openclaw.plugin.json)
- [`src/db/config.ts`](../../../src/db/config.ts)

When config keys, aliases, defaults, or precedence rules change, update all of them together.
references/diagnostics.md
# Diagnostics

For the MVP, use the native command surface first. For debugging lossless-claw behavior or failures, inspect the independent Lossless log before the shared OpenClaw gateway log.

## Fast path

### `lcm` shell CLI

Use the packaged shell CLI for bounded, structured database inspection outside an OpenClaw conversation:

```bash
lcm status --pretty
lcm conversations show --session-key 'agent:main:example'
lcm messages tail --conversation-id 42
lcm summaries list --conversation-id 42 --depth 0 --recency 7d
```

JSON is the default output. List commands return opaque keyset cursors. Database commands open `lcm.db` read-only and do not run migrations, repair, cleanup, compaction, or other write operations. `lcm config set` is the only state-changing shell command and edits one manifest-validated Lossless config path with a timestamped backup.

Path overrides use `--db`, `LCM_DATABASE_PATH`, `--openclaw-dir`, `LCM_OPENCLAW_DIR`, `OPENCLAW_STATE_DIR`, `OPENCLAW_HOME`, `--config`, and `OPENCLAW_CONFIG_PATH`. See `docs/cli.md` in the package for precedence and the complete command contract.

### Independent Lossless log

Check this first when lossless-claw needs to debug itself, because routine `[lcm]` info and debug lines are written here instead of the shared OpenClaw gateway log.

Default path:

```bash
/tmp/openclaw/lossless-claw-YYYY-MM-DD.log
```

For today's local log, use:

```bash
tail -n 200 "/tmp/openclaw/lossless-claw-$(date +%F).log"
```

Useful patterns:

```bash
rg -n "\\[lcm\\] (auto-rotate|rotate|runtime\\.llm\\.complete|summary|compact|assembly)" /tmp/openclaw/lossless-claw-*.log
rg -n "warn|error|failed|truncated|deterministic|fallback" /tmp/openclaw/lossless-claw-*.log
```

The dated default log rolls over daily. Dated files are pruned after 3 days, and oversized active logs rotate through `.1.log` to `.5.log`. Startup banners and warning/error lines are also sent to OpenClaw's runtime logger, so check `/tmp/openclaw/openclaw-YYYY-MM-DD.log` after the Lossless log when you need gateway-level startup or failure context.

### `/lossless` (`/lcm` alias)

Use this when you need a quick health snapshot.

It should answer:

- Is `lossless-claw` enabled?
- Is it selected as the context engine?
- Which DB is active?
- Is the DB growing as expected?
- Are summaries present?
- Are broken or truncated summaries present?

### `/lossless doctor`

Use this when summary corruption or truncation is suspected.

It is the single user-facing diagnostic entrypoint for summary-health issues in the MVP.

What it should help confirm:

- whether broken summaries exist
- whether truncation markers exist
- which conversations are affected most

### `/lossless doctor apply`

Use this only after `/lossless doctor` identifies broken summaries. The command rewrites affected summary content in place after creating a database backup.

- `/lossless doctor apply` repairs the current conversation and keeps the normal large/hot safety preflight.
- `/lossless doctor apply confirm-offline` overrides that preflight for the current conversation after its active channel path has been isolated.
- `/lossless doctor apply <conversation-id> confirm-offline` targets a specific conversation, including an archived or non-current conversation. Targeted repair always requires the explicit offline confirmation.

Conversation ids are gateway-wide maintenance identifiers rather than sender ownership credentials. Only authorized OpenClaw command senders can invoke the command; before targeting an id, pause or move active delivery away from that conversation and verify the displayed session key is the intended lane.

### `/lossless doctor clean`

Use this when the user wants read-only diagnostics for high-confidence junk patterns before any cleanup.

It should help confirm:

- whether archived subagent sessions are present
- whether cron sessions are accumulating unexpectedly
- whether NULL-key orphaned subagent conversations are present
- which high-confidence filters match the most conversations and messages

This command is read-only. Use it to identify likely cleanup candidates before taking any separate cleanup action.

## Interpreting common states

### `/lossless` tokens vs `/status` context

These numbers are related, but they are not the same metric.

- `/lossless` reports LCM-side conversation metrics such as the current frontier token count and compression ratio.
- `/status` reports the last assembled runtime prompt snapshot for the active model.

Why they can differ:

- runtime assembly can trim or omit frontier material before the request is sent
- model-specific token budgeting and packing happen after LCM frontier selection
- `/status` reflects a last-run snapshot, while `/lossless` reads live LCM state from the DB

Treat `/lossless` as the LCM health/shape view, and `/status` as the runtime request view.

### No summaries yet

Usually means one of:

- the conversation has not crossed compaction thresholds yet
- the plugin is not selected as the context engine
- writes are being skipped because the session matches stateless or ignored patterns

### DB exists but stays tiny

Usually means one of:

- the plugin is not receiving traffic
- the wrong DB path is configured
- the plugin is enabled but not selected

### Broken or truncated summaries detected

Treat this as a signal to inspect summary health before trusting compacted context heavily.

For MVP guidance:

- keep the user on `/lossless doctor`
- explain the count and affected conversations
- avoid advertising separate repair-vs-doctor command families

## Safe operator advice

- Do not guess exact historical details from compacted context alone.
- When a user wants a fact pattern verified, use recall tools to recover evidence.
- Prefer changing one configuration knob at a time and then re-checking `/lossless`.
references/recall-tools.md
# Recall Tools

Use recall tools when the question depends on exact historical evidence from compacted context.

## Tool selection

### `lcm_grep`

Use for:

- finding whether a term, file name, error string, or identifier appears in compacted history
- narrowing the search space before deeper inspection

Do not use it for:

- answering detail-heavy questions by itself

### `lcm_describe`

Use for:

- inspecting a specific summary or stored-file record by ID
- reading lineage and content for a known summary node

Do not use it for:

- broad discovery when you do not know the target ID yet

### `lcm_expand_query`

Use for:

- focused questions that need richer detail recovered from summaries
- evidence-oriented follow-up after `lcm_grep` or `lcm_describe`

Cross-conversation expansion runs its selected conversation buckets under one shared deadline and one shared token budget. Completed buckets still return evidence when a sibling bucket times out. Failure results identify the affected conversation, summary IDs, phase, and error code; they never invent answer text for interrupted work.

This is the best recall tool when the user asks for:

- exact commands
- exact file paths
- precise timestamps
- root-cause chains

### `lcm_expand`

Treat as a specialized sub-agent flow, not the default first step.

## Recommended workflow

1. Start with `lcm_grep` to find likely evidence.
2. Use `lcm_describe` when you have a summary or file ID.
3. Use `lcm_expand_query` when the answer requires precise recovery rather than a high-level summary.

## Conversation scope

When `conversationId` is omitted, recall tools use the current session family: the active conversation plus archived segments that share the same stable session identity. This preserves recall across session rotation and `/reset` replacement rows.

Use `conversationId` only when you need one specific physical conversation. Use `allConversations: true` for broad discovery across unrelated sessions.

## Important guardrail

Do not infer exact details from summaries alone when the user needs evidence. Expand first or state that the answer still needs expansion.
references/session-lifecycle.md
# Session lifecycle (`/new`, `/reset`, and `/lossless rotate`)

This reference describes the current behavior on `main`.

## Short version

For stock `lossless-claw` on current main:

- OpenClaw handles `/new` and `/reset` as session-reset operations.
- `lossless-claw` handles `/lossless rotate` (`/lcm rotate`) as transcript maintenance on the current conversation.
- `lossless-claw` prefers **`sessionKey`** as the stable identity for an LCM conversation.
- `/reset` archives the active conversation and creates a fresh active row for the same stable `sessionKey`.
- Cron scheduler keys (`agent:<agent>:cron:<job>...`) are isolated per runtime run when a new `sessionId` reuses the same `sessionKey`.
- For ordinary non-cron session keys, continuity still follows the stable `sessionKey`.

## What that means in practice

If a user asks whether `/new` or `/reset` gives them a fresh LCM conversation, distinguish the commands.

They get a fresh OpenClaw session runtime, but LCM continuity usually still follows the stable `sessionKey` when one is available.

So today:

- `/new` prunes active context but keeps the same LCM conversation row
- `/reset` archives the active LCM conversation row and creates a fresh active row
- ordinary chat/thread LCM history may continue in the same row across runtime `sessionId` changes when the stable `sessionKey` continues
- cron scheduler keys create fresh LCM rows per runtime run so prior runs do not enter the new run's assembled context
- `/lossless rotate` keeps that same conversation row, summaries, and context items in place while compacting only the live transcript backing

## Why

Current lossless-claw conversation resolution generally does this:

1. look up by `sessionKey` first
2. fall back to `sessionId` only when no `sessionKey` match exists
3. if the `sessionKey` already exists but the `sessionId` changed, update the stored `sessionId` on that same conversation

That behavior preserves continuity across session resets for the same chat identity.

Cron keys are the exception: when an active cron conversation exists for the same `sessionKey` but a different runtime `sessionId`, lossless-claw archives the prior active row and starts a fresh one for the new run. Prior messages remain persisted on the archived conversation.

## `/lossless rotate`

`/lossless rotate` is distinct from `/new` and `/reset`.

- it does **not** create a fresh LCM conversation row
- it does **not** archive the current conversation
- it **does** create or replace the rolling `rotate-latest` SQLite backup first
- it **does** rewrite the current transcript into a compact suffix-preserving form
- it **does** refresh bootstrap state on the same conversation so dropped transcript history is not replayed
- it **does** preserve the current conversation id, summary DAG, and active context items

This makes rotate the lightweight option when the problem is transcript bloat rather than LCM conversation structure.

## Important limitation

There is a plugin-specific `/new` vs `/reset` split in current lossless-claw behavior.

If someone is asking for semantics like:

- `/new` gives them a fresh LCM conversation row

that remains a **design/spec topic**, not current stock behavior.

## Safe operator guidance

When answering users:

- do not promise that `/new` clears LCM history
- explain that `/reset` archives the active LCM row and starts a fresh one for the same stable `sessionKey`
- explain that `/lossless rotate` compacts the current transcript without splitting the LCM conversation
- explain that ordinary current stock behavior follows `sessionKey` continuity
- explain that cron scheduler session keys are isolated per runtime run while preserving archived prior runs
- if they need a truly separate LCM history, use a different session key context (for example a different chat/thread/binding) or explicit non-MVP migration/surgery tools

## Importing past conversation data

If a user explicitly asks how to import old or past OpenClaw conversation data into Lossless, recommend the packaged session migration CLI:

```bash
npx --package @martian-engineering/lossless-claw@latest lossless-claw-migrate-sessions --state-dir ~/.openclaw
```

That command name, `lossless-claw-migrate-sessions`, is the npm package executable declared by lossless-claw. It backfills OpenClaw JSONL session files into `lcm.db`.

Use it when:

- lossless-claw was installed after useful OpenClaw sessions already existed
- lossless-claw was disabled or missing for a period
- the user wants historical JSONL sessions imported into Lossless storage

Do not present it as:

- a background replay loop
- a summarization or embedding migration
- a replacement for normal startup bootstrap/crash recovery
- a general rewrite/transplant/surgery tool

Safe recommendation pattern:

1. Run the dry-run command first and inspect the output.
2. Apply only after the user confirms the target state directory and import set:

```bash
npx --package @martian-engineering/lossless-claw@latest lossless-claw-migrate-sessions --state-dir ~/.openclaw --apply
```

The CLI defaults to `${OPENCLAW_STATE_DIR:-~/.openclaw}` and `${OPENCLAW_STATE_DIR:-~/.openclaw}/lcm.db`. On `--apply`, it creates a timestamped SQLite backup before writing when the database already exists. For narrow imports, suggest `--file <path>`, repeatable `--sessions-dir <path>`, `--since <iso-date>`, or `--limit <n>`.

## Relation to `/status`

This session behavior is separate from `/status` metrics.

- `/status` reflects runtime session state and the last assembled request snapshot
- `/lossless` reflects LCM conversation state keyed by the plugin's conversation mapping rules