Skill tool's args does bash-style $N positional substitution against SKILL.md prose, corrupting literal dollar amounts
Summary
Calling the Skill tool with a non-empty args string causes the harness to scan the rendered SKILL.md body for bare $<digit> tokens and replace each with the Nth (0-indexed) whitespace-split word of args — bash/slash-command-style positional-parameter substitution applied to skill markdown that was never authored with placeholders in mind. This silently corrupts any literal dollar amount in the skill body whose $N happens to land on a valid word index.
Repro
Skill file contains (among other rows):
| AR balance >$5,000 and 30+ days | ...
| AR balance >$0 and 90+ days | ...
| Rent PSF below $2.50/SF (under-market flag) | ...
Invocation:
Skill({ skill: "exception-detection", args: "Targeted scan: Category 2 tenant exceptions only, with emphasis on verifying the 3 new v1.2 cross-checks against HubSpot Lease Renewal deals..." })
args split on whitespace: index 0 = "Targeted", index 2 = "Category", index 5 = "exceptions".
Content actually returned to the model:
| AR balance >exceptions,000 and 30+ days | ...
| AR balance >Targeted and 90+ days | ...
| Rent PSF below Category.50/SF (under-market flag) | ...
$5,000 → "exceptions,000" (word[5]), $0 → "Targeted" (word[0]), $2.50 → "Category.50" (word[2]) — an exact 0-indexed match.
Re-tested with a controlled args string (args="zero one two three four five six seven") against the same skill file: same three tokens corrupted predictably ($5,000→"five,000", $0→"zero", $2.50→"two.50"). But a separate literal $5K/mo elsewhere in the same file was left untouched — the substitution appears to require the digit run be followed by a non-letter (space/comma/period qualify, a letter does not), i.e. there's a partial guard against clobbering shorthand like $5K/$10M, but it does not protect comma-formatted or decimal dollar amounts, which is extremely common in ordinary prose.
Skills whose body has no $<digit> substring are unaffected — in that case args is instead appended verbatim as a trailing ARGUMENTS: <raw string> line, which is the correct/safe behavior.
Why this matters
Any skill whose Markdown body contains dollar figures (financial thresholds, pricing, cost references — extremely common in real-world skill content) is silently corrupted in-context whenever it's invoked with an args string whose word count happens to land on those $N positions. The corruption is invisible unless someone happens to diff the rendered output against the source file — the model just silently reasons over garbage numbers.
Suggested fix
args should never be pattern-matched/interpolated against the skill body at all — it should always be passed through as inert appended context (exactly what already happens today for skills with no $N matches). If per-skill templating is intentionally wanted in the future, it should require an explicit, collision-proof placeholder syntax (e.g. {{arg1}} / {{ARGUMENTS}}) that skill authors opt into via frontmatter, rather than a blanket regex applied to every skill's prose regardless of whether the author ever intended a placeholder.
Environment
@anthropic-ai/claude-codev2.1.214- Windows 11 (win32-x64 build)