Skip to main content

SessionState

Struct SessionState 

Source
pub struct SessionState {
Show 24 fields pub id: String, pub version: u32, pub started_at: DateTime<Utc>, pub updated_at: DateTime<Utc>, pub project_root: Option<String>, pub shell_cwd: Option<String>, pub task: Option<TaskInfo>, pub findings: Vec<Finding>, pub decisions: Vec<Decision>, pub files_touched: Vec<FileTouched>, pub test_results: Option<TestSnapshot>, pub progress: Vec<ProgressEntry>, pub next_steps: Vec<String>, pub evidence: Vec<EvidenceRecord>, pub intents: Vec<IntentRecord>, pub active_structured_intent: Option<StructuredIntent>, pub stats: SessionStats, pub terse_mode: bool, pub compression_level: String, pub last_consolidate_ts: Option<DateTime<Utc>>, pub extra_roots: Vec<String>, pub wakeup_manifest: Vec<ManifestEntry>, pub playbook: Playbook, pub last_semantic_query: Option<String>, /* private fields */
}
Expand description

Persistent session state tracking task, findings, files, decisions, and stats.

Fields§

§id: String§version: u32§started_at: DateTime<Utc>§updated_at: DateTime<Utc>§project_root: Option<String>§shell_cwd: Option<String>§task: Option<TaskInfo>§findings: Vec<Finding>§decisions: Vec<Decision>§files_touched: Vec<FileTouched>§test_results: Option<TestSnapshot>§progress: Vec<ProgressEntry>§next_steps: Vec<String>§evidence: Vec<EvidenceRecord>§intents: Vec<IntentRecord>§active_structured_intent: Option<StructuredIntent>§stats: SessionStats§terse_mode: bool

When true, resume / compaction prompts encourage concise model replies.

§compression_level: String

Unified compression level label (off/lite/standard/max).

§last_consolidate_ts: Option<DateTime<Utc>>

Watermark: timestamp of last auto-consolidation to prevent duplicate knowledge entries.

§extra_roots: Vec<String>

Extra project roots for multi-root workspaces. Populated from config extra_roots and/or MCP roots/list.

§wakeup_manifest: Vec<ManifestEntry>

LITM placement manifest (#539): what the last wakeup injection placed where, so explicit re-recalls can be scored as placement misses.

§playbook: Playbook

ACE delta playbook (#541): incremental, stable-ID checkpoint entries — grown by ctx_compress, never rewritten (anti context-collapse).

§last_semantic_query: Option<String>

Last ctx_semantic_search query (#542): fallback query source for query-conditioned IB compression when no explicit task is set.

Implementations§

Source§

impl SessionState

Source

pub fn format_compact(&self) -> String

Formats the session state as a compact multi-line summary for agent context.

Source

pub fn build_compaction_snapshot(&self) -> String

Builds a size-limited XML snapshot of session state for context compaction.

Source

pub fn save_compaction_snapshot(&self) -> Result<String, String>

Writes the compaction snapshot to disk and returns the snapshot string.

Source

pub fn load_compaction_snapshot(session_id: &str) -> Option<String>

Loads a previously saved compaction snapshot by session ID.

Source

pub fn load_latest_snapshot() -> Option<String>

Loads the most recently modified compaction snapshot from disk.

When a project root can be derived from CWD, only snapshots whose embedded session data matches the project root are considered. This prevents cross-project snapshot leakage.

Source

pub fn build_resume_block(&self) -> String

Build a compact resume block for post-compaction injection. Max ~500 tokens. Includes task, decisions, files, and archive references.

Source§

impl SessionState

Source

pub fn save(&mut self) -> Result<(), String>

Serializes and writes the session state to disk synchronously.

Source

pub fn prepare_save(&mut self) -> Result<PreparedSave, String>

Serialize session state while holding the lock (CPU-only), reset the unsaved counter, and return a PreparedSave whose I/O can be deferred to a background thread via write_to_disk().

Source

pub fn load_latest() -> Option<Self>

Loads the most recent session matching the current working directory’s project root.

Returns None (a fresh session) rather than falling back to the global latest.json pointer: that unconditional fallback bypassed project-root matching and was the root cause of cross-project session leakage — one project’s findings/decisions/knowledge bleeding into another project’s first session. The correct project session is loaded later from the MCP roots handshake (load_latest_for_project_root).

Also refuses to scope to a broad/unsafe cwd (e.g. the MCP daemon’s HOME), which would otherwise resurrect the contaminated “HOME mega-session”.

Source

pub fn load_global_latest_pointer() -> Option<Self>

Loads the session referenced by the global latest.json pointer, regardless of project. Intended only for explicit, cross-project UX (e.g. lean-ctx session status from an arbitrary directory) — never for injecting knowledge into a new project’s context. Prefer load_latest.

Source

pub fn load_latest_for_project_root(project_root: &str) -> Option<Self>

Loads the most recent session matching a specific project root.

Source

pub fn load_by_id(id: &str) -> Option<Self>

Loads a specific session from disk by its unique ID.

Source

pub fn delete_session(id: &str) -> Result<bool, String>

Deletes a saved session and its compaction snapshot.

If the deleted session is the global latest pointer, the pointer is moved to the newest remaining session or removed when none remain.

Source

pub fn list_sessions() -> Vec<SessionSummary>

Lists all saved sessions as summaries, sorted by most recently updated.

Source

pub fn doctor_quarantine_unsafe_roots( apply: bool, ) -> (Vec<(String, String)>, usize)

Scans all saved sessions for contaminated ones — those rooted at a broad/unsafe path (HOME, filesystem root, agent sandbox dir) without a real project marker, i.e. the historic “HOME mega-session” artifact.

Returns (found, quarantined) where found is (id, root) pairs. When apply is true, each offending session file is moved to a sessions/quarantine/ subdirectory (non-destructive) instead of being loaded into any project’s context.

Source

pub fn cleanup_old_sessions(max_age_days: i64) -> u32

Deletes sessions older than max_age_days, preserving the latest. Returns count removed.

Source§

impl SessionState

Source

pub fn new() -> Self

Creates a new session with a unique ID and current timestamp.

Source

pub fn increment(&mut self)

Bumps the version counter and marks the session as dirty.

Source

pub fn should_save(&self) -> bool

Returns true if enough changes have accumulated to warrant a disk save — or, since #717, if any change has waited longer than SESSION_FLUSH_INTERVAL: the 5-change batch alone left slow sessions invisible to the dashboard (stuck “idle”) for the whole batch window. A fresh in-memory session flushes its first change immediately so new activity surfaces at once.

Source

pub fn set_task(&mut self, description: &str, intent: Option<&str>)

Sets the active task and infers a structured intent from the description.

Source

pub fn auto_infer_task(&mut self)

Auto-infers the task from available context (plans, git diff, file patterns). Only sets if no explicit task is already set or it’s stale.

Source

pub fn add_finding( &mut self, file: Option<&str>, line: Option<u32>, summary: &str, )

Records a finding (discovery or observation) in the session log.

Source

pub fn add_decision(&mut self, summary: &str, rationale: Option<&str>)

Records a design or implementation decision with optional rationale.

Source

pub fn touch_file( &mut self, path: &str, file_ref: Option<&str>, mode: &str, tokens: usize, )

Records a file read/access in the session, incrementing its read count.

Source

pub fn mark_modified(&mut self, path: &str)

Marks a previously touched file as modified (written to).

Source

pub fn set_file_summary(&mut self, path: &str, summary: &str)

Sets a one-line content summary for a touched file (max 80 chars).

Source

pub fn record_tool_call(&mut self, tokens_saved: u64, tokens_input: u64)

Increments the tool call counter and accumulates token savings.

Source

pub fn record_intent(&mut self, intent: IntentRecord)

Records an inferred or explicit intent, coalescing consecutive duplicates.

Source

pub fn record_tool_receipt( &mut self, tool: &str, action: Option<&str>, input_md5: &str, output_md5: &str, agent_id: Option<&str>, client_name: Option<&str>, )

Appends an auditable evidence record for a tool invocation.

Source

pub fn record_manual_evidence(&mut self, key: &str, value: Option<&str>)

Appends a manual (non-tool) evidence record to the audit log.

Source

pub fn has_evidence_key(&self, key: &str) -> bool

Returns true if an evidence record with the given key exists.

Source

pub fn record_cache_hit(&mut self)

Increments the session-level cache hit counter.

Source

pub fn record_command(&mut self)

Increments the session-level command counter.

Source

pub fn effective_cwd(&self, explicit_cwd: Option<&str>) -> String

Returns the effective working directory for shell commands. Priority: explicit cwd arg > session shell_cwd > project_root > process cwd. Explicit CWD and stored shell_cwd are jail-checked against the project root to prevent MCP clients from escaping the workspace.

Source

pub fn effective_cwd_checked( &self, explicit_cwd: Option<&str>, ) -> (String, Option<String>)

Like Self::effective_cwd, but also reports why an explicit cwd request was rejected by the project-root jail and silently replaced with the project root (#629).

The jail itself is deliberate sandboxing (it stops MCP clients escaping the workspace) and must stay — the only gap was that the substitution was silent, so a caller running pwd && ls in what they think is dir A actually ran in the project root with no indication why. Callers that surface output to a human/agent (e.g. ctx_shell) use the returned Option<String> reason to append a one-line hint instead of letting the swap pass unnoticed; effective_cwd keeps the original lossless behaviour.

Source

pub fn note_explicit_cwd(&mut self, cwd: &str)

Persist an explicit, jail-accepted cwd argument as the live shell cwd (#707). update_shell_cwd only tracks cd inside the command text, but clients that switch checkouts mid-session (Claude Code after EnterWorktree) pass the new directory as the cwd param of every subsequent call — without persisting it, the worktree-divergence detection in path resolution never sees the switch. Callers must pass a cwd that already passed the project-root jail.

Source

pub fn update_shell_cwd(&mut self, command: &str)

Updates shell_cwd by detecting cd in the command. Handles: cd /abs/path, cd rel/path (relative to current cwd), cd .., and chained commands like cd foo && .... The new CWD is jail-checked against the project root.

Trait Implementations§

Source§

impl Clone for SessionState

Source§

fn clone(&self) -> SessionState

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SessionState

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for SessionState

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for SessionState

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for SessionState

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more