Personal study notes on creating custom agentic prompts for Claude Code.
The Big Picture
There are 4 types of agentic prompts in Claude Code. Each lives in a specific location and serves a different purpose:
| Type | Location | Creation Method | Complexity |
|---|---|---|---|
| Command / Skill | .claude/commands/*.md or .claude/skills/<name>/SKILL.md |
Snippet template (agpc) |
Simple — write directly |
| Agent | .claude/agents/**/*.md |
Snippet template (agpa) |
Simple — write directly |
| Orchestration | .claude/commands/*.md |
Meta-prompt (plan_w_team.md) |
Complex — needs generation + team |
Since v2.1.3 (Jan 9, 2026), commands and skills are merged — same front matter, same behavior. Skills add optional features like supporting files and auto-invocation by Claude.
Key Insight
- Commands and Agents are simple enough to scaffold with VS Code snippets and fill in manually.
- Skills and Orchestration are complex — they need a meta-prompt (a command that generates the actual prompt/plan for you).
- The meta-prompt itself IS a custom command. So commands are the foundation of everything.
The Meta-Prompt Pattern (Two-Step)
Step 1: Meta-prompt (command) → generates a plan/structure
Step 2: Agents execute/build from that plan
Example: /plan_w_team is a meta-prompt command that:
- Takes user requirements as input
- Generates a spec file in
specs/with task descriptions - The spec includes team orchestration (which agents to use)
- Agents (builder, validator) then execute the plan
What Each Type Does
1. Custom Command (/slash commands)
- What: A prompt you invoke with
/command-namein Claude Code - Where:
.claude/commands/your-command.md - How it works: Front matter defines model, tools, hooks. Body is the prompt instructions. Receives user input via
$ARGUMENTS. - Example:
/plan_w_team create a REST API— runs the planning meta-prompt
All command front matter fields
---
name: my-command # Display name
description: What this command does # Shown in /command list
argument-hint: [user prompt] # Hint shown during autocomplete
model: opus|sonnet|haiku # Model to use
allowed-tools: Task, Bash, Read, Edit, Write, Glob, Grep, WebFetch, WebSearch, ...
disallowed-tools: Task, EnterPlanMode # Tools to block
disable-model-invocation: false|true # Prevent auto-invocation
user-invocable: true|false # Show/hide in /menu
context: fork # Run in forked subagent
agent: general-purpose|Explore|Plan # Subagent type when context: fork
hooks:
PreToolUse: # Before tool executes
- matcher: "Bash" # Regex match tool name
hooks:
- type: command
command: "echo 'pre-hook'"
timeout: 600
once: false|true
PostToolUse: # After tool succeeds
- matcher: "Edit|Write"
hooks:
- type: command
command: "echo 'post-hook'"
timeout: 600
once: false|true
Stop: # When Claude finishes responding
- hooks:
- type: command
command: "echo 'stop-hook'"
timeout: 600
once: false|true
UserPromptSubmit: # When user submits prompt
- hooks:
- type: command
command: "echo 'prompt-submit-hook'"
SessionStart: # When session begins
- matcher: "startup|resume|clear|compact"
hooks:
- type: command
command: "echo 'session-start-hook'"
---
2. Custom Agent (sub-agents)
- What: A specialized worker that gets spawned by commands or orchestrators
- Where:
.claude/agents/team/your-agent.md - How it works: Front matter defines name, model, color, tool restrictions. Body defines the agent’s role and workflow. Uses
TaskGet/TaskUpdateto receive and report on tasks. - Examples:
builder.md(writes code),validator.md(read-only verification)
All agent front matter fields
---
name: builder # Unique identifier (lowercase, hyphens)
description: What this agent does # When Claude should delegate to this agent
model: opus|sonnet|haiku|inherit # Model to use
color: cyan|yellow|green|red|magenta|blue # Terminal color
tools: Task, Bash, Read, Edit, Write, ... # Tools agent can use (inherits all if omitted)
disallowedTools: Write, Edit, NotebookEdit # Tools to deny
permissionMode: default|acceptEdits|dontAsk|bypassPermissions|plan
maxTurns: 25 # Max agentic turns before stopping
skills: skill-name # Skills to preload
isolation: worktree # Run in isolated git worktree
background: false|true # Run as background task
hooks:
PreToolUse: # Before tool executes
- matcher: "Bash"
hooks:
- type: command
command: "echo 'pre-hook'"
timeout: 600
PostToolUse: # After tool succeeds
- matcher: "Edit|Write"
hooks:
- type: command
command: "echo 'post-hook'"
timeout: 600
Stop: # When agent finishes
- hooks:
- type: command
command: "echo 'stop-hook'"
timeout: 600
SubagentStart: # When a sub-agent spawns
- matcher: "builder"
hooks:
- type: command
command: "echo 'subagent-start-hook'"
SubagentStop: # When a sub-agent finishes
- matcher: "builder"
hooks:
- type: command
command: "echo 'subagent-stop-hook'"
TaskCompleted: # When a task marked completed
- hooks:
- type: command
command: "echo 'task-completed-hook'"
TeammateIdle: # When teammate about to go idle
- hooks:
- type: command
command: "echo 'teammate-idle-hook'"
---
3. Custom Skill (= Command, merged since v2.1.3)
Since v2.1.3 (Jan 9, 2026), commands and skills are merged. .claude/commands/review.md and .claude/skills/review/SKILL.md both create /review and work the same way.
- What: A reusable capability with specialized knowledge
- Where:
.claude/skills/<skill-name>/SKILL.md - Same front matter as commands — model, description, allowed-tools, hooks, etc.
What skills add over commands:
| Feature | Commands | Skills |
|---|---|---|
| Location | .claude/commands/*.md |
.claude/skills/<name>/SKILL.md |
| Supporting files | No | Yes — templates, scripts, examples in same directory |
| Auto-invocation by Claude | No | Yes — Claude loads skill automatically when relevant |
disable-model-invocation |
Supported | Supported — prevent Claude from auto-triggering |
user-invocable: false |
Supported | Supported — hide from / menu, only Claude can use |
| Nested discovery (monorepo) | No | Yes — auto-discovers from subdirectories |
Skills are the recommended path. Commands still work but skills support more features.
Skill directory structure:
my-skill/
├── SKILL.md # Main instructions (required)
├── template.md # Template for Claude to fill in
├── examples/
│ └── sample.md # Example output
└── scripts/
└── validate.sh # Script Claude can execute
Key Differences: Command/Skill vs Agent
Even though commands and skills are merged, agents are fundamentally different. Here’s a clear comparison:
| Feature | Command / Skill | Agent (Sub-agent) |
|---|---|---|
| Invocation | User calls with /command-name or Claude auto-invokes |
Claude delegates automatically based on description, or user asks “use the X agent” |
| Parameters | Takes $ARGUMENTS from user input |
No user parameters — receives a task/prompt from Claude |
| Context | Runs inline in main conversation (unless context: fork) |
Always runs in isolated context — separate context window, own system prompt |
| Parallel execution | No — one at a time in main conversation | Yes — multiple agents can run in parallel |
| Git isolation | No | Yes — isolation: worktree gives agent its own git worktree copy |
| Background execution | No | Yes — background: true or Ctrl+B to background a running agent |
| Persistent memory | No | Yes — memory: user|project|local for cross-session learning |
| Permission mode | Inherits from session | Own permissionMode |
| Turn limit | No limit | maxTurns — cap how many turns before agent stops |
| Tool restrictions | allowed-tools / disallowed-tools |
tools / disallowedTools |
| Preload skills | N/A | skills field |
| MCP servers | Inherits from session | mcpServers — can specify which MCP servers agent has access to |
| Visual indicator | None | color field — colored background in terminal UI |
| Can spawn sub-agents | No (unless context: fork) |
No — sub-agents cannot spawn other sub-agents |
| Resume | No | Yes — can resume with full previous context preserved |
When to use which?
Use Command/Skill when you want reusable prompts or workflows that run in the main conversation context. Good for: code generation templates, review checklists, deploy scripts, quick actions.
Use Agent when the task needs isolation, parallelism, or independent execution. Good for: code review (read-only), testing (verbose output), research (parallel exploration), specialized workers in team orchestration.
Rule of thumb: If you’d invoke it yourself with /name, make it a command/skill. If Claude should delegate to it automatically as a worker, make it an agent.
4. Team Orchestration (meta-prompt + agents)
- What: A meta-prompt that creates a plan, then coordinates multiple agents to build it
- Where: The meta-prompt is a command (
.claude/commands/plan_w_team.md), agents are in.claude/agents/team/ - How it works:
- User runs
/plan_w_team [requirements] - Command generates a spec file in
specs/directory - Spec includes team orchestration section (which agents, what tasks)
- Stop hooks validate the output file exists and has required sections
- Agents (builder, validator) execute the plan using TaskCreate/TaskUpdate
- User runs
Concrete example — plan_w_team.md flow
User: /plan_w_team create a REST API for user management
→ Meta-prompt analyzes requirements
→ Creates specs/user-management-api.md with:
- Task Description
- Objective
- Relevant Files
- Step by Step Tasks (using TaskCreate)
- Acceptance Criteria
- Team Orchestration (builder + validator assignments)
→ Stop hooks validate the spec file:
- validate_new_file.py — checks file was created in specs/
- validate_file_contains.py — checks all required sections exist
Required files for plan_w_team.md:
.claude/
├── commands/
│ └── plan_w_team.md # The meta-prompt command
├── agents/team/
│ ├── builder.md # Executes tasks (writes code)
│ └── validator.md # Verifies work (read-only)
├── hooks/validators/
│ ├── validate_new_file.py # Stop hook: checks file created
│ └── validate_file_contains.py # Stop hook: checks required sections
specs/ # Output directory for generated plans
All Available Tool Names
For use in allowed-tools, disallowed-tools, or disallowedTools:
| Tool | Purpose |
|---|---|
Task |
Spawn subagents |
TaskOutput |
Read subagent output |
Bash |
Execute shell commands |
Glob |
Find files by pattern |
Grep |
Search file contents |
Read |
Read file contents |
Edit |
Replace text in files |
Write |
Create/overwrite files |
NotebookEdit |
Edit Jupyter notebooks |
WebFetch |
Fetch web content |
WebSearch |
Search the internet |
AskUserQuestion |
Prompt user for input |
EnterPlanMode |
Switch to planning mode |
ExitPlanMode |
Exit planning mode |
Skill |
Invoke skills |
MCP Tools: Pattern mcp__<server>__<tool> (e.g., mcp__memory__create_entities)
Tool Restriction Syntax:
Task(agent_name)— allow only specific subagent typesBash(pattern *)— pattern-based restrictionsSkill(skill-name)— restrict individual skills
All Hook Events Reference
| Event | When | Matcher | Can Block |
|---|---|---|---|
SessionStart |
Session begins/resumes | startup, resume, clear, compact |
No |
UserPromptSubmit |
User submits prompt | No | Yes |
PreToolUse |
Before tool executes | Tool name regex | Yes |
PermissionRequest |
Permission dialog appears | Tool name regex | Yes |
PostToolUse |
After tool succeeds | Tool name regex | Feedback only |
PostToolUseFailure |
After tool fails | Tool name regex | No |
Notification |
Notification sent | permission_prompt, idle_prompt |
No |
SubagentStart |
Subagent spawns | Agent type name | No |
SubagentStop |
Subagent finishes | Agent type name | Yes |
Stop |
Claude finishes responding | No | Yes |
TeammateIdle |
Teammate about to go idle | No | Yes |
TaskCompleted |
Task marked completed | No | Yes |
ConfigChange |
Config file changes | user_settings, project_settings |
Yes |
PreCompact |
Before context compaction | manual, auto |
No |
SessionEnd |
Session terminates | clear, logout |
No |
Hook Handler Types
# Command hook — runs a shell command
- type: command
command: "path/to/script.sh"
timeout: 600 # seconds
async: false # run in background
once: true # run once per session (skills only)
# Prompt hook — sends a prompt to a model
- type: prompt
prompt: "Your prompt... $ARGUMENTS"
model: haiku # default: fast model
timeout: 30
# Agent hook — runs a full agent
- type: agent
prompt: "Your prompt... $ARGUMENTS"
model: haiku
timeout: 60
Key Concept: once vs Self-Validating Hooks
once: true = run the hook one time only, then skip it for the rest of the session.
once: false (or omitted) = run the hook every time the matcher triggers.
Self-validating pattern (blocks Claude until validation passes):
- Use a Stop hook (not PostToolUse) with
once: falseor omitonce - If the validator script returns exit code 1 (fail), Claude is blocked from stopping and must keep working
- Claude will retry until the validator passes (exit code 0)
# ONE-TIME CHECK — runs once after first Edit/Write, then never again
PostToolUse:
- matcher: "Edit|Write"
hooks:
- type: command
command: "uv run validator.py"
once: true # only once
# SELF-VALIDATING — blocks Claude from finishing until it passes
Stop:
- hooks:
- type: command
command: "uv run validator.py" # exit 1 = blocked, exit 0 = pass
# no "once" = runs every time
This is how plan_w_team.md ensures the spec file is actually created with all required sections — the Stop hook keeps blocking until it’s right.
What is uv run?
uv is a fast Python package manager/runner by Astral (same team behind ruff linter). Install with brew install uv.
uv run script.py runs a Python script and automatically handles dependencies declared in the script header:
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = ["requests"]
# ///
This is why hook validator scripts use uv run — no need to manually pip install anything. The script declares what it needs and uv handles it.
Example from plan_w_team.md:
command: >-
uv run $CLAUDE_PROJECT_DIR/.claude/hooks/validators/validate_new_file.py
--directory specs
--extension .md
$CLAUDE_PROJECT_DIR is an environment variable that points to your project root, so the hook script path works regardless of the current working directory.
VS Code Snippet Templates
Installation
1. Snippet file location (global — works in all projects):
- VS Code:
~/Library/Application Support/Code/User/snippets/markdown.json - Cursor:
~/Library/Application Support/Cursor/User/snippets/markdown.json
2. Required VS Code/Cursor settings (enable snippets in Markdown files):
Add to User Settings JSON (Cmd+Shift+P → “Open User Settings JSON”):
{
"[markdown]": {
"editor.quickSuggestions": {
"other": "on",
"comments": "off",
"strings": "off"
},
"editor.snippetSuggestions": "top"
}
}
Without this setting, typing snippet prefixes in .md files won’t trigger autocomplete.
Available Snippets
| Prefix | Type | Description |
|---|---|---|
agpc |
Command | .claude/commands/*.md — ALL command front matter fields with all hook types. Delete what you don’t need. |
agpa |
Agent | .claude/agents/**/*.md — ALL agent front matter fields including permissionMode, maxTurns, isolation, all hook types. Delete what you don’t need. |
agpn |
Body only | Just markdown sections (Purpose, Variables, Instructions, Workflow, Report). No front matter. |
How to Use
- Create a new
.mdfile in the correct location (e.g.,.claude/commands/my-command.md) - Type the snippet prefix (e.g.,
agpc) - Select from autocomplete (or press
Ctrl+Spaceto trigger it) - Tab through placeholders to fill in values — some have dropdown choices (e.g., model:
opus|sonnet|haiku) - Delete any fields you don’t need — snippets include everything so you can pick and choose
Summary
Simple (use snippets) Complex (use meta-prompts)
├── Commands/Skills (agpc) └── Orchestration (/plan_w_team)
└── Agents (agpa) ↓
Meta-prompts ARE commands
that generate other prompts
Commands = Skills (merged in v2.1.3). Use .claude/skills/ when you need supporting files or auto-invocation. Use .claude/commands/ for simple single-file prompts. Both work identically.
The foundation: everything is built on commands/skills. Simple things get a snippet template. Complex things get a meta-prompt command that generates the structure for you.
