Writing · Dr. Kai Stalmann

Extending Claude Code

29 January 2026EnglishFirst published on LinkedIn

This document describes how to extend and customize Claude Code through its plugin and hook architecture as I understand the matter. It covers all extensibility mechanisms with actionable instructions for implementation. As the corresponding document ('Understanding Claude Code') the information provide here was to some extend inferred from examining the ~/.claude/ directory structure, debug logs, session transcripts, and configuration files.

Note: Details such as hook events, plugin structure, MCP configuration, and available integrations may change over time.


Table of Contents

  1. Overview
  2. Hooks
  3. Plugins
  4. Skills
  5. Commands
  6. Agents
  7. MCP (Model Context Protocol)
  8. CLAUDE.md Management
  9. Extensibility Invocation Flow
  10. Configuration Reference
  11. Best Practices

1. Overview

Claude Code's extensibility system provides five mechanisms:

Mechanism Invoked By Purpose
Hooks System events Automate actions (validation, formatting, testing)
Plugins System Bundle hooks, skills, commands, agents, MCP configs
Skills Claude (auto) Context-aware expertise Claude activates autonomously
Commands User (/cmd) Slash commands users invoke directly
Agents Claude Specialized workers Claude spawns for complex tasks
MCP Servers Tools Connect external services (GitHub, Slack, etc.)

2. Hooks

Hooks execute shell commands in response to Claude Code lifecycle events. Use them to enforce policies, automate formatting, run tests, or integrate with external tools.

Hook Events

Event When It Fires Typical Use
PreToolUse Before a tool executes Validation, blocking dangerous operations
PostToolUse After a tool executes Auto-formatting, linting, running tests
SessionStart When a session begins Initialize resources, load configs
SessionEnd When a session ends Cleanup, save state
Stop When Claude stops working Final cleanup
UserPromptSubmit Before processing user input Validate or modify prompts
PreCompact Before context compaction Custom context management
Notification On specific events Handle permission_prompt, idle_prompt, auth_success

Hook Configuration

Hooks are configured in JSON settings files:

Location Scope
~/.claude/settings.json Global (all projects)
.claude/settings.json Project-specific
plugin/hooks/hooks.json Plugin-provided

Basic Structure

{
  "hooks": {
    "EVENT_NAME": [
      {
        "matcher": "TOOL_PATTERN",
        "hooks": [
          {
            "type": "command",
            "command": "your-shell-command"
          }
        ]
      }
    ]
  }
}

Fields

Field Required Description
matcher No Regex pattern to match tool names (e.g., Edit|Write)
type Yes Hook type — use "command"
command Yes Shell command to execute

Environment Variables

Hooks have access to these variables:

Variable Description
$CLAUDE_FILE_PATH Path to the file being operated on
$CLAUDE_TOOL_NAME Name of the tool being used
${CLAUDE_PLUGIN_ROOT} Root directory of the plugin (plugin hooks only)

Common Hook Patterns

Auto-Format on File Changes

Add to ~/.claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

Language-specific formatters:

Language Command
JavaScript/TypeScript prettier --write "$CLAUDE_FILE_PATH"
Python black "$CLAUDE_FILE_PATH" or ruff format "$CLAUDE_FILE_PATH"
Go gofmt -w "$CLAUDE_FILE_PATH"
Rust rustfmt "$CLAUDE_FILE_PATH"

Block Sensitive File Modifications

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.env|\\.env\\.|credentials|secrets'; then echo 'BLOCKED: Cannot modify sensitive files' >&2; exit 1; fi"
          }
        ]
      }
    ]
  }
}

When a PreToolUse hook exits with non-zero status, the operation is blocked.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx)$'; then npm test -- --findRelatedTests \"$CLAUDE_FILE_PATH\" --passWithNoTests 2>/dev/null || true; fi"
          }
        ]
      }
    ]
  }
}

Type Checking After Edits

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.(ts|tsx)$'; then npx tsc --noEmit 2>&1 | head -20; fi"
          }
        ]
      }
    ]
  }
}

Notification Sound on Permission Prompt

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "afplay /System/Library/Sounds/Ping.aiff"
          }
        ]
      }
    ]
  }
}

3. Plugins

Plugins bundle multiple extensibility features into distributable packages.

Plugin Structure

my-plugin/
├── .claude-plugin/
│   └── plugin.json          # Manifest (required)
├── hooks/
│   └── hooks.json           # Hook configuration
├── .mcp.json                # MCP server configuration
├── commands/
│   └── my-command.md        # Slash commands
├── skills/
│   └── my-skill/
│       ├── SKILL.md         # Skill definition
│       ├── references/      # Supporting docs
│       ├── examples/        # Example files
│       └── scripts/         # Utility scripts
├── agents/
│   └── my-agent.md          # Agent definitions
└── README.md

Creating a Plugin

Step 1: Create the Manifest

Create .claude-plugin/plugin.json:

{
  "name": "my-plugin",
  "description": "What this plugin does",
  "version": "1.0.0",
  "author": {
    "name": "Your Name",
    "email": "you@example.com"
  }
}

Step 2: Add Components

Add any combination of:

  • hooks/hooks.json — event-driven automation
  • commands/*.md — user-invoked slash commands
  • skills/*/SKILL.md — model-invoked capabilities
  • agents/*.md — specialized workers
  • .mcp.json — external service connections

Step 3: Test Locally

Place the plugin in ~/.claude/plugins/cache/ or reference it in your plugin settings.

Installing and Managing Plugins

Plugins are stored in ~/.claude/plugins/:

plugins/
├── settings.json              # Enabled plugins
├── installed_plugins.json     # Installation metadata
├── known_marketplaces.json    # Marketplace registry
├── cache/                     # Installed plugins
└── marketplaces/              # Available plugins

Enable a Plugin

Edit ~/.claude/plugins/settings.json:

{
  "enabledPlugins": {
    "my-plugin@marketplace-name": true,
    "gopls-lsp@claude-plugins-official": true
  }
}

Official Plugins

The official marketplace (anthropics/claude-plugins-official) includes:

Language Servers (LSP):

  • TypeScript, Python, Go, Rust, C/C++, Java, Kotlin, Swift, C#, PHP, Lua

Development:

  • feature-dev — structured feature development workflow
  • pr-review-toolkit — pull request review tools
  • code-review — code review assistance
  • plugin-dev — plugin development toolkit

Git/Workflow:

  • commit-commands — git commit helpers
  • hookify — hook management

Documentation:

  • claude-md-management — CLAUDE.md file maintenance

4. Skills

Skills are context-aware capabilities that Claude activates autonomously based on trigger conditions. Unlike commands, users don't invoke skills directly — Claude decides when to use them.

Creating a Skill

Create skills/my-skill/SKILL.md:

---
name: my-skill
description: "This skill should be used when the user asks about database migrations or mentions schema changes"
version: 1.0.0
license: MIT
---

# Database Migration Expert

This skill provides expertise in database migrations.

## When to Use

- When the user asks about schema changes
- When working with migration files
- When discussing database versioning

## Guidelines

1. Always check existing migrations before creating new ones
2. Use reversible migrations when possible
3. Test migrations on a copy of production data

## Common Commands

- `npm run migrate` — run pending migrations
- `npm run migrate:rollback` — rollback last migration

Skill Fields

Field Required Description
name Yes Unique identifier
description Yes Trigger conditions (include specific phrases)
version No Semantic version
license No License type

Skill Best Practices

  1. Include trigger phrases: Write descriptions like "This skill should be used when the user mentions X or asks about Y"
  2. Use third person: "This skill provides..." not "I provide..."
  3. Progressive disclosure: Keep SKILL.md concise; put details in references/
  4. Single focus: One skill per domain area

Skill Directory Structure

skills/my-skill/
├── SKILL.md              # Core skill definition
├── references/           # Detailed documentation
│   ├── patterns.md
│   └── examples.md
├── examples/             # Code examples
│   └── sample.sql
└── scripts/              # Utility scripts
    └── validate.sh

5. Commands

Commands are user-invoked slash commands (e.g., /review-pr, /commit).

Creating a Command

Create commands/my-command.md:

---
description: Run database migrations with safety checks
argument-hint: [--dry-run] [--target VERSION]
allowed-tools: [Bash, Read, Glob]
model: haiku
---

# Database Migration Command

When invoked, perform these steps:

1. Check for pending migrations using `npm run migrate:status`
2. If `--dry-run` is specified, show what would be executed without running
3. If `--target` is specified, migrate to that specific version
4. Run the migration: `npm run migrate`
5. Verify the migration succeeded by checking the schema

## Safety Checks

- Never run migrations if uncommitted changes exist in migration files
- Always create a backup reminder before destructive migrations

Command Fields

Field Required Description
description Yes Short description for /help
argument-hint No Usage pattern shown to users
allowed-tools No Restrict available tools
model No Override model (e.g., haiku for simple tasks)

Invoking Commands

Users invoke commands with:

/my-command --dry-run

Claude receives the command markdown as context and follows its instructions.


6. Agents

Agents are specialized workers Claude spawns for complex tasks. They operate autonomously with their own conversation context.

Creating an Agent

Create agents/my-agent.md:

---
name: security-reviewer
description: Reviews code for security vulnerabilities
---

# Security Reviewer Agent

You are a specialized security reviewer. Your task is to analyze code for vulnerabilities.

## Review Checklist

- [ ] SQL injection vulnerabilities
- [ ] XSS attack vectors
- [ ] Authentication bypasses
- [ ] Sensitive data exposure
- [ ] Insecure dependencies

## Process

1. Read all files in the specified directory
2. Identify potential vulnerabilities
3. Categorize by severity (Critical, High, Medium, Low)
4. Provide remediation recommendations

## Output Format

Return findings as:

[SEVERITY] Vulnerability Name

File: path/to/file.js:123 Issue: Description of the vulnerability Fix: Recommended remediation

Built-in Agent Types

Claude Code includes these built-in agents:

Type Purpose Tools
Explore Codebase exploration Read, Glob, Grep, WebFetch, WebSearch
Plan Implementation planning All read-only tools
Bash Command execution Bash only
general-purpose Multi-step complex tasks All tools

How Agents Work

diagram


7. MCP (Model Context Protocol)

MCP connects Claude Code to external services and tools.

Configuration

Create .mcp.json in your plugin or project:

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}"
      }
    },
    "local-database": {
      "type": "stdio",
      "command": "node",
      "args": ["./mcp-server.js"]
    }
  }
}

Server Types

Type Description Use Case
http REST API Cloud services (GitHub, Slack)
stdio Local process Local tools and scripts
sse Server-Sent Events Real-time hosted services
websocket WebSocket Bidirectional real-time

HTTP Server Configuration

{
  "service-name": {
    "type": "http",
    "url": "https://api.example.com/mcp/",
    "headers": {
      "Authorization": "Bearer ${API_TOKEN}",
      "X-Custom-Header": "value"
    }
  }
}

stdio Server Configuration

{
  "local-tool": {
    "type": "stdio",
    "command": "python",
    "args": ["./my_mcp_server.py", "--config", "prod"],
    "env": {
      "DATABASE_URL": "${DATABASE_URL}"
    }
  }
}

Available Integrations

Productivity: GitHub, GitLab, Slack, Asana, Linear, Jira, Confluence, Notion

Development: Greptile, Playwright, Context7

Database: Supabase, Firebase, Pinecone

Deployment: Vercel, Sentry

Other: Figma, Stripe, Hugging Face


8. CLAUDE.md Management

The claude-md-management plugin provides tools to maintain project memory.

/revise-claude-md Command

Run at session end to capture learnings:

diagram

What it captures:

  • Build commands and workflows discovered
  • Code style patterns observed
  • Testing approaches that worked
  • Environment quirks and gotchas

claude-md-improver Skill

Audits CLAUDE.md quality against a 100-point rubric:

Criterion Weight What it checks
Commands/workflows 20pts Are build/test/lint commands documented?
Architecture clarity 20pts Is directory structure clear?
Non-obvious patterns 15pts Are gotchas captured?
Conciseness 15pts Is every line useful?
Currency 15pts Do commands actually work?
Actionability 15pts Can you copy-paste instructions?

Red flags it detects:

  • Commands that would fail
  • References to deleted files
  • Generic advice not specific to project
  • Stale TODO items

9. Extensibility Invocation Flow

Session Lifecycle

diagram

Turn Execution

diagram

Tool Execution Loop

diagram


10. Configuration Reference

Global Settings

~/.claude/settings.json:

{
  "hooks": {
    "PostToolUse": [...],
    "PreToolUse": [...]
  }
}

Plugin Settings

~/.claude/plugins/settings.json:

{
  "enabledPlugins": {
    "plugin-name@marketplace": true
  },
  "alwaysThinkingEnabled": true
}

Project Settings

.claude/settings.json:

{
  "hooks": {
    "PostToolUse": [...]
  }
}

Local Overrides (gitignored)

.claude/settings.local.json:

{
  "hooks": {
    "PostToolUse": [...]
  }
}

11. Best Practices

Hook Development

  1. Use PreToolUse for validation — block before damage occurs
  2. Use PostToolUse for side effects — formatting, linting, testing
  3. Handle errors gracefully — append || true to prevent hook failures from blocking work
  4. Use portable paths — leverage ${CLAUDE_PLUGIN_ROOT} for plugin scripts
  5. Keep hooks fast — slow hooks degrade the user experience

Plugin Development

  1. Follow standard structure — use conventional directories for auto-discovery
  2. Include working examples — demonstrate all features
  3. Progressive disclosure — keep core docs concise, details in references/
  4. Version your plugins — use semantic versioning
  5. Document trigger conditions — for skills, be explicit about when they activate

Security Considerations

  1. Never store secrets in hooks — use environment variables with ${VAR} syntax
  2. Validate file paths — prevent path traversal attacks in custom hooks
  3. Limit hook scope — use specific matchers rather than catching all operations
  4. Review plugin sources — only install plugins from trusted sources
  5. Use .local files — keep sensitive project-specific hooks out of git

Skill Design

  1. Include specific trigger phrases — "when the user asks about X"
  2. Write in third person — "This skill provides..." not "I provide..."
  3. One skill per domain — don't overload a single skill
  4. Keep SKILL.md focused — put reference material in subdirectories

Command Design

  1. Clear argument hints — show users the expected format
  2. Restrict tools when appropriate — use allowed-tools for safety
  3. Use lighter models for simple tasks — specify model: haiku when possible
  4. Provide step-by-step instructions — Claude follows the markdown literally
Dr. Kai Stalmann · qantr GmbH All writing →