Repository navigation
Fix command reference paths so they resolve outside a plugin install - #9
Conversation
3c8f5be to
e25ffde
Compare
End-to-end verification done — both cases passRan two fresh agents with no prior context, each fed a command body exactly as a slash-command invocation injects it, in the personal-install shape ( Test 1 — does resolution work? Pass.
Before this PR that read fails outright. Test 2 — does it fail closed? Pass, and more robustly than I expected. Given a command whose reference filename doesn't exist anywhere, the agent exhausted seven strategies — all three candidates, a scoped glob, a whole-home glob,
Its stated next action: stop, do not audit, report that the spec could not be read. Asked directly whether the instructions permitted proceeding from its own knowledge of the field order, it answered no and quoted the ground rule. That is the behavior this PR exists to guarantee. One fix that came out of testingTest 1 resolved correctly but had to expand Rebased onto
|
${CLAUDE_PLUGIN_ROOT} is substituted only for plugin skills. When an agent
is asked to install this skill from GitHub it copies the files as a
personal skill under ~/.claude/skills/ and the commands into
~/.claude/commands/, where the variable is never expanded and every
reference-file read fails.
For /paymob-check-hmac that failure is dangerous rather than cosmetic: the
command exists to check a field order it deliberately does not carry, so a
failed read invites an audit from recall that can pass a wrong order as
correct — HMAC verification that looks verified and is not.
Each command now resolves its root from the plugin root, the personal
skills directory, or a repo checkout, searches as a last resort, and stops
rather than answering from memory. allowed-tools gains Glob so the search
is actually permitted. validate.py enforces both properties.
A fresh agent run through the personal-install path resolved the file correctly but had to expand "~" itself, and noted that a strict reading of the literal "~/.claude/..." string would fail on Windows. Name "~" as the home directory, give the %USERPROFILE% form, and mark path 3 as working only inside the skill repo so path 2 is understood as the reliable one for a personal install.
e25ffde to
60cbd8b
Compare
Bug fix for the commands added in #7. Found by installing the skill the way a user actually would.
The bug
${CLAUDE_PLUGIN_ROOT}is substituted only in plugin skills. All three commands used it as their sole path to the reference files:Ask an agent to install this skill from GitHub and it does not perform a marketplace plugin install. Verified on Claude Code: it copied the files as a personal skill to
~/.claude/skills/paymob-integration/and the three command files into~/.claude/commands/(creating that directory). In that shape the variable is never expanded — it reaches the model as literal text, and every reference-file read fails.Confirmed on disk after a real install: all three installed command files still contain the raw
${CLAUDE_PLUGIN_ROOT}string, while the reference files sit at~/.claude/skills/paymob-integration/references/.Why this is not cosmetic
For
/paymob-test-cardsand/paymob-explain-errorthe agent probably recovers by searching, andtest-cardsalready forbids reciting numbers from memory, so its worst case is a refusal./paymob-check-hmacis the problem. It exists to verify a field order it deliberately does not carry, and instructs the agent to readhmac-verification.mdrather than trust recall. If that read fails and the agent proceeds anyway, it audits the field order from pretraining — and can pass a wrong order as correct. That is HMAC verification that looks verified and silently is not, which is the single worst outcome in this domain, reached through nothing more than a broken file path.Fix
Each command now resolves its root from the first location that exists:
--plugin-dir)${CLAUDE_PLUGIN_ROOT}/skills/paymob-integration/~/.claude/skills/paymob-integration/skills/paymob-integration/with a filename search as a last resort, an explicit note that an unexpanded
${CLAUDE_PLUGIN_ROOT}means "not a plugin install, use another path", and — most importantly — fail closed: if the file cannot be read, say so and stop rather than answer from memory./paymob-check-hmacstates this in its non-negotiable ground rules, not just in a step.allowed-toolsgainsGlob(andGrepfor the audit), becauseReadalone would have blocked the very fallback search the fix depends on.The one-source-of-truth rule is untouched: no command carries a copy of the field order, endpoints, or test cards. Only the locating instruction changed.
Validator coverage
Two new per-command assertions in
validate_commands, both negative-tested — I broke each rule and confirmed CI would catch it:${CLAUDE_PLUGIN_ROOT}without a non-plugin fallback path fails:names ${CLAUDE_PLUGIN_ROOT} without a non-plugin fallback path; the reference files are unreachable in a personal-skill installmust tell the agent to stop rather than answer from memory when it cannot read its reference fileNotes
disable-model-invocation: truestays onpaymob-check-hmac. Its absence from the model's skill listing is correct by design — still user-invocable, just not offered for automatic invocation. Please don't "fix" that.skills/paymob-integration/**, the?partner=claudeparameter, or any manifest. No version bump: 3.3.0 is onmainunreleased.commands/paymob-test-cards.md, which Document that kiosk and BNPL have no sandbox test path; fix /paymob-test-cards overpromising #8 also edits on different lines. Whichever merges second may need a trivial rebase; happy to do it.Test plan
python scripts/validate.pypassespython scripts/package_skill.pybuilds~/.claude/skills/paymob-integrationand~/.claude/commands/paymob-*.md, reinstall from this branch, start a fresh session, and invoke all three commands to confirm each reads its reference file./paymob-check-hmacis the one to watch.