CC-201: Plugin Architecture

Listen instead
CC-201 Plugin Architecture
0:00

Plugin System Overview

Claude Code's plugin system is the extension mechanism that transforms Claude from a powerful AI assistant into a customizable development platform. Plugins allow you to package reusable skills, commands, agents, and hooks into distributable units that extend Claude Code's capabilities for specific workflows, teams, or domains.

At its core, a plugin is a directory containing a plugin.json manifest file alongside the component files it declares. Claude Code discovers plugins through a well-defined search path and loads them at session start, making their capabilities immediately available. This architecture follows a convention-over-configuration philosophy: place your plugin in the right location with the right manifest, and Claude Code handles the rest.

Official Documentation: The canonical reference for the plugin system is the Claude Code Plugins documentation. This module expands on those docs with practical architecture guidance.

The plugin.json Manifest

Every plugin begins with its manifest file, plugin.json. This file declares the plugin's identity, its components, and configuration metadata. Here is a complete manifest example:

{
  "name": "my-dev-toolkit",
  "version": "1.0.0",
  "description": "Development workflow automation toolkit",
  "skills": [
    "skills/code-review.md",
    "skills/pr-template.md"
  ],
  "commands": [
    "commands/deploy.md",
    "commands/test-suite.md"
  ],
  "agents": [
    "agents/security-reviewer.md"
  ],
  "hooks": [
    "hooks/pre-commit-check.md"
  ]
}

The manifest fields break down as follows:

  • name — A unique identifier for the plugin. Use kebab-case. This name is used in logs, conflict resolution, and plugin references.
  • version — Semantic version string. Claude Code uses this for update detection and compatibility checks.
  • description — Human-readable summary displayed when listing installed plugins.
  • skills — Array of relative paths to skill definition files (Markdown with YAML frontmatter).
  • commands — Array of relative paths to command definition files (slash commands).
  • agents — Array of relative paths to agent definition files (subagent configurations).
  • hooks — Array of relative paths to hook definition files (event-driven behaviors).

All paths in the manifest are relative to the plugin root directory. The special variable ${CLAUDE_PLUGIN_ROOT} resolves to this directory at runtime, which is critical when your skills or hooks need to reference other files within the plugin.

Component Types

Skills

Skills are the most common plugin component. A skill is a Markdown file with YAML frontmatter that teaches Claude a specific capability. When a user's request matches a skill's trigger conditions, Claude loads the skill's instructions and follows them.

---
name: code-review
description: "Performs structured code review with security focus"
when-to-use: "When the user asks for a code review, PR review, or security audit of code"
---

# Code Review Skill

When performing a code review, follow these steps:

1. Read all changed files using the diff or file list provided
2. Check for security vulnerabilities (injection, auth bypass, data exposure)
3. Evaluate code quality (naming, complexity, duplication)
4. Verify error handling completeness
5. Output findings in structured format...

The when-to-use field is critical: it tells Claude's routing logic when this skill is relevant. Be specific and descriptive. Vague triggers lead to skills activating when they should not, or failing to activate when they should.

Commands

Commands create slash commands that users invoke explicitly. Unlike skills (which Claude selects automatically), commands are user-initiated via /command-name syntax in the chat interface.

---
name: deploy
description: "Deploy the current project to the specified environment"
arguments:
  - name: environment
    description: "Target environment (staging, production)"
    required: true
  - name: skip-tests
    description: "Skip pre-deploy test suite"
    required: false
    default: "false"
---

# Deploy Command

Deploy the current project to {{ environment }}.

{% if skip-tests == "false" %}
First, run the full test suite...
{% endif %}

Then execute the deployment pipeline...

Agents

Agents define specialized subagent configurations. When Claude spawns a subagent (using the Agent tool), it can use a plugin-defined agent profile that includes a system prompt, tool restrictions, and behavioral guidelines.

---
name: security-reviewer
description: "Specialized agent for security-focused code analysis"
system-prompt: |
  You are a security-focused code reviewer. Your only job is to find
  security vulnerabilities. Do not comment on style or performance.
allowed-tools:
  - Read
  - Grep
  - Glob
---

# Security Reviewer Agent

Focus areas:
- Injection vulnerabilities (SQL, command, path traversal)
- Authentication and authorization flaws
- Data exposure and leakage
- Cryptographic misuse...

Hooks

Hooks let plugins respond to Claude Code lifecycle events. They can enforce policies, inject context, validate outputs, or trigger side effects at specific points in the session lifecycle.

---
name: pre-commit-check
event: PreToolUse
matcher: "Bash"
---

# Pre-Commit Check Hook

Before any Bash command execution, verify:
1. The command does not include `git push --force` to main/master
2. The command does not include `rm -rf /`
3. The command does not expose secrets in echo/printf statements

If any violation is found, BLOCK the command and explain why.

Plugin Discovery and Auto-Loading

Claude Code discovers plugins through a defined search path, checked in order:

  1. Project-level.claude/plugins/*/plugin.json in the current project directory. These are project-specific plugins, often committed to version control.
  2. User-level~/.claude/plugins/*/plugin.json in the user's home directory. These are personal plugins available across all projects.

Discovery happens at session start. Claude Code walks each search path, reads every plugin.json it finds, validates the manifest schema, and registers the declared components. If two plugins declare a component with the same name, the more specific scope wins (project-level overrides user-level).

The ${CLAUDE_PLUGIN_ROOT} Variable

Inside any plugin component file, you can reference ${CLAUDE_PLUGIN_ROOT} to build paths relative to the plugin's root directory. This is essential for plugins that include data files, templates, or scripts alongside their component definitions.

---
name: generate-report
description: "Generate project report from template"
when-to-use: "When the user asks for a project status report"
---

# Generate Report

Read the template from:
${CLAUDE_PLUGIN_ROOT}/templates/report-template.md

Then populate it with project data gathered from the codebase...

This variable is resolved at load time, so it works regardless of where the user's working directory is set.

Plugin Loading Lifecycle

Understanding the loading lifecycle helps you debug plugin issues and design components that initialize correctly:

  1. Session Start — Claude Code begins a new session.
  2. Path Scan — The plugin search paths are walked for plugin.json files.
  3. Manifest Validation — Each manifest is parsed and validated. Invalid manifests are logged and skipped.
  4. Component Registration — Skills, commands, agents, and hooks from valid plugins are registered in Claude's internal registry.
  5. Hook Binding — Hooks are bound to their declared events. SessionStart hooks fire immediately after binding.
  6. Ready State — All plugins are loaded. Skills and commands are available for routing and invocation.

If a plugin's component file is missing or malformed, Claude Code logs a warning but continues loading other components. A single broken skill file does not prevent the rest of the plugin from functioning.

Distribution Patterns

Plugins can be distributed in several ways depending on your use case:

Git Repository

The most common pattern. Publish your plugin as a Git repository. Users clone it into their ~/.claude/plugins/ directory. Updates are pulled with git pull. This works well for open-source plugins and team-shared tooling.

# Install a plugin from Git
git clone https://github.com/org/my-plugin.git ~/.claude/plugins/my-plugin

Project-Embedded

For project-specific plugins, commit the plugin directory directly into your project's .claude/plugins/ path. Every developer who clones the repo gets the plugin automatically. This is ideal for project-specific conventions, deployment scripts, and team workflows.

Monorepo Plugin Directory

In a monorepo, you might maintain a shared plugins directory at the repo root with multiple plugins. Each subdirectory is an independent plugin with its own plugin.json.

Best Practices

  • Keep plugins focused. One plugin should do one thing well. Avoid kitchen-sink plugins that bundle unrelated capabilities.
  • Write precise when-to-use descriptions. This is the single most important field for skill routing accuracy.
  • Use ${CLAUDE_PLUGIN_ROOT} for all internal references. Never hardcode absolute paths in plugin components.
  • Version your plugins. Semantic versioning helps teams coordinate updates and track breaking changes.
  • Test components individually. Invoke each skill and command manually to verify they behave correctly before bundling them into a plugin.
  • Document your plugin. Include a README with installation instructions, component descriptions, and usage examples.

Key Takeaways

  • Plugins are directory-based extensions with a plugin.json manifest at the root.
  • Four component types: skills (auto-triggered), commands (user-invoked), agents (subagent configs), and hooks (event-driven).
  • ${CLAUDE_PLUGIN_ROOT} enables portable path references within plugin components.
  • Discovery is automatic at session start via project-level and user-level search paths.
  • Distribution is flexible: Git repos, project-embedded, or shared directories.