Skill `args` are substituted into `$0`/`$1`/`$2` in the SKILL.md body, silently corrupting shell commands
Summary
When the Skill tool is invoked with args, occurrences of $0, $1, $2… in the SKILL.md body are replaced with the whitespace-split words of args. The file on disk is unchanged — only the loaded content differs. Invoking the same skill without args leaves them intact.
This appears to be slash-command positional-argument interpolation being applied to the whole skill body. Fenced/inline code spans are not exempt.
The failure is silent: the result is not an error but a plausible-looking different command.
Reproduction
~/.claude/skills/zz-repro-args/SKILL.md:
---
name: zz-repro-args
description: Temporary reproduction case.
---
# Repro
Line A: `awk '{print $1}'`
Line B: `awk '{print $2}'`
Line C: price is $0.10 per GB
Invoke with args: "alpha bravo charlie" → loaded content becomes:
Line A: `awk '{print bravo}'`
Line B: `awk '{print charlie}'`
Line C: price is alpha.10 per GB
So $0→alpha, $1→bravo, $2→charlie.
Invoke the same skill with no args → $1, $2, $0.10 are preserved correctly.
Impact
Any skill whose body contains $<digit> is affected when invoked with args:
- awk field references —
awk '{print $1}'becomesawk '{print bravo}'. In awk an undefined variable is the empty string, so the command succeeds and returns nothing. ABASE_SHA=$(… | awk '{print $1}')silently yields an empty value rather than failing. - Shell positional parameters
- PostgreSQL placeholders —
UPDATE t SET n = n + $1 - Dollar amounts in documentation tables —
$0.10/GBbecomes<word>.10/GB, corrupting cost figures the model then reasons about.
This affects bundled skills as well. In the official superpowers plugin, skills/requesting-code-review/SKILL.md contains:
BASE_SHA=$(git log --oneline | grep "Task 1" | head -1 | awk '{print $1}')
Invoked with args, this resolves BASE_SHA to an empty string, so the subsequent diff range is wrong.
Expected behavior
$<digit> in a skill body should not be treated as a positional parameter, or interpolation should at minimum skip fenced code blocks and inline code spans. If positional interpolation in skills is intentional, an escape mechanism (e.g. $$1) and documentation for it would be needed.
Environment
- Claude Code 2.1.222
- macOS (Darwin 25.6.0)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗