CCAR-F · Study Guide

← Domain 3: Claude Code Configuration & Workflows

3.2 · Lesson 2 of 6

Custom Slash Commands and Skills

What You Need to Know

A skill is a named, reusable set of instructions that Claude Code loads on demand: a Markdown file, with optional YAML frontmatter and supporting files, that tells Claude how to carry out one specific workflow, such as reviewing staged changes or working through a deployment checklist. You invoke it by typing its name as a slash command (/review), or Claude loads it itself when a request matches its description. A skill is not always-on context. CLAUDE.md loads every session; a skill's instructions enter the conversation only when it runs. That distinction, on-demand workflow versus persistent configuration, is the one this task statement turns on.

Custom commands and skills have been merged into a single unified system: the Skills system. The two locations, .claude/skills/ and .claude/commands/, create slash commands that behave the same way, but their file structures differ. A skill is a directory containing a SKILL.md file (.claude/skills/deploy/SKILL.md); a command is a flat Markdown file (.claude/commands/deploy.md). A flat .md placed directly inside .claude/skills/ does not create a command. .claude/skills/ is the canonical location. .claude/commands/ still works for backward compatibility.

The Unified Skills System

Both paths produce the same result — a slash command that developers can invoke:

  • .claude/commands/deploy.md creates /deploy — a flat file whose filename becomes the command name.
  • .claude/skills/deploy/SKILL.md also creates /deploy — one directory per skill, named after the command, with SKILL.md as the required entrypoint inside it.

The skills path is the recommended one because it adds features the commands alias does not: a supporting-files directory alongside the SKILL.md, automatic discovery so Claude can load a skill when it matches your intent, and precedence when a skill and a command share the same name (the skill wins). Both paths support the same YAML frontmatter (context: fork, allowed-tools, argument-hint) and both produce the same command, so existing .claude/commands/ files keep working unchanged.

Two Scoping Levels

Project-scoped (shared via git). Place skills in .claude/skills/ (canonical) or .claude/commands/ (alias) inside your repository. Both are version-controlled and shared via git. Every developer who clones or pulls the repository gets these commands automatically. Use them for team-wide workflows: /review, /deploy-check, /lint, /migration-guide.

<!-- .claude/commands/review.md — creates /review -->
Review the staged changes against our team checklist:
1. Check error handling patterns
2. Verify test coverage for new functions
3. Confirm API naming conventions
4. Flag any hardcoded credentials or secrets

User-scoped (personal). Place skills in ~/.claude/skills/ (canonical) or ~/.claude/commands/ (alias). These are personal and not version-controlled or shared. Use them for individual productivity workflows that other team members do not need.

Skills Frontmatter

Skills in .claude/skills/ with SKILL.md files support optional YAML frontmatter. This frontmatter also works with .claude/commands/ files, but .claude/skills/ is the canonical location for configured skills. Skills are task-specific workflows invoked on demand — they aren't loaded automatically like CLAUDE.md.

The frontmatter sits at the top of the skill's SKILL.md. For a skill invoked as /analyse-feature, that file lives at .claude/skills/analyse-feature/SKILL.md:

---
description: "Analyse a feature area of the codebase and report structure, patterns and risks"
context: fork
allowed-tools:
  - Read
  - Grep
  - Glob
argument-hint: "Provide a feature description or area of the codebase to analyse"
---

context: fork. Runs the skill in an isolated sub-agent context. All the verbose output stays contained in the fork, and the main conversation stays clean. This is useful for codebase analysis (extensive file listings and code excerpts), brainstorming (many alternatives and evaluations), and any exploratory task that produces noisy output. Without context: fork, skill output flows into the main conversation and consumes context window tokens. For verbose skills, that degrades the quality of subsequent responses.

allowed-tools. The exam guide (v1.0) describes allowed-tools as restricting the skill's tool access, and that is the keyed answer: if a question asks what the field does, answer "restricts". Current Claude Code pre-approves the listed tools so Claude can use them without a permission prompt while the skill is active. It does not, by itself, remove every other tool: your permission settings still govern anything that is not listed. To remove tools from Claude's pool while a skill runs — the actual restriction boundary — list them in disallowed-tools, or add deny rules in permission settings.

---
allowed-tools:
  - Read
  - Grep
  - Glob
---

argument-hint. A hint shown during autocomplete to indicate the arguments the skill expects. It makes inputs explicit rather than relying on the developer to remember what the skill needs. It is a label, not an interactive prompt: invoking the skill with no arguments does not stop and ask for them.

---
argument-hint: "Specify the module path to analyse (e.g., src/api/auth)"
---

description. Those three fields are the ones the exam guide names. description is what Claude reads to decide whether a skill applies to what you just asked, so it matters for automatic skill matching. The docs mark it recommended rather than required: leave it out and Claude Code falls back to the first paragraph of the skill body, which is usually a worse summary than one you would write. A skill without a useful description only runs when you type /name yourself.

Skills vs CLAUDE.md

This distinction is tested directly on the exam:

  • Skills are on-demand, task-specific workflows. Their descriptions are always in context so Claude knows they exist, but the full skill body loads only when invoked. Invocation can be explicit (/skill-name) or automatic: Claude picks up skills whose description matches the user's intent, or skills with a paths frontmatter field when you are working on matching files. Skills with disable-model-invocation: true require explicit user invocation.
  • CLAUDE.md is always-loaded, universal standards. It is applied automatically to every session, with no invocation step.

Do not put task-specific procedures in CLAUDE.md. Do not put always-on reference material in skills. API naming conventions that must apply to every code generation task belong in CLAUDE.md (or .claude/rules/). A multi-step codebase analysis workflow that a developer runs occasionally belongs in a skill. For conventions that apply to a specific file type — like test files — path-scoped .claude/rules/ are the best fit because they load as always-on context alongside matching files.

Personal Skill Customisation

Create personal variants in ~/.claude/skills/ or ~/.claude/commands/ with different names so they do not affect teammates. If the team has a standard /analyse skill but you prefer a more verbose version, create your own in ~/.claude/skills/ with a different name, for example /deep-analyse. Your personal skill does not override or conflict with the team version.

Where to Place Custom Commands

NeedCanonical locationAlso worksScoping
Team-wide command.claude/skills/<name>/SKILL.md.claude/commands/<name>.mdProject (shared via git)
Team-wide command with frontmatter.claude/skills/<name>/SKILL.md.claude/commands/<name>.mdProject (shared via git)
Personal command~/.claude/skills/<name>/SKILL.md~/.claude/commands/<name>.mdUser (not shared)
Universal standards.claude/CLAUDE.md or root CLAUDE.md—Project (always loaded)
Personal preferences~/.claude/CLAUDE.md—User (not shared)

Exam traps

  • Creating a flat Markdown file directly inside .claude/skills/ (e.g., .claude/skills/review.md) and expecting a /review command

    The two paths create the same commands but have different file structures. A skill is a directory containing a SKILL.md entrypoint (.claude/skills/review/SKILL.md); a flat .md file only creates a command under .claude/commands/ (.claude/commands/review.md). A loose file dropped straight into .claude/skills/ is not picked up.

  • Placing a team-shared command in a user-scoped path (~/.claude/commands/ or ~/.claude/skills/) instead of a project-scoped path

    User-scoped paths (~/.claude/commands/ and ~/.claude/skills/) are personal and not version-controlled. Team commands that should be available to everyone on clone must go in a project-scoped path (.claude/skills/ or .claude/commands/) inside the repository. Both project-scoped paths create the same commands; .claude/skills/ is the canonical, fuller-featured location.

  • Thinking skills behave like CLAUDE.md for always-on guidance

    Skills load on-demand as task-style workflows, not as always-in-context guidance. Claude can auto-invoke a skill when the prompt matches the skill's description (or when a paths-scoped skill matches an edited file), but the skill still loads as a separate invocation-style unit rather than shaping every session by default. CLAUDE.md and .claude/rules/ load automatically into context for every session (or every matching file, for path-scoped rules). If the question asks about always-on conventions that apply to every edit, the answer is CLAUDE.md or .claude/rules/, not a skill.

  • Not knowing when to use context: fork

    context: fork isolates verbose skill output from the main conversation. Without it, brainstorming or codebase analysis output pollutes the context window. The exam will present scenarios where verbose output clutters the main conversation — the fix is context: fork.

  • Putting task-specific workflows in CLAUDE.md

    CLAUDE.md is for always-loaded universal standards. Task-specific procedures (code review workflows, analysis routines, brainstorming templates) belong in skills that are invoked on demand.

Practice scenario

A team wants a /review command available to everyone who clones the repository. A developer also wants a personal /brainstorm skill that produces verbose codebase analysis output without cluttering the main conversation. Where should each be created and what configuration does the skill need?

Choose one answer

Build exercise

Create Custom Commands and Skills

30 minutes

What you'll learn

  • Distinguish between project-scoped and user-scoped command locations
  • Configure SKILL.md frontmatter with context: fork, allowed-tools, and argument-hint
  • Understand when to use skills vs CLAUDE.md for conventions vs workflows
  • Verify scoping boundaries between shared and personal configuration
  • Apply the context: fork pattern to isolate verbose output from the main conversation
  1. Step 1

    Create a project-scoped /review command in .claude/commands/review.md containing a team code review checklist

    Put the shared review workflow in a flat Markdown file whose name becomes the slash command.

    Why: Project-scoped commands are shared via git so every developer gets them on clone. The exam tests whether you place team commands in .claude/commands/ (project) vs ~/.claude/commands/ (personal).

    You should see: A file at .claude/commands/review.md in the repository. Running /review in Claude Code triggers the code review checklist. The command appears when any developer clones the repository.

  2. Step 2

    Create a personal /brainstorm skill in ~/.claude/skills/brainstorm/SKILL.md with context: fork in the frontmatter

    Keep the verbose personal workflow in your home directory, as a skill directory with SKILL.md.

    Why: The context: fork frontmatter option isolates verbose skill output from the main conversation. Without it, codebase analysis output fills the context window and degrades subsequent responses. The exam directly tests this concept.

    You should see: A SKILL.md file at ~/.claude/skills/brainstorm/SKILL.md with YAML frontmatter containing context: fork. The skill is available only in your sessions, not shared with teammates.

  3. Step 3

    Add allowed-tools to the brainstorm skill, restricting it to Read, Grep, and Glob (read-only operations)

    List Read, Grep, and Glob in the skill frontmatter.

    Why: The exam guide describes allowed-tools as restricting which tools a skill can access, and that is the expected exam answer. In current Claude Code it pre-approves the listed tools so they run without a permission prompt (disallowed-tools is the actual boundary), but the intent is the same: a read-only analysis skill should never be using Write or Bash.

    You should see: The SKILL.md frontmatter now includes an allowed-tools list with exactly Read, Grep, and Glob. Under the exam-guide model the skill cannot use Write or Bash; in current Claude Code the list pre-approves those three tools for promptless use.

  4. Step 4

    Add argument-hint to the brainstorm skill: "Provide a feature description or codebase area to explore"

    Add the autocomplete hint as another frontmatter field.

    Why: The argument-hint is shown during autocomplete to indicate the arguments a skill expects. It improves developer experience and is one of the three SKILL.md frontmatter options tested on the exam.

    You should see: The SKILL.md frontmatter now includes argument-hint. Typing /brainstorm at the prompt shows the hint text alongside the command in autocomplete, indicating what input it expects.

  5. Step 5

    Test that /review appears for all project users (shared via git) and /brainstorm only for you

    Confirm the project file is in the repo and the personal skill is not.

    Why: This verifies the scoping boundary that the exam repeatedly tests: .claude/ is project-scoped and shared via git, while ~/.claude/ is user-scoped and personal. Confirming this experimentally solidifies the concept.

    You should see: Running /review works in any clone of the repository. Running /brainstorm works only in your session. A colleague or fresh clone without your home directory config does not see /brainstorm as an available command.

  6. Step 6

    Invoke the brainstorm skill and verify that its verbose output does not appear in the main conversation context

    Run /brainstorm on a codebase area and compare the main conversation with the forked analysis.

    Why: The context: fork option runs the skill in an isolated sub-agent. The main conversation receives only the summary, not the full verbose output. This is critical for preserving context window tokens during exploratory tasks.

    You should see: After invoking /brainstorm with a codebase area, the main conversation shows a concise summary of findings. The verbose file listings, code excerpts, and analysis notes are not visible in the main conversation history. Subsequent responses remain high quality because the context window is not filled with exploration output.

Sources