Session History
Transforms OpenClaw's single-slot session model into a multi-session history system with SQLite indexing, archive/restore, and full dashboard UI.
Architecture
~/.openclaw/agents/{agentId}/sessions/
├── sessions.json # routing table (unchanged)
├── history.db # SQLite index (auto-created)
├── {activeSessionId}.jsonl # active transcript
└── archive/
└── {sessionId}.jsonl # archived transcripts
Lifecycle:
- On
/new or session reset → old transcript moves to archive/, metadata indexed in SQLite
- On archive (from UI) → session deactivated, transcript archived, indexed, removed from store
- On resume → transcript moves back from
archive/, SQLite status flips to active
- Migration auto-runs on first access: indexes all orphaned
.jsonl files
File Map
Backend (new files)
Backend (modified files)
Frontend (modified files)
Installation
See references/INSTALL.md for step-by-step instructions.
RPC Endpoints
| Method | Params | Purpose |
|---|
sessions.archive | key | Archive active session — deactivates, moves transcript, indexes in SQLite, removes from store |
sessions.archived | agentId?, limit?, offset?, search?, status? | List archived sessions with pagination and search |
sessions.resume | sessionId, agentId? | Restore archived session to active |
sessions.rename | sessionId, displayName, agentId? | Update session display name |
sessions.deleteArchived | sessionId, agentId?, deleteTranscript? | Delete archived session + optional transcript |
UI Features
Sessions Page
- Active Sessions grid — with Archive button (hidden for Main Session), History, Delete
- Session History section — archived sessions with search, Resume/Rename/Delete buttons
- Pagination — both sections have 10/20/25 page-size dropdown + Prev/Next
Chat Dropdown
- Filters out cron/subagent/openai sessions (only user-facing sessions shown)
- "Recent Sessions"
<optgroup> with 10 most recent archived sessions
- "📋 View All Sessions" link navigates to Sessions tab
- Selecting an archived session auto-resumes it
Key Design Decisions
- SQLite over JSON: Supports search, pagination, and indexing without loading everything into memory
- Server-side pagination for archives: Pass
limit/offset to sessions.archived RPC
- Client-side pagination for live sessions: Slice the already-loaded array
- sessionId-based dropdown values: Archived sessions all share the same
sessionKey (agent:main:main), so the dropdown uses __archived__:{sessionId} as the option value
sessions.archive reuses sessions.delete param schema: Both need just { key }
Common Pitfalls
- RPC handler signature: Must use
({ params, respond }) destructuring, not (request, respond)
- assertValidParams: Takes 4 args:
(params, validator, "method.name", respond)
- Sessions directory: Use
resolveSessionTranscriptsDirForAgent(agentId) — NOT resolveGatewaySessionStoreTarget(config)
- Pagination on every load: All
loadArchivedSessions calls must pass limit and offset
- Page reset: Changing page size or search query must reset page to 1
- Archived session dropdown filtering: Filter by sessionId, not sessionKey (all archived sessions share the same sessionKey)