Home AI/ML Mastering Custom Commands in Claude Code: The Definitive Guide to Automating Your Development Workflow

Mastering Custom Commands in Claude Code: The Definitive Guide to Automating Your Development Workflow

A developer at a mid-sized startup recently told me something that stopped me in my tracks: “I used to spend 45 minutes every morning setting up my development environment, running tests, reviewing PRs, and scaffolding new features. Now I do all of it in under 5 minutes.” The secret? Not a fancy DevOps pipeline. Not a new CI/CD tool. Just seven carefully crafted custom commands in Claude Code, Anthropic’s AI-powered CLI for software development.

If you have been using Claude Code for a while, you probably know it can write code, debug issues, and answer questions about your codebase. But there is a feature hiding in plain sight that transforms Claude Code from a helpful assistant into a fully automated development partner: custom commands. These are simple Markdown files that turn complex, multi-step workflows into one-line slash commands you can invoke anytime.

Think of custom commands as macros on steroids. Instead of recording keystrokes, you are writing natural-language instructions that Claude Code follows with full access to your codebase, your terminal, and your tools. Want a single command that reviews your code for security vulnerabilities, checks for style violations, and generates a summary? Done. Want a command that scaffolds an entire API endpoint with route, handler, validation, and tests? You can build that in five minutes.

Yet despite their power, most developers barely scratch the surface. They might create one or two simple commands, but they miss the advanced patterns that make custom commands truly transformative: argument handling, conditional logic, multi-step workflows with checkpoints, and integration with project-level configuration. This guide changes that. By the time you finish reading, you will have everything you need to build a comprehensive command library that automates the most tedious parts of your development workflow — and you will have 10 complete, copy-paste-ready command files to start with.

What Are Custom Commands?

At their core, custom commands in Claude Code are Markdown files that live in a specific directory structure. When you type / in Claude Code, it scans these directories and presents every available command as a selectable option. When you invoke one, Claude Code reads the Markdown content and treats it as its instruction set — essentially, you are giving Claude a detailed prompt for a specific task, and it executes it with full context of your project.

Two Types of Commands

Claude Code recognizes commands in two locations, and understanding the difference is crucial for team workflows:

Project commands live in your project’s .claude/commands/ directory. Because they sit inside your repository, they get committed to version control and shared with every team member. When a colleague clones your repo and opens Claude Code, they automatically see and can use every project command. This makes them perfect for team-wide workflows like deployment, code review, and feature scaffolding.

User commands live in ~/.claude/commands/ — your home directory. These are personal to you and never shared via git. They are ideal for productivity shortcuts, personal preferences, and workflows that only make sense for your specific setup. Maybe you have a command that formats output in a way you prefer, or one that interacts with internal tools only you use.

Key Takeaway: Project commands (.claude/commands/) are shared with your team via git. User commands (~/.claude/commands/) are personal and stay on your machine. Use project commands for team workflows and user commands for personal productivity.

How Claude Code Discovers Commands

When you launch Claude Code in a project directory, it performs a straightforward discovery process. First, it checks for .claude/commands/ relative to the project root. Then it checks ~/.claude/commands/ in your home directory. Every .md file found in these directories becomes an available command, with the filename (minus the extension) becoming the command name. So .claude/commands/deploy.md becomes /deploy, and .claude/commands/write-post.md becomes /write-post.

This discovery happens automatically — there is no registration step, no configuration file to update, no CLI flag to set. Drop a Markdown file into the right directory and the command is instantly available. Remove it and the command disappears. This simplicity is what makes the system so powerful: the barrier to creating a new command is essentially zero.

Anatomy of a Command File

A command file is just a Markdown document, but its structure matters. Let us break down every element, starting with the basics and building up to more complex patterns.

File Naming Conventions

Command files follow a simple naming scheme:

  • Use kebab-case for filenames: write-post.md, review-code.md, create-component.md
  • Always use the .md extension
  • The filename becomes the command name: deploy.md/deploy
  • Keep names short and descriptive — you will be typing these frequently

The Markdown Structure

The content of your command file is the prompt that Claude Code receives when the command is invoked. Everything you write in this file becomes Claude’s instructions. This means you should write it as if you are giving a detailed briefing to a very capable developer who has never seen your project before.

Here is the simplest possible command file to illustrate the concept:

# File: .claude/commands/greet.md

Say hello to the user and tell them the current date and time.
List the top 3 most recently modified files in the project.

When you type /greet in Claude Code, it reads this file and follows the instructions. Simple as that. But real-world commands need much more structure. Let us look at a properly organized command.

The $ARGUMENTS Placeholder

One of the most powerful features of custom commands is the $ARGUMENTS placeholder. When you invoke a command with additional text — like /deploy staging or /write-tests src/utils/parser.py — everything after the command name gets substituted into the $ARGUMENTS placeholder in your Markdown file.

# File: .claude/commands/explain.md

Read the file or function specified by the user: $ARGUMENTS

Provide a detailed explanation that includes:
1. What the code does at a high level
2. Key algorithms or patterns used
3. Any potential issues or improvements
4. How it fits into the broader codebase

Now when you type /explain src/auth/middleware.py, Claude Code receives the full instructions with $ARGUMENTS replaced by src/auth/middleware.py. This single mechanism enables incredibly flexible commands that adapt to whatever input you provide.

A Full Command File Example

Here is a well-structured command that demonstrates all the key elements working together:

# File: .claude/commands/add-feature.md

You are a senior developer working on this project. Add a new feature
based on the following description: $ARGUMENTS

## Step 1: Understand the Request
- Parse the feature description from $ARGUMENTS
- Identify which parts of the codebase will be affected
- List the files you plan to modify or create

## Step 2: Plan the Implementation
- Outline the changes needed
- Identify any dependencies or prerequisites
- Check for existing patterns in the codebase to follow

## Step 3: Implement the Feature
- Write clean, well-documented code
- Follow existing code style and conventions in the project
- Add appropriate error handling

## Step 4: Write Tests
- Create unit tests for the new feature
- Ensure existing tests still pass by running: `npm test`

## Step 5: Summary
- List all files created or modified
- Describe the changes made
- Note any follow-up tasks or considerations

## Constraints
- Do NOT modify any configuration files without asking first
- Do NOT install new dependencies without listing them and explaining why
- Follow the project's existing code style exactly
- If $ARGUMENTS is empty, ask the user what feature they want to add

Notice several important patterns here: numbered steps give Claude a clear execution order, constraints set boundaries on what it should and should not do, and the command handles the edge case where no arguments are provided. This level of detail is what separates a good command from a great one.

Tip: Think of your command file as a detailed brief for a new team member. The more specific you are about what to do, what not to do, and what patterns to follow, the better the results will be.

Best Practices for Writing Effective Commands

After writing dozens of custom commands and watching teams adopt them across different tech stacks, clear patterns have emerged for what makes commands reliable versus flaky. The difference almost always comes down to how precisely you communicate your intent.

Be Specific and Explicit

Claude Code follows instructions literally. If you write “clean up the code,” it will make changes based on its best judgment. If you write “remove unused imports, add type hints to all function signatures, and ensure all functions have docstrings following the Google style guide,” you get exactly that. Specificity is not being pedantic — it is being precise.

Structure with Clear Steps

Numbered lists are your best friend in command files. They create a natural execution order and make it easy for Claude to report progress. Each step should be a discrete, verifiable action. Instead of “set up the project,” break it into: (1) create the directory structure, (2) initialize the package manager, (3) install dependencies, (4) create the configuration file.

Include Constraints and Guardrails

This might be the single most important practice. Always tell Claude what not to do. Without constraints, Claude will make reasonable but potentially unwanted decisions. Add explicit guardrails like “do NOT modify the database schema,” “always create a backup before overwriting,” or “never commit directly to main.”

Specify Output Format

If you want the result in a specific format — a JSON file, a Markdown report, a formatted table in the terminal — say so explicitly. Commands that end with “report what you did” tend to produce inconsistent output. Commands that end with “create a summary in the following format: [template]” produce consistent, useful results every time.

Include Error Handling Instructions

What should Claude do if a test fails? If a file does not exist? If a build breaks? Without error handling instructions, Claude will either stop and ask (slowing you down) or make a guess (potentially the wrong one). Include explicit error handling: “If the tests fail, analyze the failure, fix the issue, and re-run the tests. If they fail a second time, stop and report the errors.”

Reference Specific Files and Paths

When a command needs to work with specific parts of your codebase, reference them explicitly. Instead of “check the config file,” write “read config/settings.py and extract the database URL.” This eliminates ambiguity and ensures the command works reliably even as your project evolves.

Use Conditional Logic

Real workflows branch based on conditions. Your commands should too: “If $ARGUMENTS contains ‘staging’, deploy to the staging server. If it contains ‘production’, deploy to production with additional safety checks. If no argument is provided, default to staging.”

Keep Commands Focused

A command that tries to do everything ends up doing nothing well. Follow the single responsibility principle: one command, one job. If you have a complex workflow, break it into multiple commands that can be run in sequence. A /build command, a /test command, and a /deploy command are better than one monolithic /do-everything command.

Good vs Bad Command Patterns

Pattern Bad Example Good Example
Instructions “Fix the bugs” “Run the test suite, identify failing tests, analyze each failure, and apply minimal fixes”
File references “Update the config” “Update config/database.yml and .env.example
Error handling (none) “If tests fail, fix and re-run. After 2 failures, stop and report.”
Output format “Tell me what changed” “List changed files as a Markdown checklist with one-line descriptions”
Constraints (none) “Do NOT modify files outside src/. Do NOT add dependencies.”
Scope One giant command for build + test + deploy + notify Separate /build, /test, /deploy, and /notify commands

 

Practical Command Examples (10 Ready-to-Use Commands)

Theory is useful, but you came here for commands you can actually use. Here are 10 complete, battle-tested command files covering the most common development workflows. Each one is ready to copy into your .claude/commands/ directory and start using immediately.

The /write-post Command — Blog Publishing Workflow

This is the command that powers the very blog you are reading right now. It orchestrates the entire workflow of selecting a topic, writing a full blog post, and publishing it to WordPress — all from a single slash command.

# File: .claude/commands/write-post.md

You are a professional tech and investment blog writer.
Write and publish a blog post using the following workflow:

## Step 1: Topic Selection
- If the user provides a topic in $ARGUMENTS, use that topic.
- Otherwise, run `uv run python -m src.main select-topic` to pick
  a random topic from the configured pool.
- Show the selected topic and its category to the user.

## Step 2: Write the Blog Post
Write a high-quality, engaging blog post as clean WordPress-ready HTML5.

**Writing Style:**
- Open with a powerful hook: a surprising fact, bold question, or
  real incident
- Conversational yet professional tone
- Target: 4,000-6,000 words minimum
- Structure: Table of Contents → Introduction → 3-5 body sections
  → Conclusion → References
- No <h1> tags, no <html>/<head>/<body> wrappers

## Step 3: Save and Publish
1. Save the HTML content to `posts/{slug}.html`
2. Run the publish command:
   ```
   uv run python -m src.main publish \
     --title "<title>" --slug "<slug>" \
     --category "<category>" \
     --content-file posts/{slug}.html \
     --status publish
   ```
3. Run `uv run python -m src.main record-usage "<topic>"`
4. Report the published post URL to the user.

## Constraints
- Do NOT use external LLM APIs — you are the writer
- For investment posts, include a disclaimer
- No numbered section headings

The /review-code Command — Comprehensive Code Review

# File: .claude/commands/review-code.md

Perform a thorough code review on the following: $ARGUMENTS

If $ARGUMENTS is a file path, review that specific file.
If $ARGUMENTS is a directory, review all source files in it.
If $ARGUMENTS is empty, review all staged changes (git diff --cached).

## Review Checklist

### Security
- [ ] No hardcoded secrets, API keys, or passwords
- [ ] Input validation on all user-facing inputs
- [ ] SQL injection / XSS vulnerabilities
- [ ] Proper authentication and authorization checks

### Code Quality
- [ ] Functions are under 50 lines (flag any that exceed this)
- [ ] No code duplication (DRY principle)
- [ ] Clear variable and function names
- [ ] Proper error handling (no bare except/catch blocks)

### Performance
- [ ] No N+1 query patterns
- [ ] Efficient data structures used
- [ ] No unnecessary loops or redundant computations
- [ ] Large datasets handled with pagination or streaming

### Testing
- [ ] New code has corresponding tests
- [ ] Edge cases are covered
- [ ] Test names clearly describe what they test

## Output Format
For each issue found, report:
1. **File and line number**
2. **Severity**: Critical / Warning / Suggestion
3. **Category**: Security / Quality / Performance / Testing
4. **Description**: What the issue is
5. **Fix**: Suggested code change

End with a summary table:
| Severity | Count |
|----------|-------|
| Critical | X     |
| Warning  | X     |
| Suggestion | X   |

## Constraints
- Do NOT modify any files — this is a review only
- If no issues are found, say so explicitly
- Be constructive, not just critical

The /create-component Command — Frontend Component Scaffolding

# File: .claude/commands/create-component.md

Create a new React component based on: $ARGUMENTS

## Step 1: Parse the Request
- Component name from $ARGUMENTS (e.g., "UserProfile" or "DataTable")
- If $ARGUMENTS includes additional description, use it for the
  component's functionality

## Step 2: Check Project Conventions
- Read the project's existing components to match the style
- Detect whether the project uses TypeScript or JavaScript
- Detect the CSS approach (CSS modules, Tailwind, styled-components)
- Check if the project uses a testing library (Jest, Vitest, etc.)

## Step 3: Create the Component
Create the following files:

1. **Component file**: `src/components/{ComponentName}/{ComponentName}.tsx`
   - Use functional component with hooks
   - Include proper TypeScript interfaces for props
   - Add JSDoc comments

2. **Test file**: `src/components/{ComponentName}/{ComponentName}.test.tsx`
   - Test rendering without errors
   - Test prop variations
   - Test user interactions if applicable

3. **Styles file**: `src/components/{ComponentName}/{ComponentName}.module.css`
   (or appropriate format for the project)

4. **Index file**: `src/components/{ComponentName}/index.ts`
   - Re-export the component as default and named export

## Step 4: Integration
- Add the component to any barrel export files if they exist
- Show a usage example in the terminal

## Constraints
- Match the EXACT coding style of existing components
- Do NOT install new packages
- If the component directory pattern differs in the project, follow
  the existing pattern instead

The /deploy Command — Deployment Workflow

# File: .claude/commands/deploy.md

Deploy the application to the specified environment: $ARGUMENTS

## Environment Detection
- If $ARGUMENTS is "staging" or "stage": deploy to staging
- If $ARGUMENTS is "production" or "prod": deploy to production
- If $ARGUMENTS is empty: default to staging

## Pre-Deployment Checks (ALL must pass)
1. Run `git status` — working directory must be clean
2. Run the full test suite — all tests must pass
3. Run the linter — no errors allowed (warnings are OK)
4. Verify the current branch:
   - Staging: any branch is fine
   - Production: must be on `main` or `master`

If ANY check fails, stop immediately and report the failure.
Do NOT proceed to deployment.

## Deployment Steps

### For Staging
1. Build the project: `npm run build` (or project equivalent)
2. Deploy: `npm run deploy:staging`
3. Run smoke tests: `npm run test:smoke -- --env=staging`
4. Report the staging URL

### For Production
1. Confirm with the user: "You are about to deploy to PRODUCTION.
   Continue? (y/n)"
2. Build: `npm run build`
3. Create a git tag: `git tag -a v{date} -m "Production deploy"`
4. Deploy: `npm run deploy:production`
5. Run smoke tests: `npm run test:smoke -- --env=production`
6. Report the production URL

## Post-Deployment
- Show the deployment summary (environment, commit SHA, timestamp)
- If smoke tests fail, immediately report and suggest rollback steps

## Constraints
- NEVER deploy to production without user confirmation
- NEVER skip the pre-deployment checks
- If this is a production deploy, ensure all staging tests passed first

The /fix-bug Command — Bug Investigation and Fix

# File: .claude/commands/fix-bug.md

Investigate and fix the following bug: $ARGUMENTS

## Step 1: Understand the Bug
- Parse the bug description from $ARGUMENTS
- If a file or line number is referenced, start there
- If an error message is provided, search the codebase for it

## Step 2: Reproduce
- Identify the conditions that trigger the bug
- Check if there is an existing test that should catch this
- If possible, write a failing test that demonstrates the bug

## Step 3: Root Cause Analysis
- Trace the code path that leads to the bug
- Identify the root cause (not just the symptom)
- Check if the same pattern exists elsewhere (similar bugs waiting
  to happen)

## Step 4: Fix
- Apply the minimal change that fixes the root cause
- Do NOT refactor unrelated code — stay focused on the bug
- Ensure the fix handles edge cases

## Step 5: Verify
- Run the failing test — it should now pass
- Run the full test suite — no regressions allowed
- If the fix touches an API, verify the API contract is maintained

## Step 6: Report
Provide a structured report:
- **Bug**: One-line description
- **Root Cause**: What was actually wrong
- **Fix**: What was changed and why
- **Files Modified**: List with brief descriptions
- **Test Coverage**: What tests were added or modified
- **Risk Assessment**: Low/Medium/High — could this fix break
  anything else?

## Constraints
- Do NOT make changes unrelated to the bug
- If the fix requires a database migration, flag it but do NOT run it
- If the bug cannot be fixed without breaking changes, stop and
  report your findings

The /refactor Command — Guided Refactoring

# File: .claude/commands/refactor.md

Refactor the specified code: $ARGUMENTS

If $ARGUMENTS is a file path, refactor that file.
If $ARGUMENTS is a description (e.g., "extract auth logic into
a service"), follow those instructions.

## Step 1: Analyze Current State
- Read the target code thoroughly
- Identify code smells: duplication, long functions, deep nesting,
  unclear naming, tight coupling
- List all functions and classes that will be affected
- Check test coverage for the target code

## Step 2: Plan the Refactoring
Present a plan BEFORE making any changes:
- What patterns will you apply (Extract Method, Move to Module, etc.)
- Which files will be created, modified, or deleted
- What is the expected impact on the public API
- Wait for user approval before proceeding

## Step 3: Execute (only after approval)
- Apply changes incrementally — one refactoring pattern at a time
- After each change, run tests to catch regressions early
- Preserve all existing behavior — this is a refactor, not a rewrite

## Step 4: Update Tests
- Adjust test imports and references as needed
- Add tests for any newly extracted functions or modules
- Run the full test suite and confirm everything passes

## Step 5: Summary
- List the refactoring patterns applied
- Show before/after metrics (function count, average length, etc.)
- Note any follow-up refactoring opportunities

## Constraints
- Do NOT change external behavior or public API
- Do NOT combine refactoring with feature changes
- Run tests after EVERY significant change
- If tests fail at any point, revert the last change and report

The /write-tests Command — Test Generation

# File: .claude/commands/write-tests.md

Write comprehensive tests for: $ARGUMENTS

$ARGUMENTS can be a file path, a function name, or a module name.

## Step 1: Analyze the Target
- Read the source code for $ARGUMENTS
- Identify all public functions, methods, and classes
- Map out the logic branches (if/else, try/catch, loops)
- Identify external dependencies that need mocking

## Step 2: Determine Testing Approach
- Detect the project's testing framework (pytest, jest, vitest, etc.)
- Match the existing test file naming convention
- Match the existing test style (describe/it, test(), class-based)

## Step 3: Write Tests
For each public function or method, write tests covering:

1. **Happy path**: Normal inputs producing expected outputs
2. **Edge cases**: Empty inputs, None/null, boundary values
3. **Error cases**: Invalid inputs, exceptions, error states
4. **Integration points**: Interactions with dependencies (mocked)

Test naming convention: `test_{function_name}_{scenario}_{expected_result}`
(or the project's existing convention if different)

## Step 4: Verify
- Run the new tests: they should all pass
- Run the full test suite: no regressions
- Check coverage if a coverage tool is configured

## Output
- Created test file path
- Number of test cases written
- Coverage summary (if available)

## Constraints
- Do NOT modify the source code being tested
- Mock external dependencies (database, APIs, file system)
- Each test must be independent — no shared mutable state
- Do NOT test private/internal functions unless critical

The /db-migration Command — Database Migration Workflow

# File: .claude/commands/db-migration.md

Create a database migration for: $ARGUMENTS

## Step 1: Understand the Change
- Parse the migration description from $ARGUMENTS
- Examples: "add email_verified column to users table",
  "create orders table with foreign key to users"

## Step 2: Detect the ORM and Migration Tool
- Check for: Alembic (Python), Prisma (Node), TypeORM, Knex,
  Django migrations, Rails ActiveRecord, or raw SQL
- Read existing migrations to understand the naming convention
  and style

## Step 3: Generate the Migration
Using the detected tool:

**For Alembic (Python/SQLAlchemy):**
```
alembic revision --autogenerate -m "$ARGUMENTS"
```
Then review and adjust the generated migration.

**For Prisma:**
Update `prisma/schema.prisma`, then run:
```
npx prisma migrate dev --name {migration_name}
```

**For Django:**
Update the model, then run:
```
python manage.py makemigrations --name {migration_name}
```

**For raw SQL:**
Create up and down migration files in the migrations directory.

## Step 4: Review the Migration
- Verify the UP migration does what was requested
- Verify the DOWN migration correctly reverses the change
- Check for:
  - Missing indexes on foreign keys
  - Missing NOT NULL constraints where appropriate
  - Missing default values
  - Data loss risks in column type changes

## Step 5: Test
- Run the migration UP
- Verify the schema change
- Run the migration DOWN
- Verify the schema is restored

## Constraints
- NEVER run migrations against production — local/dev only
- Always create both UP and DOWN migrations
- Flag any migration that could cause data loss
- If adding a NOT NULL column to an existing table, include a
  default value or a backfill step

The /api-endpoint Command — API Endpoint Scaffolding

# File: .claude/commands/api-endpoint.md

Create a new API endpoint: $ARGUMENTS

$ARGUMENTS format: "METHOD /path - description"
Examples:
- "POST /api/users - create a new user"
- "GET /api/orders/:id - get order details"
- "PUT /api/settings - update user settings"

## Step 1: Parse the Request
- Extract HTTP method, path, and description from $ARGUMENTS
- Identify path parameters (e.g., :id)
- Determine the resource name (e.g., users, orders, settings)

## Step 2: Detect the Framework
Check for: Express, FastAPI, Django REST, Flask, Gin, Fiber, etc.
Read existing routes to match the project's patterns.

## Step 3: Create the Endpoint

### Route/Handler file
- Add the route to the appropriate router file
- Create the handler function with:
  - Request validation (parse and validate input)
  - Business logic (or call to service layer)
  - Response formatting
  - Error handling with appropriate HTTP status codes

### Validation/Schema
- Create request body schema (for POST/PUT)
- Create response schema
- Add validation rules (required fields, types, formats)

### Service Layer (if the project uses one)
- Create or update the service with the business logic
- Keep the handler thin — it should only handle HTTP concerns

### Tests
Create tests for:
- Successful request (200/201)
- Validation error (400)
- Not found (404) — for endpoints with path params
- Unauthorized (401) — if auth is required
- Server error handling (500)

## Step 4: Update Documentation
- If the project has an OpenAPI/Swagger spec, update it
- If the project has API docs, add the new endpoint

## Step 5: Verify
- Start the dev server (if not running)
- Run the new tests
- Show a curl example for testing the endpoint manually

## Constraints
- Follow existing patterns EXACTLY — consistency is critical
- Include proper authentication middleware if other endpoints use it
- Use the project's error handling patterns
- Do NOT add new dependencies

The /changelog Command — Changelog Generation

# File: .claude/commands/changelog.md

Generate a changelog based on recent git history.

## Parameters
- If $ARGUMENTS contains a version tag (e.g., "v1.2.0"), generate
  the changelog since that tag
- If $ARGUMENTS contains "last-release", find the most recent tag
  and generate since then
- If $ARGUMENTS is empty, generate for the last 50 commits

## Step 1: Gather Commits
Run: `git log --oneline --no-merges {range}`
Read all commit messages in the specified range.

## Step 2: Categorize Changes
Group commits into these categories:
- **New Features**: commits mentioning "add", "feat", "new",
  "implement", "introduce"
- **Bug Fixes**: commits mentioning "fix", "bug", "resolve",
  "patch", "correct"
- **Performance**: commits mentioning "perf", "optimize", "speed",
  "cache"
- **Breaking Changes**: commits mentioning "breaking", "remove",
  "deprecate", "migrate"
- **Documentation**: commits mentioning "doc", "readme", "guide"
- **Other**: everything else

## Step 3: Generate the Changelog
Format as Markdown:

```
## [Version] - YYYY-MM-DD

### New Features
- Description of feature (commit hash)

### Bug Fixes
- Description of fix (commit hash)

### Performance
- Description of improvement (commit hash)

### Breaking Changes
- Description of breaking change (commit hash)

### Other
- Description (commit hash)
```

## Step 4: Save
- Save to `CHANGELOG.md` (append to top, keep existing content)
- Show the generated changelog in the terminal

## Constraints
- Do NOT modify commit history
- If a commit message is unclear, include it under "Other" with
  the full message
- Skip merge commits
- Include commit short hashes for reference
Tip: All 10 commands above are ready to use. Copy any of them into your .claude/commands/ directory, adjust the project-specific details (test commands, directory paths, framework references), and start using them immediately.

Advanced Techniques

Once you have mastered the basics of writing custom commands, several advanced patterns unlock even more powerful workflows. These techniques are what separate simple automation from sophisticated development orchestration.

Chaining Commands

While Claude Code does not have a built-in command chaining mechanism, you can achieve the same effect by writing a command that instructs Claude to execute the same steps that other commands would. Think of it as inlining multiple commands into one master workflow.

# File: .claude/commands/ship-it.md

Execute the full ship-it workflow for: $ARGUMENTS

## Step 1: Code Review
Perform a thorough code review on all staged changes.
Check for security issues, code quality, and performance.
If any CRITICAL issues are found, stop and report them.

## Step 2: Write Tests
For any new or modified functions that lack test coverage,
write comprehensive tests following the project's conventions.
Run all tests and ensure they pass.

## Step 3: Generate Changelog
Categorize the changes being shipped and prepare a changelog entry.

## Step 4: Deploy
If all checks pass, deploy to staging.
Run smoke tests against staging.
Report the final status.

## If any step fails, stop immediately and report what went wrong.

Using Environment Context

Commands can instruct Claude to read environment files, configuration, and project metadata to make dynamic decisions. This makes the same command behave differently across different projects or environments.

# File: .claude/commands/setup-env.md

Set up the development environment for this project.

## Step 1: Detect the Project Type
- Check for `package.json` → Node.js project
- Check for `pyproject.toml` or `requirements.txt` → Python project
- Check for `go.mod` → Go project
- Check for `Cargo.toml` → Rust project

## Step 2: Install Dependencies
Based on the detected project type:
- **Node.js**: Run `npm install` or `yarn install` or `pnpm install`
  (check for lock files to determine which)
- **Python**: Run `uv sync` or `pip install -r requirements.txt`
- **Go**: Run `go mod download`
- **Rust**: Run `cargo build`

## Step 3: Configure Environment
- Check if `.env.example` exists but `.env` does not
- If so, copy `.env.example` to `.env` and tell the user to fill
  in the values
- Check for any other setup scripts in `scripts/` or `Makefile`

## Step 4: Verify
- Run a basic health check (test command, build, or lint)
- Report success or any issues found

Creative Use of $ARGUMENTS

The $ARGUMENTS placeholder can carry much more than simple strings. You can design commands that parse complex argument patterns:

# File: .claude/commands/generate.md

Generate code based on the specification: $ARGUMENTS

## Argument Parsing
Parse $ARGUMENTS as: "{type} {name} [options]"

Examples:
- `/generate model User name:string email:string admin:boolean`
- `/generate controller OrdersController --crud`
- `/generate service PaymentService --with-tests --with-docs`
- `/generate middleware AuthMiddleware`

## Type handlers:

### model
- Create a database model with the specified fields
- Field format: `fieldname:type` (string, number, boolean, date)
- Generate a migration for the new model

### controller
- Create a controller/handler file
- If `--crud` is specified, include all CRUD operations
- Generate route registrations

### service
- Create a service class with dependency injection
- If `--with-tests` is specified, also generate test file
- If `--with-docs` is specified, add JSDoc/docstring comments

### middleware
- Create a middleware function
- Include next() call and error handling

## Constraints
- Match existing code style exactly
- Use the project's established patterns for each type

Multi-Step Workflows with Checkpoints

For complex workflows where you want Claude to pause and get confirmation at critical points, you can build checkpoint patterns into your commands:

# File: .claude/commands/major-refactor.md

Perform a major refactoring: $ARGUMENTS

## CHECKPOINT 1: Analysis
- Analyze the current state of $ARGUMENTS
- Present findings: what needs to change and why
- List every file that will be affected
- Estimate the scope: Small (1-3 files) / Medium (4-10) / Large (11+)
**STOP and wait for user approval before proceeding.**

## CHECKPOINT 2: Plan
- Present a detailed, step-by-step refactoring plan
- Include rollback strategy for each step
- Highlight any risky operations
**STOP and wait for user approval before proceeding.**

## CHECKPOINT 3: Execute
- Execute the plan one step at a time
- Run tests after each step
- If tests fail, roll back the last step and report
- After all steps complete, present the final summary
**STOP and wait for user approval to finalize.**

## If the user says "abort" at any checkpoint:
- Roll back all changes made so far
- Report what was reverted

Commands That Read CLAUDE.md

One of the most powerful advanced patterns is writing commands that explicitly reference your project’s CLAUDE.md file. Since CLAUDE.md is automatically loaded by Claude Code as project context, your commands can rely on conventions defined there without repeating them:

# File: .claude/commands/new-feature.md

Implement a new feature following all project conventions
defined in CLAUDE.md: $ARGUMENTS

## Instructions
- Read CLAUDE.md to understand the project's coding standards,
  directory structure, and conventions
- Follow every guideline specified there — CLAUDE.md is the
  source of truth for how code should be written in this project
- If CLAUDE.md specifies a testing approach, follow it exactly
- If CLAUDE.md specifies commit message formats, use them
- If any instruction here conflicts with CLAUDE.md, CLAUDE.md wins

## Implementation
1. Plan the feature based on $ARGUMENTS
2. Implement following CLAUDE.md conventions
3. Write tests following CLAUDE.md testing guidelines
4. Format code according to CLAUDE.md style rules
5. Summarize what was done
Key Takeaway: Advanced commands combine multiple techniques: argument parsing, environment detection, checkpoints for human approval, and integration with CLAUDE.md. The key is designing workflows that are powerful but still give you control at critical decision points.

Project Commands vs User Commands

Choosing between project commands and user commands is a design decision that affects your team’s workflow. Here is a detailed comparison to help you decide where each command should live.

Aspect Project Commands User Commands
Location .claude/commands/ ~/.claude/commands/
Version controlled Yes — committed to git No — local to your machine
Shared with team Automatically via git Never (unless manually shared)
Available across projects Only in that project In ALL projects
Best for Team workflows, project-specific tasks Personal productivity, cross-project utilities
Examples /deploy, /create-component, /write-post /explain, /summarize, /standup-notes

 

When to Use Project Commands

Project commands are the right choice when the command is specific to the project and useful to every team member. Deployment workflows, code scaffolding that follows project conventions, and review checklists that enforce team standards all belong as project commands. The biggest advantage is consistency — when a new developer joins the team, they get the same set of automated workflows as everyone else, configured for this specific project.

When to Use User Commands

User commands shine for personal productivity and cross-project utilities. Think of commands like /explain (explain any code in detail), /summarize (summarize what you did today), or /standup-notes (generate standup notes from recent git history). These are useful in every project but reflect your personal workflow rather than a team standard.

A useful rule of thumb: if the command references specific files, directories, or tools in the project, it is a project command. If it works generically with any codebase, it is a user command.

Integration with CLAUDE.md

The relationship between CLAUDE.md and custom commands is one of the most important architectural decisions in a Claude Code project. Think of CLAUDE.md as the constitution and custom commands as the laws — commands should implement and extend the principles defined in CLAUDE.md, never contradict them.

CLAUDE.md as the Source of Truth

CLAUDE.md is loaded automatically by Claude Code every time you start a session. It defines project-wide conventions: coding style, directory structure, testing approach, deployment targets, and constraints. Custom commands inherit this context automatically — when a command tells Claude to “follow the project’s conventions,” Claude already knows what those conventions are from CLAUDE.md.

This means your commands can be shorter and more focused. Instead of repeating the coding style guide in every command, define it once in CLAUDE.md and reference it from commands:

# In CLAUDE.md:
## Coding Standards
- Use TypeScript strict mode
- All functions must have return types
- Use Prettier with the project's .prettierrc
- Tests use Vitest with describe/it blocks
- Components use the Composition API (no Options API)

# Then in .claude/commands/create-feature.md:
Create a new feature: $ARGUMENTS

Follow all coding standards from CLAUDE.md exactly.
...

Example: CLAUDE.md + Command Working Together

Here is a concrete example of how they complement each other. Suppose your CLAUDE.md contains:

# CLAUDE.md
## Project Structure
- API routes go in `src/routes/`
- Business logic goes in `src/services/`
- Database queries go in `src/repositories/`
- Tests mirror the source structure in `tests/`

## API Conventions
- All endpoints return JSON with `{ data, error, meta }` structure
- Use Zod for request validation
- Authentication via Bearer token in Authorization header
- Rate limiting on all public endpoints

Now your /api-endpoint command can be much simpler because it relies on these conventions:

# .claude/commands/api-endpoint.md

Create a new API endpoint: $ARGUMENTS

Follow the project structure and API conventions defined in CLAUDE.md.

1. Create the route handler in the appropriate file under src/routes/
2. Create or update the service in src/services/
3. Create or update the repository in src/repositories/ if DB access
   is needed
4. Add Zod validation schemas for request/response
5. Create tests mirroring the source structure in tests/
6. Ensure the endpoint returns the standard { data, error, meta }
   response format

All conventions from CLAUDE.md apply — do not deviate.

The command is concise because CLAUDE.md provides the detailed context. This is a powerful pattern: define conventions once, reference them everywhere.

Organizing Commands for Large Projects

As your command library grows, organization becomes critical. A project with 20 commands in a flat directory gets hard to navigate. Here are proven strategies for keeping things manageable.

Naming Conventions

Adopt a consistent naming prefix system that groups related commands:

.claude/commands/
├── deploy.md               # /deploy
├── deploy-staging.md       # /deploy-staging
├── deploy-production.md    # /deploy-production
├── create-component.md     # /create-component
├── create-service.md       # /create-service
├── create-migration.md     # /create-migration
├── review-code.md          # /review-code
├── review-security.md      # /review-security
├── test-unit.md            # /test-unit
├── test-integration.md     # /test-integration
├── test-e2e.md             # /test-e2e
└── fix-bug.md              # /fix-bug

The prefix-based naming (deploy-*, create-*, review-*, test-*) means related commands sort together alphabetically, making them easy to find in the / menu.

Command Discovery

Claude Code has a built-in discovery mechanism: typing / shows all available commands. This means every command you create is instantly discoverable by you and your team. For larger command libraries, consider adding a /help command that lists all available commands with brief descriptions:

# File: .claude/commands/help.md

List all available custom commands in this project.

Read all .md files in .claude/commands/ and for each one:
1. Show the command name (filename without .md)
2. Read the first line or paragraph to get a brief description
3. Note if it accepts $ARGUMENTS

Format as a clean table:
| Command | Description | Arguments |
|---------|-------------|-----------|

Sort alphabetically by command name.

Documentation Within Commands

Every command file should start with a clear, one-line description of what it does. This serves double duty: it tells Claude what the command is about, and it makes the command self-documenting for team members who read the file:

# File: .claude/commands/deploy.md

Deploy the application to staging or production environments.
Usage: /deploy [staging|production]

## Steps:
...
Caution: Avoid creating deeply nested subdirectory structures within .claude/commands/. While it might seem logical to organize commands into deploy/, create/, and test/ subdirectories, check Claude Code’s current behavior with subdirectories before committing to that structure — flat directories with prefix-based naming are the most reliable approach.

Common Mistakes and How to Avoid Them

After reviewing hundreds of custom commands across teams and projects, certain mistakes appear again and again. Here are the most common pitfalls and their solutions.

Too Vague Instructions

The most common mistake by far. “Clean up the code” could mean anything from renaming variables to rewriting the entire module. Claude will make reasonable choices, but they might not be your choices. Always specify exactly what “clean up” means in your context: remove unused imports, add type annotations, extract long functions, fix linter warnings — whatever you actually want.

Not Specifying File Paths

Commands that say “update the configuration” force Claude to guess which configuration file you mean. In a typical project, there might be config.json, .env, tsconfig.json, package.json, .eslintrc, and a dozen other configuration files. Always be explicit: “update the database configuration in config/database.yml.”

Missing Error Handling

Commands without error handling instructions produce unpredictable results when things go wrong. What should Claude do if the build fails? If a file does not exist? If a test times out? Add explicit error handling for every step that could fail: “If the build fails, read the error output, fix the issue, and retry. If it fails a second time, stop and report the errors.”

Overly Complex Single Commands

A 200-line command file that handles deployment, testing, monitoring, rollback, notification, and documentation is fragile and hard to maintain. If one part breaks, the whole command is unreliable. Split it into focused commands: /deploy, /test, /monitor, /rollback. Each one is easier to write, test, debug, and maintain.

Not Testing Before Sharing

Before committing a project command that your whole team will use, test it thoroughly. Run it with different arguments, including edge cases like empty arguments, wrong file paths, and unexpected input. A command that fails on first use destroys team confidence in the whole system. Test with --dry-run flags where possible, and verify the output matches expectations before sharing.

Forgetting Constraints

Without explicit constraints, Claude might modify files you did not want changed, install packages you did not want, or push to branches you did not intend. Every command should include a constraints section that defines the boundaries: which files are off-limits, what operations are forbidden, and what requires explicit user confirmation.

Mistake Symptom Fix
Vague instructions Inconsistent results across runs List specific actions and expectations
No file paths Claude edits the wrong file Reference every file by its exact path
No error handling Command hangs or produces garbage on failure Add “if X fails, then do Y” for each step
Monolithic commands Hard to debug, one failure breaks everything Split into focused single-purpose commands
No testing Team loses confidence in commands Test with edge cases before committing
Missing constraints Unintended file modifications or operations Add explicit “do NOT” rules for every command

 

Real-World Command Libraries by Tech Stack

To give you a head start, here are curated command sets for popular tech stacks. Each one represents the kind of command library a mature team would maintain.

Python Stack (FastAPI / Django / Flask)

.claude/commands/
├── create-endpoint.md      # Scaffold a new API endpoint
├── create-model.md         # Create a new SQLAlchemy/Django model
├── create-migration.md     # Generate an Alembic/Django migration
├── write-tests.md          # Generate pytest tests for a module
├── review-code.md          # Code review with Python-specific checks
├── lint-fix.md             # Run ruff/flake8 and auto-fix issues
├── type-check.md           # Run mypy and fix type errors
├── deploy.md               # Deploy via Docker/Kubernetes/Lightsail
├── create-service.md       # Scaffold a new service layer class
└── create-cli.md           # Scaffold a new Click/Typer CLI command

A Python-specific /create-endpoint command would include patterns for Pydantic request/response models, dependency injection, and async handlers — conventions that differ significantly from JavaScript frameworks.

Node.js Stack (Express / Next.js / NestJS)

.claude/commands/
├── create-component.md     # React/Vue component with tests
├── create-page.md          # Next.js page with SSR/SSG
├── create-api-route.md     # API route handler
├── create-hook.md          # Custom React hook with tests
├── write-tests.md          # Jest/Vitest test generation
├── review-code.md          # Code review with TS/JS checks
├── lint-fix.md             # Run ESLint and Prettier fixes
├── deploy.md               # Deploy to Vercel/AWS/Netlify
├── create-middleware.md    # Express/NestJS middleware
└── storybook.md            # Generate Storybook stories

Go Stack

.claude/commands/
├── create-handler.md       # HTTP handler with middleware
├── create-service.md       # Service with interface and impl
├── create-repository.md    # Database repository pattern
├── create-migration.md     # SQL migration files
├── write-tests.md          # Table-driven test generation
├── review-code.md          # Code review with Go idiom checks
├── lint-fix.md             # Run golangci-lint and fix issues
├── create-proto.md         # Protobuf definition + generated code
├── benchmark.md            # Write and run benchmarks
└── deploy.md               # Build and deploy Go binary

DevOps Commands (Cross-Stack)

.claude/commands/
├── docker-build.md         # Build and tag Docker images
├── docker-compose-up.md    # Start all services with health checks
├── k8s-deploy.md           # Kubernetes deployment workflow
├── create-pipeline.md      # Scaffold CI/CD pipeline config
├── create-dockerfile.md    # Generate optimized Dockerfile
├── ssl-check.md            # Check SSL certificate expiry
├── log-analyze.md          # Analyze recent error logs
├── scale.md                # Scale services up or down
├── rollback.md             # Rollback to previous deployment
└── infra-audit.md          # Audit infrastructure configuration

Documentation Commands

.claude/commands/
├── document-api.md         # Generate API documentation
├── document-function.md    # Add JSDoc/docstrings to functions
├── update-readme.md        # Update README based on current state
├── changelog.md            # Generate changelog from git history
├── adr.md                  # Create Architecture Decision Record
├── runbook.md              # Generate operations runbook
└── diagram.md              # Generate Mermaid architecture diagrams

The documentation commands are particularly valuable because documentation is the task most developers avoid. Automating it with a slash command removes the friction entirely. A simple /document-api can analyze your route handlers and generate comprehensive API docs in seconds.

Tip: Start with 3-5 commands that address your most frequent tasks. Add more as you identify repetitive workflows. A well-curated library of 10-15 commands covers most development needs without becoming overwhelming.

Conclusion

Custom commands in Claude Code are not just a convenience feature — they are a fundamentally different way of working with AI in your development workflow. Instead of typing the same detailed instructions every time you need to deploy, scaffold, review, or test, you encode that knowledge once in a Markdown file and invoke it with a single slash command for the rest of the project’s lifetime.

The impact is immediate and measurable. Teams that adopt custom commands report spending significantly less time on repetitive workflows. But the deeper benefit is consistency. When every team member uses the same /deploy command, deployments follow the same process every time. When everyone uses the same /review-code command, code reviews check the same things. The tribal knowledge that usually lives in one senior developer’s head gets encoded in files that the whole team can use, improve, and version control.

Here is the practical path forward. Start today with three commands: one for your most frequent task (probably code scaffolding or deployment), one for your most dreaded task (probably writing tests or documentation), and one for your team’s biggest pain point (probably code review or environment setup). Write them following the patterns in this guide — specific instructions, clear steps, explicit constraints, and error handling. Test them, refine them, and commit them to your repository.

Then iterate. Every time you find yourself giving Claude Code the same detailed instructions for the third time, turn those instructions into a command. Every time a teammate asks “how do I deploy?” or “what’s our testing convention?”, point them to the relevant command. Over time, your .claude/commands/ directory becomes a living, executable operations manual for your project — one that does not just describe your workflows but actually runs them.

The developers who get the most from AI coding tools are not the ones who type the fastest prompts. They are the ones who build systems that make every future interaction faster, more consistent, and more reliable. Custom commands are how you build that system in Claude Code. Start with the 10 commands in this guide, adapt them to your projects, and build from there. Your future self — and your team — will thank you.

References

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *