Skill tool: args parameter corrupts shell positional parameters ($1/$2) in SKILL.md code examples

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 29, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When the Skill tool is invoked with an args parameter, and the target SKILL.md file contains a fenced code block with shell positional parameters ($1, $2, etc., e.g. bash -c '. "$1" && some_func "$2"' _ "<path>" "<value>"), the positional-parameter tokens inside that code block get corrupted in the content that is actually surfaced to the model. The SKILL.md file on disk is unmodified and correct — the corruption only appears in what the tool_result / injected skill body contains.

I observed this twice, in two separate sessions, always with the issue-create-gate skill (which has a bash -c '. "$1" && write_ticket "$2"' _ "<lib_path>" "<user 選択値>" example at SKILL.md line 82), and always when the Skill call included a non-empty args string whose content followed a "タイトル: type(scope): keyword ..." shape (a Japanese-language convention for "Title: <conventional-commit-style prefix>: <first keyword>"):

Occurrence 1 (this session): Skill({skill: "issue-create-gate", args: "タイトル: chore(tests): assert_stdout_* Group B(...)の統合検討\n\n本文趣旨:\n..."})
→ surfaced code block became: bash -c '. ":" && write_ticket "assert_stdout_*"' _ "$HOME/.../issue-tracker-state.sh" "<user 選択値>"
(expected: bash -c '. "$1" && write_ticket "$2"' _ ...)

Occurrence 2 (earlier session, same repo/skill): Skill({skill: "issue-create-gate", args: "タイトル: chore(hooks): commit-verification-gate Phase 2 の代替設計案...\n\n背景: ..."})
→ surfaced code block became: bash -c '. ":" && write_ticket "commit-verification-gate"' _ ...

In both cases:

  • "$1" was replaced with ":" (a bare colon)
  • "$2" was replaced with the first "keyword" token that follows the type(scope): portion of the args string (i.e., whatever comes right after the second colon in the args text)

This is a consistent, reproducible pattern across two independent occurrences with different args content, which rules out a one-off rendering glitch. I verified:

  • The SKILL.md file on disk (both in ~/.claude/skills/ and the source repo it's synced from) contains the correct "$1"/"$2" form and was not modified between sessions (unchanged mtime).
  • A sibling Skill call in the same session with no args parameter (related-issue-search) rendered the same style of bash -c '. "$1" && ...' code block correctly, unmodified.
  • This is not a transcript-parsing artifact on my end — I inspected the raw JSONL bytes of the tool_result content directly and confirmed the corrupted string is what was actually recorded as having been surfaced to the model.

Executing the corrupted command as literally shown fails immediately (_: line 1: :: No such file or directory), which is how I noticed it. If a skill's code example were less obviously broken when corrupted (e.g. if the substituted value happened to be a valid path), this could silently execute the wrong command instead of failing loudly.

What Should Happen?

When a Skill tool call includes an args parameter, the skill's SKILL.md body content (including any fenced code blocks) should be surfaced to the model byte-for-byte identical to its on-disk content, regardless of the args value. Shell positional parameters ($1, $2, ...) inside example code blocks are literal instructional text for the model to copy — they should never be treated as template placeholders to be filled in from the args string.

Reproduction

  1. Create (or use an existing) skill whose SKILL.md contains a code block like:

``bash
bash -c '. "$1" && some_func "$2"' _ "/some/path" "<placeholder>"
``

  1. Invoke it via the Skill tool with a non-empty args string that has the shape "Title: type(scope): keyword ...more text..." (e.g. args: "タイトル: chore(tests): assert_stdout_* ..." or an English equivalent like "Title: fix(parser): normalize-whitespace some more context").
  2. Inspect the tool_result / injected skill body text returned by the Skill call.
  3. Expected: the code block is unchanged, still containing "$1" and "$2" literally.

Observed: "$1" becomes ":" and "$2" becomes the token immediately following the second : in the args string.

Environment

  • Claude Code CLI, Skill tool (skills loaded from ~/.claude/skills/)
  • Reproduced across two separate sessions on macOS

View original on GitHub ↗