CC-201b: Plugin Blueprint
Listen instead
Hands-On Plugin Building
This module is a practical walkthrough of building a complete Claude Code plugin from scratch. Where CC-201 covered the architecture and theory, this module puts that knowledge into action. By the end, you will have built a working plugin with skills, commands, an agent, and a hook.
Official Documentation: Follow along with the Claude Code Plugins documentation as we build each component.
Step 1: Scaffolding the Plugin
Start by creating the plugin directory structure. We will build a plugin called dev-workflow that automates common development tasks.
# Create the plugin structure
mkdir -p ~/.claude/plugins/dev-workflow/{skills,commands,agents,hooks}
# Create the manifest
cat > ~/.claude/plugins/dev-workflow/plugin.json << 'EOF'
{
"name": "dev-workflow",
"version": "1.0.0",
"description": "Development workflow automation plugin",
"skills": [
"skills/analyze-deps.md",
"skills/migration-guide.md"
],
"commands": [
"commands/standup.md",
"commands/changelog.md"
],
"agents": [
"agents/test-writer.md"
],
"hooks": [
"hooks/file-guard.md"
]
}
EOF
This gives you the standard layout: a manifest at the root, with subdirectories for each component type. The manifest declares six components that we will build one at a time.
Step 2: Creating Skills
Skills are Markdown files with YAML frontmatter. The frontmatter defines metadata and routing hints. The Markdown body contains the instructions Claude follows when the skill activates.
Skill: Dependency Analyzer
---
name: analyze-deps
description: "Analyzes project dependencies for outdated packages, security issues, and optimization opportunities"
when-to-use: "When the user asks to analyze, audit, or review project dependencies, packages, or libraries"
---
# Dependency Analysis Skill
## Process
1. Identify the project's package manager by checking for:
- `package.json` (npm/yarn/pnpm)
- `requirements.txt` or `pyproject.toml` (Python)
- `go.mod` (Go)
- `Cargo.toml` (Rust)
- `Gemfile` (Ruby)
2. Read the dependency manifest file completely.
3. For each dependency, assess:
- **Purpose**: What does this dependency do?
- **Maintenance status**: Is it actively maintained?
- **Overlap**: Are there dependencies that duplicate functionality?
- **Size impact**: Are there lighter alternatives for heavy dependencies?
4. Categorize findings:
- CRITICAL: Security vulnerabilities or abandoned packages
- WARNING: Outdated major versions or maintenance concerns
- INFO: Optimization opportunities
5. Output a structured report with actionable recommendations.
## Output Format
Use a markdown table for the summary, followed by detailed findings
for any CRITICAL or WARNING items.
Notice the when-to-use field lists multiple phrasings: "analyze", "audit", "review". This increases the chance Claude matches the skill correctly regardless of how the user words their request.
Skill: Migration Guide
---
name: migration-guide
description: "Generates step-by-step migration guides for framework or library upgrades"
when-to-use: "When the user asks to migrate, upgrade, or update a framework, library, or major dependency version"
---
# Migration Guide Skill
## Process
1. Identify the current version by reading config files and lock files.
2. Identify the target version from the user's request.
3. Research breaking changes between versions by reading changelogs
if available in the project or node_modules.
4. Generate a step-by-step migration plan:
- Pre-migration checklist (backups, branch creation)
- Ordered list of changes required
- Code modifications with before/after examples
- Post-migration verification steps
5. Flag any dependencies that may also need updating.
## Output Format
### Migration: [Library] v[Current] to v[Target]
**Risk Level**: Low / Medium / High
**Pre-Migration Checklist**
- [ ] Create a dedicated branch
- [ ] Ensure all tests pass on current version
- [ ] Back up lock files
**Migration Steps**
1. Step with code examples...
**Post-Migration Verification**
- [ ] All tests pass
- [ ] Application starts without errors
- [ ] Key user flows verified
Step 3: Creating Commands
Commands differ from skills in one key way: they are explicitly invoked by the user with a slash prefix. The user types /standup or /changelog to trigger them.
Command: Standup Report
---
name: standup
description: "Generate a standup report from recent git activity"
arguments:
- name: days
description: "Number of days to look back (default: 1)"
required: false
default: "1"
---
# Standup Report Generator
Generate a concise standup report based on the last {{ days }} day(s)
of git activity in this repository.
## Steps
1. Run `git log --oneline --since="{{ days }} days ago" --author`
to find the current user's recent commits.
2. Run `git diff --stat HEAD~10` to understand the scope of changes.
3. Check for any open branches with `git branch`.
## Output Format
### Standup - [Today's Date]
**Yesterday / Recent Work:**
- Bullet points derived from commit messages, grouped by feature/area
**Today / Next Steps:**
- Inferred from in-progress branches and recent commit patterns
**Blockers:**
- Any merge conflicts detected, failing CI references, or TODO items
found in recently modified files
Command: Changelog Generator
---
name: changelog
description: "Generate a changelog entry from commits since the last tag"
arguments:
- name: version
description: "The new version number for this changelog entry"
required: true
- name: format
description: "Output format: keepachangelog or conventional"
required: false
default: "keepachangelog"
---
# Changelog Generator
Generate a changelog entry for version {{ version }} using the
{{ format }} format.
## Steps
1. Find the most recent git tag: `git describe --tags --abbrev=0`
2. Get all commits since that tag:
`git log [last-tag]..HEAD --oneline --no-merges`
3. Categorize each commit:
- **Added**: New features (feat:, add:)
- **Changed**: Modifications (refactor:, update:, change:)
- **Fixed**: Bug fixes (fix:, bugfix:)
- **Removed**: Deletions (remove:, delete:)
- **Security**: Security patches (security:, vuln:)
4. Format according to the {{ format }} standard.
5. Output the complete changelog entry ready to prepend to CHANGELOG.md.
The arguments array in the frontmatter defines what parameters the command accepts. Required arguments must be provided when invoking the command. Optional arguments use their default value when omitted.
Step 4: Building an Agent
Agents are subagent profiles that Claude can spawn for specialized tasks. The agent definition controls the subagent's system prompt and which tools it can access.
---
name: test-writer
description: "Specialized agent for generating comprehensive test suites"
system-prompt: |
You are a test engineering specialist. Your sole purpose is to write
thorough, maintainable tests. You follow these principles:
- Test behavior, not implementation details
- Each test should test exactly one thing
- Use descriptive test names that read as specifications
- Prefer integration tests over unit tests for API routes
- Always include edge cases: empty inputs, null values, boundaries
- Mock external dependencies, never mock the system under test
- Follow the Arrange-Act-Assert pattern consistently
allowed-tools:
- Read
- Grep
- Glob
- Write
- Edit
- Bash
---
# Test Writer Agent
## Triggering Conditions
This agent should be spawned when:
- The user asks to write tests for a specific file or module
- The user asks for comprehensive test coverage
- A new feature has been implemented and needs test coverage
## Workflow
1. Read the source file(s) to understand the API/interface
2. Identify the testing framework in use (check package.json, config files)
3. Read existing test files to match project conventions
4. Generate tests covering:
- Happy path for each public function/endpoint
- Error cases and validation failures
- Edge cases and boundary conditions
- Integration points
5. Write the test file(s) to the appropriate location
The allowed-tools restriction is important for security and focus. A test-writing agent does not need network access or the ability to run arbitrary commands beyond what is necessary. Restricting tools keeps the agent focused and prevents unintended side effects.
Step 5: Implementing a Hook
Hooks fire on specific Claude Code events. A hook can inspect and modify behavior before or after tool execution, at session boundaries, or when certain conditions arise.
---
name: file-guard
event: PreToolUse
matcher: "Edit|Write"
---
# File Guard Hook
Before any file edit or write operation, check the target file path.
## Blocked Patterns
BLOCK the operation and warn the user if the target path matches any of:
- `*.env` or `.env.*` (environment files with potential secrets)
- `**/credentials*` or `**/secrets*` (credential files)
- `**/.git/**` (git internal files)
- `**/node_modules/**` (dependency files that should not be manually edited)
- `**/package-lock.json` or `**/yarn.lock` (lock files)
## Allowed Exceptions
ALLOW the operation if the user has explicitly confirmed they want to
modify the file in their most recent message.
## Response Format
When blocking, respond with:
"BLOCKED: [filename] is a protected file ([reason]). If you intended
to modify this file, please confirm explicitly."
The matcher field uses a pipe-separated list of tool names. This hook fires before any Edit or Write tool call, giving it a chance to inspect the target path and block dangerous modifications.
Step 6: Testing and Iterating
With all components written, test the plugin by starting a new Claude Code session. Here is a systematic testing checklist:
- Verify plugin loads — Start a session and check that Claude recognizes the plugin. Ask "What plugins are loaded?" or "List my available commands."
- Test each skill — Trigger each skill with natural language that matches its
when-to-usefield. Verify it activates and produces the expected output format. - Test each command — Invoke each command with
/standupand/changelog v2.0.0. Verify arguments are parsed correctly. - Test the agent — Ask Claude to write tests for a file. Verify the test-writer agent is spawned with the correct restrictions.
- Test the hook — Try to edit a
.envfile. Verify the hook blocks the operation. - Test edge cases — Try invoking commands with missing required arguments. Try triggering skills with ambiguous prompts.
Common Issues and Fixes
- Skill does not activate — Refine the
when-to-usedescription. Make it more specific and include more trigger phrasings. - Command argument not parsed — Verify the argument name in the frontmatter matches the template variable in the body exactly.
- Hook fires too broadly — Narrow the
matcherfield. Use exact tool names rather than broad patterns. - Plugin not loading — Check that
plugin.jsonis valid JSON. Verify all component file paths in the manifest exist and are spelled correctly. - Agent tool restriction ignored — Ensure the
allowed-toolslist uses the exact tool names as they appear in Claude Code (case-sensitive).
Complete Plugin Structure
After completing all steps, your plugin directory should look like this:
~/.claude/plugins/dev-workflow/
plugin.json
skills/
analyze-deps.md
migration-guide.md
commands/
standup.md
changelog.md
agents/
test-writer.md
hooks/
file-guard.md
This is a fully functional plugin with two skills, two commands, one agent, and one hook. Each component demonstrates a different aspect of the plugin system. Use this as a template when building your own plugins, adapting the specific components to your workflow needs.
Key Takeaways
- Start by scaffolding the directory structure and manifest before writing any components.
- Skills use
when-to-usefor automatic routing; commands use explicit/slashinvocation. - Agent definitions control system prompts and tool access for specialized subagents.
- Hooks bind to lifecycle events and can block, modify, or augment tool behavior.
- Test every component individually before relying on the plugin in real workflows.
- Iterate on
when-to-usedescriptions andmatcherpatterns based on real usage.