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: PathBufThe user’s repository root (never written to directly).
intent: String§engine: EngineChoiceThe 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: boolWhen 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: boolCancellation 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: boolWhether 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: boolSet 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: u64Next event sequence reserved by a durable state transition. Restored review events must not collide with events shown before the restart.
review_restored: boolReview-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: boolWhether 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: boolFarm 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: boolForeman’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.
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
impl CoderSession
Sourcepub fn execution_intent(&self) -> String
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.
pub fn new( repo: impl Into<PathBuf>, intent: impl Into<String>, engine: EngineChoice, max_iterations: u32, state_dir: Option<PathBuf>, ) -> Self
Sourcepub fn with_project(self, project: CoderProject) -> Self
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).
Sourcepub fn provision_workspace(&mut self) -> Result<PathBuf, String>
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).
Sourcepub fn transition(
&mut self,
to: CoderState,
sink: &EventSink,
) -> Result<(), String>
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.
Sourcepub fn persist(&self) -> Result<(), String>
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).
Sourcepub fn load(path: &Path) -> Result<Self, String>
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.
Sourcepub fn list(state_dir: &Path) -> Vec<CoderSession>
pub fn list(state_dir: &Path) -> Vec<CoderSession>
All persisted sessions under state_dir, newest first.
Trait Implementations§
Source§impl Debug for CoderSession
impl Debug for CoderSession
Source§impl<'de> Deserialize<'de> for CoderSession
impl<'de> Deserialize<'de> for CoderSession
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for CoderSession
impl RefUnwindSafe for CoderSession
impl Send for CoderSession
impl Sync for CoderSession
impl Unpin for CoderSession
impl UnsafeUnpin for CoderSession
impl UnwindSafe for CoderSession
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
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