Symptom
In reDeploy (onboarded before #134, plugin now 0.3.0), .claude/scripts/worktree.sh did not exist and never had:
$ git log --all --diff-filter=AD -- .claude/scripts/worktree.sh
(no output)
Nothing deleted it — no mechanism has ever existed to put it there.
Cause
#134 stopped vendoring agents/ commands/ hooks/ scripts/ skills/ into consumer repos, and sync.sh's managed-file table is only four rows (feature-fanout.js, the two .service templates, arm-loop.sh). It never copies scripts/.
But several shipped templates still assume a repo-local .claude/scripts/:
| Template |
Line |
Assumes |
templates/gates.yml |
48 |
run: bash .claude/scripts/gate.sh ${{ matrix.gate }} |
templates/action.yml |
57 |
run: bash .claude/scripts/gate.sh install |
templates/gates.json |
worktree._note |
"Run via .claude/scripts/worktree.sh setup|teardown" |
So the templates promise a directory the plugin no longer populates.
Why it can't simply be "resolve from the plugin cache"
The CI ones genuinely need a repo-local copy: a GitHub Actions runner does a bare actions/checkout and has no plugin cache at all, and ${CLAUDE_PLUGIN_ROOT} is a Claude-Code-session-only variable that is never set there. gate.sh (plus resolve-roots.sh, which it sources at line 13) must therefore exist in the repo for CI to work.
resolve-roots.sh also documents that a repo-tracked .claude/scripts layout deliberately wins over the plugin cache, because worktree implementers need the worktree as root. So a repo-local copy is by design — there is just nothing that creates or refreshes one post-#134.
Consequences observed
worktree.sh absent, so the worktree.setup bootstrap the agent prompts call (bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/worktree.sh setup) silently skips via its "if present" guard whenever CLAUDE_PLUGIN_ROOT isn't set. In-worktree gates then fail for missing node_modules / Foundry libs rather than for real defects.
- Consumers that hand-maintained the directory (reDeploy topped it up via occasional
chore(harness): sync ... commits) drift arbitrarily far: reDeploy's copy was missing ~25 scripts that 0.3.0 ships.
sync.sh reports the directory as stale-vendor conflict forever, since it can't distinguish "stale relic" from "required for CI".
Possible directions (owner's call)
- Make
gate.sh + resolve-roots.sh (+ worktree.sh?) a managed row in MANIFEST so setup/sync create and re-stamp them like arm-loop.sh. Smallest change; makes the required-repo-local set explicit and versioned.
- Have the CI templates install the plugin/marketplace in a step before calling
gate.sh, so CI needs nothing repo-local.
- Teach
sync.sh to recognise a known "required repo-local" subset and stop flagging it as stale-vendor.
Workaround applied in reDeploy
Trimmed .claude/scripts/ to the 8 files that are actually required, each refreshed byte-identical from plugin 0.3.0: gate.sh, resolve-roots.sh, worktree.sh, arm-loop.sh, prepare-pr.sh, bot-gh.sh, merge-ready.sh, notify-poll.sh.
Filed from reDeploy per #223. Labelled backlog — not self-assigning planned, per CONTRIBUTING.md.
Symptom
In reDeploy (onboarded before #134, plugin now 0.3.0),
.claude/scripts/worktree.shdid not exist and never had:Nothing deleted it — no mechanism has ever existed to put it there.
Cause
#134 stopped vendoring
agents/ commands/ hooks/ scripts/ skills/into consumer repos, andsync.sh's managed-file table is only four rows (feature-fanout.js, the two.servicetemplates,arm-loop.sh). It never copiesscripts/.But several shipped templates still assume a repo-local
.claude/scripts/:templates/gates.ymlrun: bash .claude/scripts/gate.sh ${{ matrix.gate }}templates/action.ymlrun: bash .claude/scripts/gate.sh installtemplates/gates.jsonworktree._note.claude/scripts/worktree.sh setup|teardown"So the templates promise a directory the plugin no longer populates.
Why it can't simply be "resolve from the plugin cache"
The CI ones genuinely need a repo-local copy: a GitHub Actions runner does a bare
actions/checkoutand has no plugin cache at all, and${CLAUDE_PLUGIN_ROOT}is a Claude-Code-session-only variable that is never set there.gate.sh(plusresolve-roots.sh, which it sources at line 13) must therefore exist in the repo for CI to work.resolve-roots.shalso documents that a repo-tracked.claude/scriptslayout deliberately wins over the plugin cache, because worktree implementers need the worktree as root. So a repo-local copy is by design — there is just nothing that creates or refreshes one post-#134.Consequences observed
worktree.shabsent, so theworktree.setupbootstrap the agent prompts call (bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/worktree.sh setup) silently skips via its "if present" guard wheneverCLAUDE_PLUGIN_ROOTisn't set. In-worktree gates then fail for missingnode_modules/ Foundry libs rather than for real defects.chore(harness): sync ...commits) drift arbitrarily far: reDeploy's copy was missing ~25 scripts that 0.3.0 ships.sync.shreports the directory asstale-vendor conflictforever, since it can't distinguish "stale relic" from "required for CI".Possible directions (owner's call)
gate.sh+resolve-roots.sh(+worktree.sh?) a managed row in MANIFEST sosetup/synccreate and re-stamp them likearm-loop.sh. Smallest change; makes the required-repo-local set explicit and versioned.gate.sh, so CI needs nothing repo-local.sync.shto recognise a known "required repo-local" subset and stop flagging it as stale-vendor.Workaround applied in reDeploy
Trimmed
.claude/scripts/to the 8 files that are actually required, each refreshed byte-identical from plugin 0.3.0:gate.sh,resolve-roots.sh,worktree.sh,arm-loop.sh,prepare-pr.sh,bot-gh.sh,merge-ready.sh,notify-poll.sh.Filed from reDeploy per #223. Labelled
backlog— not self-assigningplanned, per CONTRIBUTING.md.