# Best Practices for Implementing Slash Commands in Claude Plugins: A Complete Guide

> Master implementing Claude plugin slash commands. Learn best practices for permissions, descriptions, and tool restrictions using YAML frontmatter for safe, discoverable command execution.

- Repository: [Anthropic/claude-plugins-official](https://github.com/anthropics/claude-plugins-official)
- Tags: best-practices
- Published: 2026-03-13

---

**Slash commands in Claude plugins are Markdown files stored in `commands/` directories that use YAML frontmatter to declare permissions, descriptions, and tool restrictions, making them discoverable via `/help` and safe to execute.**

The `anthropics/claude-plugins-official` repository defines the standard architecture for creating reusable, discoverable functionality in Claude Code. These commands allow developers to package complex workflows into simple `/command-name` invocations that users can execute across personal, project, and plugin contexts.

## Directory Structure and File Locations

Claude auto-discovers slash commands from three specific locations based on scope. According to [`plugins/plugin-dev/skills/plugin-structure/SKILL.md`](https://github.com/anthropics/claude-plugins-official/blob/main/plugins/plugin-dev/skills/plugin-structure/SKILL.md), the system checks these directories for `.md` files:

- **Project-wide commands**: `.claude/commands/` (shared via version control with the entire team)
- **Personal commands**: `~/.claude/commands/` (available across all projects for the current user)
- **Plugin-bundled commands**: `<plugin-name>/commands/` (distributed and installed with a specific plugin)

Use **kebab-case** for file names (e.g., [`review-code.md`](https://github.com/anthropics/claude-plugins-official/blob/main/review-code.md)). The file name becomes the command trigger, so [`review-code.md`](https://github.com/anthropics/claude-plugins-official/blob/main/review-code.md) automatically registers as `/review-code` in the slash command picker. No additional registration or configuration files are required—simply placing the Markdown file in the correct directory enables the command.

## YAML Frontmatter Configuration

Every production command should include a minimal but complete YAML frontmatter block. As documented in [`plugins/plugin-dev/skills/command-development/SKILL.md`](https://github.com/anthropics/claude-plugins-official/blob/main/plugins/plugin-dev/skills/command-development/SKILL.md), the frontmatter controls discoverability, permissions, and execution behavior.

### Essential Fields

The `description` field appears in `/help` output and must stay under 60 characters for optimal display. This text determines whether users can discover your command when searching available tools.

The `allowed-tools` field implements a **whitelist approach** to security. Enumerate only the specific tools your command requires, such as `Read`, `Glob`, or `Bash(git:*)`. This restriction reduces permission prompts and prevents accidental tool abuse by limiting Claude's access during command execution.

### Optional Control Fields

Use `argument-hint` to document expected input format (e.g., `<commit-message>`). This hint displays in the UI when users invoke the command.

Set `model` only when a specific model is required (e.g., `haiku` for fast, low-cost operations). Otherwise, omit this field to inherit the conversation's active model.

For dangerous operations like destructive Bash scripts, set `disable-model-invocation: true`. This flag prevents Claude from running the command automatically during autonomous execution, requiring explicit manual confirmation.

## Security and Permission Management

Security implementation in slash commands centers on **tool-level argument filtering** and input sanitization. The [`plugins/security-guidance/hooks/security_reminder_hook.py`](https://github.com/anthropics/claude-plugins-official/blob/main/plugins/security-guidance/hooks/security_reminder_hook.py) enforces runtime checks that prevent command injection attacks.

Never interpolate untrusted user input directly into shell commands. Instead, use the tool-level filtering syntax to restrict Bash operations to specific command patterns. For example, `Bash(git:add*,git:commit*,git:status*)` limits execution to only git subcommands matching those prefixes.

Keep command bodies pure instructions for Claude. Avoid user-facing prose or conversational text in the command body—this content executes as instructions to the AI, not as documentation for the user.

## Dynamic Arguments and User Input

Commands accept dynamic input through the `$ARGUMENTS` variable. When a user types `/command-name some input here`, the string "some input here" replaces `$ARGUMENTS` in the command template.

For structured argument parsing, use `$ARGUMENT_1`, `$ARGUMENT_2`, etc., to capture positional parameters individually. Document the expected argument format in the `argument-hint` frontmatter field so users understand the required input structure when invoking the command.

## Testing and Validation Strategies

Before distributing a command, validate it using the testing strategies outlined in [`plugins/plugin-dev/skills/command-development/references/testing-strategies.md`](https://github.com/anthropics/claude-plugins-official/blob/main/plugins/plugin-dev/skills/command-development/references/testing-strategies.md). Create a local copy in `.claude/commands/` and verify:

1. The command appears in `/help` with the correct description
2. The command executes without permission errors (verify `allowed-tools` coverage)
3. Argument passing works correctly with various input types
4. The command completes the intended workflow without side effects

When updating a bundled command, increment the plugin version in [`plugin.json`](https://github.com/anthropics/claude-plugins-official/blob/main/plugin.json) as specified in `plugins/plugin-dev/skills/plugin-structure/SKILL.md#plugin-manifest-pluginjson`. Consider adding a custom `version` field to the command frontmatter for internal tracking.

## Implementation Examples

### Minimal Project Command

For simple commands requiring no special permissions, create a basic Markdown file without frontmatter:

```markdown

# Review Security

Review this code for security vulnerabilities, including:
- SQL injection
- XSS
- Authentication bypass

```

Save this as [`.claude/commands/review-security.md`](https://github.com/anthropics/claude-plugins-official/blob/main/.claude/commands/review-security.md). It appears immediately as `/review-security` in the command picker.

### Production Command with Full Frontmatter

A complete example from [`plugins/commit-commands/commands/commit.md`](https://github.com/anthropics/claude-plugins-official/blob/main/plugins/commit-commands/commands/commit.md) demonstrates proper security scoping:

```markdown
---
description: Run a git commit for staged changes
allowed-tools: Bash(git:add*,git:commit*,git:status*)
argument-hint: <commit-message>
disable-model-invocation: true
---

# Git Commit Helper

Create a concise commit message using the provided argument.

`$ARGUMENTS` will be used as the commit message.

1. Stage all changes: `git add .`
2. Commit with message: `git commit -m "$ARGUMENTS"`
3. Show the new commit hash.

```

### Plugin-Bundled Distribution Command

For commands distributed as part of a plugin package:

```markdown
---
description: Deploy the current project to staging
allowed-tools: Bash(./scripts/deploy.sh)
---

# Deploy to Staging

Run the project's deployment script.

```

./scripts/deploy.sh staging

```

```

Store this in [`my-deployer-plugin/commands/deploy-staging.md`](https://github.com/anthropics/claude-plugins-official/blob/main/my-deployer-plugin/commands/deploy-staging.md). When users install your plugin via Claude's plugin manager, this command becomes available in their workspace.

### Safe Bash Invocation Pattern

Restrict Bash access to specific command families using the colon-separated syntax:

```markdown
---
description: Show git status for the current repo
allowed-tools: Bash(git:status)
---

# Git Status

Run:

```

git status

```

```

This pattern prevents the command from executing arbitrary shell commands while permitting specific git operations.

## Summary

- **Location matters**: Place commands in `.claude/commands/`, `~/.claude/commands/`, or `<plugin>/commands/` based on sharing scope
- **Name correctly**: Use kebab-case file names that become the command trigger (e.g., [`my-command.md`](https://github.com/anthropics/claude-plugins-official/blob/main/my-command.md) → `/my-command`)
- **Frontmatter is mandatory for production**: Include `description` (under 60 characters) and `allowed-tools` whitelist for security
- **Restrict Bash access**: Use `Bash(command:subcommand*)` patterns instead of open `Bash` permissions
- **Handle arguments safely**: Use `$ARGUMENTS` for input, never interpolate directly into shell strings
- **Test locally**: Verify in `.claude/commands/` before distribution, checking `/help` visibility and execution flow
- **Document usage**: Include a "Usage" section in the command body explaining arguments and side effects

## Frequently Asked Questions

### Where should I store slash commands for a team project?

Store project-specific commands in the `.claude/commands/` directory at your repository root. Commit these files to version control so the entire team shares the same command definitions. According to [`plugins/plugin-dev/skills/plugin-structure/SKILL.md`](https://github.com/anthropics/claude-plugins-official/blob/main/plugins/plugin-dev/skills/plugin-structure/SKILL.md), Claude automatically discovers all `.md` files in this directory when loading the project context.

### How do I prevent a slash command from running dangerous operations automatically?

Add `disable-model-invocation: true` to the command's YAML frontmatter. This flag forces manual execution and prevents Claude from invoking the command during autonomous workflows. Additionally, restrict the `allowed-tools` field to specific safe patterns like `Bash(git:status)` rather than open `Bash` access.

### What is the difference between `$ARGUMENTS` and `$ARGUMENT_1`?

`$ARGUMENTS` captures the entire raw argument string provided after the command name. Use `$ARGUMENT_1`, `$ARGUMENT_2`, etc., to capture specific positional arguments when users provide space-separated inputs. The `argument-hint` frontmatter field should document which format your command expects.

### Can I specify which AI model runs my slash command?

Yes. Add the `model` field to your frontmatter (e.g., `model: haiku`) to force a specific model for that command. Omit this field to inherit the model from the current conversation context. According to the command development guidelines, only specify a model when the command requires specific performance characteristics like faster response times or lower costs.