Skills: no escape syntax for literal `$<digit>` in command bodies

Resolved 💬 4 comments Opened Apr 23, 2026 by harrisonaedwards Closed May 29, 2026

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.
  • \$0 backslash escape does not preserve digits (it does preserve letters).
  • $$0 (doubled dollar) collapses to $.
  • $ARGUMENTS is 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:

  1. Noisy breakage: awk '$0 ~ pattern'awk ' ~ pattern' → awk syntax error at runtime. Easy to catch.
  2. Quiet breakage (theoretical; not observed in my own usage): awk '{print $1}'awk '{print }' is valid awk that returns empty string. Hash-extraction patterns like sha256sum 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)

  1. Document the absence of an escape. Add a "Preserving literal $<digit>" note or workarounds section to the Skills docs. Lowest-cost option.
  2. Support a backslash escape for $<digit>, parallel to the existing $<letter> behavior. Consistent user model.
  3. 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.118 via the claude CLI 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.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗