Back to news

Can you queue slash commands in Claude Code?

Short answer: no. Claude Code 2.1.233 has no queue for slash commands, and typing /code-review /clear /simplify on one line does not run three commands. It runs the first one and hands the rest to it as plain text. We measured six cases on August 16, 2026, and the failure has two different shapes depending on which command comes first. One custom command can own a sequence, and separate invocations give you something close to a fresh start, with a caveat we found by being wrong.

Can you queue slash commands in Claude Code?

Not inside the session. Claude Code treats the first slash command on a line as the command and everything after it as that command's argument, so a queue never forms. We tested this on Claude Code version 2.1.233 on August 16, 2026, using two throwaway custom commands in .claude/commands/: echoargs, which replies with whatever arguments it received, and marker, which replies with a fixed string. Every run below was repeated in bash, zsh and sh.

What we typedWhat came backWhat that means
/echoargs /markerARGS=[/marker]Second command became text, never ran
/echoargs newline /markerARGS=[/marker]A newline does not submit twice
/clear /markeremptyBuilt-in first discards the rest
/pipeline (one command, two phases)PHASE_ONE_DONE PHASE_TWO_DONESequence works when one command owns it
separate invocation, asked to recallNO_MEMORYThe conversation does not carry over
separate invocation, file memory plantedMELANCIA99A file memory can carry over

Searching the Claude Code CLI help output for a queue or sequence flag returns no matches. A deliberately wider search, for queue, sequence, chain and batch, returns two lines, and both are the string chain sitting inside the word keychain rather than the word itself. Matching whole words returns nothing under either search, so this is the absence of a feature rather than a syntax we failed to find.

What happens when you put two slash commands on one line?

The first command runs and receives the rest as its argument string. In Claude Code, a custom command file in .claude/commands/ can contain the placeholder $ARGUMENTS, which expands to whatever the user typed after the command name. That mechanism is what quietly absorbs your second command: the parser has already decided what the command is, so /marker is no longer a command, it is a seven character string being passed along.

This is easy to miss because nothing fails. There is no error, no warning, and no message saying a command was ignored. Our echoargs command exists precisely to make the invisible visible: it prints its own arguments back, so ARGS=[/marker] is the parser showing its work. Without a command that echoes arguments, the same run would just produce a plausible answer to the first command and you would never learn that the second one evaporated.

A developer on r/ClaudeCode described this mechanism correctly in a thread published on August 16, 2026, writing that "you can't queue them on one line. the cli runs the first slash command and passes everything after it to that command as $ARGUMENTS". Another commenter in the same thread said the opposite, that queueing is possible and that they do it often. Our measurement agrees with the first and contradicts the second, which is the reason this question is worth measuring rather than polling: the two answers were sitting side by side with nothing to separate them.

Does a line break between the commands help?

No. Sending /echoargs and /marker separated by a newline returns ARGS=[/marker], exactly the same result as putting them on one line. The newline is read as part of a single input rather than as a second submission, so the second command is absorbed as argument text again. This is check number four in the script, so it is reproducible rather than asserted.

This matters because a line break is the first thing most people try after the single line fails. It looks like it should work: in a terminal, pressing return usually means submit. In Claude Code the input is a block, and the block is parsed once. Knowing this saves the second round of guessing, and it also rules out the most common workaround before anyone builds a habit on top of it.

There is a related shape we did not test and will not claim either way, which is a here document or a file piped into the non interactive mode with several commands inside. Our measurement covers text submitted as one input, whether that text has a newline in it or not.

Why does a built-in command like /clear behave differently?

Because a built-in command consumes the turn instead of passing text along. When we ran /clear /marker in Claude Code 2.1.233, the output was empty. Not an error, not a marker, nothing at all. The /clear command did its job of wiping the session and the text after it produced no visible result, which is a third outcome distinct from both running and being echoed.

This matters for the exact sequence people want to build. The request that started this measurement was a chain of review phases separated by /clear, in the shape /code-review then /clear then /simplify. That chain hits both failure modes at once. Where a custom command leads, the following /clear is swallowed as an argument and the context is never actually cleared. Where /clear leads, whatever follows disappears. A chain built from both kinds of command fails differently at different positions, which explains why two developers can hold opposite beliefs about whether it works: depending on what they chained, one saw a plausible answer and the other saw nothing.

The practical takeaway is that a silent failure is worse here than a loud one. If Claude Code rejected the second command with a message, nobody would build a review pipeline on top of it. Because the first command answers normally, a chain can look like it worked for weeks.

How do you run a sequence of phases in Claude Code?

Write one custom command that owns the whole sequence. We created a pipeline command in .claude/commands/ whose body lists two phases in order and asks for each result on its own line. Running /pipeline returned PHASE_ONE_DONE PHASE_TWO_DONE, in that order, in every one of our runs across bash, zsh and sh. The sequence works when a single command is responsible for it, because then the ordering lives inside the prompt rather than inside the parser.

This is the same fix the r/ClaudeCode commenter proposed, and our measurement supports it. It also carries an honest limitation worth stating before you build on it: a phase inside one command is not a fresh context. Everything phase one read and wrote is still in the conversation when phase two starts, so if the reason you wanted /clear between phases was to stop phase two from inheriting phase one's assumptions, one orchestrating command does not give you that. It gives you ordering, not isolation.

If ordering is all you need, this is the cheapest shape and it stays inside one session. If you need each phase to start clean, a single command cannot deliver it and separate invocations get closer, though not as close as we first believed.

Does a separate invocation really start clean?

Mostly, and the exception is the most useful thing we measured. The conversation genuinely does not carry over: one invocation was told to remember the word BANANA42 and replied OK, and a second invocation in the same directory, asked which word it had just been told, answered NO_MEMORY. We saw that in three consecutive runs across bash, zsh and sh, and we wrote the confident version of this article on the strength of it.

Then a fourth run answered BANANA42, and the confident version was wrong. Claude Code can keep a file memory keyed to the working directory, stored under .claude/projects with an index and one file per fact. The run that failed our check had written the word into that memory on its own, with a timestamp, and the next invocation read it back. Of twelve test directories created during this work, exactly one ended up with the word saved, and it was the run that broke the result. Writing the memory is the agent's decision, not a setting we turned on, and one case in twelve is far too thin to publish as a rate.

So NO_MEMORY never proved that memory was absent. It proved only that nothing had been written that time. To make the mechanism reproducible instead of accidental, the last check in the script plants a memory file for the working directory and asks a fresh invocation to read it. It came back with MELANCIA99 in nine of our ten attempts, and the single miss came in a run where the earlier check had already written to that same memory folder. The practical rule that survives all of this: if your phases must not contaminate each other, a separate invocation is necessary and not sufficient, so check whether a memory directory exists for that path before trusting the isolation.

How do you check the parser behaviour yourself?

The script that produced every number in this article is printed in two parts, and the part below holds the four parser checks. It creates a throwaway working directory, writes the three custom commands into it, and runs the checks that concern how input is parsed. It pins a small model by default to keep the cost low, and you can override that with the MODEL variable. Copy this part and the memory part into a single file, in that order, and run it. Both parts end and begin on a comment line, so nothing breaks if the join loses its line break. The script is identical in the English, Portuguese and Spanish versions of this article, with its comments and markers left in English on purpose, because it is executable code and changing the markers would change the output the checks compare against.

#!/usr/bin/env bash
# Does Claude Code run a queue of slash commands? Six checks.
set -uo pipefail
MODEL="${MODEL:-claude-haiku-4-5-20251001}"

lab=$(mktemp -d) || { echo "no temp dir"; exit 1; }
trap 'rm -rf "$lab"' EXIT
mkdir -p "$lab/.claude/commands"
printf -- '---\ndescription: echo\n---\nReply with exactly: ARGS=[$ARGUMENTS]\n' \
  > "$lab/.claude/commands/echoargs.md"
printf -- '---\ndescription: marker\n---\nReply with exactly: MARKER_TWO_RAN\n' \
  > "$lab/.claude/commands/marker.md"
printf -- '---\ndescription: two phases\n---\nDo both phases in order, one per line:\nPhase 1: reply PHASE_ONE_DONE\nPhase 2: reply PHASE_TWO_DONE\n' \
  > "$lab/.claude/commands/pipeline.md"

# Match only the markers, because a model may wrap them in extra prose.
run() {
  (cd "$lab" && claude -p "$1" --model "$MODEL" < /dev/null 2>/dev/null) \
    | grep -oE 'ARGS=\[[^]]*\]|MARKER_TWO_RAN|PHASE_[A-Z]+_DONE|NO_MEMORY|BANANA42|MELANCIA99' \
    | tr '\n' ' '
}

echo "version: $(claude --version)"
echo "1 two commands one line : $(run '/echoargs /marker')"
echo "2 built-in /clear first : [$(run '/clear /marker')]"
echo "3 one command, 2 phases : $(run '/pipeline')"
echo "4 separated by newline  : $(run '/echoargs
/marker')"
# ---- the memory checks continue below ----

The grep line is there because of something we hit while testing: on one run a model wrapped a marker in an extra sentence of explanation, which made the raw output differ between runs even though the answer was the same. Matching only the markers keeps the four results comparable from run to run.

How do you check the memory behaviour yourself?

The two memory checks continue the same script, and they need a warning the parser checks do not. They create, and then delete, a folder inside your own .claude/projects, because that is where a planted memory has to live for the last check to mean anything. Only the folder matching the temporary directory the script itself created is deleted. Before building that deletion path the script refuses to continue unless the resolved path looks like a deep key and your HOME is set, and it arms the cleanup before creating anything, so an interruption in between cannot leave the planted folder behind.

# ---- memory checks ----
run 'Remember the word BANANA42. Reply only OK.' > /dev/null
echo "5 next run remembers?   : $(run 'Which word did I just tell you? If unknown, reply NO_MEMORY.')"

# Check 5 is not reliable on its own, and check 6 says why: Claude Code can
# keep a FILE memory keyed to the working directory, and that does survive a
# new invocation. We plant one and ask a fresh run to read it.
enc=$(printf '%s' "$(cd "$lab" && pwd -P)" | tr '/.' '--')
# Refuse to build a delete path from a value that is not a deep path key.
# An unreadable $lab makes enc empty, which would point the cleanup at the whole
# projects directory; a shallow value like a single dash would point it at a real
# folder that is not ours. Require at least three separators, and a real HOME.
case "$enc" in
  -*-*-*) : ;;
  *) echo "refusing to continue: could not resolve the lab path"; exit 1 ;;
esac
[ -n "${HOME:-}" ] || { echo "refusing to continue: HOME is not set"; exit 1; }
proj="$HOME/.claude/projects/$enc"
mem="$proj/memory"
# Arm the wider cleanup BEFORE creating anything, so a Ctrl-C in between
# cannot leave the planted folder behind.
trap 'rm -rf "$lab" "$proj"' EXIT
mkdir -p "$mem" || { echo "could not create the memory folder"; exit 1; }
printf -- '---\nname: planted\ndescription: word planted by this check\nmetadata:\n  type: reference\n---\n\nMELANCIA99\n' \
  > "$mem/planted.md"
printf -- '- [MELANCIA99](planted.md) - planted word\n' > "$mem/MEMORY.md"
echo "6 file memory crosses?  : $(run 'What is the planted secret word? If you do not know, reply NO_MEMORY.')"

That refusal is a scar, and it grew in two stages, which is the part worth copying into anything you write that deletes by a computed path. The first draft built the deletion target by expanding a variable without checking it, so an unreadable directory made the variable empty and pointed the cleanup at the entire projects folder. We added a check that the value starts with a separator, then attacked that check and found it still too loose: a single separator would have passed, and a folder with exactly that name exists in a real installation. Requiring a deep key closes both, and each stage was confirmed by forcing the failure and watching the script abort with the projects folder untouched.

What does this measurement not cover?

It covers one version on one machine, and the pieces most likely to age are named so you can recheck them. Everything here was measured on Claude Code 2.1.233 on macOS on August 16, 2026. The npm registry lists twelve Claude Code versions published between August 3 and August 14, 2026, which means the parser behaviour described here is a fact with a short shelf life rather than a permanent property of the tool. If you are reading this months later, run the script yourself: six checks, a couple of minutes, and you get the answer for the version you actually have installed.

Three limits beyond the version. We tested the non interactive mode, claude -p, because it is the mode a script can drive and check; the interactive session may accept input differently, and we did not measure it. We tested with two custom commands and one built-in, not with the full set of built-in commands, so it is possible some built-in behaves in a fourth way we did not see. And on the file memory, we established that it exists, that it survives a new invocation and that the agent sometimes writes it unprompted, but neither writing nor reading it proved fully deterministic in our runs, and we did not map what decides either one.

One more thing worth being straight about, since we sell a tool in this space. CanvasCode, our Mac app that runs the official agent CLIs side by side on one canvas, does not add a slash command queue to Claude Code and cannot, because the parsing happens inside the CLI. What running several agents side by side changes is that phases which do not depend on each other can run at the same time instead of in a line, which is a different problem from the one this article measures.