Bug report: orchestrator scripts break when run from the plugin cache (CLAUDE_PLUGIN_ROOT)
Repo: robercano/ai-project-orchestrator · Plugin: orchestrator@ai-project-orchestrator v0.1.1
Found in: consumer repo robercano/reDeploy, 2026-07-07, while running a /pr-loop tick.
Symptom
The pr-loop tick prompt invokes helper scripts as:
bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/notify-poll.sh
With the plugin installed, CLAUDE_PLUGIN_ROOT resolves to the install cache:
~/.claude/plugins/cache/ai-project-orchestrator/orchestrator/0.1.1/
and the script immediately fails:
bash: /home/rcano/.claude/plugins/cache/ai-project-orchestrator/orchestrator/.claude/scripts/bot-gh.sh:
No such file or directory
Every script that shells out to bot-gh.sh is affected the same way. The tick only worked because
reDeploy still tracks legacy copies under .claude/scripts/ (the :-.claude fallback) — which defeats
the point of moving the scripts into the plugin.
Root cause — one root variable serving two different roots
All scripts assume they live at <repo-root>/.claude/scripts/<script>.sh and derive:
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # scripts/*.sh, e.g. notify-poll.sh:14
gh() { bash "$root/.claude/scripts/bot-gh.sh" "$@"; }
That holds in the marketplace/source checkout (<repo>/.claude/scripts/…), but the install cache strips
the .claude/ prefix — the plugin root contains scripts/, agents/, commands/, … directly. So from
the cache, ../.. lands on …/orchestrator/ (the version dir's parent), and $root/.claude/scripts/…
doesn't exist.
Affected root= derivations (all in v0.1.1 cache): bot-gh.sh:25, merge-ready.sh:29,
notify-poll.sh:14, pr-feedback.sh:18, gate.sh:12, prepare-pr.sh:47, seed-issues.sh:32,
worktree.sh:23, cockpit.sh:33.
There are really two distinct roots being conflated:
- Plugin root — where sibling scripts live (
bot-gh.sh). Derivable from BASH_SOURCE in both
layouts as simply the script's own dir.
- Consumer project root — where
.env (GH_BOT_TOKEN), .claude/gates.json, the notify-poll
cursor state, and the git repo live. From the cache this is not derivable from script location at
all — even fixing (1) leaves bot-gh.sh looking for .env at $root/.env inside the cache.
Suggested fix
Split the two concerns in every script:
# siblings: same dir in both layouts (repo .claude/scripts/ AND cache scripts/)
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
gh() { bash "$script_dir/bot-gh.sh" "$@"; }
# consumer project: env var first, then git, then cwd
root="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
- Sibling-script references (
$root/.claude/scripts/X.sh) → $script_dir/X.sh.
- Project assets (
.env, gates.json, cursor/state files, cd "$root") → the new root.
gate.sh is a special case: it's repo-tracked in consumers (scaffolded/managed), so its ../..
derivation is fine — but if it's ever invoked from the cache it has the same issue.
- The command prompts (
commands/pr-loop.md, pr-loop-self.md) can keep
${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/… once the scripts themselves are layout-agnostic.
Repro
cd <any consumer repo with .env + gates.json>
CLAUDE_PLUGIN_ROOT=~/.claude/plugins/cache/ai-project-orchestrator/orchestrator/0.1.1 \
bash "$CLAUDE_PLUGIN_ROOT/scripts/notify-poll.sh"
# -> No such file or directory: …/orchestrator/.claude/scripts/bot-gh.sh
Works from the marketplace checkout layout (<repo>/.claude/scripts/notify-poll.sh) because ../..
happens to be the repo root there.
Bug report: orchestrator scripts break when run from the plugin cache (
CLAUDE_PLUGIN_ROOT)Repo: robercano/ai-project-orchestrator · Plugin:
orchestrator@ai-project-orchestratorv0.1.1Found in: consumer repo robercano/reDeploy, 2026-07-07, while running a
/pr-looptick.Symptom
The pr-loop tick prompt invokes helper scripts as:
With the plugin installed,
CLAUDE_PLUGIN_ROOTresolves to the install cache:and the script immediately fails:
Every script that shells out to
bot-gh.shis affected the same way. The tick only worked becausereDeploy still tracks legacy copies under
.claude/scripts/(the:-.claudefallback) — which defeatsthe point of moving the scripts into the plugin.
Root cause — one
rootvariable serving two different rootsAll scripts assume they live at
<repo-root>/.claude/scripts/<script>.shand derive:That holds in the marketplace/source checkout (
<repo>/.claude/scripts/…), but the install cache stripsthe
.claude/prefix — the plugin root containsscripts/,agents/,commands/, … directly. So fromthe cache,
../..lands on…/orchestrator/(the version dir's parent), and$root/.claude/scripts/…doesn't exist.
Affected
root=derivations (all in v0.1.1 cache):bot-gh.sh:25,merge-ready.sh:29,notify-poll.sh:14,pr-feedback.sh:18,gate.sh:12,prepare-pr.sh:47,seed-issues.sh:32,worktree.sh:23,cockpit.sh:33.There are really two distinct roots being conflated:
bot-gh.sh). Derivable fromBASH_SOURCEin bothlayouts as simply the script's own dir.
.env(GH_BOT_TOKEN),.claude/gates.json, the notify-pollcursor state, and the git repo live. From the cache this is not derivable from script location at
all — even fixing (1) leaves
bot-gh.shlooking for.envat$root/.envinside the cache.Suggested fix
Split the two concerns in every script:
$root/.claude/scripts/X.sh) →$script_dir/X.sh..env,gates.json, cursor/state files,cd "$root") → the newroot.gate.shis a special case: it's repo-tracked in consumers (scaffolded/managed), so its../..derivation is fine — but if it's ever invoked from the cache it has the same issue.
commands/pr-loop.md,pr-loop-self.md) can keep${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/…once the scripts themselves are layout-agnostic.Repro
Works from the marketplace checkout layout (
<repo>/.claude/scripts/notify-poll.sh) because../..happens to be the repo root there.