# Custom Commands

<SlideStart />

## How to create a custom command

Custom commands are plain Markdown files stored in `.claude/commands/`. The filename determines the command name: `review-pr.md` becomes `/review-pr`, `summarize.md` becomes `/summarize`. Claude Code scans that directory automatically — no registration step required.

To create your first command:

```bash
# Create the commands directory if it doesn't exist
> mkdir -p .claude/commands

# Create a command file
> touch .claude/commands/review-pr.md
```

Open `review-pr.md` and write the prompt you want Claude to receive when you type `/review-pr`. No frontmatter required — the file content is the prompt template. Any text typed after the command name is passed in as `$ARGUMENTS`.

For example, if your file contains `Review the pull request at $ARGUMENTS for correctness and style` and you type `/review-pr #142`, Claude receives `Review the pull request at #142 for correctness and style`.

<DiagramViewer title="How a custom command resolves">
```d2
direction: right

cmd: "/review-notebook notebooks/churn.ipynb"
file: .claude/commands/review-notebook.md
prompt: "Prompt with arguments"
claude: Claude Code

cmd -> file
file -> prompt
prompt -> claude
```
</DiagramViewer>

<SlideEnd />

<SlideStart />

## Template

Here is a complete, realistic command for a DS/ML workflow. It reviews a Jupyter notebook for common issues that affect reproducibility and model correctness.

```markdown title=".claude/commands/review-notebook.md"
Review the notebook at $ARGUMENTS for:
1. Reproducibility — are random seeds set? are paths relative?
2. Data leakage — does any preprocessing use future information?
3. Code quality — are functions documented? is logic reusable?
4. Output — are all cells run in order? are large outputs cleared?

Provide a structured report with a severity level (high/medium/low) for each issue found.
```

To invoke it:

```bash
/review-notebook notebooks/churn_model.ipynb
```

Claude replaces `$ARGUMENTS` with `notebooks/churn_model.ipynb` and runs the prompt. You can reuse the same command on any notebook in your project — no edits needed.

`$ARGUMENTS` captures everything after the command name as a single string. For instance, `/compare-models models/v1.pkl models/v2.pkl` passes `models/v1.pkl models/v2.pkl` as one block of text.

When you need individual arguments separately, use positional access: `$ARGUMENTS[0]` for the first, `$ARGUMENTS[1]` for the second — or the shorthand `$0`, `$1`, `$2`. A command that compares two model versions might use:

```markdown title=".claude/commands/compare-models.md"
Compare $0 and $1. Focus on accuracy, latency, and memory footprint.
Output a structured table with one row per metric.
```

Running `/compare-models models/v1.pkl models/v2.pkl` substitutes each argument by position.

A few things worth getting right when writing command templates:

- Be explicit about the output format. If you want a numbered list with severity labels, say so.
- Do not assume Claude knows your project context. If the command depends on a convention (like "all data is in `data/raw/`"), state it in the template.
- Write the prompt as carefully as you would write it by hand. The command is not magic — it is just a saved prompt.

<SlideEnd />

<SlideStart />

## Dos and don'ts

| Do | Don't |
|----|-------|
| Write commands for workflows you repeat more than twice a week | Create commands for one-off tasks |
| Use `$ARGUMENTS` to make commands reusable | Hardcode specific file paths |
| Keep command files in `.claude/commands/` and commit them | Store commands in ad-hoc places outside the project |
| Write the prompt as clearly as you'd write it manually | Assume Claude will infer missing context |
| Test the command on a real case before sharing | Share untested commands with the team |

The test-before-sharing rule matters more than it looks. A command that works well on one notebook may produce shallow results on another if the prompt is underspecified. Run it on two or three real cases before committing it as a team standard.

<SlideEnd />