Session Persistence
Relevant source files
The following files were used as context for generating this wiki page:
- packages/coding-agent/src/session/session-manager.ts
- packages/coding-agent/src/session/session-storage.ts
- packages/coding-agent/test/session-manager-immediate-persist.test.ts
- packages/coding-agent/test/session-manager/file-operations.test.ts
- packages/coding-agent/test/session-manager/draft.test.ts
- packages/coding-agent/DEVELOPMENT.md
Session Persistence in the Oh My Pi coding harness is a durability layer designed to store and navigate an append-only conversation journal. The system ensures that conversation history, tool results, and agent metadata survive application crashes and are resumable across different working directories. It primarily utilizes a JSONL (JSON Lines) format where each line represents a discrete session entry, structured into a tree via parent-child relationships.
The persistence layer is managed by the SessionManager, which coordinates between in-memory state, high-level session operations (like branching or forking), and the underlying storage implementations. It is designed to be software-crash safe by writing entries synchronously as they are created, though it does not explicitly perform fsync for power-loss safety.
Sources: packages/coding-agent/src/session/session-manager.ts:246-254, packages/coding-agent/DEVELOPMENT.md:54-57
Architecture and Data Flow
The session persistence architecture relies on a clear separation between the high-level management logic and the physical storage medium. The SessionManager maintains derived views (indices) over the entry list to provide efficient access to session trees and branches.
Component Overview
| Component | Responsibility |
|---|---|
| SessionManager | Orchestrates appends, branches, and persistence logic. Maintains the SessionEntryIndex. |
| SessionStorage | Interface for abstracting file system operations (File vs Memory). |
| SessionEntryIndex | In-memory lookup and tree structure for O(1) access to specific session nodes. |
| BlobStore | Handles large binary data (like images) separately from the text-based JSONL logs. |
Sources: packages/coding-agent/src/session/session-manager.ts:133-145, packages/coding-agent/src/session/session-storage.ts:9-15
Persistence Flow
The following diagram illustrates how a new message moves from the agent into persistent storage:
The persistence logic uses a "lazy gate": a brand-new session is not written to disk until it contains at least one assistant message or persistence is explicitly forced (e.g., via ensureOnDisk).
Sources: packages/coding-agent/src/session/session-manager.ts:405-410, packages/coding-agent/src/session/session-manager.ts:450-455, packages/coding-agent/test/session-manager-immediate-persist.test.ts:74-85
Data Structures and Formats
JSONL Session File
A session file consists of a header line followed by multiple entry lines. Each line is an independent JSON object.
// Header example
{ "type": "session", "version": 3, "id": "uuid-v7", "timestamp": "ISO-8601", "cwd": "/path/to/project" }
// Entry example
{ "type": "message", "id": "entry-id", "parentId": "parent-uuid", "timestamp": "...", "message": { ... } }
Sources: packages/coding-agent/src/session/session-manager.ts:246-250, packages/coding-agent/test/session-manager/file-operations.test.ts:24-28
Session Tree Management
Entries form a tree structure using id and parentId fields. The SessionManager tracks a leafId which represents the current active tip of the conversation.
Key Operations
Resuming and Reserving Breadcrumbs
When a session starts, the manager writes a "terminal breadcrumb." This allows the CLI to implement --continue behavior by looking up the last session associated with a specific working directory.
- Breadcrumb Logic: If a user moves a project directory, the manager detects the stale breadcrumb and offers to re-root the moved session to the new location.
- Resolution: Subagent sessions (which live in artifact subdirectories) are resolved back to their interactive root to ensure
--continueresumes the main conversation.
Sources: packages/coding-agent/src/session/session-manager.ts:98-105, packages/coding-agent/src/session/session-manager.ts:980-1005
Branching and Forking
The persistence layer supports non-linear history:
- Branching: Moves the
leafIdto an earlier entry. Subsequent appends create a new path in the tree without deleting existing data. - Forking: Creates a brand-new JSONL file containing the current session's history, allowing the user to start a separate line of work while preserving the parent's state.
Sources: packages/coding-agent/src/session/session-manager.ts:890-905, packages/coding-agent/src/session/session-manager.ts:634-645
Draft Persistence
The manager supports "draft" persistence for unsent user text. Drafts are stored as draft.txt within a session's specific artifacts directory.
Storage Implementation
The system abstracts file operations through the SessionStorage interface, allowing for different backends.
FileSessionStorage
The standard implementation used for CLI persistence. It supports:
- Synchronous Appends: Used for immediate durability during
appendMessage. - Atomic Rewrites: Uses a temp-write + rename strategy to prevent file truncation during full session rewrites (e.g., after migration or compaction).
- Title Updates: Can update the session title slot (a metadata prefix in the JSONL file) independently of the entry stream.
Sources: packages/coding-agent/src/session/session-storage.ts:9-15, packages/coding-agent/src/session/session-manager.ts:383-395
Artifact Management
Sessions often generate sidecar files (logs, tool outputs, drafts). These are stored in a directory named after the session file (minus the .jsonl suffix).
- Directory Mapping:
path/to/session.jsonl->path/to/session/ - Cleanup: When a session is dropped via
dropSession, theSessionManageralso recursively removes the associated artifacts directory.
Sources: packages/coding-agent/src/session/session-manager.ts:88-90, packages/coding-agent/test/session-manager/draft.test.ts:35-45
Summary
Session Persistence in Oh My Pi is a specialized logging system designed for LLM workflows. By combining an append-only JSONL format with an in-memory tree index, it provides a balance between high-performance synchronous durability and flexible history navigation. The use of storage abstraction and artifact management ensures that entire agent environments—including binary blobs and unsent drafts—remain portable and resumable.