[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C47VHM23TX6AVJ8N87GKVJ":3,"skill-same:01M6C47VHM23TX6AVJ8N87GKVJ":82},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":43,"linkOnly":44,"markdownContent":45,"markdownBody":46,"frontMatter":47,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":6,"ownerHtmlUrl":54,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":55,"install":56,"resources":69},"01M6C47VHM23TX6AVJ8N87GKVJ","subagent-env-handshake",null,"Subagent environment-handshake contract for Claude Code Agent-tool dispatch. Use when a parent session dispatches a subagent that may make tree-grounded claims such as file existence, branch identity, or landed changes - the handshake lets the subagent verify its live working-tree view matches the parent's before it prosecutes tree-grounded findings. DO NOT USE FOR: research subagents that never touch git\u002Ftree state; Copilot subagent dispatch (execution model differs).","Grimblaz\u002Fagent-orchestra","Grimblaz","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F74755849?v=4","01M6C430M9XZDHGHPWQVTQ3KMA","01M6C430RJY3MMX0QAZ3X8DR3Y",3,"MIT","https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fsubagent-env-handshake\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42],"subagent env handshake","subagent","model","dispatch","only","never","use","session","environment","view","branch","research","tool","verify","execution","file","state","git","code","copilot","2026-11-10 10:12:30",false,"---\nname: subagent-env-handshake\ndescription: \"Subagent environment-handshake contract for Claude Code Agent-tool dispatch. Use when a parent session dispatches a subagent that may make tree-grounded claims such as file existence, branch identity, or landed changes - the handshake lets the subagent verify its live working-tree view matches the parent's before it prosecutes tree-grounded findings. DO NOT USE FOR: research subagents that never touch git\u002Ftree state; Copilot subagent dispatch (execution model differs).\"\nscope: claude-only\n---\n\n# Subagent Environment Handshake (v1)\n\nShared contract for parent → subagent handoff of live working-tree state in Claude Code `Agent`-tool dispatch. Exists to eliminate the failure mode from [#380](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F380) \u002F [#383](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F383) where a subagent confidently reported tree-grounded claims (file existence, branch identity) grounded in a stale `\u003Cenv>` block injected once at dispatch time and never refreshed.\n\n> **Survival**: `SMC-14` governs this handshake as `per-dispatch`: the block is prompt-carried, delegated\u002Finformational, and intentionally not persisted.\n\n## When to use\n\nUse this handshake for any dispatch where the subagent **may claim**:\n\n- `file X exists` \u002F `file X does not exist`\n- `branch is Y`\n- `commit Z landed` \u002F `commit Z is not in this branch`\n- any equivalent tree-grounded assertion\n\nLayer-1 `Explore` fan-out dispatches under `workspace_mode: shared` are an intentionally waived tree-claiming class — waived on live-shared-tree-reading grounds (not the ND-3 exemption below), per `research-methodology` § Two-Layer Research Delegation.\n\nSkip the handshake for dispatches that only consume task descriptions, web content, or passed-in documents without live-verifying against the working tree. The opt-in rubric keeps the prompt tax off research\u002Fnon-tree subagents (ND-3).\n\n## Scope (ND-4)\n\nThe handshake covers exactly four working-tree facts that can appear stale in a subagent's injected `\u003Cenv>` block:\n\n**In-scope fields:**\n\n- `parent_head` — parent's live `git rev-parse HEAD`\n- `parent_branch` — parent's live `git rev-parse --abbrev-ref HEAD`\n- `parent_cwd` — parent's live `pwd`\n- `parent_dirty_fingerprint` — SHA-256 (first 12 hex chars) of `git status --porcelain` output with line endings normalized to LF\n\n**Explicitly out of scope:**\n\n- Environment variables (`PATH`, `NODE_ENV`, etc.) — subagent has its own shell env; not reflected in the `\u003Cenv>` block.\n- Tool versions (node, pwsh, gh) — orthogonal to tree-state divergence.\n- Terminal\u002FTTY state — not a tree property.\n- File permissions, symlink targets — outside the symptom class.\n\nA handshake covering additional fields is a v2 schema change, not a v1 extension.\n\n## Reserved values\n\n- `workspace_mode: 'shared'` — default. Parent and subagent share a working tree (Claude Code's default dispatch model per the Claude Code subagents docs).\n- `workspace_mode: 'worktree'` — **reserved, not defined in v1**. The `isolation: worktree` frontmatter opt-in exists in Claude Code, but v1 subagent-side verifiers MUST treat `workspace_mode: worktree` as an error path (equivalent to missing handshake). v2 will define worktree-specific verification rules.\n\n## Schema (v1)\n\nAuthoritative schema block — the dispatch prompt-text carrier. Consumer scripts and prose templates below grep between the sentinel comment lines to build or verify the block.\n\n```yaml\n# --- subagent-env-handshake v1 schema begin ---\nparent_head: \u003Csha> # string, 40 hex chars, output of `git rev-parse HEAD` in the parent\nparent_branch: \u003Cbranch-name> # string, output of `git rev-parse --abbrev-ref HEAD` in the parent\n# Note: on detached HEAD, this field is the literal string `HEAD` on both sides — comparison succeeds; commit identity is still verified via `parent_head`\nparent_cwd: \u003Cabsolute-path> # string, output of `pwd` in the parent\nparent_dirty_fingerprint: \u003C12-hex> # string, SHA-256(LF-normalized `git status --porcelain`) truncated :12\nworkspace_mode: \u003Cshared|worktree> # enum. v1: 'shared' is the only active value; 'worktree' is reserved → error path.\nhandshake_issued_at: \u003Ciso-8601-utc> # string, parent-side `(Get-Date).ToUniversalTime().ToString('o')` or equivalent\n# --- subagent-env-handshake v1 schema end ---\n```\n\nSix fields, no optional fields. The block is emitted as a Markdown HTML-comment-wrapped fenced code region (see template below) so it survives intact through prompt concatenation.\n\n## Inline prompt template (prose form)\n\nParent dispatch code that cannot invoke PowerShell (e.g., the markdown in `commands\u002Fplan.md`) constructs the handshake block directly from Bash-captured values. Copy this template verbatim, substitute the six values, and prepend to the `Agent` tool `prompt` parameter:\n\n```markdown\n\u003C!-- subagent-env-handshake v1 -->\n\nparent_head: 0000000000000000000000000000000000000000\nparent_branch: main\nparent_cwd: \u002Fabsolute\u002Fpath\u002Fto\u002Frepo\nparent_dirty_fingerprint: 000000000000\nworkspace_mode: shared\nhandshake_issued_at: 1970-01-01T00:00:00.0000000Z\n\n\u003C!-- \u002Fsubagent-env-handshake -->\n```\n\nField names and order MUST match the schema block above. Drift is locked by the schema-parity Pester test in `.github\u002Fscripts\u002FTests\u002Fsubagent-env-handshake.Tests.ps1`.\n\n## Subagent contract — match \u002F mismatch \u002F error \u002F missing-handshake\n\nWhen a dispatched subagent loads, its first action (before shared-body load, before any tree-grounded claim) is:\n\n1. Parse the `\u003C!-- subagent-env-handshake v1 -->` block from the dispatch prompt. If absent → **missing-handshake** path.\n2. Run live git verification via `Bash`:\n   - `git rev-parse HEAD`\n   - `git rev-parse --abbrev-ref HEAD`\n   - `pwd`\n   - LF-normalized SHA-256 :12 of `git status --porcelain`\n3. If any of those commands **exits non-zero** (covers `git` binary missing, repo-outside, permission errors uniformly) → error path.\n4. If `workspace_mode` is `worktree` → error path (reserved in v1).\n5. Compare observed to handshake field-by-field.\n\n### Match path\n\nAll **four** working-tree fields match. The subagent proceeds to shared-body load \u002F role work with no environmental caveat. Tree-grounded findings carry implicit environmental consistency because the handshake matched.\n\n### Mismatch path (ND-2 default: halt)\n\nOne or more of `parent_head`, `parent_branch`, `parent_cwd`, `parent_dirty_fingerprint` differs. The subagent emits exactly one finding using the template below verbatim and halts role work. No tree-grounded claims are produced on this dispatch.\n\n```markdown\n## Finding: environment-divergence (halting)\n\n**Expected (from parent handshake):**\n\n- HEAD: {parent_head}\n- branch: {parent_branch}\n- CWD: {parent_cwd}\n- dirty fingerprint: {parent_dirty_fingerprint}\n\n**Observed (live git verification):**\n\n- HEAD: {observed_head}\n- branch: {observed_branch}\n- CWD: {observed_cwd}\n- dirty fingerprint: {observed_dirty_fingerprint}\n\n**Diverged fields:** {comma-separated list}\n\nThe subagent halted role work because its live environment does not match\nthe parent's dispatched handshake. No tree-grounded claims are emitted\non this dispatch. The parent session should reconcile the divergence\n(e.g., commit pending edits, re-dispatch from the intended branch, or\nexplicitly acknowledge the mismatch) and re-dispatch.\n```\n\n### Error path (unverified)\n\nHandshake block is missing, unparseable, or any live-verification command returned non-zero, OR `workspace_mode` is `worktree`. The subagent MAY proceed with role work but MUST tag every tree-grounded finding with `environment-unverified`. Non-tree-grounded findings (claims sourced from the task description, passed-in content, or non-tree web\u002Ffile lookups) remain untagged.\n\n## Tree-grounded vs non-tree-grounded findings\n\nThe error-path tag applies only to tree-grounded findings. The distinction:\n\n- **Tree-grounded finding** — any claim whose truth depends on the current working-tree state. Canonical forms: \"file X exists \u002F does not exist at path P\", \"branch is Y\", \"commit Z landed \u002F is not in this branch\", \"file F currently contains Q\". These require live git \u002F filesystem verification against the parent's tree.\n- **Non-tree-grounded finding** — a claim sourced from the dispatch prompt's task description, from passed-in document content, from a web fetch, or from reasoning that does not reference the working tree. Example: \"the proposed API in the spec document has inconsistent field naming.\" These are unaffected by `\u003Cenv>` staleness.\n\nSubagent authors: if a finding would read the same whether the subagent was looking at the parent's tree or a stale snapshot, it is non-tree-grounded. Otherwise assume tree-grounded and tag accordingly in the error path.\n\n## Parent-side construction — three helper forms\n\nThe SKILL exposes three carriers for block construction. Choose the form that fits your caller:\n\n1. **`Get-FreshHandshake` (canonical capture-then-construct entry point)**: `skills\u002Fsubagent-env-handshake\u002Fscripts\u002FNew-SubagentDispatchPrompt.ps1`. Dot-source and call `Get-FreshHandshake` to live-capture all four fields and produce a ready-to-prepend block in one call. Captures `parent_head`, `parent_branch`, and `parent_dirty_fingerprint` via `git -C $RepoRoot` invocations; captures `parent_cwd` via `bash -c 'pwd'` from the **caller's working directory** (not from RepoRoot). Override params (`-HeadShaOverride`, `-BranchOverride`, `-CwdOverride`, `-PorcelainOutput`) enable DI-based testing without Pester `Mock`. Use this form from PowerShell scripts that control their own dispatch flow.\n\n2. **`New-SubagentDispatchPrompt` (explicit-field form)**: dot-sourceable from the same file. Use when you have already captured the four values via Bash commands and want to pass them explicitly. Deterministic output given fixed inputs; unit-tested for fingerprint stability and field order.\n\n3. **Inline prose template** (above): construct from Bash values in markdown command files that cannot invoke PowerShell. Field order must match the schema block.\n\nAll three forms produce field-identical output for identical inputs. Scenario (f) validates field names and order, and covers `Get-FreshHandshake` with DI override params.\n\n### Per-dispatch recapture policy\n\nBefore each downstream `Agent` dispatch that uses this handshake, the parent MUST construct a fresh block by live-recapturing HEAD (`parent_head`), branch (`parent_branch`), CWD (`parent_cwd` via `pwd`), and dirty fingerprint (`parent_dirty_fingerprint`) immediately before that dispatch. Mutable orchestration trees can change between prosecution, defense, judge, and specialist calls, so the parent MUST NOT reuse or carry forward a command-entry, entry-time, single, or earlier handshake for a later `Agent` dispatch.\n\n### Capture ordering\n\n\u003C!-- capture-ordering-anchor begin -->\n\n**Rule**: Capture MUST occur AFTER all parent-side mutations and as close to the `Agent` dispatch as possible. Capturing before the final round of edits produces a stale dirty fingerprint that diverges from the live state the subagent will observe.\n\n**Non-atomicity**: The four capture invocations (`git rev-parse HEAD`, `git rev-parse --abbrev-ref HEAD`, `pwd`, `git status --porcelain | sha256sum`) are separate subprocess calls, not a single atomic snapshot. If the working tree changes between capture commands — for example because an edit tool fires in an interleaved async turn — the fingerprint will be inconsistent with the other fields. This is an inherent property of sequential captures; minimize the window by capturing all four immediately before the parallel emit (see Parallel-batch dispatch).\n\n**Counter-example (#429)**: In the pre-PR hook work (issue #429), the Code-Conductor captured a handshake at command-entry time and then wrote the credit-ledger comment to the branch. The post-write dirty fingerprint diverged from the pre-write fingerprint stored in the handshake, triggering a spurious ND-2 halt on every downstream specialist dispatch in that run. The fix was to move the capture to after the final write, immediately before the `Agent` call.\n\n\u003C!-- \u002Fcapture-ordering-anchor -->\n\nIf a downstream shell does not yet implement Step 0 environment-handshake verification, the parent may pass freshly captured values only as contextual metadata. Do not label that metadata as a verified handshake.\n\n### Parallel-batch dispatch\n\nWhen a parent emits multiple `Agent` calls in one parallel tool-use block (for example `commands\u002Fplan.md` and `commands\u002Forchestra-review.md` prosecution × 3), per-dispatch recapture is satisfied by a **single live recapture immediately before the parallel block**, with one handshake block constructed per dispatch from those captured values. Every dispatch in the batch carries **one shared UTC ISO-8601 `handshake_issued_at` timestamp**, captured with the other values (a single `-IssuedAt` for the whole batch), so all six handshake fields — the four tree fields (`parent_head`, `parent_branch`, `parent_cwd`, `parent_dirty_fingerprint`), `workspace_mode`, and `handshake_issued_at` — are field-identical across the batch. Sharing the timestamp keeps same-model panel prompts byte-identical through the entire handshake block so they can share a cached prompt prefix (#975); it is sound because the four tree fields are already recaptured once for the batch and the batch is dispatched from one instant. (The timestamp remains a distinct per-dispatch value across *sequential* stages, which recapture — see below.)\n\n\u003C!-- parallel-batch-honest-premise-anchor begin -->\nThis is consistent with the per-dispatch policy because, while sibling subagents in `workspace_mode: shared` share the working tree and could theoretically mutate it, our load-bearing guarantee relies on strict subagent working-tree discipline to ensure no tree mutation occurs between members of one parallel tool-use block.\n\u003C!-- \u002Fparallel-batch-honest-premise-anchor -->\n\nThe single-capture-per-batch rule does NOT extend across pipeline stages. Sequential stages (e.g. parallel prosecution → defense → judge in `\u002Forchestra:review`) MUST recapture between stages because the tree may have mutated. The single-capture-per-batch rule applies only within one parallel tool-use block.\n\n#### Failure Mode\n\nWhen subagents dispatched in parallel do not maintain working-tree discipline, they may generate concurrent tree mutations (e.g. redirecting analysis output to files in the repository). In `workspace_mode: shared`, these untracked files will be visible during other sibling subagents' Step 0 verification, causing a mismatch in the observed dirty fingerprint and triggering a halting `environment-divergence` finding. See ### Subagent working-tree discipline (under workspace_mode: shared) for the strict discipline that prevents this.\n\n#### Dispatch sites\n\nWe classify all parallel-batch dispatch sites based on whether they are analysis-only (in scope for working-tree discipline) or editor-required (out of scope):\n\n- **In-Scope (Analysis-Only):**\n  - `commands\u002Fplan.md` prosecution × 3 parallel block\n  - `commands\u002Forchestra-review.md` prosecution × 3 parallel block\n  - `skills\u002Fdesign-exploration\u002FSKILL.md` design-challenge × 3 parallel block\n\n#### Out of scope\n\n- **Out-of-Scope (Editor-Parallel):**\n  - Code-Conductor `Execution Mode: parallel` Code-Smith ↔ Test-Writer parallel batches (see [skills\u002Fparallel-execution\u002FSKILL.md](skills\u002Fparallel-execution\u002FSKILL.md) § Requirement Contract coordination)\n  - Parallel Doc-Keeper batches (see [skills\u002Fparallel-execution\u002FSKILL.md](skills\u002Fparallel-execution\u002FSKILL.md) § Requirement Contract coordination)\n\nUntil v2 worktree mode lands, editor-parallel batches under `workspace_mode: shared` may produce ND-2 cascades equivalent to those described above; there is no documented recovery clause for these batches in v1 — see issue [#606](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F606) for tracking.\n\n#### Diagnostic Note\n\nIn parallel dispatches, attributing the root cause of an ND-2 halt is limited because multiple subagents execute concurrently. When a halt occurs, the divergent dirty fingerprint indicates that at least one sibling subagent mutated the shared tree, but the system logs might not isolate which specific subagent introduced the mutation.\n\n#### Forward-Compatibility Note\n\nFuture versions of this handshake contract will support `workspace_mode: worktree` (v2) to run each parallel subagent in an isolated git worktree environment. This structural isolation will completely eliminate inter-subagent tree mutations and the associated ND-2 environment-divergence cascades, removing the reliance on manual working-tree discipline.\n\n### Subagent working-tree discipline (under workspace_mode: shared)\n\nTo ensure parallel subagent dispatches under `workspace_mode: shared` do not trigger environment-divergence halts, we establish a strict read-only-during-analysis discipline. Dispatched subagents operating in parallel batches under `workspace_mode: shared` MUST NOT write or redirect any output to the working tree of this repository during their analysis phase. Any temporary artifacts, logging, or scratch space must be written outside the repository root. For POSIX platforms, subagents should allocate temporary space using `mktemp -d` or the `\u002Ftmp` directory. For Windows systems, they should use `$env:TEMP\u002F$(New-Guid)` or the system temp directory. Subagents must avoid using `Bash` shell redirects (e.g. `>` or `>>`) to paths within the working tree, as sibling subagents running in the same parallel block will observe these untracked files during their own Step 0 verification, causing their dirty fingerprints to diverge.\n\nThis discipline is a `scope: claude-only` requirement that complements the Copilot exemption documented under the Copilot exemption clause, as tree-view divergence does not occur in Copilot's sequential or isolated environments. The working-tree discipline is explicitly conditional on `workspace_mode: shared` because the reserved `workspace_mode: worktree` (v2) provides complete isolation and eliminates this inter-subagent tree mutation dependency. Furthermore, we maintain a one-line cross-reference to issue #485 for cost-completeness tempfile-exception coordination, ensuring that any allowed tempfile patterns are aligned with this discipline, with temporary files meeting these criteria fully coordinated outside the repository root. Implementing this discipline is consistent with our design intent, and empirical confirmation is gathered via the CE Gate Scenario S1 functional scenario.\n\n### Parent-side error handling\n\nIf the parent's `git` invocations fail during construction (non-zero exit on `git rev-parse HEAD`, etc.), the parent SHOULD skip handshake construction entirely and dispatch without the block. The subagent's error path takes over at that point — tagging tree-grounded findings `environment-unverified`. The parent is not responsible for emitting the environment-divergence finding; that is the subagent's role on mismatch.\n\n## Related\n\n**Current adoption guidance**: Claude parent surfaces that dispatch tree-dependent subagents MUST adopt this handshake as follows:\n\n1. **Parent-side construction:** construct the handshake via `New-SubagentDispatchPrompt` (or the inline prose template) in the dispatch prose, prepended to the `Agent` tool `prompt` parameter as its first content.\n2. **Subagent-side verification:** include a `## Step 0: Environment Handshake Verification` H2 in the subagent shell (or equivalent first-action section) that executes **before** shared-body load. The Step 0 prose directs parse → live-verify → branch (match\u002Fmismatch\u002Ferror).\n3. **ND-2 finding template:** quote the ND-2 `## Finding: environment-divergence (halting)` template verbatim from the block in this SKILL. Do not paraphrase — the schema-parity test enforces byte parity.\n\nLayer-1 `Explore` fan-out dispatches under `workspace_mode: shared` are excepted per the canonical section referenced above.\n\nResearch or non-tree-dependent dispatches may skip the handshake entirely; opt-in is intentional (ND-3).\n\nSubagent shells that implement Step 0 environment-handshake verification use the same first-action contract. If a downstream shell does not yet implement Step 0 verification, the parent may pass freshly captured values only as contextual metadata per the per-dispatch recapture policy above.\n\n> **CWD capture (Windows)**: Always capture `parent_cwd` using `pwd` in the Bash tool, not `(Get-Location).Path` in PowerShell. On Windows, PowerShell produces `C:\\Users\\...` while the Bash tool produces `\u002Fc\u002FUsers\u002F...`; these formats will never compare equal and will trigger a mismatch halt.\n\n**Cross-references:**\n\n- Pilot site (this feature): `commands\u002Fplan.md` → `agents\u002Fissue-planner.md` (the only existing real `Agent`-tool dispatch in the Claude plugin as of 2026-04-20).\n- Related plan hygiene: [#389](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F389) — plugin version bump required for cache invalidation when this skill ships.\n- Copilot exemption: `scope: claude-only` — Copilot's subagent model shares the parent workspace with different tool bindings, so tree-view divergence does not arise. No Copilot-side port is planned.\n\n## Gotchas\n\n- **CWD format mismatch (Windows):** Always capture `parent_cwd` using `pwd` in the Bash tool, not `(Get-Location).Path` in PowerShell. PowerShell produces `C:\\Users\\...`; Bash produces `\u002Fc\u002FUsers\u002F...`. They will never compare equal and will cause a spurious mismatch halt on every Windows dispatch.\n- **Detached HEAD:** When the parent is in detached-HEAD state, `git branch --show-current` returns an empty string. `parent_branch` will be recorded as `HEAD` (or empty depending on the capture command). The subagent's live branch check must tolerate this — do not assume `parent_branch` is always a branch name.\n- **sha256sum availability:** `sha256sum` is not available on macOS by default (use `shasum -a 256` instead) and may be absent in some CI images. The parent-side helper must guard against missing commands; on failure, skip dirty-fingerprint construction and dispatch without the field rather than halting the parent.\n- **Missing-handshake is not an error:** Subagents dispatched without a handshake block (research tasks, Copilot dispatch, pre-adoption callers) route to `missing-handshake` → `environment-unverified`, not to `error`. Do not conflate the two paths.\n- **Schema-parity test enforces byte identity:** The Pester contract test verifies that the `## Finding: environment-divergence (halting)` block in the verifier stub is byte-identical to the copy in this SKILL.md. If you edit the finding template here, you must update the fixture too (and vice versa), or the test will fail.\n\n\u003C!-- gotcha-rev-parse-head -->\n- **Short-hash or log-based HEAD capture:** Using `git log -1 --format=%h` (short hash) or `git log -1 --format=%H` when git is configured with `log.abbrevCommit=true` can produce a short or abbreviated SHA rather than the required 40-char full hex. A short hash will never compare equal to a 40-char `parent_head` stored in the handshake, causing every dispatch to trigger a spurious mismatch halt. **Fix:** Always use `git rev-parse HEAD` (produces exactly 40 hex chars regardless of git config) to capture `parent_head`, and always compare against the full 40-char hex.\n\n## Reproducer Evidence (from design phase)\n\nPinned from the ND-5 reproducer run during the #383 design phase (2026-04-20). This appendix lives in-repo so the evidence is durably grep-able, not dependent on the rotating GitHub issue timeline.\n\n**Original hypothesis (from issue body):** the Claude `Agent` tool spawns subagents against a worktree snapshot taken at conversation start; subagents therefore see a frozen tree that diverges from the parent's live edits.\n\n**Reproducer — Claude Code official docs (`code.claude.com\u002Fdocs\u002Fen\u002Fsub-agents`, verified 2026-04-20):**\n\n- **Line 225** (default dispatch model): _\"A subagent starts in the main conversation's current working directory. Within a subagent, `cd` commands do not persist between Bash or PowerShell tool calls and do not affect the main conversation's working directory.\"_ → The default is **shared live working tree**, not a snapshot.\n- **Line 246** (opt-in isolation): _\"[isolation: worktree] runs the subagent in a temporary git worktree, giving it an isolated copy of the repository.\"_ → Worktree isolation is a **frontmatter opt-in**, not the default.\n- **Line 223** (injected env context): _\"Subagents receive only this system prompt (plus basic environment details like working directory), not the full Claude Code system prompt.\"_ → The subagent receives a small `\u003Cenv>` block (working dir, branch, status, recent commits) **injected once at dispatch time**.\n\n**In-session parent evidence:** the parent session's own injected `\u003Cenv>` block captured at conversation start became stale within the session — at dispatch time the `\u003Cenv>` said `feature\u002Fissue-382-runtime-shared-body-enforcement` \u002F HEAD `a9bc897`, while the live `git rev-parse HEAD` returned `feature\u002Fissue-383-subagent-env-consistency` \u002F HEAD `6bf7aaa`. Divergence reproduced live.\n\n**Reproduced mechanism:** the divergence is **not** \"subagent runs on a snapshot.\" It is **\"LLM trusts stale injected `\u003Cenv>` context instead of running live `git` verification.\"** The `\u003Cenv>` block is captured once and never refreshes. Any tree-grounded claim the subagent makes that relies on the injected `\u003Cenv>` rather than on a live `git` call will be wrong whenever the parent has switched branches or committed since the `\u003Cenv>` was captured.\n\n**Why four fields (ND-4), not one:** HEAD, branch, CWD, and dirty-tree state each appear in the injected `\u003Cenv>` block and each can go stale independently. A handshake that covered only HEAD would miss the CWD-drift and uncommitted-edit failure modes the reproducer exposed.\n","# Subagent Environment Handshake (v1)\n\nShared contract for parent → subagent handoff of live working-tree state in Claude Code `Agent`-tool dispatch. Exists to eliminate the failure mode from [#380](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F380) \u002F [#383](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F383) where a subagent confidently reported tree-grounded claims (file existence, branch identity) grounded in a stale `\u003Cenv>` block injected once at dispatch time and never refreshed.\n\n> **Survival**: `SMC-14` governs this handshake as `per-dispatch`: the block is prompt-carried, delegated\u002Finformational, and intentionally not persisted.\n\n## When to use\n\nUse this handshake for any dispatch where the subagent **may claim**:\n\n- `file X exists` \u002F `file X does not exist`\n- `branch is Y`\n- `commit Z landed` \u002F `commit Z is not in this branch`\n- any equivalent tree-grounded assertion\n\nLayer-1 `Explore` fan-out dispatches under `workspace_mode: shared` are an intentionally waived tree-claiming class — waived on live-shared-tree-reading grounds (not the ND-3 exemption below), per `research-methodology` § Two-Layer Research Delegation.\n\nSkip the handshake for dispatches that only consume task descriptions, web content, or passed-in documents without live-verifying against the working tree. The opt-in rubric keeps the prompt tax off research\u002Fnon-tree subagents (ND-3).\n\n## Scope (ND-4)\n\nThe handshake covers exactly four working-tree facts that can appear stale in a subagent's injected `\u003Cenv>` block:\n\n**In-scope fields:**\n\n- `parent_head` — parent's live `git rev-parse HEAD`\n- `parent_branch` — parent's live `git rev-parse --abbrev-ref HEAD`\n- `parent_cwd` — parent's live `pwd`\n- `parent_dirty_fingerprint` — SHA-256 (first 12 hex chars) of `git status --porcelain` output with line endings normalized to LF\n\n**Explicitly out of scope:**\n\n- Environment variables (`PATH`, `NODE_ENV`, etc.) — subagent has its own shell env; not reflected in the `\u003Cenv>` block.\n- Tool versions (node, pwsh, gh) — orthogonal to tree-state divergence.\n- Terminal\u002FTTY state — not a tree property.\n- File permissions, symlink targets — outside the symptom class.\n\nA handshake covering additional fields is a v2 schema change, not a v1 extension.\n\n## Reserved values\n\n- `workspace_mode: 'shared'` — default. Parent and subagent share a working tree (Claude Code's default dispatch model per the Claude Code subagents docs).\n- `workspace_mode: 'worktree'` — **reserved, not defined in v1**. The `isolation: worktree` frontmatter opt-in exists in Claude Code, but v1 subagent-side verifiers MUST treat `workspace_mode: worktree` as an error path (equivalent to missing handshake). v2 will define worktree-specific verification rules.\n\n## Schema (v1)\n\nAuthoritative schema block — the dispatch prompt-text carrier. Consumer scripts and prose templates below grep between the sentinel comment lines to build or verify the block.\n\n```yaml\n# --- subagent-env-handshake v1 schema begin ---\nparent_head: \u003Csha> # string, 40 hex chars, output of `git rev-parse HEAD` in the parent\nparent_branch: \u003Cbranch-name> # string, output of `git rev-parse --abbrev-ref HEAD` in the parent\n# Note: on detached HEAD, this field is the literal string `HEAD` on both sides — comparison succeeds; commit identity is still verified via `parent_head`\nparent_cwd: \u003Cabsolute-path> # string, output of `pwd` in the parent\nparent_dirty_fingerprint: \u003C12-hex> # string, SHA-256(LF-normalized `git status --porcelain`) truncated :12\nworkspace_mode: \u003Cshared|worktree> # enum. v1: 'shared' is the only active value; 'worktree' is reserved → error path.\nhandshake_issued_at: \u003Ciso-8601-utc> # string, parent-side `(Get-Date).ToUniversalTime().ToString('o')` or equivalent\n# --- subagent-env-handshake v1 schema end ---\n```\n\nSix fields, no optional fields. The block is emitted as a Markdown HTML-comment-wrapped fenced code region (see template below) so it survives intact through prompt concatenation.\n\n## Inline prompt template (prose form)\n\nParent dispatch code that cannot invoke PowerShell (e.g., the markdown in `commands\u002Fplan.md`) constructs the handshake block directly from Bash-captured values. Copy this template verbatim, substitute the six values, and prepend to the `Agent` tool `prompt` parameter:\n\n```markdown\n\u003C!-- subagent-env-handshake v1 -->\n\nparent_head: 0000000000000000000000000000000000000000\nparent_branch: main\nparent_cwd: \u002Fabsolute\u002Fpath\u002Fto\u002Frepo\nparent_dirty_fingerprint: 000000000000\nworkspace_mode: shared\nhandshake_issued_at: 1970-01-01T00:00:00.0000000Z\n\n\u003C!-- \u002Fsubagent-env-handshake -->\n```\n\nField names and order MUST match the schema block above. Drift is locked by the schema-parity Pester test in `.github\u002Fscripts\u002FTests\u002Fsubagent-env-handshake.Tests.ps1`.\n\n## Subagent contract — match \u002F mismatch \u002F error \u002F missing-handshake\n\nWhen a dispatched subagent loads, its first action (before shared-body load, before any tree-grounded claim) is:\n\n1. Parse the `\u003C!-- subagent-env-handshake v1 -->` block from the dispatch prompt. If absent → **missing-handshake** path.\n2. Run live git verification via `Bash`:\n   - `git rev-parse HEAD`\n   - `git rev-parse --abbrev-ref HEAD`\n   - `pwd`\n   - LF-normalized SHA-256 :12 of `git status --porcelain`\n3. If any of those commands **exits non-zero** (covers `git` binary missing, repo-outside, permission errors uniformly) → error path.\n4. If `workspace_mode` is `worktree` → error path (reserved in v1).\n5. Compare observed to handshake field-by-field.\n\n### Match path\n\nAll **four** working-tree fields match. The subagent proceeds to shared-body load \u002F role work with no environmental caveat. Tree-grounded findings carry implicit environmental consistency because the handshake matched.\n\n### Mismatch path (ND-2 default: halt)\n\nOne or more of `parent_head`, `parent_branch`, `parent_cwd`, `parent_dirty_fingerprint` differs. The subagent emits exactly one finding using the template below verbatim and halts role work. No tree-grounded claims are produced on this dispatch.\n\n```markdown\n## Finding: environment-divergence (halting)\n\n**Expected (from parent handshake):**\n\n- HEAD: {parent_head}\n- branch: {parent_branch}\n- CWD: {parent_cwd}\n- dirty fingerprint: {parent_dirty_fingerprint}\n\n**Observed (live git verification):**\n\n- HEAD: {observed_head}\n- branch: {observed_branch}\n- CWD: {observed_cwd}\n- dirty fingerprint: {observed_dirty_fingerprint}\n\n**Diverged fields:** {comma-separated list}\n\nThe subagent halted role work because its live environment does not match\nthe parent's dispatched handshake. No tree-grounded claims are emitted\non this dispatch. The parent session should reconcile the divergence\n(e.g., commit pending edits, re-dispatch from the intended branch, or\nexplicitly acknowledge the mismatch) and re-dispatch.\n```\n\n### Error path (unverified)\n\nHandshake block is missing, unparseable, or any live-verification command returned non-zero, OR `workspace_mode` is `worktree`. The subagent MAY proceed with role work but MUST tag every tree-grounded finding with `environment-unverified`. Non-tree-grounded findings (claims sourced from the task description, passed-in content, or non-tree web\u002Ffile lookups) remain untagged.\n\n## Tree-grounded vs non-tree-grounded findings\n\nThe error-path tag applies only to tree-grounded findings. The distinction:\n\n- **Tree-grounded finding** — any claim whose truth depends on the current working-tree state. Canonical forms: \"file X exists \u002F does not exist at path P\", \"branch is Y\", \"commit Z landed \u002F is not in this branch\", \"file F currently contains Q\". These require live git \u002F filesystem verification against the parent's tree.\n- **Non-tree-grounded finding** — a claim sourced from the dispatch prompt's task description, from passed-in document content, from a web fetch, or from reasoning that does not reference the working tree. Example: \"the proposed API in the spec document has inconsistent field naming.\" These are unaffected by `\u003Cenv>` staleness.\n\nSubagent authors: if a finding would read the same whether the subagent was looking at the parent's tree or a stale snapshot, it is non-tree-grounded. Otherwise assume tree-grounded and tag accordingly in the error path.\n\n## Parent-side construction — three helper forms\n\nThe SKILL exposes three carriers for block construction. Choose the form that fits your caller:\n\n1. **`Get-FreshHandshake` (canonical capture-then-construct entry point)**: `skills\u002Fsubagent-env-handshake\u002Fscripts\u002FNew-SubagentDispatchPrompt.ps1`. Dot-source and call `Get-FreshHandshake` to live-capture all four fields and produce a ready-to-prepend block in one call. Captures `parent_head`, `parent_branch`, and `parent_dirty_fingerprint` via `git -C $RepoRoot` invocations; captures `parent_cwd` via `bash -c 'pwd'` from the **caller's working directory** (not from RepoRoot). Override params (`-HeadShaOverride`, `-BranchOverride`, `-CwdOverride`, `-PorcelainOutput`) enable DI-based testing without Pester `Mock`. Use this form from PowerShell scripts that control their own dispatch flow.\n\n2. **`New-SubagentDispatchPrompt` (explicit-field form)**: dot-sourceable from the same file. Use when you have already captured the four values via Bash commands and want to pass them explicitly. Deterministic output given fixed inputs; unit-tested for fingerprint stability and field order.\n\n3. **Inline prose template** (above): construct from Bash values in markdown command files that cannot invoke PowerShell. Field order must match the schema block.\n\nAll three forms produce field-identical output for identical inputs. Scenario (f) validates field names and order, and covers `Get-FreshHandshake` with DI override params.\n\n### Per-dispatch recapture policy\n\nBefore each downstream `Agent` dispatch that uses this handshake, the parent MUST construct a fresh block by live-recapturing HEAD (`parent_head`), branch (`parent_branch`), CWD (`parent_cwd` via `pwd`), and dirty fingerprint (`parent_dirty_fingerprint`) immediately before that dispatch. Mutable orchestration trees can change between prosecution, defense, judge, and specialist calls, so the parent MUST NOT reuse or carry forward a command-entry, entry-time, single, or earlier handshake for a later `Agent` dispatch.\n\n### Capture ordering\n\n\u003C!-- capture-ordering-anchor begin -->\n\n**Rule**: Capture MUST occur AFTER all parent-side mutations and as close to the `Agent` dispatch as possible. Capturing before the final round of edits produces a stale dirty fingerprint that diverges from the live state the subagent will observe.\n\n**Non-atomicity**: The four capture invocations (`git rev-parse HEAD`, `git rev-parse --abbrev-ref HEAD`, `pwd`, `git status --porcelain | sha256sum`) are separate subprocess calls, not a single atomic snapshot. If the working tree changes between capture commands — for example because an edit tool fires in an interleaved async turn — the fingerprint will be inconsistent with the other fields. This is an inherent property of sequential captures; minimize the window by capturing all four immediately before the parallel emit (see Parallel-batch dispatch).\n\n**Counter-example (#429)**: In the pre-PR hook work (issue #429), the Code-Conductor captured a handshake at command-entry time and then wrote the credit-ledger comment to the branch. The post-write dirty fingerprint diverged from the pre-write fingerprint stored in the handshake, triggering a spurious ND-2 halt on every downstream specialist dispatch in that run. The fix was to move the capture to after the final write, immediately before the `Agent` call.\n\n\u003C!-- \u002Fcapture-ordering-anchor -->\n\nIf a downstream shell does not yet implement Step 0 environment-handshake verification, the parent may pass freshly captured values only as contextual metadata. Do not label that metadata as a verified handshake.\n\n### Parallel-batch dispatch\n\nWhen a parent emits multiple `Agent` calls in one parallel tool-use block (for example `commands\u002Fplan.md` and `commands\u002Forchestra-review.md` prosecution × 3), per-dispatch recapture is satisfied by a **single live recapture immediately before the parallel block**, with one handshake block constructed per dispatch from those captured values. Every dispatch in the batch carries **one shared UTC ISO-8601 `handshake_issued_at` timestamp**, captured with the other values (a single `-IssuedAt` for the whole batch), so all six handshake fields — the four tree fields (`parent_head`, `parent_branch`, `parent_cwd`, `parent_dirty_fingerprint`), `workspace_mode`, and `handshake_issued_at` — are field-identical across the batch. Sharing the timestamp keeps same-model panel prompts byte-identical through the entire handshake block so they can share a cached prompt prefix (#975); it is sound because the four tree fields are already recaptured once for the batch and the batch is dispatched from one instant. (The timestamp remains a distinct per-dispatch value across *sequential* stages, which recapture — see below.)\n\n\u003C!-- parallel-batch-honest-premise-anchor begin -->\nThis is consistent with the per-dispatch policy because, while sibling subagents in `workspace_mode: shared` share the working tree and could theoretically mutate it, our load-bearing guarantee relies on strict subagent working-tree discipline to ensure no tree mutation occurs between members of one parallel tool-use block.\n\u003C!-- \u002Fparallel-batch-honest-premise-anchor -->\n\nThe single-capture-per-batch rule does NOT extend across pipeline stages. Sequential stages (e.g. parallel prosecution → defense → judge in `\u002Forchestra:review`) MUST recapture between stages because the tree may have mutated. The single-capture-per-batch rule applies only within one parallel tool-use block.\n\n#### Failure Mode\n\nWhen subagents dispatched in parallel do not maintain working-tree discipline, they may generate concurrent tree mutations (e.g. redirecting analysis output to files in the repository). In `workspace_mode: shared`, these untracked files will be visible during other sibling subagents' Step 0 verification, causing a mismatch in the observed dirty fingerprint and triggering a halting `environment-divergence` finding. See ### Subagent working-tree discipline (under workspace_mode: shared) for the strict discipline that prevents this.\n\n#### Dispatch sites\n\nWe classify all parallel-batch dispatch sites based on whether they are analysis-only (in scope for working-tree discipline) or editor-required (out of scope):\n\n- **In-Scope (Analysis-Only):**\n  - `commands\u002Fplan.md` prosecution × 3 parallel block\n  - `commands\u002Forchestra-review.md` prosecution × 3 parallel block\n  - `skills\u002Fdesign-exploration\u002FSKILL.md` design-challenge × 3 parallel block\n\n#### Out of scope\n\n- **Out-of-Scope (Editor-Parallel):**\n  - Code-Conductor `Execution Mode: parallel` Code-Smith ↔ Test-Writer parallel batches (see [skills\u002Fparallel-execution\u002FSKILL.md](skills\u002Fparallel-execution\u002FSKILL.md) § Requirement Contract coordination)\n  - Parallel Doc-Keeper batches (see [skills\u002Fparallel-execution\u002FSKILL.md](skills\u002Fparallel-execution\u002FSKILL.md) § Requirement Contract coordination)\n\nUntil v2 worktree mode lands, editor-parallel batches under `workspace_mode: shared` may produce ND-2 cascades equivalent to those described above; there is no documented recovery clause for these batches in v1 — see issue [#606](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F606) for tracking.\n\n#### Diagnostic Note\n\nIn parallel dispatches, attributing the root cause of an ND-2 halt is limited because multiple subagents execute concurrently. When a halt occurs, the divergent dirty fingerprint indicates that at least one sibling subagent mutated the shared tree, but the system logs might not isolate which specific subagent introduced the mutation.\n\n#### Forward-Compatibility Note\n\nFuture versions of this handshake contract will support `workspace_mode: worktree` (v2) to run each parallel subagent in an isolated git worktree environment. This structural isolation will completely eliminate inter-subagent tree mutations and the associated ND-2 environment-divergence cascades, removing the reliance on manual working-tree discipline.\n\n### Subagent working-tree discipline (under workspace_mode: shared)\n\nTo ensure parallel subagent dispatches under `workspace_mode: shared` do not trigger environment-divergence halts, we establish a strict read-only-during-analysis discipline. Dispatched subagents operating in parallel batches under `workspace_mode: shared` MUST NOT write or redirect any output to the working tree of this repository during their analysis phase. Any temporary artifacts, logging, or scratch space must be written outside the repository root. For POSIX platforms, subagents should allocate temporary space using `mktemp -d` or the `\u002Ftmp` directory. For Windows systems, they should use `$env:TEMP\u002F$(New-Guid)` or the system temp directory. Subagents must avoid using `Bash` shell redirects (e.g. `>` or `>>`) to paths within the working tree, as sibling subagents running in the same parallel block will observe these untracked files during their own Step 0 verification, causing their dirty fingerprints to diverge.\n\nThis discipline is a `scope: claude-only` requirement that complements the Copilot exemption documented under the Copilot exemption clause, as tree-view divergence does not occur in Copilot's sequential or isolated environments. The working-tree discipline is explicitly conditional on `workspace_mode: shared` because the reserved `workspace_mode: worktree` (v2) provides complete isolation and eliminates this inter-subagent tree mutation dependency. Furthermore, we maintain a one-line cross-reference to issue #485 for cost-completeness tempfile-exception coordination, ensuring that any allowed tempfile patterns are aligned with this discipline, with temporary files meeting these criteria fully coordinated outside the repository root. Implementing this discipline is consistent with our design intent, and empirical confirmation is gathered via the CE Gate Scenario S1 functional scenario.\n\n### Parent-side error handling\n\nIf the parent's `git` invocations fail during construction (non-zero exit on `git rev-parse HEAD`, etc.), the parent SHOULD skip handshake construction entirely and dispatch without the block. The subagent's error path takes over at that point — tagging tree-grounded findings `environment-unverified`. The parent is not responsible for emitting the environment-divergence finding; that is the subagent's role on mismatch.\n\n## Related\n\n**Current adoption guidance**: Claude parent surfaces that dispatch tree-dependent subagents MUST adopt this handshake as follows:\n\n1. **Parent-side construction:** construct the handshake via `New-SubagentDispatchPrompt` (or the inline prose template) in the dispatch prose, prepended to the `Agent` tool `prompt` parameter as its first content.\n2. **Subagent-side verification:** include a `## Step 0: Environment Handshake Verification` H2 in the subagent shell (or equivalent first-action section) that executes **before** shared-body load. The Step 0 prose directs parse → live-verify → branch (match\u002Fmismatch\u002Ferror).\n3. **ND-2 finding template:** quote the ND-2 `## Finding: environment-divergence (halting)` template verbatim from the block in this SKILL. Do not paraphrase — the schema-parity test enforces byte parity.\n\nLayer-1 `Explore` fan-out dispatches under `workspace_mode: shared` are excepted per the canonical section referenced above.\n\nResearch or non-tree-dependent dispatches may skip the handshake entirely; opt-in is intentional (ND-3).\n\nSubagent shells that implement Step 0 environment-handshake verification use the same first-action contract. If a downstream shell does not yet implement Step 0 verification, the parent may pass freshly captured values only as contextual metadata per the per-dispatch recapture policy above.\n\n> **CWD capture (Windows)**: Always capture `parent_cwd` using `pwd` in the Bash tool, not `(Get-Location).Path` in PowerShell. On Windows, PowerShell produces `C:\\Users\\...` while the Bash tool produces `\u002Fc\u002FUsers\u002F...`; these formats will never compare equal and will trigger a mismatch halt.\n\n**Cross-references:**\n\n- Pilot site (this feature): `commands\u002Fplan.md` → `agents\u002Fissue-planner.md` (the only existing real `Agent`-tool dispatch in the Claude plugin as of 2026-04-20).\n- Related plan hygiene: [#389](https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fissues\u002F389) — plugin version bump required for cache invalidation when this skill ships.\n- Copilot exemption: `scope: claude-only` — Copilot's subagent model shares the parent workspace with different tool bindings, so tree-view divergence does not arise. No Copilot-side port is planned.\n\n## Gotchas\n\n- **CWD format mismatch (Windows):** Always capture `parent_cwd` using `pwd` in the Bash tool, not `(Get-Location).Path` in PowerShell. PowerShell produces `C:\\Users\\...`; Bash produces `\u002Fc\u002FUsers\u002F...`. They will never compare equal and will cause a spurious mismatch halt on every Windows dispatch.\n- **Detached HEAD:** When the parent is in detached-HEAD state, `git branch --show-current` returns an empty string. `parent_branch` will be recorded as `HEAD` (or empty depending on the capture command). The subagent's live branch check must tolerate this — do not assume `parent_branch` is always a branch name.\n- **sha256sum availability:** `sha256sum` is not available on macOS by default (use `shasum -a 256` instead) and may be absent in some CI images. The parent-side helper must guard against missing commands; on failure, skip dirty-fingerprint construction and dispatch without the field rather than halting the parent.\n- **Missing-handshake is not an error:** Subagents dispatched without a handshake block (research tasks, Copilot dispatch, pre-adoption callers) route to `missing-handshake` → `environment-unverified`, not to `error`. Do not conflate the two paths.\n- **Schema-parity test enforces byte identity:** The Pester contract test verifies that the `## Finding: environment-divergence (halting)` block in the verifier stub is byte-identical to the copy in this SKILL.md. If you edit the finding template here, you must update the fixture too (and vice versa), or the test will fail.\n\n\u003C!-- gotcha-rev-parse-head -->\n- **Short-hash or log-based HEAD capture:** Using `git log -1 --format=%h` (short hash) or `git log -1 --format=%H` when git is configured with `log.abbrevCommit=true` can produce a short or abbreviated SHA rather than the required 40-char full hex. A short hash will never compare equal to a 40-char `parent_head` stored in the handshake, causing every dispatch to trigger a spurious mismatch halt. **Fix:** Always use `git rev-parse HEAD` (produces exactly 40 hex chars regardless of git config) to capture `parent_head`, and always compare against the full 40-char hex.\n\n## Reproducer Evidence (from design phase)\n\nPinned from the ND-5 reproducer run during the #383 design phase (2026-04-20). This appendix lives in-repo so the evidence is durably grep-able, not dependent on the rotating GitHub issue timeline.\n\n**Original hypothesis (from issue body):** the Claude `Agent` tool spawns subagents against a worktree snapshot taken at conversation start; subagents therefore see a frozen tree that diverges from the parent's live edits.\n\n**Reproducer — Claude Code official docs (`code.claude.com\u002Fdocs\u002Fen\u002Fsub-agents`, verified 2026-04-20):**\n\n- **Line 225** (default dispatch model): _\"A subagent starts in the main conversation's current working directory. Within a subagent, `cd` commands do not persist between Bash or PowerShell tool calls and do not affect the main conversation's working directory.\"_ → The default is **shared live working tree**, not a snapshot.\n- **Line 246** (opt-in isolation): _\"[isolation: worktree] runs the subagent in a temporary git worktree, giving it an isolated copy of the repository.\"_ → Worktree isolation is a **frontmatter opt-in**, not the default.\n- **Line 223** (injected env context): _\"Subagents receive only this system prompt (plus basic environment details like working directory), not the full Claude Code system prompt.\"_ → The subagent receives a small `\u003Cenv>` block (working dir, branch, status, recent commits) **injected once at dispatch time**.\n\n**In-session parent evidence:** the parent session's own injected `\u003Cenv>` block captured at conversation start became stale within the session — at dispatch time the `\u003Cenv>` said `feature\u002Fissue-382-runtime-shared-body-enforcement` \u002F HEAD `a9bc897`, while the live `git rev-parse HEAD` returned `feature\u002Fissue-383-subagent-env-consistency` \u002F HEAD `6bf7aaa`. Divergence reproduced live.\n\n**Reproduced mechanism:** the divergence is **not** \"subagent runs on a snapshot.\" It is **\"LLM trusts stale injected `\u003Cenv>` context instead of running live `git` verification.\"** The `\u003Cenv>` block is captured once and never refreshes. Any tree-grounded claim the subagent makes that relies on the injected `\u003Cenv>` rather than on a live `git` call will be wrong whenever the parent has switched branches or committed since the `\u003Cenv>` was captured.\n\n**Why four fields (ND-4), not one:** HEAD, branch, CWD, and dirty-tree state each appear in the injected `\u003Cenv>` block and each can go stale independently. A handshake that covered only HEAD would miss the CWD-drift and uncommitted-edit failure modes the reproducer exposed.\n",{"name":5,"scope":48,"description":7},"claude-only","main","d5486aacc32c9ca1b07173cfd530f8fe75c29e58","skills\u002Fsubagent-env-handshake",0,"https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra","https:\u002F\u002Fgithub.com\u002FGrimblaz","2026-08-16 01:12:46",{"source":8,"skillName":5,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add Grimblaz\u002Fagent-orchestra --skill subagent-env-handshake",{"tool":62,"command":63},"bunx","bunx skills add Grimblaz\u002Fagent-orchestra --skill subagent-env-handshake",{"tool":65,"command":66},"pnpm","pnpm dlx skills add Grimblaz\u002Fagent-orchestra --skill subagent-env-handshake","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fsubagent-env-handshake\u002FSKILL.md",true,[70,76],{"path":71,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":74,"sourceHtmlUrl":75},"platforms\u002Fclaude.md","REFERENCE","参考文档",2465,"https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fsubagent-env-handshake\u002Fplatforms\u002Fclaude.md",{"path":77,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":80,"sourceHtmlUrl":81},"scripts\u002FNew-SubagentDispatchPrompt.ps1","SCRIPT","脚本",9110,"https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fsubagent-env-handshake\u002Fscripts\u002FNew-SubagentDispatchPrompt.ps1",[83,116,140,155,178,199],{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":97,"publishedAt":43},"01M6C48YMJVFHM7DVGG1WWW5RJ","webapp-testing","Playwright end-to-end testing guidance for web apps, with practical patterns and setup steps. Use when creating or improving browser-based E2E coverage, test stability, and CI execution. DO NOT USE FOR: React component tests (use ui-testing), canvas game interaction (use browser-canvas-testing), TDD workflow (use test-driven-development), debugging failures (use systematic-debugging), or randomized property tests (use property-based-testing).","https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fwebapp-testing\u002FSKILL.md",[89,94],{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":95,"categoryName":96,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000009","前端开发",[98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,37,113,114,115,29],"testing","webapp testing","webapp","canvas","tdd","workflow","playwright","test","web","react","component","debugging","development","browser","ci","e2e","game","coverage",{"skillNo":117,"name":118,"nameZh":6,"description":119,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":122,"publishedAt":43},"01M6C48TNNP2KCSQXV8YK7SK49","verification-before-completion","Evidence-based verification checklist before marking work complete. Use before PRs, releases, marking tickets done, or any \"I'm finished\" declaration; also when naming a baseline commit for a differential suite claim, when designing a mutation campaign or red-run evidence, when making an absence claim, a universal claim, or a one-time demonstration offered as a standing guarantee, when attributing a measurement or claiming a sweep or verification loop is complete, and when stating what a check or a CI suite will do about a change. DO NOT USE FOR: post-merge cleanup or archival (use post-pr-review) or processing GitHub review comments (use code-review-intake).","https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fverification-before-completion\u002FSKILL.md",[],[123,124,125,126,127,128,129,130,131,41,132,133,112,134,135,136,137,29,138,139],"verification","verification before completion","review","change","commit","merge","pr","cleanup","run","code-review","intake","loop","verification loop","work","check","evidence","campaign",{"skillNo":141,"name":142,"nameZh":6,"description":143,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":144,"categories":145,"keywords":146,"publishedAt":43},"01M6C48QZWNTP7JGKD32QZAKKX","validation-methodology","Reusable validation and review methodology for staged validation, failure triage, and prosecution-depth setup. Use when running validation ladders, triaging failures, or executing adversarial review passes. DO NOT USE FOR: CE Gate orchestration, specialist dispatch ownership, or step execution flow (keep those in Code-Conductor).","https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fvalidation-methodology\u002FSKILL.md",[],[147,148,149,125,150,151,152,153,41,154,37,29,26],"validation","methodology","validation methodology","triage","orchestration","setup","adversarial review","flow",{"skillNo":156,"name":157,"nameZh":6,"description":158,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":159,"categories":160,"keywords":167,"publishedAt":43},"01M6C48MCAHG5Z79BJ369CRYRZ","upstream-onboarding","Shared opening-phase protocol for upstream agents (Experience-Owner, Solution-Designer, Issue-Planner) and Code-Conductor when invoked on an existing GitHub issue. Renders a scaled context brief and runs a standards check on inherited work at each phase boundary. Use when a user-invocable agent receives a request referencing an existing GitHub issue and must load solution-authoring and upstream-onboarding at the opening phase. DO NOT USE FOR: subagent dispatches (which already operate within an assessed session context); post-merge review (use post-pr-review); research or non-tree subagents.","https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fupstream-onboarding\u002FSKILL.md",[161,164],{"categoryNo":162,"categoryName":163,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":165,"categoryName":166,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000038","人力资源",[168,169,125,170,34,128,171,129,41,172,173,174,175,24,176,136,137,177,30,29],"onboarding","upstream onboarding","github","standards check","protocol","brief","boundary","designer","planner","user",{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":192,"publishedAt":43},"01M6C48GPVE120TGPMD1CS365H","ui-testing","Resilient React component testing strategies focusing on user behavior. Use when writing or reviewing component-level React tests, fixing flaky component tests, or establishing React testing patterns. DO NOT USE FOR: Playwright E2E tests (use webapp-testing), canvas game interaction (use browser-canvas-testing), TDD workflow (use test-driven-development), debugging failures (use systematic-debugging), UI component design (use frontend-design), or randomized property tests (use property-based-testing).","https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fui-testing\u002FSKILL.md",[184,185,186,189],{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},{"categoryNo":95,"categoryName":96,"taxonomyType":92,"taxonomyTypeDesc":93},{"categoryNo":187,"categoryName":188,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":190,"categoryName":191,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000032","设计师",[98,193,194,195,196,197,101,103,104,105,107,108,109,110,111,198,113,114,29,100],"ui","ui testing","frontend","design","writing","testing patterns",{"skillNo":200,"name":201,"nameZh":6,"description":202,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":203,"categories":204,"keywords":207,"publishedAt":43},"01M6C48DRJ9XBDR2FW0W37DY53","ui-iteration","Reusable screenshot-driven UI polish workflow for iterative visual refinement. Use when improving layout, hierarchy, spacing, feedback, or Tailwind-based presentation through repeated review-and-adjust passes. DO NOT USE FOR: functional bug fixing, accessibility-only audits, or major redesign strategy work (use Code-Smith or frontend-design).","https:\u002F\u002Fgithub.com\u002FGrimblaz\u002Fagent-orchestra\u002Fblob\u002Fmain\u002Fskills\u002Fui-iteration\u002FSKILL.md",[205,206],{"categoryNo":95,"categoryName":96,"taxonomyType":92,"taxonomyTypeDesc":93},{"categoryNo":190,"categoryName":191,"taxonomyType":20,"taxonomyTypeDesc":21},[193,208,195,196,125,103,209,41,210,211,212,213,214,136,215,216,29,27],"ui iteration","accessibility","screenshot","Tailwind","polish","ui polish","feedback","redesign","strategy"]