Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ CASE_NUM=$((CASE_NUM + 1))
case_dir=$(new_case_dir)
project_dir="$case_dir/git-project-root"
mkdir -p "$project_dir/nested/subdir"
(cd "$project_dir" && git init -q && git config user.email t@t.test && git config user.name t && git commit -q --allow-empty -m init)
(cd "$project_dir" && git init -q && git -c user.email=t@t.test -c user.name=t -c commit.gpgsign=false commit -q --allow-empty -m init)
# Derive the native-Windows form from `git rev-parse --show-toplevel` itself
# (forward-slash-to-backslash only) rather than `cygpath -w`: on this
# machine cygpath silently 8.3-shortens a profile segment (KyleSexton ->
Expand Down
6 changes: 3 additions & 3 deletions plugins/source-control/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "source-control",
"version": "0.52.1",
"description": "Git and GitHub delivery workflow: /commit (Conventional Commits + Co-Authored-By trailer via safe heredoc mechanics), /pull-request (prep, create, CI monitoring, review-comment triage, merge, CI-log fetch), /babysit-prs (self-pacing fleet loop — safe by default; opt-in worker/autopilot tiers add gate-checked merge and thread resolution behind a deterministic Python engine), /babysit-loop (the loop-lane merge lane: a standing or drain loop that invokes babysit-prs per cycle, configured through repo-scoped babysit_loop_* keys on the layered source-control.md seam, with merge authority human-only until the target repo's tracked config adopts the lane, a gate-proven C2-mechanical baseline once adopted, and standing merge-rung raises binding from the team-tracked layer only — with one named exception, where an invocation line explicitly typing both the autopilot tier keyword and the dedicated raise argument --merge c3-this-run widens that single invocation's merge authority up to C3 behind a fresh independent frontier-tier resolver, while C4-structural and C5-untrusted-provenance stay unconditionally human-merge), /worktree (create, status, cleanup, audit for parallel-session isolation), /setup (check the effective commit-subject / PR-title convention merged across its config layers and the babysit-prs config, or apply — interview the repo and write the convention config to a chosen layer), and /resolve-conflicts (intent-first merge/rebase conflict resolution with a semantic-conflict sweep — never --abort). The commit-subject / PR-title convention is configurable via a source-control.md config written by a re-runnable setup skill, layered across a ~/.claude user-global file, the tracked team file, and a gitignored .claude/source-control.local.md personal overlay merged per key; Conventional Commits is the default when no convention is declared.",
"version": "0.53.0",
"description": "Git and GitHub delivery workflow: /commit (Conventional Commits + Co-Authored-By trailer via safe heredoc mechanics), /pull-request (prep, create, CI monitoring, review-comment triage, merge, CI-log fetch), /babysit-prs (self-pacing fleet loop \u2014 safe by default; opt-in worker/autopilot tiers add gate-checked merge and thread resolution behind a deterministic Python engine), /babysit-loop (the loop-lane merge lane: a standing or drain loop that invokes babysit-prs per cycle, configured through repo-scoped babysit_loop_* keys on the layered source-control.md seam, with merge authority human-only until the target repo's tracked config adopts the lane, a gate-proven C2-mechanical baseline once adopted, and standing merge-rung raises binding from the team-tracked layer only \u2014 with one named exception, where an invocation line explicitly typing both the autopilot tier keyword and the dedicated raise argument --merge c3-this-run widens that single invocation's merge authority up to C3 behind a fresh independent frontier-tier resolver, while C4-structural and C5-untrusted-provenance stay unconditionally human-merge), /worktree (create, status, cleanup, audit for parallel-session isolation), /setup (check the effective commit-subject / PR-title convention merged across its config layers and the babysit-prs config, or apply \u2014 interview the repo and write the convention config to a chosen layer), and /resolve-conflicts (intent-first merge/rebase conflict resolution with a semantic-conflict sweep \u2014 never --abort). The commit-subject / PR-title convention is configurable via a source-control.md config written by a re-runnable setup skill, layered across a ~/.claude user-global file, the tracked team file, and a gitignored .claude/source-control.local.md personal overlay merged per key; Conventional Commits is the default when no convention is declared.",
"author": {
"name": "Melodic Software",
"email": "info@melodicsoftware.com"
Expand Down Expand Up @@ -180,7 +180,7 @@
"worktree_root": {
"type": "directory",
"title": "Worktree root",
"description": "External root under which /worktree create places worktrees, as <root>/<owner>-<repo>-<slug> \u2014 a path OUTSIDE every repository (on Windows, the same drive as the repo). Absent: the worktrees/ subdirectory of the plugin data dir, which the skill supplies explicitly rather than reading from the environment (not per-plugin in a Bash-tool subprocess). Deliberately outside the repository tree AND outside repository-discovery roots such as a ghq root, which a checkout-relative default would land inside. Never the in-repo .claude/worktrees/ default: from a worktree nested inside a checkout, a read matching a path-scoped rule's glob also loads the parent checkout's copy of that rule."
"description": "External root under which /worktree create places worktrees, as <root>/<owner>-<repo>-<slug> \u2014 a path OUTSIDE every repository (on Windows, the same drive as the repo). Absent: the worktrees/ subdirectory of the plugin data dir, which the skill supplies explicitly rather than reading from the environment (not per-plugin in a Bash-tool subprocess). Deliberately outside the repository tree AND outside repository-discovery roots such as a ghq root, which a checkout-relative default would land inside. Never the in-repo .claude/worktrees/ default, whose nested placement the nesting invariant forbids \u2014 that claim is stated, measured, dated and given an expiry in exactly one place: `skills/worktree/SKILL.md` \u00a7 \"The nesting invariant, verified\"."
},
"worktree_stale_days": {
"type": "number",
Expand Down
72 changes: 72 additions & 0 deletions plugins/source-control/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,78 @@
All notable changes to the `source-control` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.53.0]

### Changed

- **The nesting-invariant claim has one owner and twelve pointers, instead of 13 undated copies**
(`skills/worktree/SKILL.md`, `skills/worktree/context/create.md`, `scripts/worktree-create.sh`,
`hooks/worktree-create-gate.sh`, `.claude-plugin/plugin.json`, `README.md`; #2213). The mechanism
claim justifying a machine-wide placement rule enforced by a fail-closed hook was restated as an
**undated absolute at 13 sites** against exactly two dated statements — and the one site asserting
freshness ("It is the live constraint, not a historical one") was itself undated, so a pointer
landed the reader precisely there. `SKILL.md` now carries the claim under an explicit
`### The nesting invariant, verified` heading and everything else points at it. Not thirteen
updated copies: one owner, and a test (`skills/worktree/nesting-invariant-ssot.test.sh`) that
fails when a second site states the mechanism, so the next person to explain it in place has to
point instead.
- **Deviation from the filed fix direction, stated so it is not read as an oversight.** The issue
asks pointers to restate the as-of at each pointer site. They do not: twelve restated dates are
twelve drift sites, which is the defect being removed. Pointers instead say the claim is dated
and measured, and name the section that carries the stamp.
- **The two exit-3 heredocs keep a short restatement** alongside their pointer. They are read at
the moment creation fails, when the reader cannot go follow a link; a pointer-only refusal there
would be a regression. Both restatements are deliberately non-causal ("can pick up") rather than
the absolute the rest of the sweep removed.
- **The nesting invariant now carries an unconditional expiry, because both of its event triggers
were structurally unable to fire** (`skills/worktree/SKILL.md`; #2213). The triggers were "a
release note naming worktree rule-file loading" and "upstream #16600 changing state". #16600 has
not changed state since well before the 2026-08-07 as-of date, and an opaque release stanza
("Bug fixes and reliability improvements", 2.1.226) cannot fire an event-keyed trigger at all — so
the most consequential claim in this plugin was guarded by two triggers that could not go off. The
stamp now adds **2.1.244 or 2026-11-07, whichever comes first**, composed with
`docs/conventions/upstream-drift/` rather than inventing a parallel mechanism.
- **The `SKILL.md` ownership claim is no longer a false absolute, and it gained a back-channel**
(`skills/worktree/SKILL.md`; #2213). "This skill is the canonical owner … — no external prose doc"
was untrue: a consumer doc outside this repository defers mechanism to this skill *and* is more
current than it. Ownership is now scoped to this plugin fleet, and states how a consumer who
measures something contradicting the owner gets that correction back into the owner. Canonical
ownership with no inbound channel makes the owner the last to know.

### Fixed

- **The nesting-invariant measurement is downgraded to the modality it actually has, and its fixture
is now recorded** (`skills/worktree/SKILL.md`, `skills/worktree/fixtures/`; #2212). The 2.1.224
leak measurement was **disputed, not refuted** — a 2.1.227 counter-reproduction did not observe
it — and *neither run recorded its fixture*, so the two results could not be compared and the
claim was not adjudicable. It read as settled anyway. The section now names the dispute, carries
an arm-by-arm status table so a fix to one arm cannot silently weaken another (the
**nested-in-an-unrelated-repo** arm is untested by anyone and **not** refuted — the dispute does
not reach it), and ships `fixtures/nesting-invariant-probe.sh`, which pins every discriminator
neither original run disclosed: creation mechanism, launch mode, the exact `paths:` glob and its
anchoring root, whether the parent's rule file was committed, and the three placements as separate
arms. **The probe is written and has NOT been run** — that is stated at the top of the script and
in `fixtures/README.md`, and nothing is claimed on its authority. It converts a recheck *trigger*
into a recheck *procedure*.
- **The reproduction guidance no longer contradicts the hooks docs** (`skills/worktree/SKILL.md`;
#2212). It claimed the single-string command shape "silently never fires". That is not what
<https://code.claude.com/docs/en/hooks> says (raw markdown, fetched 2026-08-11): both command
forms are documented with no event-specific carve-out, and the documented rule is narrower — "Set
`args` whenever the hook references a path placeholder, since each element is passed as one
argument with no quoting." This plugin's own `hooks/hooks.json` registers all three of its hooks
in the single-string form and they fire. The guidance now states the documented rule, and the
genuinely unknown part is named as unknown: whether the single-string form fires for an
`InstructionsLoaded` hook supplied via `claude -p --settings <file>` is **unprobed by anyone**.
- **The 2.1.224 version basis no longer reads as a release fact** (`skills/worktree/SKILL.md`;
#2212). "which 2.1.224 already handles correctly" sat several sentences from the only "Basis:"
clause and had already been misread as a version fact by two independent readers. The basis is now
inlined at the claim: it is a **null result from the same trace**, not a release note, and the
changelog scan behind it is packet-sourced and has not been re-run. Supersedes the in-place
correction shipped in 0.52.1 (#2332), which fixed the same two rows (`D-F1`, `D-F6`) inside the
old single-paragraph shape; both of its corrections are preserved here, restated inside the
restructured owner section, and `D-F2` — the missing fixture that #2332 left open — is what
this release adds.

## [0.52.1]

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion plugins/source-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ reads it from.
| `babysit_advisory_fix_round_cap` | number | `100` | `CLAUDE_PLUGIN_OPTION_BABYSIT_ADVISORY_FIX_ROUND_CAP` | Per-PR cap on advisory-only fix rounds (never caps blocking defects). |
| `babysit_worker_concurrency_cap` | number | `10` | `CLAUDE_PLUGIN_OPTION_BABYSIT_WORKER_CONCURRENCY_CAP` | Maximum per-PR workers dispatched concurrently in one cycle. |
| `babysit_worktree_root` | directory | *(none)* | `CLAUDE_PLUGIN_OPTION_BABYSIT_WORKTREE_ROOT` | Root directory for babysit-managed ephemeral worktrees. Absent: the worktrees/ subdirectory of the plugin data dir. |
| `worktree_root` | directory | *(none)* | `CLAUDE_PLUGIN_OPTION_WORKTREE_ROOT` | External root under which /worktree create places worktrees, as <root>/<owner>-<repo>-<slug> — a path OUTSIDE every repository (on Windows, the same drive as the repo). Absent: the worktrees/ subdirectory of the plugin data dir, which the skill supplies explicitly rather than reading from the environment (not per-plugin in a Bash-tool subprocess). Deliberately outside the repository tree AND outside repository-discovery roots such as a ghq root, which a checkout-relative default would land inside. Never the in-repo .claude/worktrees/ default: from a worktree nested inside a checkout, a read matching a path-scoped rule's glob also loads the parent checkout's copy of that rule. |
| `worktree_root` | directory | *(none)* | `CLAUDE_PLUGIN_OPTION_WORKTREE_ROOT` | External root under which /worktree create places worktrees, as <root>/<owner>-<repo>-<slug> — a path OUTSIDE every repository (on Windows, the same drive as the repo). Absent: the worktrees/ subdirectory of the plugin data dir, which the skill supplies explicitly rather than reading from the environment (not per-plugin in a Bash-tool subprocess). Deliberately outside the repository tree AND outside repository-discovery roots such as a ghq root, which a checkout-relative default would land inside. Never the in-repo .claude/worktrees/ default, whose nested placement the nesting invariant forbids — that claim is stated, measured, dated and given an expiry in exactly one place: `skills/worktree/SKILL.md` § "The nesting invariant, verified". |
| `worktree_stale_days` | number<br>*min 1* | `14` | `CLAUDE_PLUGIN_OPTION_WORKTREE_STALE_DAYS` | Days since last commit before /worktree status classifies a worktree as stale |
| `fetch_logs_max_bytes` | number<br>*min 1* | `52428800` | `CLAUDE_PLUGIN_OPTION_FETCH_LOGS_MAX_BYTES` | Abort a CI-log ZIP fetch larger than this |
| `branch_issue_pattern` | string | *(none)* | `CLAUDE_PLUGIN_OPTION_BRANCH_ISSUE_PATTERN` | POSIX ERE for extracting the numeric GitHub issue number from the current branch name; the LAST capture group holds it and must resolve to digits (Closes #N honors only a numeric issue). Set this for a non-default branch scheme that places the number differently, e.g. '^\[^/\]+/(\[0-9\]+)-' for 'alice/1234-slug' or '-(\[0-9\]+)$' for 'feat/add-widget-1234'. Absent: the built-in '<type>/<N>-<slug>' (and routine-issue-<N>) convention. |
Expand Down
7 changes: 5 additions & 2 deletions plugins/source-control/hooks/worktree-create-gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
# The `/worktree create` skill already routes through scripts/worktree-create.sh,
# but three creation paths bypass the skill entirely — `claude --worktree`, a
# subagent with `isolation: "worktree"`, and a background session. Those land in
# the in-repo default, where a read matching a path-scoped rule's glob also loads
# the PARENT checkout's copy of that rule. This hook is the seam that covers them,
# the in-repo default — the nested placement the nesting invariant exists to
# avoid; that claim is owned, measured and dated in exactly one place, and this
# comment does not restate it: see
# skills/worktree/SKILL.md § "The nesting invariant, verified".
# This hook is the seam that covers those three paths,
# and it is a thin stdin adapter over the same helper so there is one placement
# implementation rather than two.
#
Expand Down
Loading