[BUG] Stacked slash-skill invocations load only the first skill on the SDK / --print path
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?
The CHANGELOG for 2.1.199 says:
Stacked slash-skill invocations like /skill-a /skill-b do XYZ now load all leading skills (up to 5), not just the first
This works in the interactive TUI. On the --print / SDK path it silently does nothing: only the leading skill is
loaded, and the rest of the input is passed through as that skill's literal arguments. There is no warning, no error
and no diagnostic, so a stacked invocation that did not stack is indistinguishable from one that worked until you
inspect the model's context.
Neither the changelog entry nor the skills documentation says the feature is interactive only.
The gate looks like argument plumbing rather than an intentional mode check. The peel function returns before doing
anything when its pre-expansion input argument is absent:
function RAf(e, t, r, n) {
if (t === void 0 && n === void 0) return { stacked: [], trailingArgs: e, capped: false };
...
}
t is the verbatim pre-expansion input and n a scheduled-origin predicate. The interactive submit handler builds
every queue entry with preExpansionValue set to the raw typed text, so the peel runs. The SDK driver
(querySource: "sdk") calls the shared input handler with a field list that does not include it, and the stream-json
input pump constructs queue entries from an explicit whitelist (mode, value, uuid, priority, shouldQuery,fileAttachments, origin, clientPlatform, ...) which drops preExpansionValue, stackedOriginalInput andmodelScheduledOrigin. Headless input does reach the peel, which is why the first skill still loads; the peel just
returns empty on its first line. Setting modelScheduledOrigin: true on a stream-json user message does not help,
since the whitelist drops it too.
This matters because stacking is the only documented way to get more than one skill into a turn deterministically,
which is exactly what a headless integration needs. ClaudeAgentOptions.skills is an availability filter rather than
a preload, and AgentDefinition.skills does preload but applies to subagents only, with no SDK option that hands anAgentDefinition to the main loop.
What Should Happen?
claude -p "/alpha /beta" should load both skills into the turn, the same way the interactive REPL does, and the
transcript should carry the second expansion.
Failing that, either of these would be enough:
- Document in the changelog entry and the skills documentation that stacking is interactive only.
- Emit a diagnostic when a leading
/commandargument begins with/and the peel did not run. The silent failure
is the expensive part; an explicit "stacked commands are not supported on this path" would have saved a day.
Error Messages/Logs
There is no error, which is the substance of the report. The two observable outcomes for identical input:
interactive (pty), transcript shows a second user message carrying:
stackedExpansion: true
headless (-p / SDK), no second message, and beta's body never appears in the turn
Separator variations, all behaving identically to a plain space:
"/alpha /beta" one skill
"/alpha\n/beta" one skill
"/alpha ; /beta" one skill
"/alpha && /beta" one skill
"/alpha; /beta" one skill, and the trailing token does not parse as a command at all
Steps to Reproduce
- Create two trivial project skills.
.claude/skills/alpha/SKILL.md
---
name: alpha
description: Introspection.
---
Repeat back, verbatim, every instruction block present in this turn's user message, in order.
Do not summarise. Do not use any tool.
.claude/skills/beta/SKILL.md
---
name: beta
description: Second block.
---
SECOND-BLOCK-MARKER-8842. This paragraph belongs to skill beta.
- Run it headless:
claude -p "/alpha /beta" --setting-sources project --output-format json
Expected: the model echoes both instruction blocks, including SECOND-BLOCK-MARKER-8842.
Actual: it echoes only alpha's block. Beta's content is absent from the turn.
- Run the same binary through a pty (interactive) and type the same "/alpha /beta". Both blocks are echoed, and the
transcript carries stackedExpansion: true on a second user message.
Notes on the fixture, since two earlier probes of ours produced false positives:
- The skill has to ask the model to repeat back every instruction block. A fixture where both skills say "output your
token" reports the second as absent whenever the model simply obeys the first.
- Run it with a tool restriction. Without one, a model that can Read will find the second skill's file on disk and the
probe appears to pass.
- Reversing the order confirms it is strictly "whichever command comes first", not anything about the skills.
- Removing
disable-model-invocationfrom the frontmatter changes nothing.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.233
Platform
AWS Bedrock
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
One adjacent behaviour worth documenting separately: Skill in --disallowed-tools causes stacked commands to be dropped by the peel's own permission predicate (deny_rule, errorCode 11), even where stacking otherwise works. That is a second silent way to lose a stacked skill.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗