How to Make Custom Slash Commands in Claude Code: A Complete Guide to the Skills Architecture

Custom slash commands in Claude Code are implemented as Skills—directories containing a SKILL.md file with YAML front-matter and instructions—stored in .claude/skills/<name>/ and invoked by typing /<command-name>.

Claude Code supports custom slash commands through a unified Skills architecture that replaced the legacy .claude/commands/ directory system. According to the luongnv89/claude-howto repository, these user-defined Skills allow you to package scripts, templates, and reusable instructions into directory-based modules that Claude can invoke automatically or on demand. This guide covers how to create, configure, and migrate custom slash commands using the modern Skills system.

Understanding the Skills Architecture

Claude Code resolves slash commands through a hierarchical search order defined in 01-slash-commands/README.md. When you type /command-name, the system checks:

  1. Built-in commands — Native functionality implemented in Claude Code.
  2. Skills — Looks for .claude/skills/<name>/SKILL.md.
  3. Legacy commands — Falls back to .claude/commands/<name>.md for backward compatibility.
  4. Plugins and MCP prompts — Loads external extensions.

The Skills architecture offers significant advantages over the legacy system. Because Skills are directory-based, you can bundle auxiliary files—such as scripts, templates, or reference documentation—alongside the main SKILL.md file. Skills also support auto-invocation, where Claude automatically calls a Skill when its description matches the current context, and isolated execution through sub-agents.

Creating Your First Custom Skill

To create a custom slash command, create a directory under .claude/skills/ and add a SKILL.md file with YAML front-matter followed by plain-text instructions.


# Create the skill directory structure

mkdir -p .claude/skills/hello-world

# Create the SKILL.md file

cat > .claude/skills/hello-world/SKILL.md <<'EOF'
---
name: hello-world
description: Say hello to the user
---

# Hello World

When invoked, simply respond with:

Hello, Claude Code user! 👋


EOF

Invoke the command by typing /hello-world in the Claude Code interface. The name field in the front-matter determines the command trigger, while the description helps Claude decide when to suggest the Skill during auto-invocation scenarios.

Configuring Skill Behavior with Front-Matter

The SKILL.md front-matter controls execution permissions, argument handling, and runtime environment. According to the reference table in 01-slash-commands/README.md, these fields configure custom slash commands:

Field Purpose Default
name Command trigger that becomes /<name> Directory name
description Human-readable hint for auto-invocation First paragraph of content
argument-hint Template shown during auto-completion None
allowed-tools Tool whitelist (e.g., Bash(git *)) Inherits global permissions
model Explicit model override Inherits session model
disable-model-invocation When true, only users can run the command false
user-invocable Hide from the / menu when false true
context Set to fork to execute in an isolated sub-agent None
agent Agent type used when context: fork general-purpose

Configure these fields at the top of your SKILL.md file between triple dashes:

---
name: review-pr
description: Review a pull request with specified priority
argument-hint: "<pr-number> <priority-level>"
allowed-tools: Bash(gh *), Read()
---

Handling Arguments and Dynamic Context

Skills consume arguments through placeholder variables. Use positional arguments ($0, $1, $2) to capture specific tokens, or $ARGUMENTS to receive the entire argument string as a single value.

---
name: assign-issue
description: Assign a GitHub issue to a user
argument-hint: "<issue-id> <github-username>"
allowed-tools: Bash(gh *)
---
Assign issue #$0 to @$1 using the GitHub CLI:

!`gh issue edit $0 --assignee $1`

When invoked as /assign-issue 1234 alice, $0 resolves to "1234" and $1 resolves to "alice".

For dynamic context, embed shell command outputs directly into the prompt using the back-tick syntax: !`command`. Claude injects the command result before processing the Skill.

---
name: commit
allowed-tools: Bash(git *)
---

## Context

- Current git status: !`git status`
- Current branch:   !`git branch --show-current`

## Your task

Create a single commit based on the above changes.

You can also reference repository files with the @ prefix (e.g., Review the implementation in @src/utils/helpers.js).

Isolated Execution and Security Controls

To prevent a custom command from modifying your main session's state, set context: fork in the front-matter. This executes the Skill in a separate sub-agent with its own file system view.

---
name: run-tests
description: Execute the test suite in a fresh environment
context: fork
agent: general-purpose
allowed-tools: Bash(npm test)
---
Run the project's test suite and report any failures:

!`npm test --silent`

Use allowed-tools to restrict which tools the Skill can access—such as Bash(git *) to permit only Git commands—or set disable-model-invocation: true to ensure only human users (not Claude itself) can trigger the command.

Migrating from Legacy Commands

If you have existing custom commands in .claude/commands/<name>.md, migrate them to the Skills architecture by moving the file to a directory-based structure.

Migration steps from 01-slash-commands/README.md:


# Create the new skill directory

mkdir -p .claude/skills/optimize

# Copy the legacy command file

cp .claude/commands/optimize.md .claude/skills/optimize/SKILL.md

After migration, /optimize resolves to the Skill version. If both locations exist, the Skills version takes precedence in the search order.

Summary

  • Custom slash commands in Claude Code are created as Skills in .claude/skills/<name>/SKILL.md.
  • Front-matter fields like name, description, allowed-tools, and context control execution behavior and permissions.
  • Arguments are passed via $0, $1, or $ARGUMENTS placeholders, while dynamic context uses !`command` syntax.
  • Isolated execution is achieved with context: fork, running the Skill in a separate sub-agent.
  • Legacy commands from .claude/commands/ should be migrated to the Skills architecture for full feature support.

Frequently Asked Questions

Where should I store custom slash commands in Claude Code?

Store custom slash commands in .claude/skills/<command-name>/SKILL.md. This directory-based structure replaces the legacy .claude/commands/<name>.md format and supports bundling additional files, isolated execution, and advanced front-matter configuration.

What is the difference between Skills and legacy commands?

Skills are directory-based packages that support front-matter metadata, auto-invocation, isolated sub-agents via context: fork, and bundled resources. Legacy commands are single Markdown files in .claude/commands/ that lack these advanced features but remain supported for backward compatibility.

How do I pass arguments to a custom slash command?

Use positional placeholders like $0 and $1 in your SKILL.md content, or $ARGUMENTS to capture the entire input string. Define the expected format in the argument-hint front-matter field to provide auto-completion guidance when users type the command.

Can I restrict which tools a custom command can access?

Yes. Set the allowed-tools front-matter field to a comma-separated list of permitted tools, such as Bash(git *), Read() to allow only Git operations and file reading. This creates a sandboxed execution environment for the specific slash command.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →