Skip to content
Merged
7 changes: 7 additions & 0 deletions .changes/discovery/docs-accepted-shapes-pointer-5673c3e6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
bump: patch
---

### Changed

- Parent contract: points worker Bash calls to the source-control accepted-command-shapes record for worktree-isolated sessions ([#5673](https://github.com/melodic-software/claude-code-plugins/issues/5673)).
7 changes: 7 additions & 0 deletions .changes/playbooks/docs-precompute-var-record-5673b2d5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
bump: patch
---

### Changed

- `skill-authoring` pre-compute reference: the `$VAR`-without-git record now says acceptance is unsettled after a 2026-09-30 refusal contradicted the 2.1.257 fix, and points to the source-control accepted-shapes record ([#5673](https://github.com/melodic-software/claude-code-plugins/issues/5673)).
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
bump: patch
---

### Changed

- `worktree` gather-block reference: records the accepted Bash command shapes for body-time and subagent calls in a worktree-isolated session, which refusal classes come from the built-in isolation guard, and that whether a plain `$VAR` read is accepted is unsettled ([#5673](https://github.com/melodic-software/claude-code-plugins/issues/5673)).
4 changes: 3 additions & 1 deletion plugins/discovery/reference/parent-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,9 @@ path as an argument and stop there: no `; echo exit=$?`, no `for` loop, and no `
chain. The tool result already carries a non-zero exit. A worktree-isolated session
refused a compound command whose words included a slice path ending in `git`, and
allowed the same path as one plain command. The side-effect-free `--help` probes in
"Pre-flight" stay chained; they take no slice path.
"Pre-flight" stay chained; they take no slice path. The accepted shapes for any worker Bash call
are recorded by `/source-control:worktree`, under "Accepted command shapes for body-time and
subagent Bash".

- **Pointer**: when a worktree-isolated Bash command is refused, fetch [worktrees: how Claude Code enforces isolation](https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation) live. The probe is [#6067](https://github.com/melodic-software/claude-code-plugins/issues/6067).
- **As of**: 2026-10-11 (pointer anchor); the probe ran 2026-10-03
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,18 @@ command name computed at runtime, syntax it cannot parse, or an expansion such a
`${ command; }` that could run a command the text does not spell out. Claude Code 2.1.257 stopped
refusing loops, `$VAR` reads, `"$(…)"`, and heredocs that never touch git, and 2.1.259 stopped
refusing common loops, xargs pipelines, and launcher-wrapped commands that cannot reach the main
checkout. A `$` expansion in a block that never runs git is not that check. The compose gate
checkout. Whether a plain `$VAR` read is accepted today is unsettled: a 2026-09-30 session had
`sed -n ... $F` refused, which may contradict the 2.1.257 fix (the report names no release), and no
probe has reconciled them (`/source-control:worktree` owns the record, under "Accepted command
shapes for body-time and subagent Bash"). The compose gate
(`scripts/check-skill-precompute-compose.sh`) already fires only when a pre-compute block holds a
git command and more than one injection line. A composed pre-compute block still leaves `$` out, other than a bare `$HOME` a probe has
shown the guard accepts, because a block that expands anything else is the shape the page still
refuses when the expansion can hide a command.

**Record.** Claim: the refusal cases in the paragraph above, including the two changelog fixes and the git-only scope of the compose gate.
Basis: <https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation> (Command
shape), `plugins/source-control/skills/worktree/reference/gather-block.md`, and the Claude Code 2.1.257 and 2.1.259 changelog items for worktree-isolated Bash.
shape), the gather-block composition record in `/source-control:worktree`, and the Claude Code 2.1.257 and 2.1.259 changelog items for worktree-isolated Bash.
As of: 2026-09-28. Recheck: the Command shape bullet changes which expansions are refused, or a
release note again changes which Bash forms an isolated session accepts.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ calls, one command per call, where each is screened on its own.
invocations, so the composition itself is not a documented fact.
- [Worktrees: how Claude Code enforces isolation](https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation)
documents the checks an isolated session applies. The one this record rests on is the
command-shape check, which is scoped to git: a `$` expansion that never runs git is not that
check. **Pointer:** that section. **As of:** 2026-10-11. **Recheck trigger:** a re-fetch of that
section that drops the command-shape check or stops scoping it to git.
command-shape check.
[Errors: command blocked by the worktree isolation checks](https://code.claude.com/docs/en/errors#command-blocked-by-the-worktree-isolation-checks)
lists the refusal reasons, including which expansions are refused in a command that never names
git. **Pointer:** both sections. **As of:** 2026-10-17. **Recheck trigger:** a re-fetch of
either section that drops the command-shape check or changes the expansions it names.
- `scripts/check-skill-precompute-compose.sh` in this repository is the gate that encodes the
observed behavior. It refuses a skill whose pre-compute block holds a git command together with
more than one injection line, which is the shape that breaks only in isolated agents while
Expand All @@ -38,3 +40,39 @@ or `check-skill-precompute-compose.sh` stops refusing the git-plus-multiple-line

**Scope.** The composition claim is the load-bearing half. The isolation half is documented
upstream and stands on the worktrees page alone.

## Accepted command shapes for body-time and subagent Bash

The owner record for which Bash shapes a worktree-isolated session runs without a retry. It covers
every Bash call in the session, a skill's body steps and each subagent it spawns, not only a
pre-compute block. A worker brief that sends a subagent into an isolated session points here
instead of restating the shapes.

**Accepted.** One plain command per call, with a literal absolute path and no `$` expansion other
than a bare `$HOME`, which the guard accepts per the observation
`/session-flow:handoff` records for its run-time gather. Give
each git read its own call. Read a file with the Read tool rather than `sed`, `cat` or `head` over
a path held in a variable.

**Refused.** The first and third classes come from Claude Code's built-in isolation guard;
the second is attributed to it by owner decision (see its basis). None of the refusal texts quoted
in #5673 appears in this repository's hooks.

| Class | Rewrite | Basis |
| --- | --- | --- |
| A command whose text the guard cannot verify keeps any git inside the worktree; the errors section lists the shapes | Split into plain, separate commands and spell each value literally | [Worktrees: command shape](https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation); [Errors: command blocked by the worktree isolation checks](https://code.claude.com/docs/en/errors#command-blocked-by-the-worktree-isolation-checks) |
| A compound command with a path word the guard reads as git, such as `github` in a ghq path (`~/repos/github.com/...`) or a slice path ending in `git` | Run it as one plain call | Owner decision on #5673, from one machine's hook list; the slice-path probe in #6067 allowed the same path as one plain command. The upstream pages do not document path-word matching |
| `eval` as a command word | Stop and give the user the exact command to run | `/evals:plugin-eval`; upstream watch in #5696 |

**Not settled.** The pre-compute record says Claude Code 2.1.257 stopped refusing a `$VAR` read
that never touches git. The #5673 report of a 2026-09-30 refusal of `sed -n ... $F`, with `F` a scratchpad file,
may contradict it; the report names no Claude Code release or full command, so it could predate the
fix or have set `F` in the same compound command. No probe from an isolated session on the current release has reconciled the
two. Keep `$` other than a bare `$HOME` out of worker commands until one does.

**Basis.** The two upstream sections linked in the table, both read 2026-10-17, and, for the bare
`$HOME` exception, the observation `/session-flow:handoff` records for its run-time gather (as of
2026-10-11, citing melodic-software/claude-code-plugins#1687). **Recheck trigger.** Either section
changes the expansions it names or the scope of the check, a release note changes how
worktree-isolated agents treat `$`-expansion, or a probe from an isolated session runs
`sed -n 1,5p` on a `$F` scratchpad path.
Loading