AnswerQA

How do I pass arguments to my custom slash command?

Answer

Use `$ARGUMENTS` for the whole input, `$0`/`$1`/`$ARGUMENTS[N]` for positional, or named placeholders via the `arguments` frontmatter list. Multi-word values need quotes. Inline `!`shell`` expands before Claude sees the prompt unless you have disabled skill shell execution.

By Kalle Lamminpää Verified May 7, 2026

A skill argument string can be referenced four ways ($ARGUMENTS for the whole, $ARGUMENTS[N] or $N for positional, named placeholders via the arguments frontmatter list); inline !`command` runs in your shell before Claude sees the prompt, except in user/project/plugin/additional-directory skills when disableSkillShellExecution is set.

The four ways to access arguments

Each example below is a complete SKILL.md file you can drop in ~/.claude/skills/<name>/SKILL.md.

$ARGUMENTS is the whole argument string, as typed:

---
description: Fix a GitHub issue with our standards in mind.
---

Fix GitHub issue $ARGUMENTS following our coding standards.

/fix-issue 42 high-priority substitutes 42 high-priority for $ARGUMENTS.

$ARGUMENTS[N] (or shorthand $N) for positional access, 0-based, shell-quoted:

---
description: Migrate a component from one framework to another.
---

Migrate the $0 component from $1 to $2.

/migrate-component SearchBar React Vue substitutes SearchBar, React, and Vue. /migrate-component "search bar" React Vue substitutes search bar (one quoted argument) for $0.

Named arguments declared in frontmatter map to positions in declaration order:

---
description: Fix an issue and switch to its branch.
arguments: [issue, branch]
---

Fix issue $issue on branch $branch.

/fix-and-branch 42 hotfix-auth makes $issue expand to 42 and $branch to hotfix-auth.

argument-hint is purely cosmetic; it shows up during autocomplete:

---
description: Fix an issue and switch to its branch.
argument-hint: "<issue-id> <branch-name>"
arguments: [issue, branch]
---

Fix issue $issue on branch $branch.

What happens when args do not match

The skill body has $ARGUMENTS and the user passed nothing. $ARGUMENTS expands to empty. The body now reads “Fix GitHub issue following our coding standards.”, which Claude usually figures out from context but can also misread as a malformed prompt. Defend the case in the body: “If $ARGUMENTS is empty, ask the user which issue to fix.”

The skill body uses $ARGUMENTS and the user passed extra text. All of it lands in the substitution. A multi-line argument is fine; quoting is irrelevant for the whole-string placeholder.

The skill body has no $ARGUMENTS and the user passed text anyway. Claude Code appends ARGUMENTS: <your input> to the end of the skill content automatically. The argument is not lost; it is just unstructured. Useful when you want a body that mostly hard-codes the prompt and only occasionally takes an override.

The skill body uses $0/$1 and the user passed fewer arguments. Missing positions expand to empty. The same defensive prompt applies: tell Claude what to do with empty placeholders (“if $1 is missing, default to main”).

Inline shell expansion

Backtick-bang (!`command`) runs the command in your shell before the skill body is sent to Claude. The output replaces the literal in the prompt. A complete SKILL.md using inline shell:

---
description: Review the current branch's diff against main.
---

Review the diff below against `main`. Flag SQL safety issues, missing tests, and side effects in conditionals.

## Diff

!`git diff main...HEAD`

The git diff runs locally; Claude sees the diff text inline. That is how skills stay grounded in live state instead of guessing.

Two scopes for shell expansion to be aware of:

  • Per-skill shell choice via the shell frontmatter field (bash default, powershell on Windows when CLAUDE_CODE_USE_POWERSHELL_TOOL=1).
  • Global kill switch via the disableSkillShellExecution: true setting. With that on, every !`command` is replaced with a “shell command execution disabled by policy” placeholder; the skill loads but loses its live data. Managed environments commonly enable this; check /status if a known-working skill suddenly returns generic answers.

Frontmatter that affects argument flow

FieldWhat it does
argument-hintCosmetic autocomplete hint
argumentsDeclare named positional arguments ([issue, branch]$issue, $branch)
shellShell to use for ! blocks (bash default; powershell on Windows)
disable-model-invocationPrevents Claude from triggering the skill automatically; the user must invoke explicitly
allowed-toolsPre-approves tools while the skill is active so Claude does not need to ask

Footguns

Positional access uses shell-style quoting. /my-skill hello world second is three arguments; $0 is hello, $1 is world, $2 is second. To pass "hello world" as a single argument, the user has to quote it: /my-skill "hello world" second. New users assume natural-language input; positional skills need either explicit user discipline or a wrapper that uses $ARGUMENTS and parses inside the skill body.

The $N shorthand is single-digit only. $ARGUMENTS[10] is valid bracket-index syntax for the eleventh argument; $10 is not. Use $ARGUMENTS[N] whenever the index reaches double digits, and stick to $0$9 for the shorthand. Mixing them in one skill body works fine.

Named arguments still use positional binding. arguments: [issue, branch] does not create a flag-style API; the user still passes positional values, and the placeholder names map to positions in declaration order. There is no --issue 42 --branch hotfix shape natively. If you need flag-style, parse $ARGUMENTS yourself in the skill body.

disableSkillShellExecution: true silently kills ! injections in user, project, plugin, and additional-directory skills. Bundled skills and managed skills are exempt and keep running shell expansions. A user-level or project-level skill that was working can suddenly return generic answers because someone (or a security script) set the flag. The skill still loads; the body just lacks the live data the ! block was supposed to fetch. Check /status for the active settings sources before debugging the skill itself.

disable-model-invocation: true removes the description from context too. Normally Claude sees every skill’s description and can auto-invoke based on the user’s prompt. With disable-model-invocation: true, the description is omitted from context, the model cannot suggest the skill, and you have to type /skill-name explicitly. Useful for destructive skills (deploy, push); confusing if you wanted “Claude should know this skill exists but only run it when I ask”.

allowed-tools is pre-approval, not restriction. Listing a tool there means “do not prompt me for this while the skill is active”. It does not mean “deny all other tools”. A skill that tries a tool not in allowed-tools still works; the user just gets a permission prompt for it. If you want to actually restrict the skill’s tool surface, run it inside a subagent (context: fork) with that subagent’s tools list set explicitly.

When NOT to use arguments

  • The prompt does not vary. A skill that always says “review the current diff” does not need arguments. Skip the frontmatter and let the body hard-code the prompt.
  • You want a structured form (flags, types, validation). Slash command arguments are stringly-typed and shell-quoted. Validation belongs in the skill body or in a subagent that the skill calls. For genuinely structured input, build a small CLI tool and call it from a Bash(...) line in the skill.
  • You want different Claude responses based on argument presence. That is conditional logic in the body (“if $ARGUMENTS is empty, …”); it is not free. Test with both empty and full inputs to make sure the prompt holds together.
  • The argument is sensitive. A /deploy "$STRIPE_LIVE_KEY" invocation puts the key into the skill body, which goes into Claude’s context, which is logged. Do not pass secrets as arguments; reference them via env vars in the !shell“ step instead.

Sources

  • Extend Claude with skills
    Authoritative: argument shapes ($ARGUMENTS, $ARGUMENTS[N], $N, named via `arguments` frontmatter), shell-style quoting on positional access, !\`shell\` expansion, `argument-hint`, `disable-model-invocation`, `allowed-tools`, and the `disableSkillShellExecution` setting.
  • Claude Code settings
    Where `disableSkillShellExecution: true` lives. The flag kills `!`shell`` injection in user, project, plugin, and additional-directory skills and custom commands. Bundled and managed skills are exempt and keep running their shell expansions.
  • Permission rules
    Context for `allowed-tools` in skill frontmatter: pre-approves listed tools while the skill is active. Permission rules still apply for tools the skill does not pre-approve.

Was this helpful?