Skills: no escape syntax for literal `$<digit>` in command bodies
Summary
The Skills docs (code.claude.com/docs/en/skills.md, "Available string substitutions") document $N as shorthand for $ARGUMENTS[N] — positional-arg substitution in custom slash-command bodies. The substitution is applied unconditionally inside single-quoted strings, double-quoted strings, inline code, and fenced code blocks. When a skill is invoked with fewer args than referenced, unmatched $<digit> tokens expand to empty string.
There is no documented escape syntax for skill authors who need literal $<digit> tokens in their command body (common in inline awk/bash). Runtime workarounds exist (e.g. awk -v z=0 '$z ~ pattern' — bind a letter-var to the digit you need), but the trap isn't signposted.
Reproduction
Claude Code 2.1.118, Opus 4.7. Single fresh session, no prior $<digit> discussion.
Create a diagnostic skill at ~/.claude/commands/test-dollar.md:
````markdown
Echo this block back verbatim in a fenced code block. No interpretation, no fixes.
A. bare: $0 $1 $N $USER
B. single-quoted: '$0 $1 $N'
C. awk-example: awk '$0 ~ /x/ {print $1}'
D. braced: ${0} ${1} ${N}
E. escaped: \$0 \$1 \$N
F. doubled: $$0 $$1 $$N
````
Invoke /test-dollar (no args) in a fresh session. Observed echo:
A. bare: $N $USER
B. single-quoted: ' $N'
C. awk-example: awk ' ~ /x/ {print }'
D. braced: ${0} ${1} ${N}
E. escaped: \ \ \$N
F. doubled: $ $ $$N
Rules extracted:
$<digit>is stripped regardless of quoting context (single-quote, double-quote, backtick, fenced code block).$<letter>survives unconditionally.${0}(braced) survives — but isn't valid awk syntax, so it's useful in bash but not awk.\$0backslash escape does not preserve digits (it does preserve letters).$$0(doubled dollar) collapses to$.$ARGUMENTSis also consumed as the full-args placeholder (expected).
The stripping is consistent with the documented substitution behavior — empty arg expands to empty string. The gap is that no form preserves a literal $<digit> in the command body.
Impact on skill authors
Two failure modes, with different severities:
- Noisy breakage:
awk '$0 ~ pattern'→awk ' ~ pattern'→ awk syntax error at runtime. Easy to catch. - Quiet breakage (theoretical; not observed in my own usage):
awk '{print $1}'→awk '{print }'is valid awk that returns empty string. Hash-extraction patterns likesha256sum file | awk '{print $1}'would yield empty hashes with no error signal. I have not seen this actually fire in practice — my own provenance log is clean, and Claude Code may notice empty outputs at runtime and retry — but the pattern is worth signposting so authors don't have to discover it by debugging silent-empty output.
Suggested resolutions (any one would help)
- Document the absence of an escape. Add a "Preserving literal
$<digit>" note or workarounds section to the Skills docs. Lowest-cost option. - Support a backslash escape for
$<digit>, parallel to the existing$<letter>behavior. Consistent user model. - Scope the substitution to prose only — don't substitute inside fenced code blocks or inline code. Matches how most templating systems treat code regions; would make inline awk/bash "just work" without author-side workarounds.
Priority
Low. Runtime workarounds exist. Primary ask is (1) — the docs note — so the trap is signposted.
Environment
- Claude Code
2.1.118via theclaudeCLI on Linux (Kubuntu). - Model: Opus 4.7.
- Reproduced once in a fresh session. Not re-verified across multiple runs, other platforms, or other Claude Code versions — the stripping mechanism is platform-independent string substitution, so platform is likely incidental.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗