Session Resumption
Session resumption is the ability to continue a previous conversation with full context intact. It sounds simple — reload the messages and keep going — but the details are where implementations diverge. What happens to tool call results? How do you handle a conversation that was compacted before it was saved? What if the user wants to fork from a specific point rather than continue at the end? Each reference implementation answers these questions differently. For on-disk schema details behind these resume semantics, see Session Directory Layout. For chat compaction behavior that affects what can be resumed, see Chat History.
Aider Implementation
Section titled “Aider Implementation”Commit: b9050e1d
Aider’s resume mechanism is the simplest: it parses a Markdown chat history file back into messages and optionally triggers background summarization.
CLI Flag
Section titled “CLI Flag”--restore-chat-history (args.py:290-294)Boolean flag, default False. When set, Aider reads the chat history file on startup and populates done_messages with the parsed history.
Resume Flow
Section titled “Resume Flow”The core logic lives in base_coder.py:519-523:
if not self.done_messages and restore_chat_history: history_md = self.io.read_text(self.io.chat_history_file) if history_md: self.done_messages = utils.split_chat_history_markdown(history_md) self.summarize_start()The guard not self.done_messages prevents double-loading if messages already exist from a previous coder handoff.
Markdown Parser
Section titled “Markdown Parser”utils.split_chat_history_markdown() (utils.py:148-196) is a state machine that reconstructs message objects from Aider’s chat log format:
def split_chat_history_markdown(text, include_tool=False): messages = [] user = [] assistant = [] tool = [] lines = text.splitlines(keepends=True)The parsing rules:
- Lines starting with
#are skipped (section headers) - Lines starting with
####are user messages (the####prefix is stripped) - Lines starting with
>are tool output (the>prefix is stripped) - All other lines are assistant response text
- Role transitions flush the current buffer into a message
Tool messages are filtered out by default (include_tool=False), which means tool execution results are lost on resume. The model sees the user’s request and the assistant’s response but not the intermediate tool invocations.
Post-Resume Summarization
Section titled “Post-Resume Summarization”summarize_start() (base_coder.py:1005-1023) kicks off a background thread to compress the restored history:
def summarize_start(self): if self.summarizer_thread: return if not self.main_model.can_prefill: return self.summarizer_thread = threading.Thread(target=self._summarize_thread) self.summarizer_thread.start()The thread runs ChatSummary.summarize_real() which recursively splits the message list (keeping the recent 50%), summarizes the head with the weak model, and produces a condensed history. If summarization fails, the full history is kept.
State Preserved
Section titled “State Preserved”- User prompts (text only)
- Assistant responses (full text)
State Lost
Section titled “State Lost”- Tool execution results (filtered by default)
- File contents at the time of each turn
- Repo map state
- Edit format metadata
- Token counts and cost tracking
No Session Discovery
Section titled “No Session Discovery”Aider has no session listing or selection UI. The chat history file is a single file per project directory (.aider.chat.history.md). There is no concept of multiple named sessions, forking, or branching.
Codex Implementation
Section titled “Codex Implementation”Commit: 4ab44e2c5
Codex uses event-sourced JSONL rollout files for session persistence. Resume replays the event log to reconstruct the full conversation state, preserving tool call results and metadata.
CLI Entry Points
Section titled “CLI Entry Points”Two commands in cli/src/main.rs:186-221:
Resume(ResumeCommand) { session_id: Option<String>, // UUID or thread name last: bool, // --last: continue most recent session all: bool, // --all: show all sessions (no CWD filter)}
Fork(ForkCommand) { // Same structure as Resume, but creates a new session from checkpoint}codex --resume opens an interactive session picker if no session ID is specified. codex --resume --last skips the picker and continues the most recent session.
Session Picker
Section titled “Session Picker”tui/src/resume_picker.rs:114-219 implements an interactive session browser:
- Filtering: by provider, session source (CLI-only by default), and CWD
- Sorting: by
CreatedAt(default) orUpdatedAt(Tab to toggle) - Search: type to filter by title/content
- Preview: shows first user message, timestamps, git branch, working directory
- Pagination: cursor-based, loads pages on demand via
RolloutRecorder::list_threads() - Deduplication:
seen_pathsHashSet prevents showing the same session twice across pages (line 546)
Session Discovery
Section titled “Session Discovery”RolloutRecorder::find_resume_path() (recorder.rs:310-350) searches for a resumable session:
- First checks the state database (
codex-statecrate) for indexed sessions - Falls back to file-system scanning of
~/.codex/sessions/directories select_resume_path()(recorder.rs:950-964) filters by CWD match — if the session’s working directory matches the current CWD, it is eligible
fn select_resume_path(page: &ThreadsPage, filter_cwd: Option<&Path>) -> Option<PathBuf> { match filter_cwd { Some(cwd) => page.items.iter().find_map(|item| { if item.cwd.as_ref().is_some_and(|session_cwd| cwd_matches(session_cwd, cwd)) { Some(item.path.clone()) } else { None } }), None => page.items.first().map(|item| item.path.clone()), }}Rollout File Format
Section titled “Rollout File Format”Sessions are stored as JSONL files at:
~/.codex/sessions/YYYY/MM/DD/rollout-{timestamp}-{uuid}.jsonlEach line is a RolloutLine:
struct RolloutLine { timestamp: String, // RFC 3339 item: RolloutItem { SessionMeta { meta, git }, EventMsg { ... }, // UserMessage, AssistantResponse, ExecCommandEnd, etc. }}Resume Replay
Section titled “Resume Replay”When a session is resumed (codex.rs:1041-1051):
InitialHistory::Resumed(resumed_history) => ( resumed_history.conversation_id, RolloutRecorderParams::resume( resumed_history.rollout_path.clone(), event_persistence_mode, ),)The ResumedHistory struct contains:
conversation_id: the original thread UUID (preserves prompt cache key)rollout_path: path to the JSONL filehistory:Vec<ResponseItem>— the full conversation replayed from the JSONL
The rollout recorder opens the existing file in append mode. New events are appended; old events are never modified. This is the append-only event-sourcing pattern.
History Reconstruction
Section titled “History Reconstruction”metadata::builder_from_items() (rollout/metadata.rs) reconstructs session metadata (token counts, timestamps, tool usage statistics) from the replayed items. This metadata is used by the TUI for display but doesn’t affect the model — the model receives the raw ResponseItem history.
Fork (codex --fork) creates a new session with a new ThreadId but copies the entire history from the source session up to the fork point. The forked_from_id field preserves lineage:
RolloutRecorderParams::new( conversation_id, forked_from_id, // Optional<ThreadId> session_source, base_instructions, dynamic_tools, event_persistence_mode,)State Preserved
Section titled “State Preserved”- Complete message history (user prompts, assistant responses)
- Tool execution results (command outputs, exit codes, durations)
- File diffs and patch applications
- Session metadata (CWD, git branch/SHA, timestamps)
- Dynamic tools registered during the session
- Base instructions at session creation time
- Ghost snapshots (stripped from prompt but preserved in rollout)
State Lost
Section titled “State Lost”- TUI layout and scroll position
- In-progress approval dialogs
- Partially streamed responses (if the process crashed mid-stream)
Compaction Interaction
Section titled “Compaction Interaction”If a session was auto-compacted before being saved, the rollout file contains the compaction result — the summarized history replaces the original messages. Resumed sessions continue from the compacted state.
OpenCode Implementation
Section titled “OpenCode Implementation”Commit: 7ed449974
OpenCode stores sessions in SQLite and resumes by querying the database directly. There is no replay step — messages are stored as final state.
Session Selection
Section titled “Session Selection”The TUI presents a session list. The Session.list() generator (session/index.ts:508-545) queries the database:
export function* list(input?: { directory?: string, roots?: boolean, // Filter to root sessions only (no forks) start?: number, // Filter by timestamp search?: string, // LIKE query on title limit?: number, // Max results (default 100)}) { const conditions = [eq(SessionTable.project_id, project.id)] // ... build conditions const rows = Database.use((db) => db.select().from(SessionTable) .where(and(...conditions)) .orderBy(desc(SessionTable.time_updated)) .limit(limit) .all() ) for (const row of rows) yield fromRow(row)}Sessions are always filtered to the current project and sorted by most recently updated.
Message Loading
Section titled “Message Loading”Session.messages() (session/index.ts:492-506) loads messages with their associated parts:
export const messages = fn( z.object({ sessionID: Identifier.schema("session"), limit: z.number().optional(), }), async (input) => { const result = [] as MessageV2.WithParts[] for await (const msg of MessageV2.stream(input.sessionID)) { if (input.limit && result.length >= input.limit) break result.push(msg) } result.reverse() return result },)MessageV2.stream() uses an async generator that queries MessageTable and PartTable via Drizzle ORM, streaming results to avoid loading everything into memory at once. The reverse() at the end converts from database order (newest first) to chronological order.
Message-to-Model Conversion
Section titled “Message-to-Model Conversion”MessageV2.toModelMessages() converts stored messages back into the format the LLM expects. Each MessageV2.WithParts contains:
info: metadata (role, timestamps, parentID, error state, finish reason)parts: array ofMessagePartvariants (text, tool call, tool result, reasoning, file diff, etc.)
The conversion handles:
- Compacted parts (flagged with
time.compacted) — these are stripped or replaced with summaries - Tool results with metadata — formatted back into the provider-specific shape
- Reasoning parts — included or excluded based on model capabilities
Fork Mechanism
Section titled “Fork Mechanism”Session.fork() (session/index.ts:210-250) clones a session up to a specific message:
export const fork = fn( z.object({ sessionID: Identifier.schema("session"), messageID: Identifier.schema("message").optional(), }), async (input) => { const original = await get(input.sessionID) const title = getForkedTitle(original.title) const session = await createNext({ parentID: input.sessionID, directory: original.directory, title, })
const msgs = await messages({ sessionID: input.sessionID }) const idMap = new Map<string, string>()
for (const msg of msgs) { if (input.messageID && msg.info.id >= input.messageID) break
const newID = Identifier.ascending("message") idMap.set(msg.info.id, newID)
const parentID = msg.info.role === "assistant" && msg.info.parentID ? idMap.get(msg.info.parentID) : undefined
const cloned = await updateMessage({ ...msg.info, sessionID: session.id, id: newID, ...(parentID && { parentID }), })
for (const part of msg.parts) { await updatePart({ ...part, id: Identifier.ascending("part"), messageID: cloned.id, sessionID: session.id, }) } } return session },)Key details:
messageIDparameter allows forking from a specific point (messages with ID >= messageID are excluded)idMaptracks old-to-new message ID mapping for parentID resolution- All parts are cloned individually with new IDs
- The
parentIDon the session preserves the fork lineage
Session Hierarchy
Section titled “Session Hierarchy”Sessions form a tree:
- Root sessions have
parentID: null - Forked sessions reference their source via
parentID Session.children()queries for all forks of a sessionSession.remove()recursively deletes children before the parent (cascade)
Compaction Markers
Section titled “Compaction Markers”When a session is compacted, a time_compacting timestamp is set on the session row. During message loading, parts with time.compacted set are handled differently — they may be replaced with summary text or excluded from the model context entirely. This allows resumed sessions to continue from the compacted state without replaying the full history.
Web Sharing as Import
Section titled “Web Sharing as Import”OpenCode supports importing shared sessions. The import creates a new root session with cloned messages, effectively acting as a remote fork. The share.url field on the original session tracks where it was shared.
State Preserved
Section titled “State Preserved”- Full message history with all parts (text, tool calls, tool results, reasoning, diffs)
- Session metadata (directory, permissions, timestamps)
- Fork lineage (parentID chain)
- Compaction state (which parts have been summarized)
State Lost
Section titled “State Lost”- TUI scroll position and layout
- Active permission dialogs
- LSP server state (must reinitialize on resume)
Claude Code Implementation
Section titled “Claude Code Implementation”Claude Code’s session resumption combines conversation continuation (--continue/--resume), session forking (--continue --fork-session), checkpoint-based rewind, and persistent memory that survives across sessions regardless of conversation state.
Session Continuation
Section titled “Session Continuation”Claude Code offers two continuation modes:
claude --continue— continue the most recent conversation in the current projectclaude --resume— display a session picker to choose from past conversations
Sessions are identified by session_id (visible in the status line JSON data and in the transcript file path). Sessions are scoped to a project (derived from the git root or working directory).
Transcript Persistence
Section titled “Transcript Persistence”Each session produces a transcript file at a path exposed via transcript_path in the status line data. The transcript preserves all messages including compaction artifacts, allowing post-session analysis even when in-context messages have been compacted.
claude --continue --fork-session creates a new session branching from the current one. The fork preserves the source session intact while starting a new conversation from that point:
- The original session remains unmodified
- The fork gets a new
session_id - Both sessions continue independently from the fork point
This differs from the rewind menu’s “Summarize from here” which stays in the same session and compresses context.
Checkpoint-Based Rewind
Section titled “Checkpoint-Based Rewind”The checkpoint system (one checkpoint per user prompt, tracking file editing tool changes) provides session-level undo without requiring a full session save/restore:
| Action | Effect on Conversation | Effect on Files |
|---|---|---|
| Restore code and conversation | Rewind to checkpoint message | Revert files to checkpoint state |
| Restore conversation | Rewind to checkpoint message | Keep current files |
| Restore code | Keep current conversation | Revert files to checkpoint state |
| Summarize from here | Compress from checkpoint forward | No file changes |
Checkpoints persist across sessions (30-day TTL, configurable). Only file editing tool changes are tracked — bash command file modifications are invisible to the checkpoint system.
Memory Persistence (Cross-Session)
Section titled “Memory Persistence (Cross-Session)”Claude Code has persistent memory that survives session boundaries independently of conversation history:
Auto memory (~/.claude/projects/<project>/memory/):
MEMORY.md— index file, first 200 lines loaded into system prompt at every session start- Topic files (
debugging.md,api-conventions.md, etc.) — loaded on demand - Claude reads and writes these during sessions
- Per-project (derived from git root); git worktrees get separate directories
CLAUDE.md hierarchy (six levels, loaded at session start):
- Managed policy → Project → Project rules → User → Project local → Auto memory
- Loaded regardless of which session is resumed — same instructions apply to all sessions in a project
- Project rules support path-scoped activation via glob patterns in YAML frontmatter
This means session resumption in Claude Code is less critical than in Aider/Codex/OpenCode because key learnings are persisted in memory files rather than solely in conversation history. A new session in the same project starts with all accumulated knowledge from previous sessions via auto memory.
Compaction State on Resume
Section titled “Compaction State on Resume”When resuming a session that was compacted:
- The conversation continues from the compacted state
- The compaction summary provides context for everything before the compaction point
- The original pre-compaction messages are preserved in the transcript (not loaded into context)
- Server-side compaction blocks are passed through to the API, which auto-drops content before them
State Preserved on Resume
Section titled “State Preserved on Resume”- Full conversation history (with compaction markers)
- Checkpoints (file state snapshots, 30-day TTL)
- Auto memory (no TTL, persists indefinitely)
- CLAUDE.md hierarchy (re-loaded from disk)
- Session metadata (project, directory, costs)
State Lost on Resume
Section titled “State Lost on Resume”- TUI state (scroll position, layout)
- Active permission dialogs
- Status line script state (re-executes on first message)
- In-progress tool executions (if session crashed mid-tool)
Comparison Table
Section titled “Comparison Table”| Aspect | Aider | Codex | OpenCode | Claude Code |
|---|---|---|---|---|
| Resume mechanism | --restore-chat-history flag | --resume / --resume --last | Session list in TUI | --continue / --resume |
| Session picker | None (single file per project) | Interactive browser with search/filter | TUI session list | Session picker (project-scoped) |
| Fork | Not supported | --fork (copy JSONL, new thread ID) | Session.fork() (clone messages with new IDs) | --continue --fork-session |
| Tool results on resume | Lost by default | Fully preserved (JSONL replay) | Fully preserved (SQLite) | Preserved (with compaction markers) |
| Cross-session memory | None | None | None | Auto memory + CLAUDE.md hierarchy |
| Session undo | None | None | None | Checkpoint rewind (4 actions) |
| Compaction on resume | Immediate summarization if too large | Compacted state in JSONL | Load from last compaction boundary | Server-side compaction blocks |
| Prompt cache reuse | Lost on resume | Preserved (conversation_id) | Lost on resume | Depends on compaction block caching |
| File state tracking | Not tracked | Ghost snapshots in rollout | Not tracked | Checkpoints (file editing tools only) |
Pitfalls & Hard Lessons
Section titled “Pitfalls & Hard Lessons”Aider’s Lossy Resume
Section titled “Aider’s Lossy Resume”Tool output is filtered by default during Markdown parsing. This means the model loses context about what commands were run and what their outputs were. For debugging workflows where the tool output is critical context, this is a significant limitation. The include_tool=True parameter exists but isn’t exposed to users.
JSONL Corruption
Section titled “JSONL Corruption”Codex’s append-only JSONL is robust against crashes (partial writes produce an incomplete final line that can be skipped), but corruption from disk issues requires manual editing. There is no automatic recovery or checksum verification.
SQLite WAL Checkpoint Timing
Section titled “SQLite WAL Checkpoint Timing”OpenCode uses SQLite in WAL mode. If the application crashes between a write and a WAL checkpoint, the changes are in the WAL file but not the main database. On next startup, SQLite automatically replays the WAL, so data is preserved — but if the WAL file is deleted (e.g., by a cleanup script), recent writes are lost.
Conversation ID and Prompt Cache
Section titled “Conversation ID and Prompt Cache”Codex preserves the conversation_id across resume, which means the OpenAI server-side prompt cache may still be warm. This is a significant performance advantage — the first API call after resume can hit the cache. Aider and OpenCode both lose any prompt cache on resume because they reconstruct the conversation from scratch.
Fork Semantics Are Not Obvious
Section titled “Fork Semantics Are Not Obvious”Both Codex and OpenCode support forking from a specific point, but the behavior differs:
- Codex copies the JSONL file and appends to it (cheap, but the fork contains the full source history)
- OpenCode clones individual messages with new IDs (more expensive, but creates a clean independent session)
Neither implementation tracks file system state at the fork point — if the user’s files have changed since the original session, the resumed conversation may reference stale file contents.
Compaction Before Resume
Section titled “Compaction Before Resume”If a session was compacted (summarized) before saving, the resumed session starts from the compacted state. The model has no way to “un-compact” — it sees only the summary, not the original detailed history. This is usually fine, but can be surprising if the user expects to see their full conversation on resume.
Session Discovery Filters Must Match
Section titled “Session Discovery Filters Must Match”Codex filters sessions by CWD on resume. If the user navigates to a different directory, their sessions won’t appear. OpenCode filters by project ID, which is more stable (derived from the git root or directory path). Both approaches have edge cases with monorepos or moved projects.
Cascade Deletes Need Care
Section titled “Cascade Deletes Need Care”OpenCode’s Session.remove() recursively deletes child sessions. If a user deletes a parent session, all forks are lost. This matches the intent (parent is the “source of truth”) but can be surprising. Codex avoids this by treating each rollout file as independent.
Auto Memory Can Diverge from Session State
Section titled “Auto Memory Can Diverge from Session State”Claude Code’s auto memory persists independently of sessions. If Claude saves a learning to memory during session A, then the user rewinds session A past that point, the memory file still contains the learning. This creates a divergence where memory reflects a state that was “undone” in the conversation. There’s no mechanism to revert auto memory writes alongside checkpoint rewinds.
Checkpoint TTL Creates Silent Data Loss
Section titled “Checkpoint TTL Creates Silent Data Loss”Checkpoints auto-clean after 30 days. If a user tries to resume a session older than 30 days, the conversation is available but checkpoint rewind is not. This is undocumented in the session list — there’s no indicator that a session has lost its rewind capability.
Fork Is One-Way
Section titled “Fork Is One-Way”Claude Code’s fork creates an independent session — there’s no merge-back mechanism. If the user explores two approaches via fork and wants to combine insights, they must manually copy information between sessions or rely on auto memory to capture learnings.
OpenOxide Blueprint
Section titled “OpenOxide Blueprint”Storage: SQLite with Event Log
Section titled “Storage: SQLite with Event Log”Combine the best of both approaches:
- SQLite for session metadata, message storage, and fast queries (OpenCode pattern)
- Append-only event log in the database for crash recovery (Codex pattern)
Use rusqlite with WAL mode. Schema:
CREATE TABLE sessions ( id TEXT PRIMARY KEY, parent_id TEXT REFERENCES sessions(id), project_id TEXT NOT NULL, directory TEXT NOT NULL, title TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL);
CREATE TABLE messages ( id TEXT PRIMARY KEY, session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE, parent_id TEXT, role TEXT NOT NULL, -- "user", "assistant", "system" created_at INTEGER NOT NULL, compacted_at INTEGER, -- NULL if not compacted data BLOB NOT NULL -- MessagePack-encoded content);
CREATE TABLE parts ( id TEXT PRIMARY KEY, message_id TEXT NOT NULL REFERENCES messages(id) ON DELETE CASCADE, session_id TEXT NOT NULL, type TEXT NOT NULL, -- "text", "tool_call", "tool_result", "reasoning", "diff" created_at INTEGER NOT NULL, compacted_at INTEGER, data BLOB NOT NULL);Resume Flow
Section titled “Resume Flow”- User selects session from TUI picker (query
sessionstable, filter by project) - Load messages via streaming query (
ORDER BY created_at ASC) - For each message, load associated parts
- Convert to model message format, respecting compaction markers
- Reconstruct system prompt (environment + instructions)
- Continue conversation with full context
pub async fn fork(session_id: &str, at_message: Option<&str>) -> Result<Session> { let source = Session::get(session_id).await?; let forked = Session::create(CreateParams { parent_id: Some(session_id), directory: source.directory, title: format!("{} (fork)", source.title), }).await?;
let messages = Message::stream(session_id).await; let mut id_map = HashMap::new();
for msg in messages { if let Some(cutoff) = at_message { if msg.id >= cutoff { break; } } let new_id = generate_id(); id_map.insert(msg.id.clone(), new_id.clone()); // Clone message and parts with new IDs }
Ok(forked)}Session Listing
Section titled “Session Listing”pub fn list(params: ListParams) -> impl Iterator<Item = SessionInfo> { // Query sessions table with: // - project_id filter (always) // - directory filter (optional) // - roots_only filter (parent_id IS NULL) // - search filter (LIKE on title) // - ORDER BY updated_at DESC // - LIMIT (default 100)}Crates
Section titled “Crates”openoxide-session— Session CRUD, message storage, fork, resumeopenoxide-db— SQLite wrapper with WAL mode, migrationsrusqlite— SQLite bindingrmp-serde— MessagePack serialization for message/part data
Key Design Decisions
Section titled “Key Design Decisions”- SQLite over JSONL — queries, indexing, and atomic operations are worth the complexity
- MessagePack for part data — more compact than JSON, schema-flexible
- Cascade deletes with confirmation — warn before deleting sessions with children
- Preserve conversation_id — enables prompt cache reuse on resume (Codex insight)
- Stream-based message loading — avoid loading entire sessions into memory
- Compaction markers on parts, not messages — finer-grained control over what the model sees
- Persistent memory separate from sessions — auto memory survives session rewind/deletion (Claude Code insight)
- Checkpoint system with TTL — per-prompt file state snapshots with configurable expiry (Claude Code insight)
- Fork as independent session — new session_id, full message clone, no merge-back (Claude Code/Codex insight)
- Server-side compaction preference — when provider supports it, prefer over client-side (Claude Code insight)
Checkpoint System (from Claude Code)
Section titled “Checkpoint System (from Claude Code)”Add a checkpoint table alongside sessions:
CREATE TABLE checkpoints ( id TEXT PRIMARY KEY, session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE, message_id TEXT NOT NULL REFERENCES messages(id), created_at INTEGER NOT NULL, expires_at INTEGER NOT NULL -- created_at + ttl_days * 86400);
CREATE TABLE checkpoint_files ( id TEXT PRIMARY KEY, checkpoint_id TEXT NOT NULL REFERENCES checkpoints(id) ON DELETE CASCADE, path TEXT NOT NULL, content_hash TEXT NOT NULL, content BLOB -- NULL if file was deleted, content if modified);Checkpoint creation: before each file edit tool execution, snapshot the current file state. Group all edits within a single user prompt under one checkpoint.
Auto Memory Integration (from Claude Code)
Section titled “Auto Memory Integration (from Claude Code)”pub struct AutoMemory { pub dir: PathBuf, // ~/.openoxide/projects/<project>/memory/ pub index: MemoryIndex, // MEMORY.md, first N lines loaded at startup pub topic_files: Vec<PathBuf>, // loaded on demand}
impl AutoMemory { /// Load index file (first 200 lines) into system prompt pub fn load_index(&self) -> String { ... }
/// Agent writes a learning to memory pub async fn save(&self, topic: &str, content: &str) -> Result<()> { ... }
/// Agent reads a topic file on demand pub async fn read_topic(&self, name: &str) -> Result<String> { ... }}Memory persists across sessions and is loaded at every session start, ensuring accumulated knowledge survives session deletion, rewind, and compaction.