{"slug":"session-source-fork","title":"session-source-fork","summary":"Use when authoring a rig spec member or `rig expand` payload that needs to start a new managed seat from a prior runtime conversation source — `session_source: { mode: fork, ref: { kind, value } }`. v1 supports `mode: fork` with `ref.kind: native_id` for Claude and Codex. The new","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-31T16:20:48.752996Z","repo":{"url":"https://github.com/mvschwarz/openrig","stars":371,"forks":51,"license":"Apache-2.0","updatedAt":"2026-09-25T04:59:18Z"},"bodyHtml":"<hr>\n<h2>name: session-source-fork\ndescription: |\nUse when authoring a rig spec member or <code>rig expand</code> payload that needs to start a new managed seat from a prior runtime conversation source — <code>session_source: { mode: fork, ref: { kind, value } }</code>. v1 supports <code>mode: fork</code> with <code>ref.kind: native_id</code> for Claude and Codex. The new seat persists a NEW post-fork token; the parent token is NEVER written onto the new seat. NOT for restoring an existing seat or for artifact-backed mental-model rebuild.\nmetadata:\nopenrig:\nstage: factory-approved\nsibling_skills:\n- claude-compaction-restore\n- mental-model-ha\n- scope-recovery\n- session-compaction-and-restore\n- agent-startup-and-context-ingestion\n- agent-starters\n- composable-priming-packs\n- seat-continuity-and-handover\n- claude-compact-in-place\n- pre-maintenance-agent-preservation</h2>\n<h1>session_source Fork</h1>\n<p><code>session_source</code> is a <strong>member-level OpenRig field</strong> that declares how a\nnewly-launched managed seat should derive its initial conversation\ncontinuity from a prior runtime conversation source.</p>\n<p>v1 supports one mode: <strong><code>fork</code></strong> — start a <em>new</em> managed seat from a\nprior native runtime conversation source without claiming the original\nseat continued.</p>\n<p>The schema is runtime-neutral; implementation is runtime-specific (Claude\nand Codex have their own native fork commands).</p>\n<h2>Use this when</h2>\n<ul>\n<li>Authoring a rig spec member that should fork from a prior session</li>\n<li>Authoring a <code>rig expand</code> payload with <code>session_source</code></li>\n<li>Reasoning about whether to use <code>fork</code> vs <code>rebuild</code> vs <code>resume</code> vs <code>fresh</code> for a new seat</li>\n<li>Composing fork + handover (seat-handover-over-fork) — see <code>seat-continuity-and-handover</code> skill</li>\n</ul>\n<h2>Don't use this when</h2>\n<ul>\n<li>The seat is being <strong>restored</strong>, not created. Restore continues an existing managed seat. Fork creates a new seat.</li>\n<li>The continuity is <strong>artifact-backed mental-model rebuild</strong> (packet-derived understanding, not native runtime continuity). Use <code>mode: rebuild</code> (see <code>seat-continuity-and-handover</code> for the rebuild surface) — do NOT collapse fork into artifact-backed reentry; the distinction is load-bearing.</li>\n<li>The runtime is <code>terminal</code>. Terminal runtime rejects <code>session_source</code>.</li>\n</ul>\n<h2>The shape (canonical YAML)</h2>\n<pre><code>members:\n  - id: reviewer-2\n    runtime: claude-code        # or \"codex\"; not valid on terminal\n    agent_ref: specs/agents/reviewer.yaml\n    profile: reviewer\n    cwd: .\n    session_source:\n      mode: fork\n      ref:\n        kind: native_id          # v1 fork mode supports native_id only\n        value: \"0b0165d7-cb4d-4650-90de-15c0a1ede9e6\"\n</code></pre>\n<p>Rules:</p>\n<ul>\n<li><code>mode</code> v1 only valid value: <code>fork</code>.</li>\n<li><code>ref.kind</code> v1 supports <code>native_id</code> only. Schema rejects <code>artifact_path</code>, <code>name</code>, <code>last</code>, and <code>artifact_set</code> pre-launch with explicit deferred/weaker/wrong-mode error messages (see <code>packages/daemon/src/domain/rigspec-schema.ts</code> validateSessionSourceFork). Adapter-level refusal exists as defensive handling but should not be reachable in v1 because schema rejects first.</li>\n<li><code>value</code> required for <code>ref.kind: native_id</code> in v1 (the only schema-accepted kind). Future-state value semantics for <code>artifact_path</code> / <code>name</code> / <code>last</code> are not active in v1 because schema rejects those kinds pre-launch.</li>\n<li><code>rig expand</code> accepts the same shape so dynamically-added members can carry session-source attribution.</li>\n</ul>\n<p>The primitive does NOT introduce a new top-level command. It flows\nthrough existing rig spec and expansion pathways.</p>\n<h2>State model</h2>\n<p><code>session_source</code> is a <strong>launch-time input</strong>, not a long-lived stateful field:</p>\n<ol>\n<li><strong>Declared</strong> — present in member config or expansion payload</li>\n<li><strong>Resolved</strong> — at launch time, OpenRig resolves the <code>ref</code> against the runtime</li>\n<li><strong>Realized</strong> — runtime fork succeeds; new managed seat receives a <strong>NEW</strong> native continuity token (Claude session id or Codex thread id). OpenRig persists that NEW token. <strong>Parent token is NEVER written onto the new seat.</strong></li>\n<li><strong>Failed</strong> — resolution or fork failed; seat not launched as a fork; clear error names the resolution step that failed</li>\n</ol>\n<p>Once realized, <code>session_source</code> is essentially history. Restoring the\nseat later is <code>restore</code> of the new seat, not re-fork-from-parent.</p>\n<h2>Failure modes (5)</h2>\n<ol>\n<li><strong>Source session id not found</strong> — runtime cannot resolve <code>native_id</code>. <strong>Action</strong>: emit error naming runtime + missing id; do NOT silently launch fresh. (Future-state note: when <code>artifact_path</code> is supported in a follow-up slice, it could become a candidate fallback for Claude; in v1 schema rejects <code>artifact_path</code> pre-launch so no fallback path exists.)</li>\n<li><strong>Source artifact path missing</strong> <em>(out of v1 scope)</em> — would apply once <code>ref.kind: artifact_path</code> becomes schema-accepted. v1 schema rejects this kind pre-launch.</li>\n<li><strong>Unsupported runtime/kind combination</strong> <em>(largely pre-empted in v1 by schema rejection)</em> — schema rejects all non-<code>native_id</code> kinds upfront. Adapter-level refusal exists as defensive handling but is not reached in v1.</li>\n<li><strong>Fork launch failed after source resolution</strong> — runtime command (<code>claude --resume &lt;parent&gt; --fork-session</code> or <code>codex fork &lt;id&gt;</code>) returned non-zero or hung. Preserve runtime stderr; do not record new seat as launched; do not write parent token onto seat.</li>\n<li><strong>Persistence inconsistency</strong> — fork succeeded but seat-token persistence cannot record new continuity token. <strong>Internal failure</strong>: seat is not considered launched until new token is durably written.</li>\n</ol>\n<h2>Honest UX rule (verbatim)</h2>\n<p>The primitive must NOT report \"restored the original agent\" or \"resumed\nthe original seat\" or \"snapshot.\" The correct framing is <strong>\"forked from\nsource session\"</strong> / <strong>\"started from prior conversation source.\"</strong></p>\n<p>Negative-grep over adapter source confirms ZERO <code>restored</code> / <code>resumed</code> /\n<code>snapshot</code> strings in fork code paths.</p>\n<h2>Hard boundaries (do-not list; verbatim)</h2>\n<ul>\n<li><strong>Do NOT introduce a DIVERGENT fork primitive.</strong> The primitive flows through existing spec/expansion pathways. <em>(Update 2026-08-07: <code>rig fork &lt;source-session&gt;</code> has since shipped as a thin convenience verb that COMPOSES the existing agent-image fork path — this honors the boundary; it is not a divergent primitive. The rule now reads: no NEW fork mechanics outside the spec / expansion / agent-image pathways.)</em></li>\n<li><strong>Do NOT report \"restored\" / \"resumed the original seat\" / \"snapshot\"</strong> in any UX surface.</li>\n<li><strong>Do NOT couple <code>session_source</code> to AgentSpec.</strong> It's a member-level launch-time input.</li>\n<li><strong>Do NOT change <code>restore</code> semantics.</strong> <code>session_source</code> creates a seat; <code>restore</code> continues an existing managed seat.</li>\n</ul>\n<h2>Adapter command shape (shipped v1)</h2>\n<table>\n<thead>\n<tr>\n<th>Runtime</th>\n<th>Command shape</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Claude (<code>mode: fork</code> + <code>ref.kind: native_id</code>)</td>\n<td><code>claude --resume &lt;parent-id&gt; --fork-session</code></td>\n</tr>\n<tr>\n<td>Codex (<code>mode: fork</code> + <code>ref.kind: native_id</code>)</td>\n<td><code>codex... fork &lt;parent-id&gt;</code></td>\n</tr>\n<tr>\n<td>Terminal</td>\n<td>Rejected at schema level</td>\n</tr>\n</tbody>\n</table>\n<p>Mutual exclusion between <code>resumeToken</code> (restore path) and <code>forkSource</code>\n(fork path) is enforced at three layers in the daemon.</p>\n<h2>Continuity outcome literals</h2>\n<table>\n<thead>\n<tr>\n<th>Outcome</th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>forked</code></td>\n<td>Fork succeeded; new seat has new native token; parent never written onto new seat</td>\n</tr>\n<tr>\n<td><code>fresh</code></td>\n<td>Fresh launch (no <code>session_source</code> declared)</td>\n</tr>\n<tr>\n<td><code>resumed</code></td>\n<td>Restore of existing managed seat</td>\n</tr>\n<tr>\n<td><code>failed</code></td>\n<td>Resolution or fork failed</td>\n</tr>\n</tbody>\n</table>\n<p>For <code>seat handover over fork</code> composition, the binding outcome is\nindependent (see <code>seat-continuity-and-handover</code> skill).</p>\n<h2>Active-daemon caveat (live-runtime gap)</h2>\n<p>2026-04-30 live scale-out dogfood found: source checkout contained fork\nsupport, but active daemon was running from a pre-fork commit. <strong>Verify\nthe active daemon/runtime commit contains the fork path before live\nproof.</strong> Isolated daemon proof at the target commit can prove the\nfeature safely; live forked scale-out remains unproven until the active\ndaemon parity is verified.</p>\n<h2>Currently shipped (v1) vs deferred</h2>\n<p>Shipped at openrig <code>c7b6df1</code> (2026-04-30):</p>\n<ul>\n<li>Schema accept/reject for full Honest Refusal Matrix</li>\n<li>Codec roundtrip (serialize → parse → normalize preserves <code>session_source</code> faithfully)</li>\n<li>Expansion path through <code>rig expand</code> member-input</li>\n<li>Adapter command shape for Claude + Codex <code>native_id</code></li>\n<li>Persistence honesty (seat's <code>resume_token</code> is the NEW post-fork token; parent token NEVER written)</li>\n<li>Honest UX literal contract (<code>continuityOutcome: forked</code>)</li>\n</ul>\n<p>Deferred:</p>\n<ul>\n<li>Tier 2 real-runtime fork proof (disposable Tart VM cycle, human-gated)</li>\n<li>Claude <code>artifact_path</code> mode (schema currently refuses with deferred message)</li>\n<li>Provenance columns (<code>parent_native_id</code> / <code>created_via</code> for queryable RSI consumer)</li>\n<li>Cross-host fork (source on host A, new seat on host B) — depends on <code>cross-host-rig-commands</code></li>\n</ul>\n<h2>See also</h2>\n<ul>\n<li><code>seat-continuity-and-handover</code> skill — sibling occupant-creation primitives (resume / fork / rebuild / fresh) + seat-binding (handover composes with fork)</li>\n<li><code>agent-starters</code> skill — composes session_source fork into named reusable starting points</li>\n<li><code>cross-host-rig-commands</code> skill — multi-host fork (deferred)</li>\n</ul>\n","files":[{"path":"SKILL.md","sizeBytes":9191,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-12T07:21:45.060291Z","sha256":"53196EDBE0971478D368937C5FF79C02DFF08C9C9D2EE8850B6245D386879DF1","sizeBytes":3838},"review":null,"source":{"repositoryUrl":"https://github.com/mvschwarz/openrig","path":"skills/_canonical/core/session-source-fork","license":"Apache-2.0","commit":"b374dde300fd2a3cf1ee139b89b11e2fa3945784","subtreeSha":"35BE65E181CE2E1A5501D5A9BBF4CCC3044295E78836CB8D01C2F2775BE027B4","lastSyncedAt":"2026-09-25T06:48:47.236757Z"},"reviewedAt":"2026-09-12T07:22:12.552237Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/mvschwarz/openrig/tree/main/skills/_canonical/core/session-source-fork"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install mvschwarz-openrig@llmmart"},{"target":"git","command":"git clone https://github.com/mvschwarz/openrig.git"}]}