[BUG] Claude Code sends the argument text of a stacked-skill prompt two times per skill (six copies of a pasted document for three skills)

Status Open
Reported on v2.1.274
Maintainer reply None cached
Activity 1 comment · opened Sep 17, 2026

Environment

Claude Code 2.1.274 (CLI) on macOS 14.6 (Darwin 23.6.0), with model claude-fable-5. The oldest case in my transcripts has version 2.1.201; v2.1.199 added stacked skill invocation.

Summary

Since v2.1.199, Claude Code expands stacked skill invocations like /skill-a /skill-b do XYZ. The skills docs say that /write-tests /fix-issue 123 "loads both skills and passes the trailing text 123 as $ARGUMENTS to each of them"; when the trailing text is a short value, the extra copies add almost no tokens.

When the trailing text is a pasted document, Claude Code writes the full document into the request two times for each skill. My prompt had three stacked project commands (.claude/commands/*.md, no $ARGUMENTS placeholder) and a meeting transcript of 61,716 characters; the first API request of the session contained six copies of the transcript and used 188,065 input tokens.

A second session with the same prompt structure and a longer transcript used 203,614 input tokens in the first request, which exceeds a 200K context window. By the same mechanism, six stacked skills (the maximum) send the text twelve times.

This is the prompt as ~/.claude/history.jsonl stores it, with the pasted content removed.

/pm:sprint-overview /pm:bulk-anti-slop-issues-linear /discord:bot-ops

<transcript>[Pasted text #18 +493 lines]</transcript>

(about 1,400 characters of notes)

Mechanism

For each stacked skill, Claude Code writes a group of entries to the session JSONL, and every group contains the full argument string two times. All groups have the same promptId; Claude Code wrote the three groups within 36 ms, before the first API request.

  1. A user message with <command-name> and <command-args>, and the <command-args> element contains the full argument string.
  2. An isMeta user message with the skill body. The body has no $ARGUMENTS placeholder, so Claude Code appends ARGUMENTS: <full argument string> to it (as the docs describe).
  3. Eight attachments (environment, model, output_style_instructions, deferred_tools_delta, agent_listing_delta, mcp_instructions_delta, output_style, command_permissions). The three groups contain identical copies of these attachments; I compared their hashes.

The docs give a reason for the ARGUMENTS: append ("so Claude still sees what you typed"). The <command-args> message of the same skill already contains that text, so the append adds a second copy also when the prompt has only one skill.

The following excerpt shows the session JSONL entries before the first assistant entry.

line   entry                                          promptId  chars   transcript copies
4      user    /pm:sprint-overview                    e3c70f5d  63,245  1
5      isMeta  skill body + ARGUMENTS                 e3c70f5d  76,838  1
6-14   9 attachments (the 8 in the list + skill_listing)
15     user    /pm:bulk-anti-slop-issues-linear       e3c70f5d  63,271  1
16     isMeta  skill body + ARGUMENTS                 e3c70f5d  66,677  1
17-24  8 attachments (identical to the 8 in lines 6-14)
25     user    /discord:bot-ops                       e3c70f5d  63,239  1
26     isMeta  skill body + ARGUMENTS                 e3c70f5d  75,055  1
27-34  8 attachments (identical to the 8 in lines 6-14)
35-39  hook_success, instructions, session_context, date, prompt_snapshot
44     assistant (input_tokens 2, cache_creation_input_tokens 165,195, cache_read_input_tokens 22,868)

Expected

Claude receives the body of each stacked skill (up to 6) and the rest of the message one time. A skill body contains a copy of the message text only where the skill author wrote a $ARGUMENTS placeholder.

Suggested fix

  • Write the argument string one time per prompt (for example, only in the <command-args> message of the first skill) and do not copy it into the entries of the other skills.
  • Do not append ARGUMENTS: <value> to a skill body when a <command-args> message of the same prompt already contains the value.
  • Write the per-turn attachments one time per prompt, not one time per stacked skill.

Workaround

Write the long text to a file and give the file path as the argument; Claude then reads the file one time with the Read tool. As an alternative, send the skill that needs the long text in its own prompt, and send the other skills in a second prompt with a short argument.

Not a duplicate

The open issues about stacked commands report autocomplete defects (#89398, #89522, #91337) or ask for stacked built-in commands such as /model opus /effort xhigh (#93076). None of them reports the argument copies or their token cost.

#56082 requested this composition and asked Claude Code to "pass the surrounding text as shared arguments". The implementation in v2.1.199 copies the text into each skill, and it does not share one copy.

The author of a comment in #89398 scanned JSONL files for turns with two or more <command-name> blocks and found none. In the CLI (2.1.274), each stacked skill is a separate user entry with the same promptId, so that count does not detect stacked invocations.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗