Claude Code Extensibility Guide¶
Purpose
Claude Code is more than a chat interface โ it's an extensible agentic development environment. This guide covers the five main building blocks you can use to customize Claude's behavior: CLAUDE.md, Skills, Custom Agents, Hooks, and MCP Servers. Understanding when to use each one is the key to getting consistent, high-quality output across your team.
The Extensibility Landscape¶
Each extensibility mechanism serves a different purpose. Choosing the right one matters:
| Feature | File | Scope | When Loaded | Best For |
|---|---|---|---|---|
| CLAUDE.md | CLAUDE.md |
Project-wide | Every session, always | Repo conventions, coding standards, universal rules |
| Skills | .claude/skills/*/SKILL.md |
Task-specific | When description matches the current task | Domain workflows, technology-specific guidance |
| Custom Agents | .claude/agents/*.md |
Delegated work | When spawned via the Agent tool | Specialized parallel workers, isolated review tasks |
| Hooks | .claude/settings.json |
Event-driven | On specific tool calls or events | Automated checks, formatting, notifications |
| MCP Servers | .mcp.json |
Tool-level | When tools are invoked | External integrations (Databricks, APIs, databases) |
flowchart TD
A[Should every task see these instructions?] -->|Yes| B["CLAUDE.md"]
A -->|No| C[Does it apply to a specific type of task?]
C -->|Yes, and runs in the main conversation| D["Skill"]
C -->|Yes, but should run as an isolated worker| E["Custom Agent"]
C -->|No, it's triggered by an event| F["Hook"]
C -->|No, it connects to an external system| G["MCP Server"]
style B fill:#2196F3,color:#fff
style D fill:#4CAF50,color:#fff
style E fill:#9C27B0,color:#fff
style F fill:#FF9800,color:#fff
style G fill:#F44336,color:#fff
CLAUDE.md โ Project Instructions¶
CLAUDE.md is a markdown file at the root of your project (or in subdirectories) that Claude reads at the start of every session. It sets the baseline for how Claude behaves in your repo.
Where to Place It¶
| Location | Scope |
|---|---|
~/CLAUDE.md |
User-level โ applies to all your projects |
./CLAUDE.md |
Project root โ applies to everyone working in this repo |
./src/CLAUDE.md |
Directory-level โ applies when working in that subtree |
Claude reads all applicable CLAUDE.md files and merges them, with more specific files taking precedence.
What to Put In It¶
CLAUDE.md is for instructions that should always be active:
# Project: customer-analytics
## Tech Stack
- Python 3.11, Databricks, Delta Lake, dbt
- CI/CD via Azure DevOps
## Conventions
- Use `ruff` for Python formatting (line length 120)
- All SQL follows uppercase keywords, lowercase identifiers
- Tests go in `tests/` mirroring the `src/` structure
- Never commit secrets โ use Azure Key Vault references
## Running Things
- Tests: `pytest tests/ -v`
- Linting: `ruff check src/`
- Local dev server: `make dev`
Keep CLAUDE.md lean
CLAUDE.md is loaded every session. If it grows too large, Claude spends tokens processing instructions that may not be relevant. Move task-specific guidance into skills and keep CLAUDE.md focused on universal rules.
Folder-Level Context with claude-mem¶
For larger projects, you can use claude-mem to auto-generate folder-level CLAUDE.md files that track recent activity per directory. Instead of manually maintaining context files in every subfolder, claude-mem observes your work and writes activity timelines into CLAUDE.md files using <claude-mem-context> tags.
How it works:
- claude-mem tracks which files you access during work
- It generates a "Recent Activity" section per folder with timestamps, activity types, and descriptions
-
The generated content uses emoji indicators for quick scanning:
Emoji Activity Type ๐ด Bug fix ๐ฃ Feature ๐ Refactoring โ Change ๐ต Discovery โ๏ธ Decision ๐ฏ Session
Enable it by editing ~/.claude-mem/settings.json:
Key behaviors:
- The project root
CLAUDE.md(next to.git) is never overwritten โ your manually written instructions are safe - Any content you write outside the
<claude-mem-context>tags is preserved through regeneration cycles - Supports git worktrees โ context is gathered from parent repos and worktree directories
Management commands:
# Preview what would be generated
bun scripts/regenerate-claude-md.ts --dry-run
# Remove all generated content
bun scripts/regenerate-claude-md.ts --clean
# Regenerate for a specific project
bun scripts/regenerate-claude-md.ts --project=my-project
To commit or not to commit?
Decide as a team whether to commit the generated CLAUDE.md files. Committing them gives visibility to all contributors and reviewers. Gitignoring them keeps the repo clean and allows per-machine context. A common pattern is to commit only the root CLAUDE.md and ignore the rest:
Skills โ Contextual Instructions¶
Skills are reusable instruction sets in SKILL.md files that Claude loads only when relevant to the current task. Instead of repeating the same prompt every session, you write a skill once and Claude applies it automatically.
How Skills Work¶
flowchart LR
A[You type a task] --> B{Claude checks skill descriptions}
B -->|Description matches| C[Skill loaded into context]
B -->|No match| D[Normal response]
C --> E[Claude follows skill instructions]
style C fill:#4CAF50,color:#fff
Creating a Skill¶
Skills live in .claude/skills/ inside your project:
your-project/
โโโ .claude/
โ โโโ skills/
โ โโโ sql-style-guide/
โ โโโ SKILL.md
โโโ src/
โโโ ...
Every skill needs a SKILL.md file with frontmatter (metadata) and body (instructions):
---
name: SQL Style Guide
description: >
Enforces our team's SQL coding standards when writing or reviewing
SQL queries โ uppercase keywords, lowercase identifiers, CTEs over
subqueries, explicit column lists.
---
When writing or reviewing SQL:
1. Use UPPERCASE for SQL keywords (SELECT, FROM, WHERE, JOIN)
2. Use lowercase_snake_case for table and column names
3. Prefer CTEs over subqueries for readability
4. Always use explicit column lists โ never SELECT *
5. Use table aliases that are meaningful (not single letters)
SKILL.md Frontmatter Reference¶
| Field | Required | Description |
|---|---|---|
name |
Yes | Human-readable name for the skill |
description |
Yes | Critical โ Claude uses this to decide when to activate the skill |
allowed-tools |
No | Restrict which tools the skill can use (security boundary) |
Writing Good Descriptions¶
The description is the single most important part. Claude uses it to decide whether to load the skill. A vague description means unreliable triggering.
| Quality | Example | Why |
|---|---|---|
| Bad | "Helps with database stuff" |
Too vague โ triggers unpredictably |
| Bad | "Code review skill" |
Every task could involve code review |
| Good | "Guides creation of Databricks jobs, including cluster configuration, task dependencies, retry policies, and notification setup." |
Specific technology, action, and scope |
| Good | "Applies when reviewing Python pull requests. Checks for type hints, docstring conventions, test coverage, and error handling patterns." |
Clear trigger condition and checklist |
Description writing checklist
- Does it mention the specific technology or domain?
- Does it mention the specific action?
- Would Claude know when NOT to trigger this skill?
- If two skills could overlap, does the description distinguish this one?
Multi-File Skills¶
A skill directory can include reference files, templates, and examples:
.claude/skills/
โโโ databricks-job-builder/
โโโ SKILL.md
โโโ job-template.json
โโโ cluster-policies.md
โโโ examples/
โโโ simple-etl-job.json
โโโ multi-task-workflow.json
Reference them from your SKILL.md:
---
name: Databricks Job Builder
description: >
Guides creation of Databricks jobs with our standard cluster
policies, task configurations, and alerting setup.
---
Use the template in `job-template.json` as a starting point.
Refer to `cluster-policies.md` for approved cluster configs.
See `examples/` for reference implementations.
Restricting Tools¶
For security-sensitive skills, limit which tools Claude can use:
---
name: Production Database Query
description: >
Used when querying production databases. Enforces read-only
access and prevents any write operations.
allowed-tools:
- Read
- Grep
- Glob
- mcp__databricks__execute_sql
---
Only execute SELECT queries against production.
Never run INSERT, UPDATE, DELETE, DROP, ALTER, or TRUNCATE.
Always include a LIMIT clause (max 1000 rows).
Invoking Skills Manually¶
Skills can be invoked explicitly using slash commands. Type /<skill-name> in Claude Code to force-load a skill regardless of description matching. Useful for:
- Skills that don't auto-trigger often enough
- Running a skill on demand (e.g., "run the security review now")
- Testing a skill during development
Skill Organization¶
.claude/skills/
โโโ data-engineering/
โ โโโ databricks-jobs/
โ โ โโโ SKILL.md
โ โโโ spark-optimization/
โ โโโ SKILL.md
โโโ analytics/
โ โโโ power-bi-measures/
โ โโโ SKILL.md
โโโ deployment/
โ โโโ azure-bicep/
โ โโโ SKILL.md
โโโ review/
โโโ security-review/
โโโ SKILL.md
One concern per skill
Keep skills focused on a single task or domain. A skill that covers "all Databricks things" will have a vague description and unreliable triggering. Split it: one for jobs, one for clusters, one for Unity Catalog.
Custom Agents โ Specialized Workers¶
Custom agents are defined in .claude/agents/*.md files. Unlike skills (which inject instructions into your main conversation), custom agents are independent workers that Claude can spawn to handle tasks in parallel or in isolation.
How Custom Agents Work¶
flowchart LR
A[Main Claude session] -->|Spawns| B[Custom Agent]
A -->|Spawns| C[Custom Agent]
B -->|Returns result| A
C -->|Returns result| A
style B fill:#9C27B0,color:#fff
style C fill:#9C27B0,color:#fff
When Claude uses the Agent tool with your custom agent type, it:
- Starts a fresh conversation with the agent's system prompt
- Gives the agent access to only the tools you specified
- The agent works independently and returns a summary
- The main conversation continues with the agent's findings
Creating a Custom Agent¶
Place an .md file in .claude/agents/:
your-project/
โโโ .claude/
โ โโโ agents/
โ โโโ data-quality-reviewer.md
โ โโโ security-auditor.md
โโโ src/
โโโ ...
Each agent file uses frontmatter to configure its behavior:
---
name: data-quality-reviewer
description: >
Reviews data pipeline code for quality issues โ checks for missing
null handling, schema validation, data type mismatches, and SLA
compliance in Databricks notebooks and dbt models.
model: sonnet
tools:
- Read
- Grep
- Glob
- mcp__databricks__execute_sql
- mcp__databricks__get_table_stats_and_schema
---
You are a data quality reviewer. When given code to review:
1. Check for missing null/empty handling on all input columns
2. Verify schema expectations are explicitly validated
3. Look for implicit type coercions that could silently corrupt data
4. Check that SLA-critical tables have freshness monitoring
5. Verify that all JOINs have appropriate null handling
Report findings as a structured list:
- **Critical**: Will cause data loss or corruption
- **Warning**: Could cause silent quality degradation
- **Info**: Improvement suggestions
Agent Frontmatter Reference¶
| Field | Required | Description |
|---|---|---|
name |
Yes | Identifier used when spawning the agent (used as subagent_type) |
description |
Yes | Tells Claude when this agent is the right choice for a task |
model |
No | Which Claude model to use: opus, sonnet, or haiku. Defaults to the session's model. Use haiku for fast, cheap tasks; opus for complex reasoning. |
tools |
No | List of tools the agent can access. Omit to give access to all tools. |
When to Use Agents vs. Skills¶
| Use a Skill when... | Use a Custom Agent when... |
|---|---|
| Instructions should apply in the main conversation | Work should happen in isolation |
| The task is part of your current flow | The task can run independently or in parallel |
| You need Claude to apply rules while you work | You need a specialized worker to complete a task and report back |
| Context from the main conversation is needed | A fresh perspective without conversation context is preferred |
Practical examples:
- Skill: "When writing SQL, follow our style guide" โ augments the main conversation
- Agent: "Review this PR for security issues" โ isolated, parallel worker
- Skill: "When deploying, use these Bicep patterns" โ guidance during your workflow
- Agent: "Check data quality across these 5 tables" โ delegated, independent task
Agent Examples¶
Lightweight linter agent (fast and cheap with Haiku):
---
name: quick-lint
description: >
Fast linting pass over changed files. Checks for common issues
like unused imports, missing type hints, and print statements.
model: haiku
tools:
- Read
- Grep
- Glob
---
Review the changed files for:
- Unused imports
- Missing type hints on function signatures
- Print/debug statements that should be removed
- TODO comments without ticket references
Report only confirmed issues. No false positives.
Keep your response under 200 words.
Deep architecture reviewer (thorough with Opus):
---
name: architecture-review
description: >
Deep review of architectural decisions โ evaluates module
boundaries, dependency directions, API surface area, and
consistency with existing patterns in the codebase.
model: opus
tools:
- Read
- Grep
- Glob
- Bash
---
You are a senior architect reviewing code changes.
Evaluate:
1. Do the module boundaries make sense?
2. Are dependencies flowing in the right direction?
3. Is the API surface area minimal and consistent?
4. Does this follow existing patterns in the codebase?
5. Are there abstraction or coupling concerns?
Read the surrounding code to understand existing patterns
before making judgments. Cite specific files and lines.
Hooks โ Event-Driven Automation¶
Hooks are shell commands that execute automatically in response to Claude Code events. They're defined in .claude/settings.json and run before or after specific tool calls.
How Hooks Work¶
flowchart LR
A[Claude calls a tool] --> B{Pre-hook defined?}
B -->|Yes| C[Run pre-hook command]
C -->|Exit 0| D[Tool executes]
C -->|Exit non-zero| E[Tool blocked]
D --> F{Post-hook defined?}
F -->|Yes| G[Run post-hook command]
F -->|No| H[Done]
G --> H
style E fill:#F44336,color:#fff
Configuring Hooks¶
Hooks are configured in .claude/settings.json (project-level) or ~/.claude/settings.json (user-level):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"command": "echo 'File being modified: check formatting'"
}
],
"PostToolUse": [
{
"matcher": "Bash",
"command": "echo 'Command executed โ verify output'"
}
]
}
}
Hook Events¶
| Event | When It Fires | Use Cases |
|---|---|---|
PreToolUse |
Before a tool is executed | Block dangerous operations, validate parameters, require confirmation |
PostToolUse |
After a tool completes | Run formatters, trigger notifications, log actions |
Notification |
When Claude sends a notification | Forward to Slack, Teams, or other channels |
Stop |
When Claude finishes a response | Run cleanup, validation, or summary actions |
Practical Hook Examples¶
Auto-format Python files after edits:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "ruff format --quiet $CLAUDE_FILE_PATH 2>/dev/null || true"
}
]
}
}
Prevent edits to production config files:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"command": "echo $CLAUDE_FILE_PATH | grep -q 'prod\\|production' && echo 'BLOCKED: Cannot edit production files directly' && exit 2 || exit 0"
}
]
}
}
Hook exit codes matter
- Exit 0: Hook passes, tool proceeds normally
- Exit 2: Hook blocks the tool call (Claude sees the block message and adjusts)
- Any other non-zero: Hook failed, but tool still proceeds
MCP Servers โ External Integrations¶
MCP (Model Context Protocol) servers connect Claude Code to external systems โ databases, APIs, cloud platforms, and custom tools. They extend Claude's capabilities beyond local file operations.
For MCP configuration specific to Databricks, see the dedicated guide: Connect Databricks MCP to Claude Code.
How MCP Works¶
flowchart LR
A[Claude Code] -->|MCP Protocol| B[MCP Server]
B -->|Tools & Resources| C[External System]
style B fill:#F44336,color:#fff
An MCP server exposes tools (actions Claude can take) and resources (data Claude can read). Claude discovers available tools at session start and uses them as needed.
Configuring MCP Servers¶
MCP servers are defined in .mcp.json at the project root (per-project) or ~/.claude/.mcp.json (global):
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["-y", "@my-org/my-mcp-server"],
"env": {
"API_KEY": "..."
},
"defer_loading": true
}
}
}
| Field | Description |
|---|---|
command |
How to start the MCP server process |
args |
Arguments passed to the command |
env |
Environment variables for the server process |
defer_loading |
If true, tools are loaded on first use instead of at session start (recommended for large tool sets) |
Verifying MCP Connections¶
Type /mcp in a Claude Code session to see all connected MCP servers and their status.
Putting It All Together¶
Here's how a well-configured project might use all five extensibility features:
your-project/
โโโ CLAUDE.md # Universal rules: tech stack, conventions, commands
โโโ .mcp.json # MCP server connections (Databricks, APIs)
โโโ .claude/
โ โโโ settings.json # Hooks, permissions, env vars
โ โโโ skills/
โ โ โโโ sql-style-guide/
โ โ โ โโโ SKILL.md # SQL conventions (triggers when writing SQL)
โ โ โโโ databricks-deployment/
โ โ โ โโโ SKILL.md # Deployment workflow
โ โ โ โโโ checklist.md # Pre-deployment checklist
โ โ โโโ dbt-model-builder/
โ โ โโโ SKILL.md # dbt conventions (triggers when creating models)
โ โโโ agents/
โ โโโ data-quality-reviewer.md # Parallel data quality checks
โ โโโ security-auditor.md # Isolated security review
โโโ src/
โโโ ...
Decision Flow¶
When deciding which feature to use, ask:
- Does every session need this? โ
CLAUDE.md - Does it apply to a specific type of task? โ Skill
- Should it run as an independent worker? โ Custom Agent
- Should it trigger automatically on an event? โ Hook
- Does it connect to an external system? โ MCP Server
Sharing Across the Team¶
All five features live in the project directory and can be committed to Git:
CLAUDE.mdโ committed, reviewed in PRs.claude/skills/โ committed, reviewed in PRs.claude/agents/โ committed, reviewed in PRs.claude/settings.jsonโ committed (project-level hooks and permissions).mcp.jsonโ committed (but sensitive env values should use references, not literals)
Review extensibility changes in PRs
Treat skill, agent, and hook changes like code changes. Bad instructions silently degrade output quality across the entire team. A poorly written skill description can cause Claude to apply wrong guidance to the wrong tasks.
For user-level configuration that shouldn't be shared (personal preferences, local paths), use:
~/.claude/CLAUDE.mdโ personal instructions~/.claude/settings.jsonโ personal hooks and permissions~/.claude/.mcp.jsonโ personal MCP connections
Troubleshooting¶
Skills¶
| Symptom | Cause | Fix |
|---|---|---|
| Skill never triggers | Description too vague | Rewrite with specific technology, action, and scope |
| Skill triggers for wrong tasks | Description too broad | Narrow the description to distinguish from other skills |
| Skill loads but output is wrong | Instructions are ambiguous | Add concrete examples and explicit rules |
| Skill not found | Wrong file name or location | Must be .claude/skills/<name>/SKILL.md |
allowed-tools blocks needed tool |
Restriction too tight | Add the missing tool to the list |
Custom Agents¶
| Symptom | Cause | Fix |
|---|---|---|
| Agent not available | File not in .claude/agents/ |
Move the .md file to .claude/agents/ |
| Agent uses wrong model | model field missing or misspelled |
Set to opus, sonnet, or haiku |
| Agent can't access needed tool | tools list is too restrictive |
Add the missing tool or remove the tools field entirely |
| Agent returns shallow results | Prompt is too vague | Give the agent specific instructions on what to check and how to report |
Hooks¶
| Symptom | Cause | Fix |
|---|---|---|
| Hook doesn't fire | matcher doesn't match the tool name |
Check the exact tool name (case-sensitive) |
| Hook blocks everything | Exit code is always non-zero | Ensure the command exits 0 for the pass case |
| Hook runs but has no effect | Output not visible to Claude | Use exit code 2 to block, or print messages to stdout |
Diagnostic Commands¶
| Command | What It Shows |
|---|---|
/skills |
All discovered skills and their trigger status |
/mcp |
Connected MCP servers and their status |
/config |
Current Claude Code configuration |