Skip to content

fix(plugins): paired body+rule rewrite for seven interpreter-led allowed-tools grants #2221

Description

@kyle-sexton

Defect

Seven skill allowed-tools grants across five plugins are interpreter-led (Bash(bash <path>…)) and,
in four cases, written with ${CLAUDE_PLUGIN_ROOT} — which is not substituted in allowed-tools
frontmatter, so those grants are inert literal strings that never match.

row skill grant at HEAD state
B1 prototype/explore-directions Bash(bash ${CLAUDE_PLUGIN_ROOT}/scripts/detect-ecosystems.sh:*) inert
B2 prototype/pressure-test same inert
B3 code-tidying/tidy Bash(bash ${CLAUDE_PLUGIN_ROOT}/skills/tidy/scripts/open-pr-count.sh:*) inert
B4 repo-hygiene/clean Bash(bash ${CLAUDE_PLUGIN_ROOT}/skills/clean/scripts/*) inert + wildcarded target
B5 repo-fleet-hygiene/audit Bash(bash ${CLAUDE_SKILL_DIR}/scripts/audit-fleet.sh *) dead — quote mismatch
B6 code-tidying/audit-comment-residue Bash(bash *audit-comment-residue/scripts/detect.sh*) works, anti-pattern
B7 docs-hygiene/audit-noise Bash(bash *audit-noise/scripts/detect.sh*) works, anti-pattern

The corrected mechanism — the originally prescribed fix is falsified

The originating item prescribed "drop bash from the rule." That is wrong and would convert an
anti-pattern into a dead grant. bash is not one of the wrappers Claude Code strips before matching
Bash rules (the stripped set is timeout, time, nice, nohup, stdbuf, command, builtin,
noglobhttps://code.claude.com/docs/en/permissions), and this repo's own convention already
records that at docs/conventions/permission-rule-hygiene/README.md:218-220. Every one of the seven
skill bodies invokes its script through bash "<path>", so a rule without bash stops matching
the command the body actually runs.

The correct fix is a paired body + rule rewrite: change the body to invoke the bundled script
directly (shebang + exec bit, both already present and verified to survive plugin-cache install), and
write the rule against that same string using ${CLAUDE_SKILL_DIR}, which is substituted in
allowed-tools (https://code.claude.com/docs/en/skills).

Two traps

Evidence at HEAD (685dd381)

plugins/prototype/skills/explore-directions/SKILL.md:6 / :17,
plugins/prototype/skills/pressure-test/SKILL.md:6 / :17,
plugins/code-tidying/skills/tidy/SKILL.md:6 / :18,
plugins/code-tidying/skills/audit-comment-residue/SKILL.md:6 / :17 / :49,
plugins/repo-hygiene/skills/clean/SKILL.md:5-6 (+ body lines 40, 102–166 and context/*.md),
plugins/repo-fleet-hygiene/skills/audit/SKILL.md:6 / :67,
plugins/docs-hygiene/skills/audit-noise/SKILL.md:6 / :17 / :62.

The shipped detector reports all seven as warning [P1] at HEAD.

Checklist

  • B1 prototype/explore-directions
  • B2 prototype/pressure-test
  • B3 code-tidying/tidy
  • B4 repo-hygiene/clean
  • B5 repo-fleet-hygiene/audit
  • B6 code-tidying/audit-comment-residue
  • B7 docs-hygiene/audit-noise

Not in scope

context7/setup's Bash(npm view ctx7 version*) (ledger row B8) is NOT_REPRODUCED — a
fully-pinned rule the convention explicitly exempts at README.md:94-100. It is flagged only by a
P1_ERE regex over-reach, filed separately by the verifier as ledger row A19 against
claude-config.

Provenance

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions