# Session storage guide
## Scope
Owns durable 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` |
| Secure storage preparation | `store.rs` |
| Export archive and destination checks | `export.rs` |
| Frontend list/replay, durable projection cursors, exclusive 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, durable writes, rollback, and metadata updates. Preserve the distinction between rolled-back and uncertain append outcomes.
- Metadata markers include session id, schema, file length, and modification time. Rebuild stale sidecars from JSONL rather than repairing JSONL from a cache.
- Read limits count original line bytes. Tolerant diagnostics report line numbers and safe errors, never malformed line contents.
- Unknown event kinds remain readable. Provider replay selection lives in `../context/replay.rs`; retain terminal partial-text records required by the root manual companion.
- Frontend replay is an allowlist over existing conversation replay: user/assistant text, terminal status, and a valid compaction summary. Preserve cancelled/failed partial text; omit raw records, tool payloads, and local-only fields. Apply existing text redaction without claiming arbitrary secrets cannot occur in conversation text.
- Acquire the append/rotation lock for a durable replay snapshot, not the attachment writer lock. Bound the tail read and complete encoded page payload; expose gaps and stale-prefix resync rather than hiding omissions.
- Projection cursors bind the session and accepted prefix across restarts. Compaction, rewrites, corruption, or a moving window can invalidate them; live service event IDs are unrelated.
- Frontend listing scans a bounded number of directory entries and fails on scan exhaustion; never paginate an arbitrary filesystem-order subset. Keep metadata reads bounded and report skipped candidates with `incomplete`.
- The exclusive frontend writer lease is separate from retention protection. Service attachments own their lease; standalone admission stores it in `Session` clones through worker cleanup. Acquire writer, then activation, then append locks; nested standalone work reuses admission. `frontend/ownership.rs` supplies bounded advisory hints only, never admission authority. Pruning removes ownership sidecars after successful session deletion.
- Keep linked-worktree scope normalization in `scope.rs` and retention deletion in `prune.rs`.
- Title events and metadata are recorded here; provider/background title work belongs to `../session_titles.rs`. Best-effort title/cache failures must not replace required append outcomes.
- Export has its own cancellation and destination checks; do not bypass them with a direct archive write.
- Usage checkpoints cover only the removed JSONL prefix; retain active-run records so suffix snapshots can replace partial usage without double counting. Missing or unfinished request usage remains incomplete.
- Rewind forks copy the ordered prefix before a retained prompt, remap top-level session ids, and append through the normal durable batch path. Keep event-count compaction cutoffs intact; prompt numbering follows compaction aggregate counts. The source JSONL is never truncated. The unsent rewind prompt is local diagnostic metadata, not provider replay.