openclaw - ✅(Solved) Fix [Feature]: Session compaction: archive transcript files before deletion, with configurable retention [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#63119Fetched 2026-04-09 07:58:17
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1labeled ×1

Root Cause

  1. Compaction is invisible until it's too late: Users don't know compaction will delete their transcript until it's already gone
  2. Upgrades trigger compaction: System upgrades often trigger compaction, and users may not realize their conversations are at risk
  3. Multi-session environments: In shared or long-running setups, losing conversation history disrupts continuity

Fix Action

Fixed

PR fix notes

PR #63161: feat(sessions): archive transcript before compaction truncation

Description (problem / solution / changelog)

Summary

  • When truncateAfterCompaction is enabled, transcript entries are now archived to {sessionFile}.compaction.{timestamp} before deletion, instead of being permanently lost
  • Configurable retention period via compactionArchiveRetention (default: 7 days)
  • Archived files are automatically cleaned up during regular session store maintenance

Closes #63119

Changes

  • src/agents/pi-embedded-runner/compact.ts — generate archive path and pass to truncation
  • src/config/sessions/artifacts.ts — register compaction as archive artifact type
  • src/config/types.agent-defaults.ts — add archiveBeforeTruncation option
  • src/config/types.base.ts — add compactionArchiveRetention config
  • src/config/sessions/store-maintenance.ts — resolve retention config
  • src/config/sessions/store.ts — cleanup expired compaction archives

Test plan

  • Existing session-truncation tests pass (9/9)
  • Store pruning integration tests pass (10/10)
  • Session-utils.fs tests pass (51/51)
  • Pre-commit hooks (lint, typecheck) pass
  • Manual: trigger compaction, verify .compaction.* file created
  • Manual: wait past retention, verify cleanup

🤖 Generated with Claude Code

Changed files

  • src/agents/pi-embedded-runner/compact.ts (modified, +9/-1)
  • src/agents/pi-embedded-runner/session-truncation.ts (modified, +4/-1)
  • src/config/sessions/artifacts.ts (modified, +3/-2)
  • src/config/sessions/store-maintenance.ts (modified, +22/-0)
  • src/config/sessions/store.ts (modified, +74/-1)
  • src/config/types.agent-defaults.ts (modified, +7/-0)
  • src/config/types.base.ts (modified, +5/-0)
  • src/config/zod-schema.agent-defaults.ts (modified, +2/-0)
  • src/config/zod-schema.session.ts (modified, +20/-0)

Code Example

Session reset/compaction
Old transcript.jsonl deleted
New transcript.jsonl created
[DATA PERMANENTLY LOST]

---

Session reset/compaction
Old transcript.jsonl → renamed to transcript.jsonl.archived.{timestamp}
New transcript.jsonl created
Archived files retained for N days (configurable)
Background cleanup removes archived files older than N days

### Proposed solution

## Proposed Solution

Add a configuration option for transcript archival on compaction:

---

### Behavior

- `archiveOnCompaction: true` (default: `false`)
  - Before deleting/replacing a transcript file, rename it to `.{sessionId}.archived.{timestamp}.jsonl`
  - If `archiveDirectory` is set, move the archived file there instead of keeping it in the sessions directory

- `archivedRetentionDays: 7` (default: `7`)
  - Background job removes archived transcripts older than N days
  - If `0`, archived files are kept forever (manual cleanup required)

- Background cleanup runs on Gateway startup and every 24 hours

### Alternative: Soft delete

Instead of renaming, add a `deletedAt` field to the sessions.json entry and move the transcript to an archive location. This preserves the sessions.json reference for potential recovery.

## Why this matters

1. **Compaction is invisible until it's too late**: Users don't know compaction will delete their transcript until it's already gone
2. **Upgrades trigger compaction**: System upgrades often trigger compaction, and users may not realize their conversations are at risk
3. **Multi-session environments**: In shared or long-running setups, losing conversation history disrupts continuity

## Implementation hints

The relevant code is in `src/lib/session/compaction.ts` or similar. The key change is in the `compactSession` flow:

1. Before deleting the old transcript, call `fs.rename()` to a backup path
2. Add archived file records to a simple manifest (or just rely on filesystem timestamps)
3. Add a `cleanupArchivedTranscripts()` function that runs on startup and via a timer

For the sessions.json, consider adding an `archivedSessions` array that tracks deleted/replaced sessions:
RAW_BUFFERClick to expand / collapse

Summary

Problem

When a session undergoes compaction (either automatic due to context limits or manual reset), the transcript file is permanently deleted with no recovery mechanism. This causes:

  1. Irreversible data loss: Hours/days of conversation history vanish instantly
  2. No grace period: Deleted transcripts cannot be recovered even if compaction was triggered unintentionally
  3. No visibility: Users have no warning that compaction will delete their transcript until it's already gone

Real-world impact

A user reported losing 4+ hours of conversation content (4/6 15:45-23:47 Beijing time) when a session reset occurred during a system upgrade. The reset happened at the filesystem level — the transcript file was deleted and replaced with a new one, leaving no trace of the original content.

Problem to solve

Current behavior

Session reset/compaction
Old transcript.jsonl deleted
New transcript.jsonl created
[DATA PERMANENTLY LOST]

Expected behavior

Session reset/compaction
Old transcript.jsonl → renamed to transcript.jsonl.archived.{timestamp}
New transcript.jsonl created
Archived files retained for N days (configurable)
Background cleanup removes archived files older than N days

### Proposed solution

## Proposed Solution

Add a configuration option for transcript archival on compaction:

```json
{
  "session": {
    "compaction": {
      "archiveOnCompaction": true,
      "archivedRetentionDays": 7,
      "archiveDirectory": null
    }
  }
}

Behavior

  • archiveOnCompaction: true (default: false)

    • Before deleting/replacing a transcript file, rename it to .{sessionId}.archived.{timestamp}.jsonl
    • If archiveDirectory is set, move the archived file there instead of keeping it in the sessions directory
  • archivedRetentionDays: 7 (default: 7)

    • Background job removes archived transcripts older than N days
    • If 0, archived files are kept forever (manual cleanup required)
  • Background cleanup runs on Gateway startup and every 24 hours

Alternative: Soft delete

Instead of renaming, add a deletedAt field to the sessions.json entry and move the transcript to an archive location. This preserves the sessions.json reference for potential recovery.

Why this matters

  1. Compaction is invisible until it's too late: Users don't know compaction will delete their transcript until it's already gone
  2. Upgrades trigger compaction: System upgrades often trigger compaction, and users may not realize their conversations are at risk
  3. Multi-session environments: In shared or long-running setups, losing conversation history disrupts continuity

Implementation hints

The relevant code is in src/lib/session/compaction.ts or similar. The key change is in the compactSession flow:

  1. Before deleting the old transcript, call fs.rename() to a backup path
  2. Add archived file records to a simple manifest (or just rely on filesystem timestamps)
  3. Add a cleanupArchivedTranscripts() function that runs on startup and via a timer

For the sessions.json, consider adding an archivedSessions array that tracks deleted/replaced sessions:

interface ArchivedSession {
  sessionId: string;
  archivedAt: number;  // Unix timestamp
  archivedPath: string;
  originalStartedAt?: number;
}

See also

  • docs/reference/session-management-compaction.md - Current compaction documentation
  • Related issue: Session transcript hygiene has no recovery path

Alternatives considered

No response

Impact

NOTHING

Evidence/examples

No response

Additional information

No response

extent analysis

TL;DR

Implementing a transcript archival mechanism on session compaction can prevent permanent data loss by renaming and retaining the old transcript file for a configurable number of days.

Guidance

  • To address the issue of permanent data loss during session compaction, consider adding a configuration option for transcript archival, allowing for the retention of archived files for a specified number of days.
  • Modify the compactSession flow in src/lib/session/compaction.ts to rename the old transcript file to a backup path before creating a new one, ensuring data is not lost immediately.
  • Implement a background cleanup function, cleanupArchivedTranscripts(), to remove archived transcripts older than the configured retention days, running this function on startup and at regular intervals (e.g., every 24 hours).
  • For tracking and potential recovery, add an archivedSessions array to the sessions.json file to keep records of deleted or replaced sessions, including their archived paths and timestamps.

Example

// Simplified example of renaming the transcript file during compaction
import * as fs from 'fs';
import * as path from 'path';

// Within the compactSession function
const transcriptPath = 'path/to/transcript.jsonl';
const archivedPath = `path/to/transcript.archived.${Date.now()}.jsonl`;
fs.rename(transcriptPath, archivedPath, (err) => {
  if (err) {
    console.error('Error archiving transcript:', err);
  } else {
    console.log('Transcript archived successfully.');
    // Proceed with creating a new transcript file
  }
});

Notes

  • The implementation should consider the trade-off between data retention and storage space, especially in environments with high session turnover or large transcript files.
  • Ensuring the archival mechanism is configurable allows for adapting to different use cases and requirements.

Recommendation

Apply the workaround by implementing the transcript archival mechanism as described, allowing for configurable retention of archived transcripts to mitigate the risk of permanent data loss during session compaction. This approach provides a balance between preventing data loss and managing storage requirements.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Session reset/compaction
Old transcript.jsonl → renamed to transcript.jsonl.archived.{timestamp}
New transcript.jsonl created
Archived files retained for N days (configurable)
Background cleanup removes archived files older than N days

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING