> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wednesdayai.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Session Pruning

# Session Pruning

Session pruning trims **old tool results** from the in-memory context right before each LLM call. It does **not** rewrite the on-disk session history (`*.jsonl`).

## When it runs

* When `mode: "cache-ttl"` is enabled and the last Anthropic call for the session is older than `ttl`.
* Only affects the messages sent to the model for that request.
* Only active for Anthropic API calls (and OpenRouter Anthropic models).
* For best results, match `ttl` to your model `cacheRetention` policy (`short` = 5m, `long` = 1h).
* After a prune, the TTL window resets so subsequent requests keep cache until `ttl` expires again.

## Smart defaults (Anthropic)

* **OAuth or setup-token** profiles: enable `cache-ttl` pruning and set heartbeat to `1h`.
* **API key** profiles: enable `cache-ttl` pruning, set heartbeat to `30m`, and default `cacheRetention: "short"` on Anthropic models.
* If you set any of these values explicitly, OpenClaw does **not** override them.

## What this improves (cost + cache behavior)

* **Why prune:** Anthropic prompt caching only applies within the TTL. If a session goes idle past the TTL, the next request re-caches the full prompt unless you trim it first.
* **What gets cheaper:** pruning reduces the **cacheWrite** size for that first request after the TTL expires.
* **Why the TTL reset matters:** once pruning runs, the cache window resets, so follow‑up requests can reuse the freshly cached prompt instead of re-caching the full history again.
* **What it does not do:** pruning doesn’t add tokens or “double” costs; it only changes what gets cached on that first post‑TTL request.

## What can be pruned

* Only `toolResult` messages.
* User + assistant messages are **never** modified.
* The last `keepLastAssistants` assistant messages are protected; tool results after that cutoff are not pruned.
* If there aren’t enough assistant messages to establish the cutoff, pruning is skipped.
* Tool results containing **image blocks** are skipped (never trimmed/cleared).

## Context window estimation

Pruning uses an estimated context window (chars ≈ tokens × 4). The base window is resolved in this order:

1. `models.providers.*.models[].contextWindow` override.
2. Model definition `contextWindow` (from the model registry).
3. Default `200000` tokens.

If `agents.defaults.contextTokens` is set, it is treated as a cap (min) on the resolved window.

## Mode

### cache-ttl

* Pruning only runs if the last Anthropic call is older than `ttl` (default `5m`).
* When it runs: same soft-trim + hard-clear behavior as before.

## Soft vs hard pruning

* **Soft-trim**: only for oversized tool results.
  * Keeps head + tail, inserts `...`, and appends a note with the original size.
  * Skips results with image blocks.
* **Hard-clear**: replaces the entire tool result with `hardClear.placeholder`.

## Tool selection

* `tools.allow` / `tools.deny` support `*` wildcards.
* Deny wins.
* Matching is case-insensitive.
* Empty allow list => all tools allowed.

## Interaction with other limits

* Built-in tools already truncate their own output; session pruning is an extra layer that prevents long-running chats from accumulating too much tool output in the model context.
* Compaction is separate: compaction summarizes and persists, pruning is transient per request. See [/concepts/compaction](/concepts/compaction).

## Defaults (when enabled)

* `ttl`: `"5m"`
* `keepLastAssistants`: `3`
* `softTrimRatio`: `0.3`
* `hardClearRatio`: `0.5`
* `minPrunableToolChars`: `50000`
* `softTrim`: `{ maxChars: 4000, headChars: 1500, tailChars: 1500 }`
* `hardClear`: `{ enabled: true, placeholder: "[Old tool result content cleared]" }`

## Examples

Default (off):

```json5 theme={"dark"}
{
  agents: { defaults: { contextPruning: { mode: "off" } } },
}
```

Enable TTL-aware pruning:

```json5 theme={"dark"}
{
  agents: { defaults: { contextPruning: { mode: "cache-ttl", ttl: "5m" } } },
}
```

Restrict pruning to specific tools:

```json5 theme={"dark"}
{
  agents: {
    defaults: {
      contextPruning: {
        mode: "cache-ttl",
        tools: { allow: ["exec", "read"], deny: ["*image*"] },
      },
    },
  },
}
```

See config reference: [Gateway Configuration](/gateway/configuration)

## Session archival

When a session is reset (`/new`, `/reset`) or removed during maintenance, OpenClaw **archives** the JSONL transcript rather than deleting it. Archival keeps the data on disk so you can recover or audit it later.

### What archival means

* The transcript file is **renamed in-place** — nothing is erased.
* The new name follows the pattern `<sessionId>.jsonl.<reason>.<timestamp>`, for example:
  * `abc123.jsonl.reset.2026-05-23T14-30-00.000Z` (from `/new` or `/reset`)
  * `abc123.jsonl.deleted.2026-05-23T08-00-00.000Z` (from maintenance cleanup)
* The original session slot is freed so a fresh JSONL starts on the next message.

A separate config block, `session.archival`, controls in-session JSONL trimming. When enabled, OpenClaw can trim the head of the live JSONL file down to `keepLastTurns` turns and writes an `archive_marker` entry so the session remains usable. This function is also available to plugins via `archiveSessionTranscript` from `openclaw/plugin-sdk`.

### Configuration

```json5 theme={"dark"}
{
  session: {
    // Optional: enable in-session JSONL compaction (trim old turns from live transcript)
    archival: {
      enabled: true, // default: false
      keepLastTurns: 20, // min 5, max 100
    },
    maintenance: {
      mode: "enforce",
      pruneAfter: "30d",
      // How long to keep *.reset.<timestamp> archives; defaults to pruneAfter.
      // Set false to keep archives forever.
      resetArchiveRetention: "14d",
    },
  },
}
```

| Field                                       | Type                | Default              | Description                                                                           |
| ------------------------------------------- | ------------------- | -------------------- | ------------------------------------------------------------------------------------- |
| `session.archival.enabled`                  | boolean             | `false`              | Trim old turns from the live transcript during active sessions.                       |
| `session.archival.keepLastTurns`            | integer (5–100)     | —                    | Number of conversation turns to keep in the live JSONL; older turns are archived.     |
| `session.maintenance.resetArchiveRetention` | duration \| `false` | same as `pruneAfter` | How long `*.reset.*` archives are kept before being purged. `false` disables purging. |

### Where archived files go

All archive files live alongside the primary transcript in the agent sessions directory:

```
~/.openclaw/agents/<agentId>/sessions/
  <sessionId>.jsonl                        # live transcript
  <sessionId>.jsonl.reset.2026-05-23T…    # post-reset archive
  <sessionId>.jsonl.deleted.2026-05-23T…  # maintenance-removed archive
```

### Recovering or inspecting archived sessions

Archived JSONL files are plain text. You can inspect them directly:

```bash theme={"dark"}
# List archives for an agent
ls ~/.openclaw/agents/<agentId>/sessions/*.reset.* 2>/dev/null
ls ~/.openclaw/agents/<agentId>/sessions/*.deleted.* 2>/dev/null

# Read the last 50 lines of a reset archive
tail -n 50 ~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl.reset.<timestamp>
```

To restore a session, rename the archive back to the primary name (or a new session ID) before starting the gateway so the session store picks it up on next write.

## Troubleshooting

**Pruning is enabled but tool results are not being trimmed**
Pruning only fires for `mode: "cache-ttl"` when the last Anthropic call for the session is older than `ttl` (default `5m`). If requests arrive within the TTL window, pruning intentionally skips so the cached prompt stays valid. Wait for the session to go idle past `ttl`, then send another message. Also check that `contextPruning.mode` is set in `agents.defaults` (not a top-level key) and that the gateway has restarted since the config change.

**Tool results with images are never pruned even when context is large**
This is expected behavior. Tool results containing image blocks are always protected from both soft-trim and hard-clear. If image-heavy tool results are inflating context, consider capping image output at the tool level or reducing how many images are returned per tool call.

**Archived session file is missing or not found after `/reset`**
Check `~/.openclaw/agents/<agentId>/sessions/` for a file matching `<sessionId>.jsonl.reset.*`. Archival renames the file in place rather than moving it. If the file is absent, the session may have had no transcript written yet (no turns completed before reset), which means there is nothing to archive.

**`resetArchiveRetention` purged an archive I needed**
Archives are purged on the next maintenance run after the retention window expires. To stop future purges, set `session.maintenance.resetArchiveRetention: false` in config. To recover an already-purged archive, check filesystem-level backups; OpenClaw does not keep secondary copies.

*Related: [Session management](/concepts/session) · [Compaction](/concepts/compaction) · [Gateway configuration](/gateway/configuration)*
