Skip to main content

CoderSession

Struct CoderSession 

Source
pub struct CoderSession {
Show 56 fields pub id: String, pub repo: PathBuf, pub intent: String, pub engine: EngineChoice, pub requested_engine: Option<EngineChoice>, pub engine_ran: Option<EngineChoice>, pub state: CoderState, pub contract: Option<OutcomeContract>, pub workspace_path: Option<PathBuf>, pub project: Option<String>, pub project_kind: Option<ProjectKind>, pub existing_agent_id: Option<String>, pub builder_draft: Option<AgentBuilderDraft>, pub built_agent: Option<DeclarativeAgentSpec>, pub agent_build_progress: Option<AgentBuildProgress>, pub iterations: u32, pub max_iterations: u32, pub cost_usd: Option<f64>, pub repair_invokes: Option<u32>, pub transient_retries: Option<u32>, pub keep_workspace_on_failure: bool, pub keep_workspace_on_cancel: bool, pub model: Option<String>, pub last_check_results: Vec<CheckResult>, pub baseline: Vec<CheckResult>, pub baseline_gates_nothing: bool, pub result_branch: Option<String>, pub result_commit: Option<String>, pub checkout_identity: Option<CheckoutIdentity>, pub inputs_snapshot: Option<String>, pub result_delivery: Option<String>, pub failure_kind: Option<String>, pub discussion_id: Option<String>, pub discussion_constraints: Vec<String>, pub steering_messages: Vec<String>, pub resumed_from: Option<String>, pub execution_stopped: bool, pub review_identity: Option<ReviewIdentity>, pub event_cursor: u64, pub review_restored: bool, pub base: Option<String>, pub no_change_finding: Option<NoChangeFinding>, pub start_commit: Option<String>, pub browser: bool, pub distributed: bool, pub workers: Vec<String>, pub pool_workers: Vec<String>, pub placements: Vec<Placement>, pub integrated_subtasks: Vec<IntegratedSubtask>, pub repaired_locally: bool, pub authored_by: Vec<String>, pub created_at: u64, pub updated_at: u64, pub error: Option<String>, pub workspace: Option<AgentWorkspace>, pub state_dir: Option<PathBuf>,
}
Expand description

A coding session. Serializes to the JSON snapshot persisted on every transition; the live worktree handle is process-only (#[serde(skip)]).

Fields§

§id: String§repo: PathBuf

The user’s repository root (never written to directly).

§intent: String§engine: EngineChoice

The engine that was RESOLVED for this session — never the raw request. --engine auto that picks claude-code and an explicit --engine external:claude-code both land here as External("claude-code"), which is why requested_engine below had to exist. Read by placement_for and by self-heal’s re-start, both of which want the resolved choice, so nothing may overwrite it with the engine that actually ran.

§requested_engine: Option<EngineChoice>

What the caller ASKED for at coder.start, before resolution (car#1534). The only durable record of whether the operator named an engine, and therefore the input to the fallback policy: an explicit external:/foreman: request is never silently replaced by the native engine. Resolution’s prose reason (“explicitly requested”) carries the same fact, but prose is not a contract — this codebase already burned once on an e != "cancelled" compare.

None on a snapshot written before this field existed; treated as not explicit, which is the pre-car#1534 behaviour for those sessions.

§engine_ran: Option<EngineChoice>

The engine that actually produced the outcome (car#1534). Native when an external engine fell back, otherwise whichever engine finished. None until the loop ends, and on a snapshot older than this field — a client that sees null falls back to showing engine.

Separate from engine because the two answer different questions, and collapsing them is the defect: a session that asked for one engine and was run by another looked identical to one that got what it asked for.

§state: CoderState§contract: Option<OutcomeContract>§workspace_path: Option<PathBuf>

Where the throwaway worktree lives (kept in the snapshot so orphaned sessions after a daemon restart can still report it).

§project: Option<String>

When this session works on a CAR-managed project (vs. a raw repo path), the project slug + kind. Drives delivery (commit straight to the project’s main instead of publishing a car/coder/<id> branch) and, for Agent projects, the scenario-based contract + agent registration on approve. None = raw-repo session (the original behavior).

§project_kind: Option<ProjectKind>§existing_agent_id: Option<String>

Registered identity an Agent-project edit replaces. None means a new agent whose id is derived from the project slug.

§builder_draft: Option<AgentBuilderDraft>

The user-authored Agent Builder answers staged for the generated spec.

§built_agent: Option<DeclarativeAgentSpec>

For an Agent project: the declarative agent spec the build loop produced, stashed so approve_merge can register it. Persisted so coder.get can show what was built.

§agent_build_progress: Option<AgentBuildProgress>

Present only for Agent-project builds. Additive on coder.get; older hosts ignore it and older snapshots deserialize with None.

§iterations: u32§max_iterations: u32§cost_usd: Option<f64>

Metered inference spend, when anything reported it. None is unknown, not free — the native loop does not meter.

§repair_invokes: Option<u32>

Per-session external-engine hypothesis budget. None = engine default.

§transient_retries: Option<u32>

Per-session external-engine availability budget. None = engine default.

§keep_workspace_on_failure: bool

When a session ends Failed, keep the throwaway worktree on disk (and its handle in-process) so the operator can inspect it for a postmortem instead of having it reaped on the terminal transition. Sourced from ~/.car/coder.toml (keep_workspace_on_failure); default false.

§keep_workspace_on_cancel: bool

Cancellation preserves unfinished work, including a racing failure or restart.

§model: Option<String>

Pin the native loop’s inference model (e.g. "parslee/reasoning"). None = adaptive routing. Sourced from ~/.car/coder.toml (model).

§last_check_results: Vec<CheckResult>§baseline: Vec<CheckResult>

The contract’s red-green baseline — how each check fared against the unmodified worktree (car#707). Stored rather than recomputed because it is part of how the current draft READS: a board renders the contract with its baseline beside it, so a coder.revise_contract that could not be honored has to hand back both, or the contract it swore was unchanged visibly changes anyway when the baseline blanks out.

§baseline_gates_nothing: bool

Whether every baseline check already passed — i.e. the contract gates nothing for this task. Travels with baseline for the same reason.

§result_branch: Option<String>§result_commit: Option<String>

Immutable delivered revision for conversational follow-up. Branch names can move; never infer this value from a branch during recovery.

§checkout_identity: Option<CheckoutIdentity>

Checkout identity captured before task execution; required for local delivery. None whenever the worktree does NOT start from the checkout’s HEAD (an explicit base, a follow-up on a prior branch delivery, a continuation whose checkout has since moved) — a patch computed against a tree the checkout does not have would apply cleanly and leave it holding this task’s changes without the base’s.

§inputs_snapshot: Option<String>

The private refs/car/coder-inputs/<id> commit this task starts from, when it was started from a dirty checkout (carried forward by a continuation of the same worktree). Its tree holds the user’s uncommitted work, so branch delivery must rebuild its commit on the checkout’s HEAD rather than publishing that snapshot’s contents.

§result_delivery: Option<String>§failure_kind: Option<String>

Why a failed session failed, as a machine-readable kind: "budget_exhausted" | "auth_required" | "configuration" | "infrastructure" | "stalled" | "error". Persisted so a summary read from disk after a daemon restart still distinguishes “ran out of clock” from “nobody signed in” from “routing excludes every model” from “the machinery broke” from “the work was judged and rejected” — a live-only derivation would go blank exactly when the operator comes back to look.

"infrastructure" is the one a scorer must act on: nothing was judged, so the session is not a task loss. See rpc::failure_kind_for for how it is chosen and why it is not folded into "error".

§discussion_id: Option<String>

The coder.discuss conversation this run was distilled from, when the operator went through a discussion. Provenance only — the run itself is independent of the discussion’s lifetime.

§discussion_constraints: Vec<String>

Constraints captured when the task starts; revisions must recheck them.

§steering_messages: Vec<String>

Accepted guidance, retained with unfinished work. Acceptance does not claim the loop applied it before cancellation or failure.

§resumed_from: Option<String>

Prior task whose retained native worktree this attempt continues.

§execution_stopped: bool

Set after the native execution loop returns or cancellation joins it. A crash orphan does not establish this and cannot be automatically reopened.

§review_identity: Option<ReviewIdentity>

Identity of the staged result shown at review. Absent on older snapshots and no-change findings. Does not by itself restore a live approval gate.

§event_cursor: u64

Next event sequence reserved by a durable state transition. Restored review events must not collide with events shown before the restart.

§review_restored: bool

Review-only restoration; prior activity is unavailable and checks are historical. No execution loop is restarted by opening this task.

§base: Option<String>

The commit the worktree was provisioned at, when the caller named one (coder.start { base }) instead of taking the repository’s HEAD. Resolved to a full SHA before provisioning and persisted in the session snapshot, so it names exactly what the session started from even after the ref it came from moves. Reported on the coder.start reply.

§no_change_finding: Option<NoChangeFinding>

The “no code should change” finding this session reached, if any: nominated by the model through report_no_change, or observed by the runtime when the run finished green with an unchanged worktree. verification is None while it waits at the approval gate and HumanApproved once coder.approve_merge accepted it.

§start_commit: Option<String>

The commit the worktree was at the moment it was provisioned — before the contract baseline ran any check in it. A no-change conclusion is judged against this, so a check or a model that commits inside the worktree cannot pass the result off as an untouched tree. None for a worktree this session did not provision (a reopened one), which makes every no-change conclusion fail closed.

§browser: bool

Whether this session explicitly opted into the assistant’s browser tool surface. False by default and persisted so contract review cannot change which tools the later confirmed run receives.

§distributed: bool

Farm subtasks across reachable CAR instances rather than this machine alone. Only the foreman engine reads it.

Persisted, and reported on the coder.list row, so a finished run can say which way it ran. That is the whole reason — a session does NOT resume across a daemon restart (adopt_orphaned_sessions rewrites every non-terminal orphan to Failed), so this is not protecting a resumed run from silently becoming local.

§workers: Vec<String>

Instances a distributed run is restricted to. Empty = every instance that can serve the repository.

The operator’s FILTER, not the resolved pool — see Self::pool_workers for what the run actually got.

§pool_workers: Vec<String>

The peers the pool actually resolved to, recorded when it is built.

workers above is what the operator asked to restrict to; this is what answering that restriction against reachability, enrollment and repo eligibility produced. It was emitted as a foreman: "pool" event and then dropped, so a subscriber that was not attached saw nothing and the snapshot carried no record at all.

Written BEFORE any subtask runs, which is what makes it the durable answer to “which machines was this farmed to?”. Self::placements cannot answer it on its own: a placement is recorded when a worker RETURNS, and foreman runs a level under join_all rather than spawning, so coder.cancel’s abort drops every in-flight future before it records — the subtasks running at the moment an operator gives up are exactly the ones the ledger omits (car#1346). Empty on a local run.

§placements: Vec<Placement>

Where each of a distributed run’s subtasks actually ran, including the workers that failed it first.

Empty for a local run, and for a distributed one that fell off the foreman rung before farming anything out.

Not a proxy for “a distributed run completed.” A cancelled run carries this populated with Self::integrated_subtasks empty, and so does a run whose foreman union the gate rejected — three different states, separated by state and by nothing else. And it is a floor, not a census: subtasks still in flight at a cancel never reach it, which is what Self::pool_workers is for.

foreman.run has reported this all along; the pipeline that DELIVERS had strictly less provenance than the one that only reports, because fleet_pool_for erased FleetPool to Arc<dyn WorktreeAgent> and placements() is on the concrete type (car#1322). CAR’s position is that receipts decide completion, and a delivered commit whose hunks were authored on unnamed machines is the wrong artifact for that claim — the question arrives the first time a distributed run produces something surprising.

§integrated_subtasks: Vec<IntegratedSubtask>

Which of those subtasks actually LANDED in the worktree, and what each wrote. The diagnostic record above says what happened; this says what is in the tree, and only this may back a claim in the delivered commit.

§repaired_locally: bool

Foreman’s union was integrated and then the native loop repaired on top of it, so some delivered hunks were written locally by no listed worker.

Without this the commit body would credit the fleet for a diff it only partly wrote — the same false attribution as crediting it for one it did not write at all, in a milder form.

§authored_by: Vec<String>

Every model that AUTHORED part of this session’s work, as opposed to Self::model, which is the pin the caller asked for.

They differ exactly when it matters: unpinned, the router chooses, and on a machine with one reachable credential that choice can also be a review-panel seat — the self-review the gate refuses when a coder is pinned, permitted by default because nothing knew who wrote the change (car#1299).

A projection of the journal (EventSink::authoring_models), not a second record of the same fact — two records can disagree and then the question is which one the gate believes. Empty for a session with no native turns (foreman/external), which is the DEFAULT engine: read it as “CAR’s own loop did not write this”, not “nobody did”.

§created_at: u64§updated_at: u64§error: Option<String>§workspace: Option<AgentWorkspace>

RAII worktree handle. Dropping it removes the worktree, so terminal transitions release it explicitly.

§state_dir: Option<PathBuf>

Where snapshots/journals/worktrees go; None disables persistence.

Implementations§

Source§

impl CoderSession

Source

pub fn execution_intent(&self) -> String

The execution request includes user requirements even when generated checks do not cover them. Keep the concise original intent for labels.

Source

pub fn new( repo: impl Into<PathBuf>, intent: impl Into<String>, engine: EngineChoice, max_iterations: u32, state_dir: Option<PathBuf>, ) -> Self

Source

pub fn with_project(self, project: CoderProject) -> Self

Mark this session as working on a managed project (builder so existing call sites and tests stay green).

Source

pub fn short_id(&self) -> &str

Short suffix for branch names and worktree dirs.

Source

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

Provision the throwaway git worktree under the state dir (NOT inside the user’s repo, so their git status stays clean).

Source

pub fn transition( &mut self, to: CoderState, sink: &EventSink, ) -> Result<(), String>

Validated state transition: updates timestamps, emits StateChanged, persists the snapshot, and releases the worktree on terminal states.

Source

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

Write the JSON snapshot to <state_dir>/<id>.json (no-op without a state dir, e.g. in unit tests).

Source

pub fn load(path: &Path) -> Result<Self, String>

Load a snapshot from disk. The worktree handle is NOT restored — a loaded session is history until explicitly admitted for recovery.

Source

pub fn list(state_dir: &Path) -> Vec<CoderSession>

All persisted sessions under state_dir, newest first.

Trait Implementations§

Source§

impl Debug for CoderSession

Source§

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

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

impl<'de> Deserialize<'de> for CoderSession

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 CoderSession

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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

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<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

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, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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