pub struct SessionStore { /* private fields */ }Expand description
A filesystem session store rooted at a directory.
Implementations§
Source§impl SessionStore
impl SessionStore
Sourcepub fn at(root: impl Into<PathBuf>) -> Self
pub fn at(root: impl Into<PathBuf>) -> Self
Address a store at root without touching the filesystem. Read-only
discovery paths use this so merely checking whether a named session
exists cannot create an empty store directory. Mutating methods still
create their required directories before writing.
Sourcepub fn open(root: impl Into<PathBuf>) -> Result<Self>
pub fn open(root: impl Into<PathBuf>) -> Result<Self>
Open (creating if needed) a store at root.
Sourcepub fn sidecar_path(&self, name: &str) -> PathBuf
pub fn sidecar_path(&self, name: &str) -> PathBuf
The path a sidecar for name lives (or would live) at:
<root>/<name>.sidecar.jsonl. Does not validate name or touch the
filesystem — like the private transcript_path/meta_path helpers,
it’s the read/write methods (save_sidecar, load_sidecar, and
Agent::resume_recorded’s caller) that enforce validate_name before
any I/O happens.
Sourcepub fn reduction_log_path(&self, name: &str) -> Result<PathBuf>
pub fn reduction_log_path(&self, name: &str) -> Result<PathBuf>
The active reduction-log path for name. Like Self::sidecar_path,
this is a path projection only; callers that read or write must still
go through the validated store methods.
Sourcepub fn session_path(&self, name: &str) -> Result<PathBuf>
pub fn session_path(&self, name: &str) -> Result<PathBuf>
Canonical active transcript location for a validated session name. The file need not exist yet; runtime registration uses this to report where the SDK owner will persist successful turns.
Sourcepub fn session_path_for(&self, name: &str, archived: bool) -> Result<PathBuf>
pub fn session_path_for(&self, name: &str, archived: bool) -> Result<PathBuf>
Exact active/archive transcript path. Unlike Self::session_path,
this preserves an explicit archived-family selection.
Sourcepub fn sidecar_path_for(&self, name: &str, archived: bool) -> Result<PathBuf>
pub fn sidecar_path_for(&self, name: &str, archived: bool) -> Result<PathBuf>
Exact active/archive native-v2 sidecar path.
Sourcepub fn subagent_transcript_path_for(
&self,
parent_name: &str,
child_id: &str,
archived: bool,
) -> Result<PathBuf>
pub fn subagent_transcript_path_for( &self, parent_name: &str, child_id: &str, archived: bool, ) -> Result<PathBuf>
Exact active/archive stored-child sidecar path.
Sourcepub fn save_sidecar(&self, name: &str, sidecar_jsonl: &str) -> Result<()>
pub fn save_sidecar(&self, name: &str, sidecar_jsonl: &str) -> Result<()>
Overwrite (or create) <name>’s sidecar file with sidecar_jsonl
verbatim.
Sourcepub fn load_sidecar(&self, name: &str) -> Result<Option<String>>
pub fn load_sidecar(&self, name: &str) -> Result<Option<String>>
Read <name>’s sidecar file (active or archived), if it exists.
None when no sidecar has ever been recorded for this session (e.g.
a plain, non-reduced resume).
Sourcepub fn load_sidecar_from(
&self,
name: &str,
archived: bool,
) -> Result<Option<String>>
pub fn load_sidecar_from( &self, name: &str, archived: bool, ) -> Result<Option<String>>
Read a sidecar from exactly the selected active/archive family.
Sourcepub fn save_reduction_log(&self, name: &str, log: &ReductionLog) -> Result<()>
pub fn save_reduction_log(&self, name: &str, log: &ReductionLog) -> Result<()>
Persist <name>’s ReductionLog (the stub index) as
<name>.reduction.json.
Sourcepub fn load_reduction_log(&self, name: &str) -> Result<Option<ReductionLog>>
pub fn load_reduction_log(&self, name: &str) -> Result<Option<ReductionLog>>
Read <name>’s ReductionLog (active or archived), if one has
ever been saved.
Sourcepub fn load_reduction_log_from(
&self,
name: &str,
archived: bool,
) -> Result<Option<ReductionLog>>
pub fn load_reduction_log_from( &self, name: &str, archived: bool, ) -> Result<Option<ReductionLog>>
Read a reduction log from exactly the selected active/archive family.
Sourcepub fn save_usage_log(&self, name: &str, records: &[UsageRecord]) -> Result<()>
pub fn save_usage_log(&self, name: &str, records: &[UsageRecord]) -> Result<()>
P4b: overwrite (or create) <name>’s usage log with records
(bulk-write, like Self::save_reduction_log — not an incremental
append — so a caller with the full in-memory
crate::usage_log::UsageRecord list, e.g. crate::Agent::usage_records,
can persist it in one call).
Sourcepub fn load_usage_log(&self, name: &str) -> Result<Vec<UsageRecord>>
pub fn load_usage_log(&self, name: &str) -> Result<Vec<UsageRecord>>
P4b: read <name>’s usage log (active or archived). Empty (not an
error) when no usage log has ever been saved for this session.
Sourcepub fn save_model_change_log(
&self,
name: &str,
records: &[ModelChangeRecord],
) -> Result<()>
pub fn save_model_change_log( &self, name: &str, records: &[ModelChangeRecord], ) -> Result<()>
P4c: overwrite (or create) <name>’s model-change log with
records — same bulk-write shape as Self::save_usage_log, for a
caller with the full in-memory crate::model_change::ModelChangeRecord
list (e.g. crate::Agent::model_change_records).
Sourcepub fn load_model_change_log(
&self,
name: &str,
) -> Result<Vec<ModelChangeRecord>>
pub fn load_model_change_log( &self, name: &str, ) -> Result<Vec<ModelChangeRecord>>
P4c: read <name>’s model-change log (active or archived). Empty
(not an error) when no model-change log has ever been saved for this
session — the overwhelmingly common case (allow_switch = false,
the default, or a session that never switched models).
Sourcepub fn save_git_metadata(
&self,
name: &str,
record: &GitMetadataRecord,
) -> Result<()>
pub fn save_git_metadata( &self, name: &str, record: &GitMetadataRecord, ) -> Result<()>
P4e (§1.6/§3.1 core.session.git_metadata): persist <name>’s
captured git metadata as <name>.git.json — a single-record
overwrite, like Self::save_reduction_log, not an append.
Sourcepub fn load_git_metadata(&self, name: &str) -> Result<Option<GitMetadataRecord>>
pub fn load_git_metadata(&self, name: &str) -> Result<Option<GitMetadataRecord>>
P4e: read <name>’s captured git metadata (active or archived).
None (not an error) when no git metadata was ever saved for this
session — the default (session_git_metadata = false).
Sourcepub fn save(
&self,
name: &str,
title: &str,
transcript_jsonl: &str,
) -> Result<()>
pub fn save( &self, name: &str, title: &str, transcript_jsonl: &str, ) -> Result<()>
Save (or overwrite) a session’s transcript JSONL and title.
Sourcepub fn load(&self, name: &str) -> Result<String>
pub fn load(&self, name: &str) -> Result<String>
Read a session’s transcript JSONL (active or archived).
Sourcepub fn load_from(&self, name: &str, archived: bool) -> Result<String>
pub fn load_from(&self, name: &str, archived: bool) -> Result<String>
Read a transcript from exactly the selected active/archive family.
Sourcepub fn load_if_present_from(
&self,
name: &str,
archived: bool,
) -> Result<Option<String>>
pub fn load_if_present_from( &self, name: &str, archived: bool, ) -> Result<Option<String>>
Read a transcript from exactly the selected family when its directory
entry exists, preserving Self::load_if_present’s error semantics.
Sourcepub fn load_if_present(&self, name: &str) -> Result<Option<String>>
pub fn load_if_present(&self, name: &str) -> Result<Option<String>>
Read a session’s transcript JSONL when a transcript directory entry exists (active or archived).
Unlike Self::transcript_mtime, this distinguishes genuine absence
from metadata/read failures. A dangling symlink, directory in place of
the transcript, permission failure, or any other present-but-unreadable
entry is an error rather than None.
Sourcepub fn list(&self) -> Vec<SessionInfo>
pub fn list(&self) -> Vec<SessionInfo>
List all sessions (active and archived).
Sourcepub fn archive(&self, name: &str) -> Result<()>
pub fn archive(&self, name: &str) -> Result<()>
Move a session into the archive: the whole <name>.* family (D1) —
transcript, meta, sidecar, reduction log, and event log — tolerating
any member that doesn’t exist (e.g. a session never recorded in
reduced mode has no sidecar/reduction/events file).
Sourcepub fn delete(&self, name: &str) -> Result<()>
pub fn delete(&self, name: &str) -> Result<()>
Permanently delete a session (active or archived): the whole
<name>.* family (D1) — a delete that left a full-fidelity sidecar
behind would be a data-retention surprise. Tolerates any member that
doesn’t exist.
Sourcepub fn set_title(&self, name: &str, title: &str) -> Result<()>
pub fn set_title(&self, name: &str, title: &str) -> Result<()>
Rename the human-readable title of a session, preserving its other
recorded stats (reduced, tier, byte/stub counts, …) rather than
resetting them to defaults.
Sourcepub fn transcript_mtime(&self, name: &str) -> Option<SystemTime>
pub fn transcript_mtime(&self, name: &str) -> Option<SystemTime>
The transcript file’s mtime (active or archived), if it exists.
Legacy session names embed a creation timestamp (<tag>-<micros>),
so callers could derive age/order from the name alone. UX-25’s
memorable names (<tag>-<adjective>-<noun>) carry no timestamp, so
callers that need one — ordering sessions list, resolving
--continue/--last — fall back to this instead.
Sourcepub fn set_reduction_stats(
&self,
name: &str,
title: &str,
full_bytes: u64,
view_bytes: u64,
stub_count: u32,
) -> Result<()>
pub fn set_reduction_stats( &self, name: &str, title: &str, full_bytes: u64, view_bytes: u64, stub_count: u32, ) -> Result<()>
Record (or update) a session’s reduced-mode stats (C1/C9):
reduced = true plus the full/view byte counts and stub count.
Creates <name>.meta.json with title if it doesn’t exist yet (so a
reduced-mode resume is visible to sessions list even before any
plain transcript has been saved for it under this name); otherwise
preserves the existing title/archived flag, like Self::set_title.
Sourcepub fn fork(
&self,
from: &str,
to: &str,
title: &str,
truncate_at_message: Option<usize>,
timestamp_ms: i64,
) -> Result<ForkProvenance>
pub fn fork( &self, from: &str, to: &str, title: &str, truncate_at_message: Option<usize>, timestamp_ms: i64, ) -> Result<ForkProvenance>
P4e (§1.6 obligation-6 “fork-to-new-file WITH provenance”, CX shape:
“linear store, fork copies + truncation”): copy session from’s
transcript into a NEW session to, optionally truncated to the
first truncate_at_message lines (each line is one message; None
is a full, byte-identical copy — the pre-P4e sessions fork
behavior), and persist a ForkProvenance record for to (typed,
lossless per §1.13: an auditor/translator can always recover exactly
which session and message offset a fork came from). Does NOT touch
from at all – the source session’s own full fidelity is
unaffected regardless of whether to is truncated.
Sourcepub fn save_fork_provenance(
&self,
name: &str,
provenance: &ForkProvenance,
) -> Result<()>
pub fn save_fork_provenance( &self, name: &str, provenance: &ForkProvenance, ) -> Result<()>
Persist <name>’s ForkProvenance as <name>.fork.json —
overwrite semantics, like Self::save_reduction_log.
Sourcepub fn load_fork_provenance(&self, name: &str) -> Result<Option<ForkProvenance>>
pub fn load_fork_provenance(&self, name: &str) -> Result<Option<ForkProvenance>>
Read <name>’s ForkProvenance (active or archived). None
(not an error) when <name> was never created via Self::fork.
Sourcepub fn save_tree(&self, name: &str, tree: &SessionTree) -> Result<()>
pub fn save_tree(&self, name: &str, tree: &SessionTree) -> Result<()>
P5-5 (design §2 module 21 session.tree, §1.6 “typed session data …
folded into archive/delete/list”): persist <name>’s
crate::session_tree::SessionTree as <name>.tree.json —
overwrite semantics, like Self::save_reduction_log.
Sourcepub fn save_claude_runtime_manifest(
&self,
name: &str,
manifest: &ClaudeRuntimeManifest,
) -> Result<()>
pub fn save_claude_runtime_manifest( &self, name: &str, manifest: &ClaudeRuntimeManifest, ) -> Result<()>
Persist the non-executing Claude runtime manifest as a member of this session’s sidecar family.
Sourcepub fn load_claude_runtime_manifest(
&self,
name: &str,
) -> Result<Option<ClaudeRuntimeManifest>>
pub fn load_claude_runtime_manifest( &self, name: &str, ) -> Result<Option<ClaudeRuntimeManifest>>
Load a Claude runtime manifest from the active or archived family.
Sourcepub fn load_claude_runtime_manifest_from(
&self,
name: &str,
archived: bool,
) -> Result<Option<ClaudeRuntimeManifest>>
pub fn load_claude_runtime_manifest_from( &self, name: &str, archived: bool, ) -> Result<Option<ClaudeRuntimeManifest>>
Load a Claude runtime manifest from exactly the selected family.
Sourcepub fn load_tree(&self, name: &str) -> Result<Option<SessionTree>>
pub fn load_tree(&self, name: &str) -> Result<Option<SessionTree>>
Read <name>’s crate::session_tree::SessionTree (active or
archived). None (not an error) when no tree operation was ever
persisted for this session — the default, degenerate-single-path
case (see Self::tree_path’s doc comment).
Sourcepub fn save_subagent_transcript(
&self,
parent_name: &str,
child_id: &str,
sidecar_jsonl: &str,
) -> Result<()>
pub fn save_subagent_transcript( &self, parent_name: &str, child_id: &str, sidecar_jsonl: &str, ) -> Result<()>
P5-3 (design §2 module 9 D5 “subagent transcripts”): persist a
natively-spawned child’s full sidecar (native-v2 JSONL, typically
crate::session::Session::to_native_jsonl_v2’s output, carrying
the child’s own lineage header — see that method’s doc comment) at
<parent_name>.subagents/<child_id>.sidecar.jsonl. child_id is
validated exactly like a top-level session name (it becomes a file
stem too) — same path-traversal floor as Self::validate_name.
Sourcepub fn save_imported_subagents(
&self,
parent_name: &str,
subagents: &[Session],
) -> Result<usize>
pub fn save_imported_subagents( &self, parent_name: &str, subagents: &[Session], ) -> Result<usize>
Persist every subagent attached to an imported crate::session::Session
into this store’s existing <parent_name>.subagents/ family.
Each child is wrapped in native-v2 before it is written, so its
foreign-harness raw body survives a later process/disk reload
byte-for-byte. All ids are validated (and duplicates rejected) before
the first write: an import with incomplete lineage must fail loudly
instead of silently dropping or overwriting a child transcript.
Sourcepub fn load_subagent_transcript(
&self,
parent_name: &str,
child_id: &str,
) -> Result<Option<String>>
pub fn load_subagent_transcript( &self, parent_name: &str, child_id: &str, ) -> Result<Option<String>>
Read a child’s sidecar (active or archived). None when this
(parent_name, child_id) pair was never saved.
Sourcepub fn load_subagent_transcript_from(
&self,
parent_name: &str,
child_id: &str,
archived: bool,
) -> Result<Option<String>>
pub fn load_subagent_transcript_from( &self, parent_name: &str, child_id: &str, archived: bool, ) -> Result<Option<String>>
Read a child sidecar from exactly the selected parent family.
Sourcepub fn save_subagent_lineage(
&self,
parent_name: &str,
child_id: &str,
record: &SubagentLineage,
) -> Result<()>
pub fn save_subagent_lineage( &self, parent_name: &str, child_id: &str, record: &SubagentLineage, ) -> Result<()>
P5-3: persist a child’s typed crate::subagents::SubagentLineage
record at <parent_name>.subagents/<child_id>.lineage.json —
overwrite semantics, like Self::save_reduction_log.
Sourcepub fn load_subagent_lineage(
&self,
parent_name: &str,
child_id: &str,
) -> Result<Option<SubagentLineage>>
pub fn load_subagent_lineage( &self, parent_name: &str, child_id: &str, ) -> Result<Option<SubagentLineage>>
Read a child’s lineage record (active or archived). None when this
(parent_name, child_id) pair was never saved.
Sourcepub fn list_subagent_ids(&self, parent_name: &str) -> Result<Vec<String>>
pub fn list_subagent_ids(&self, parent_name: &str) -> Result<Vec<String>>
P5-3: every child id natively spawned under parent_name (active AND
archived, deduped and sorted) — discovered from the .sidecar.jsonl
members of Self::subagents_dir, the same “list what’s on disk”
posture Self::list uses for top-level sessions.
Sourcepub fn list_subagent_ids_from(
&self,
parent_name: &str,
archived: bool,
) -> Result<Vec<String>>
pub fn list_subagent_ids_from( &self, parent_name: &str, archived: bool, ) -> Result<Vec<String>>
List child ids from exactly the selected active/archive family.
Sourcepub fn prune_expired(
&self,
retention_days: u32,
now: SystemTime,
) -> Result<Vec<String>>
pub fn prune_expired( &self, retention_days: u32, now: SystemTime, ) -> Result<Vec<String>>
P4e (§1.6/§3.1 core.session.retention_days): permanently delete
every ARCHIVED session (never an active one — retention is a
post-archive concern, matching every peer harness) whose transcript
is older than retention_days days as of now. Returns the names
deleted (empty if nothing was old enough, or retention_days == 0
which this treats as “prune nothing” rather than “prune
everything” – an explicit, non-surprising floor).