Pixir.Subagents.WarmStart (pixir v0.1.13)

Copy Markdown View Source

Warm-start a Delegate child from a named prior Session in the same workspace (#435).

A warm-started child does not open on an empty Log. Its Log is created up front with:

  1. a seq-0 session_fork lineage Event naming the seed Session and inheriting the seed's fork-tree root, so the child joins the seed's Provider cache family (ADR 0020) instead of deriving a fresh s_ segment from its own id;
  2. the seed Session's COMPLETE replayable conversational prefix, copied under the existing replay_v1 rules owned by Pixir.Fork (ADR 0024) — full, never a summary and never truncated, because the byte-stable shared prefix is exactly what earns the cache hit;
  3. a runtime-authored lineage boundary marker appended after that prefix.

The boundary marker is a runtime artifact

The marker is authored here, by Pixir, never by the operator and never by the model. No spec field can suppress it, reword it, or move it after the child's first new user message: the child's first new user message is appended by the Turn after this Log already ends with the marker. It is a user_message so it actually reaches the Provider — a subagent_event would be dropped from the input array and the child would inherit the transcript with no boundary at all.

Seeding grants context, never scope

replay_v1 copies subagent_event and permission_decision Events verbatim. Those arrive in the child Log as inert historical transcript. The child's effective policy is resolved from the NEW request only: the Subagents Manager writes the child's own spawn-time permission_posture record with child lineage after this Log exists, and no code path reads a replayed posture or permission decision as live policy input. Restrict-never-widen is untouched.

Summary

Functions

The marker kind stamped on every runtime-authored lineage boundary Event.

The runtime-authored boundary text.

The per-child envelope projection for warm-start lineage.

Create the warm-started child Log for child_session_id from seed_session_id.

Validate a seed reference without writing anything.

Functions

boundary_marker_kind()

@spec boundary_marker_kind() :: String.t()

The marker kind stamped on every runtime-authored lineage boundary Event.

boundary_text(seed_session_id)

@spec boundary_text(String.t()) :: String.t()

The runtime-authored boundary text.

Public so contract tests can pin the substance without reimplementing the wording.

envelope_projection(lineage)

@spec envelope_projection(map() | nil) :: map()

The per-child envelope projection for warm-start lineage.

Cold children report the absence of a seed rather than omitting the distinction, so an operator can tell a warm child from a cold one without reading Logs.

seed_child_log(child_session_id, seed_session_id, opts \\ [])

@spec seed_child_log(String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, map()}

Create the warm-started child Log for child_session_id from seed_session_id.

Fails before creating anything when the seed is unusable, so no partial child Log is ever left behind. Returns the lineage evidence the envelope reports per child.

Pass :child_workspace when the child's Log lives somewhere other than the seed's workspace — an isolated Subagent runs in a snapshot directory, and snapshots exclude .pixir, so the seed Log is read from the delegate workspace and written into the child's. It defaults to the seed workspace (a shared-workspace child).

validate(seed_session_id, opts \\ [])

@spec validate(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, map()}

Validate a seed reference without writing anything.

Returns the resolved lineage (seed_session_id, fork_root_session_id, replay_event_count) so callers can reject a bad seed before any child Session is created. A seed that does not exist, is empty of replayable content, or lives outside the delegate workspace is rejected here.