pub struct ClaudeSession {Show 76 fields
pub pid: u32,
pub session_id: String,
pub cwd: String,
pub project_name: String,
pub started_at: u64,
pub elapsed: Duration,
pub tty: String,
pub status: SessionStatus,
pub cpu_percent: f32,
pub cpu_history: Vec<f32>,
pub mem_mb: f64,
pub own_input_tokens: u64,
pub own_output_tokens: u64,
pub own_cache_read_tokens: u64,
pub own_cache_write_tokens: u64,
pub own_cache_write_1h_tokens: u64,
pub last_usage_msg_id: Option<String>,
pub subagent_input_tokens: u64,
pub subagent_output_tokens: u64,
pub subagent_cache_read_tokens: u64,
pub subagent_cache_write_tokens: u64,
pub subagent_cache_write_1h_tokens: u64,
pub total_input_tokens: u64,
pub total_output_tokens: u64,
pub model: String,
pub command_args: String,
pub session_name: String,
pub jsonl_path: Option<PathBuf>,
pub jsonl_offset: u64,
pub last_message_ts: u64,
pub cache_read_tokens: u64,
pub cache_write_tokens: u64,
pub cost_usd: f64,
pub context_tokens: u64,
pub context_max: u64,
pub prev_cost_usd: f64,
pub burn_rate_per_hr: f64,
pub burn_rate_ewma: f64,
pub burn_samples: VecDeque<f64>,
pub subagent_count: usize,
pub active_subagent_count: usize,
pub active_subagent_jsonl_paths: Vec<PathBuf>,
pub subagent_rollups: HashMap<PathBuf, SubagentRollup>,
pub activity_history: Vec<u8>,
pub files_modified: HashMap<String, u32>,
pub tool_usage: HashMap<String, ToolStats>,
pub worktree_id: Option<String>,
pub telemetry_status: TelemetryStatus,
pub usage_metrics_available: bool,
pub cost_estimate_unverified: bool,
pub model_profile_source: String,
pub last_msg_type: String,
pub last_stop_reason: String,
pub is_waiting_for_task: bool,
pub pending_tool_name: Option<String>,
pub pending_tool_input: Option<String>,
pub pending_file_path: Option<String>,
pub has_file_conflict: bool,
pub last_tool_error: bool,
pub last_error_message: Option<String>,
pub recent_errors: Vec<ErrorEntry>,
pub total_tokens_at_edit_count: u64,
pub edit_event_count: u32,
pub baseline_tokens_per_edit: Option<f64>,
pub error_counts_per_window: Vec<u32>,
pub current_window_errors: u32,
pub window_tick_counter: u32,
pub baseline_error_rate: Option<f64>,
pub file_reads_since_edit: HashMap<String, u32>,
pub total_error_count: u32,
pub decay_score: u32,
pub worker_origin: Option<String>,
pub agent_family: String,
pub tmux_target: Option<String>,
pub remote_user: Option<String>,
pub remote_host: Option<String>,
}Fields§
§pid: u32§session_id: StringRead by the send hotkey (#510), which is why this no longer carries an
allow(dead_code) — see the #465 audit for why those expire.
cwd: String§project_name: String§started_at: u64§elapsed: Duration§tty: String§status: SessionStatus§cpu_percent: f32§cpu_history: Vec<f32>§mem_mb: f64§own_input_tokens: u64§own_output_tokens: u64§own_cache_read_tokens: u64§own_cache_write_tokens: u64§own_cache_write_1h_tokens: u64The subset of own_cache_write_tokens written with a 1-hour TTL, which
bills at 2x base input rather than 1.25x.
last_usage_msg_id: Option<String>The message id whose usage was counted most recently.
Claude Code writes one JSONL line per content block of an assistant
turn — thinking, text, tool_use — and repeats the turn’s whole
usage on each. Counting every line charged the same tokens two or
three times over. Duplicate lines are always adjacent (verified across
4814 turns in 25 transcripts), so remembering one id is enough, and it
has to live on the session because parsing is incremental and a turn’s
lines can straddle two reads.
subagent_input_tokens: u64§subagent_output_tokens: u64§subagent_cache_read_tokens: u64§subagent_cache_write_tokens: u64§subagent_cache_write_1h_tokens: u641-hour-TTL subset of subagent_cache_write_tokens.
total_input_tokens: u64§total_output_tokens: u64§model: String§command_args: String§session_name: String§jsonl_path: Option<PathBuf>§jsonl_offset: u64§last_message_ts: u64§cache_read_tokens: u64§cache_write_tokens: u64§cost_usd: f64§context_tokens: u64§context_max: u64§prev_cost_usd: f64§burn_rate_per_hr: f64§burn_rate_ewma: f64EWMA-smoothed burn rate ($/hr) used for budget forecasting. Damps the
tick-to-tick flicker of burn_rate_per_hr. See forecast (#370).
burn_samples: VecDeque<f64>Recent instantaneous burn samples ($/hr), capped at BURN_SAMPLE_CAP,
for the p10/p90 ETA band. In-memory only (rebuilt at runtime).
subagent_count: usize§active_subagent_count: usize§active_subagent_jsonl_paths: Vec<PathBuf>§subagent_rollups: HashMap<PathBuf, SubagentRollup>§activity_history: Vec<u8>§files_modified: HashMap<String, u32>§tool_usage: HashMap<String, ToolStats>§worktree_id: Option<String>§telemetry_status: TelemetryStatus§usage_metrics_available: bool§cost_estimate_unverified: bool§model_profile_source: String§last_msg_type: StringPersisted across ticks so status inference works when no new JSONL arrives.
last_stop_reason: String§is_waiting_for_task: bool§pending_tool_name: Option<String>Pending tool call details for rule-based auto-actions.
pending_tool_input: Option<String>§pending_file_path: Option<String>§has_file_conflict: bool§last_tool_error: bool§last_error_message: Option<String>§recent_errors: Vec<ErrorEntry>§total_tokens_at_edit_count: u64Cumulative tokens at each Edit/Write event (for efficiency trending).
edit_event_count: u32Number of Edit/Write events (for averaging tokens-per-edit).
baseline_tokens_per_edit: Option<f64>Baseline tokens-per-edit, frozen after first 5 edits.
error_counts_per_window: Vec<u32>Error count ring buffer: one entry per window (~10s each).
current_window_errors: u32Accumulator for current error window.
window_tick_counter: u32Ticks since last window flush.
baseline_error_rate: Option<f64>Baseline error rate (errors per window), frozen after 3 windows.
file_reads_since_edit: HashMap<String, u32>File reads since last edit: path -> read count. Reset when file is edited.
total_error_count: u32All-time error count.
decay_score: u32Cached composite decay score (0-100), recomputed each tick.
worker_origin: Option<String>If set, this session is from a remote worker (not local). Terminal actions (approve, kill, etc.) are disabled for remote sessions; switching attaches over ssh when the fields below are known.
agent_family: StringWhich coding agent this session belongs to — claude-code, codex
(#524). Defaults to claude-code in every existing constructor, so
nothing that predates the field changes behaviour.
The type keeps its name. A Codex session fills the same fields and flows through the same views, and renaming a struct that is public API across three crates buys nothing a field does not.
tmux_target: Option<String>The tmux pane (session:window.pane) this session runs in, on the
machine that owns it. Filled by the relay’s collector, which ships it
to peers so they can attach; None when the session isn’t in tmux.
remote_user: Option<String>Remote sessions only: the login on the owning machine, as that machine
advertised it. None from a peer too old to send it.
remote_host: Option<String>Remote sessions only: the address this machine reaches the owning peer
at, from the relay connection. None when the relay doesn’t know it.
Implementations§
Source§impl ClaudeSession
impl ClaudeSession
pub fn from_raw(raw: RawSession) -> Self
Sourcepub fn record_activity(&mut self)
pub fn record_activity(&mut self)
Record current status into the activity sparkline ring buffer. Max 15 entries (one per tick, at 2s default = 30s of history).
Sourcepub fn record_burn_sample(&mut self, interval_secs: f64)
pub fn record_burn_sample(&mut self, interval_secs: f64)
Fold the current instantaneous burn_rate_per_hr into the EWMA and the
rolling sample window. Call once per refresh after burn is recomputed.
interval_secs is the refresh cadence (shapes the EWMA half-life).
Sourcepub fn budget_eta(&self, budget_usd: f64) -> EtaBand
pub fn budget_eta(&self, budget_usd: f64) -> EtaBand
Forecast time-to-budget for this session given a per-session cap, as a
p10/p90 interval. None when the session isn’t burning or has no cap.
Sourcepub fn format_sparkline(&self) -> String
pub fn format_sparkline(&self) -> String
Render the sparkline as unicode block characters.
pub fn display_name(&self) -> &str
Sourcepub fn is_claude_code(&self) -> bool
pub fn is_claude_code(&self) -> bool
Whether this is a Claude Code session (#524).
The question to ask when the answer is about Claude Code’s file
layout — ~/.claude/projects transcripts, /tmp/claude-<uid>
subagent tasks — rather than about permission to act. A remote Claude
session is still a Claude Code session; is_actionable is what says
you cannot touch it.
Sourcepub fn is_actionable(&self) -> bool
pub fn is_actionable(&self) -> bool
Whether claudectl can act on this session — send input, interrupt, approve, kill (#524).
False for two different reasons, which is why this is one predicate rather than scattered checks:
- A remote session’s process is on another machine.
- A non-Claude-Code session has no process claudectl can address.
For Codex specifically this is not “not implemented yet”: the
ChatGPT app runs one
codex … app-serverfor every session at once, so there is no pid that means this session, and the pid we do hold is 0. Signalling it would reach the caller’s own process group.
Read it as the question “may I touch this?”, not “is this local?” —
is_remote answers the latter and is still the right check for
display and fleet labelling.
Sourcepub fn unactionable_reason(&self) -> Option<&'static str>
pub fn unactionable_reason(&self) -> Option<&'static str>
Why this session cannot be acted on, as a line fit for a status bar —
or None when it can.
The two reasons are genuinely different and a caller that collapses them tells the user something false, so the reason travels with the verdict rather than being re-derived at each of the gate sites.
Sourcepub fn has_known_cost(&self) -> bool
pub fn has_known_cost(&self) -> bool
Whether this session’s cost_usd means anything (#524).
Codex is subscription-billed and its transcripts record tokens only, so a Codex session’s cost is absent, not zero. Anything summing or rendering cost should ask this rather than trusting a 0.0 that cannot be told apart from a session that genuinely cost nothing.
Sourcepub fn from_codex_rollout(summary: &RolloutSummary) -> Self
pub fn from_codex_rollout(summary: &RolloutSummary) -> Self
Build a session from a parsed Codex rollout transcript (#524).
pid is 0 and is_actionable() is false — see that method for why
there is no process to hold. cost_usd stays 0 with
usage_metrics_available false, so it reads as absent rather than
free.
Sourcepub fn from_remote_json(worker_id: &str, json: &Value) -> Option<Self>
pub fn from_remote_json(worker_id: &str, json: &Value) -> Option<Self>
Build a ClaudeSession from remote JSON (as received via heartbeat/HTTP).
pub fn format_subagent_summary(&self) -> String
pub fn subagent_breakdown(&self) -> Vec<SubagentBreakdown>
pub fn format_elapsed(&self) -> String
pub fn format_tokens(&self) -> String
pub fn format_mem(&self) -> String
pub fn format_cost(&self) -> String
pub fn context_percent(&self) -> f64
Sourcepub fn format_context(&self) -> String
pub fn format_context(&self) -> String
Format context as “450k/1M 45%” or a visual bar
Sourcepub fn format_context_bar(&self, width: usize) -> String
pub fn format_context_bar(&self, width: usize) -> String
Visual bar for context usage: ████░░ 62%
Sourcepub fn to_json_value(&self) -> Value
pub fn to_json_value(&self) -> Value
Produce a JSON-serializable value for –json export.
pub fn format_burn_rate(&self) -> String
pub fn telemetry_label(&self) -> &'static str
pub fn has_usage_metrics(&self) -> bool
Trait Implementations§
Source§impl Clone for ClaudeSession
impl Clone for ClaudeSession
Auto Trait Implementations§
impl Freeze for ClaudeSession
impl RefUnwindSafe for ClaudeSession
impl Send for ClaudeSession
impl Sync for ClaudeSession
impl Unpin for ClaudeSession
impl UnsafeUnpin for ClaudeSession
impl UnwindSafe for ClaudeSession
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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