# Session storage guide
Owns JSONL events, reads, metadata, retention, scope, export, and bounded frontend projections.
## Where to look
| Event kinds and local-only classification | `event.rs` |
| Session creation/open/list | `manager.rs` |
| Id validation and bounded reads | `read.rs` |
| Append outcomes and record helpers | `write.rs` |
| Usage totals and rotation checkpoints | `usage.rs` |
| Sidecar validation and compaction lookup | `metadata.rs` |
| Retention and worktree scope | `prune.rs`, `scope.rs` |
| Storage preparation | `store.rs` |
| Export archive and destination checks | `export.rs` |
| Frontend list/replay, cursors and writer lease | `frontend.rs` |
| Prompt targets and recoverable rewind forks | `rewind.rs` |
## Local rules
- Validate session ids before constructing paths. A new session may have no JSONL file until its first append.
- Use `Session::append_with_outcome`; `append_owned_batch` owns validation, redaction, locking, writes, rollback and metadata updates. Distinguish rolled-back from uncertain outcomes.
- Metadata markers include session id, schema, file length and modification time. Rebuild stale sidecars from JSONL.
- Read limits count original line bytes. Tolerant diagnostics report line numbers and safe errors, never malformed line contents. Unknown event kinds stay readable; provider replay selection belongs to `../context/replay.rs`.
- Frontend replay allowlists user/assistant text, terminal status and valid compaction summaries from conversation replay. Preserve cancelled/failed partial text; omit raw records, tool payloads and local-only fields. Apply existing redaction without claiming arbitrary secrets cannot occur in conversation text.
- Durable replay snapshots take the append/rotation lock, not attachment writer lock. Bound tail reads and complete encoded pages; expose gaps and stale-prefix resync rather than hide omissions.
- Projection cursors bind session and accepted prefix across restarts. Compaction, rewrites, corruption or moving windows can invalidate them; service event IDs are unrelated.
- Frontend listing bounds directory entries scanned and fails on exhaustion; never paginate an arbitrary filesystem-order subset. Bound metadata reads and report skipped candidates with `incomplete`.
- Writer leases are separate from retention protection. Service attachments own leases; standalone admission retains them in `Session` clones through worker cleanup. Lock order is writer, activation, append; nested standalone work reuses admission. `frontend/ownership.rs` provides bounded advisory hints, never admission authority. Pruning removes ownership sidecars after successful session deletion.
- Keep linked-worktree normalization in `scope.rs` and deletion in `prune.rs`.
- Title recording belongs here, provider/background work in `../session_titles.rs`. Best-effort title/cache failures cannot replace required append outcomes.
- Export owns cancellation and destination checks; do not bypass them with direct archive writes.
- Usage checkpoints cover only removed JSONL prefixes. Retain active-run records so suffix snapshots replace partial usage without double counting. Missing/unfinished request usage stays incomplete.
- Rewind forks copy the ordered prefix before a retained prompt, remap top-level session ids and use normal durable batches. Preserve event-count compaction cutoffs; prompt numbering follows compaction aggregate counts. Never truncate source JSONL. Unsent rewind prompts are local diagnostic metadata, not provider replay.