Module 5: Plugins — Creating and Distributing

3. Creating a Plugin from a Scaffold — Structure, Manifest, and Local Testing

3. Creating a Plugin from a Scaffold — Structure, Manifest, and Local Testing

Description

You understand the anatomy of a plugin. Now you build it. In this capsule you create a plugin from scratch — from npm init to verifying that its agents load correctly in a Claude Code session. You're not going to publish it yet (that's capsule 04). First you create it, structure it, and test it locally.

The process follows a natural sequence: initialize the npm package, create the directory structure, write the manifest with the correct fields, create the agent files designed for distribution, add skills, install locally with claude plugins add ./, and verify that everything works. Each step has its verification — you don't move to the next until the current one works.

By the end you'll have a functional plugin installed locally, with its agents available in your Claude Code session and its skill preloaded. Ready to publish in capsule 04.


⚠️ EXPERIMENTAL FEATURE

The claude plugins add commands and the automatic loading of plugin components reflect the functionality available as of March 2026. If the commands change, the principles (create an npm package with a standard structure, test locally before publishing) hold.

Last check: March 2026


Step 1: Initialize the Package

Create the directory and the package.json

mkdir -p ~/plugins-workshop/my-quality-plugin
cd ~/plugins-workshop/my-quality-plugin

npm init -y

npm init -y generates a basic package.json. Now adapt it for a plugin:

{
  "name": "@your-org/code-quality-plugin",
  "version": "1.0.0",
  "description": "Code quality agents: reviewer and implementer with team conventions",
  "claudeCodePlugin": true,
  "files": [
    "agents",
    "skills"
  ],
  "keywords": [
    "claude-code",
    "plugin",
    "code-quality",
    "reviewer"
  ],
  "author": "Your Name",
  "license": "MIT"
}

Verify the manifest

cat package.json | grep claudeCodePlugin

If you see "claudeCodePlugin": true, the manifest is correct.

Fields you can omit

The package.json generated by npm init -y includes fields a plugin doesn't need:

{
  "main": "index.js",       // ← Not needed (it's not a JS library)
  "scripts": {
    "test": "echo ..."      // ← Optional (useful for CI but not required)
  }
}

You can remove them or leave them — they don't affect the plugin's operation.


Step 2: Create the Directory Structure

mkdir -p agents skills

Resulting structure:

my-quality-plugin/
├── package.json
├── agents/          ← Empty for now
└── skills/          ← Empty for now

Verify

ls -la

You should see package.json, agents/, and skills/.


Step 3: Create the First Agent File

The reviewer agent

Create agents/reviewer.md — a read-only agent that analyzes code without modifying it:

---
name: reviewer
description: Reviews code for quality, security issues, and convention compliance. Read-only agent that produces structured reports with severity levels.
tools: Read, Glob, Grep
model: sonnet
maxTurns: 20
---

## Role

You are a code reviewer. You analyze code for quality issues,
security vulnerabilities, and convention compliance. You NEVER
modify files — you only read and report.

## What You Review

1. **Code Quality** — Duplication, complexity, naming, error handling
2. **Security** — Hardcoded secrets, injection, unvalidated input
3. **Conventions** — Read CLAUDE.md, check file organization and naming

## Process

1. Read CLAUDE.md for project conventions
2. Use Glob to discover project structure
3. Analyze each file against quality, security, and convention criteria
4. Produce structured report

## Output Format

### Code Review Report
**Scope:** [directories/files reviewed]
**Issues found:** [critical: N, warning: N, info: N]

#### Critical Issues
- **[file:line]** — [issue] — Risk: [risk] — Fix: [action]

#### Warnings
- **[file:line]** — [issue] — Recommendation: [suggestion]

#### Info
- **[file:line]** — [observation]

**Overall Assessment:** PASS | NEEDS_WORK | CRITICAL_ISSUES

Why this agent file is plugin-ready

  1. No hardcoded paths — It discovers the structure with Glob and reads CLAUDE.md
  2. Not framework-specific — It works with Python, JavaScript, Go, any language
  3. Read-only — Only Read, Glob, Grep in tools, never modifies files
  4. Structured output — Consistent format any team can use
  5. Self-contained — It doesn't reference other agent files or external files

Step 4: Create the Second Agent File

The implementer agent

Create agents/implementer.md — an agent that implements changes following conventions:

---
name: implementer
description: Implements code changes following project conventions. Reports all changes with rationale.
tools: Read, Write, Edit, Glob, Grep, Bash
model: sonnet
maxTurns: 25
---

## Role

You implement code changes following project conventions.
You report every change with rationale.

## Before Implementing

1. Read CLAUDE.md for project conventions
2. Examine existing code patterns in the relevant directory
3. Check for existing utilities to reuse

## Standards

1. Follow existing patterns — match surrounding code style
2. One responsibility per function
3. Error handling for every operation that can fail
4. Type safety where the project uses it
5. No dead code — no commented-out code or unused imports

## Output Format

### Implementation Report
**Task:** [description]
**Status:** DONE | PARTIAL | BLOCKED
**Files created:** [path] — [purpose]
**Files modified:** [path] — [what and why]
**Decisions made:** [decision] — [rationale]

Step 5: Create the Skill File

api-conventions skill

Create skills/api-conventions.md — a domain knowledge file that agents consume as context:

---
name: api-conventions
description: Team API conventions covering endpoint design, response format, error handling, and authentication patterns.
---

## Endpoint Design
- URLs: kebab-case (`/user-profiles`), plural nouns (`/users`)
- Nested resources: `/users/{id}/posts`
- HTTP methods: GET (read), POST (create→201), PUT (full update), PATCH (partial), DELETE (→204)

## Response Format
- Success: `{ "data": {...}, "meta": { "timestamp": "...", "request_id": "..." } }`
- Error: `{ "error": { "code": "VALIDATION_ERROR", "message": "...", "details": [...] } }`
- Status codes: 200/201/204 for success, 400/401/403/404/422/500 for errors

## Authentication
- Bearer token in Authorization header (JWT)
- Claims: sub, role, exp, iat

## Pagination
- Cursor-based: `?cursor=<opaque>&limit=20` (max 100)
- Response includes `next_cursor` in meta

## Validation
- Validate all input at the API boundary with schema validation
- Return 400 with field-level error details

Step 6: Verify the Structure

find . -type f | head -20

You should see:

./package.json
./agents/reviewer.md
./agents/implementer.md
./skills/api-conventions.md

Structure checklist

✅ package.json with claudeCodePlugin: true
✅ package.json with files: ["agents", "skills"]
✅ agents/reviewer.md with valid YAML frontmatter
✅ agents/implementer.md with valid YAML frontmatter
✅ skills/api-conventions.md with valid YAML frontmatter
✅ No hardcoded paths in the agent files
✅ No specific-project dependencies

Step 7: Install Locally

The local installation command

cd ~/your-test-project

claude plugins add ~/plugins-workshop/my-quality-plugin

This command tells Claude Code: "load this plugin from a local path." It's not published to any registry — it's a direct installation from the filesystem.

Verify the installation

claude plugins list

You should see your plugin listed:

Installed plugins:
  @your-org/code-quality-plugin (1.0.0) — local
    agents: reviewer, implementer
    skills: api-conventions

Verify that the agents are available

Start a Claude Code session:

claude

Inside the session, verify:

/agents

You should see reviewer and implementer in the list of available agents, marked as coming from the plugin.


Step 8: Test the Plugin's Agents

Testing the reviewer

In the Claude Code session:

Use the reviewer agent to analyze this project.
Focus on the most recently modified files.

What you expect: The reviewer reads CLAUDE.md, discovers the structure, analyzes files, and produces a report with the format defined in its agent file.

What you verify:

  • ✅ The reviewer is invoked correctly
  • ✅ It reads CLAUDE.md for context
  • ✅ It produces the defined report format
  • ✅ It doesn't try to modify files (only Read, Glob, Grep)

Testing the implementer

Use the implementer agent to create a helper function
that validates email format. Place it where it makes sense
according to the project structure.

What you expect: The implementer reads the structure, identifies the correct directory, creates the file with project conventions, and reports what it did.

What you verify:

  • ✅ The implementer is invoked correctly
  • ✅ It reads the project before implementing
  • ✅ It follows the existing conventions
  • ✅ It produces the defined report format

Testing the skill

Use the reviewer agent to analyze this project's API endpoints
against the team's conventions.

What you expect: The reviewer applies the api-conventions conventions (kebab-case, response format, status codes) when analyzing the endpoints.

What you verify:

  • ✅ The reviewer mentions the skill's conventions (kebab-case, response format)
  • ✅ The skill's rules are applied in the review
  • ✅ The report references the team's specific conventions

Step 9: Iterate on the Plugin

Local development cycle

1. Edit the agent file in ~/plugins-workshop/my-quality-plugin/agents/
2. Reinstall: claude plugins add ~/plugins-workshop/my-quality-plugin
3. Test in a new Claude Code session
4. Repeat until satisfied

Common adjustments after the first test

If the reviewer is too verbose:

## Output Rules
- Maximum 5 critical issues, 10 warnings, 5 info
- Each issue description: maximum 2 lines
- Skip issues with severity below WARNING unless asked

If the implementer doesn't follow the project conventions:

## MANDATORY First Steps
1. Read CLAUDE.md COMPLETELY before any implementation
2. List at least 3 conventions found in CLAUDE.md
3. Read 2 existing files similar to what you'll create
4. Match their patterns EXACTLY

If the skill is too generic:

Add specific sections to the skill with more concrete rules. Skills can be as detailed as you need — there's no length limit.


Comparison: Local Plugin vs Published Plugin

AspectLocal plugin (./path)Published plugin (registry)
Installationclaude plugins add ./pathclaude plugins add @org/name
UpdateReinstall from pathAutomatic npm update
DistributionShare the directorynpm install from registry
VersioningManual (you change files directly)Semver in package.json
Ideal useDevelopment and testingDistribution to a team
DependenciesThe path must exist on the machineAccessible registry

When to stick with local

  • You're iterating quickly on the agent files
  • Only you use the plugin
  • You don't have access to an npm registry
  • It's a prototype that may change drastically

When to publish

  • The team needs access
  • You want formal versioning
  • You need reproducibility across machines
  • The plugin is stable and tested

Manual Alternative: Setup Script

If claude plugins add isn't available, create an installation script:

#!/bin/bash
# install-quality-plugin.sh

PLUGIN_DIR="$(dirname "$0")"
TARGET="${1:-.}"

echo "Installing code quality plugin to $TARGET"

mkdir -p "$TARGET/.claude/agents"
mkdir -p "$TARGET/.claude/skills"

cp "$PLUGIN_DIR/agents/"*.md "$TARGET/.claude/agents/"
cp "$PLUGIN_DIR/skills/"*.md "$TARGET/.claude/skills/"

echo "Installed:"
echo "  Agents: $(ls "$TARGET/.claude/agents/"*.md | wc -l) files"
echo "  Skills: $(ls "$TARGET/.claude/skills/"*.md | wc -l) files"
echo ""
echo "Done. Start Claude Code to use the new agents."

Usage:

bash ~/plugins-workshop/my-quality-plugin/install-quality-plugin.sh ~/my-project

It's not a formal plugin, but it fulfills the basic distribution function. You lose automatic versioning and dynamic loading, but you gain immediate portability.


Exercises

Exercise 1: Minimal viable plugin (Easy)

Create a plugin with a single agent file that does basic linting (checks naming conventions) and nothing else. Install it locally and verify that the agent appears available.

See solution
mkdir -p ~/mini-plugin/agents
cd ~/mini-plugin

package.json:

{
  "name": "mini-lint-plugin",
  "version": "1.0.0",
  "claudeCodePlugin": true,
  "files": ["agents"]
}

agents/linter.md:

---
name: linter
description: Checks naming conventions across the project. Read-only.
tools: Read, Glob, Grep
model: haiku
maxTurns: 10
---

## Role
Check file names and variable names follow conventions.

## Rules
- Files: kebab-case (my-component.tsx, user-service.py)
- Functions: camelCase (JS/TS) or snake_case (Python)
- Classes: PascalCase
- Constants: UPPER_SNAKE_CASE

## Output
List files/functions that violate conventions with recommended names.
cd ~/your-project
claude plugins add ~/mini-plugin
claude  # start session
# inside: /agents → verify that "linter" appears

Exercise 2: Add a third agent (Easy)

To the quality plugin you created in this capsule, add a third agent file: test-writer.md that generates unit tests based on the existing code. Reinstall and verify.

See solution

agents/test-writer.md:

---
name: test-writer
description: Generates unit tests for existing code. Reads source files and creates corresponding test files.
tools: Read, Write, Glob, Grep, Bash
model: sonnet
maxTurns: 20
---

## Role
Write unit tests for existing functions and classes.

## Process
1. Read CLAUDE.md for testing conventions
2. Discover test framework (pytest, jest, vitest, etc.)
3. Read the source file to test
4. Create test file following project structure
5. Write tests covering: happy path, edge cases, error cases

## Standards
- One test file per source file
- Follow existing test patterns in the project
- Descriptive test names: test_[function]_[scenario]_[expected]
- No mocking unless necessary

## Output
**Source:** [file tested]
**Test file:** [created test file]
**Tests written:** [count]
**Coverage:** [functions/methods covered]

Update the package.json files (it already includes "agents", no change needed).

claude plugins add ~/plugins-workshop/my-quality-plugin

Exercise 3: Multi-section skill (Medium)

Create a skill file python-standards.md covering: naming conventions, import ordering, type hints, docstrings, and error handling — all specific to Python. Add it to the plugin and verify that the reviewer uses it when analyzing Python code.

See solution

skills/python-standards.md:

---
name: python-standards
description: Python coding standards covering naming, imports, type hints, docstrings, and error handling.
---

## Naming
- Functions/variables: snake_case
- Classes: PascalCase
- Constants: UPPER_SNAKE_CASE
- Private: _prefixed
- Dunder methods: __name__

## Import Ordering
1. Standard library (os, sys, pathlib)
2. Third-party (fastapi, pydantic, sqlalchemy)
3. Local imports (from . import, from app import)
Separate each group with a blank line. Use isort.

## Type Hints
- All function parameters: typed
- All return values: typed (use -> None explicitly)
- Use Optional[X] for nullable, not X | None (for 3.9 compat)
- Complex types: define TypeAlias

## Docstrings
- Google style: Args, Returns, Raises sections
- All public functions must have docstrings
- One-line docstrings for obvious helpers

## Error Handling
- Catch specific exceptions, never bare except
- Custom exceptions inherit from app base exception
- Always log before re-raising
- Use contextlib.suppress for intentional ignoring

Verify: claude plugins add ./ → open a session → ask the reviewer to analyze a Python file → it should mention these conventions.

Exercise 4: Plugin with an incorrect structure — diagnosis (Medium)

This plugin doesn't work. Identify all the errors without running anything:

broken-plugin/
├── package.json
├── agent/                    ← note: singular
│   └── reviewer.md
├── skill/                    ← note: singular
│   └── conventions.md
└── src/
    └── helpers.js
{
  "name": "@team/broken plugin",
  "version": "1",
  "claudeCodePlugin": "true",
  "files": ["agent", "skill", "src"]
}

reviewer.md:

name: reviewer
description: Reviews code

You are a reviewer. Read and analyze code.
See solution

Errors found:

  1. agent/ singular → It must be agents/ (plugin convention)
  2. skill/ singular → It must be skills/ (plugin convention)
  3. "name": "@team/broken plugin" → Space in the name not valid → "@team/broken-plugin"
  4. "version": "1" → Semver requires 3 numbers → "1.0.0"
  5. "claudeCodePlugin": "true" → It's a string, must be a boolean → true without quotes
  6. "files": ["agent", "skill", "src"] → Incorrect directories and src isn't a plugin component → ["agents", "skills"]
  7. reviewer.md without YAML frontmatter → Missing the --- delimiter block
  8. reviewer.md without tools field → The agent has no tools defined
  9. src/helpers.js → Not a valid plugin component, shouldn't be distributed

Corrected version:

Rename the directories, fix package.json, add frontmatter to reviewer.md, remove src/.

Exercise 5: Plugin with coordinated reviewer + implementer (Hard)

Modify the plugin's agent files so they work as a flow: the reviewer produces an "Actionable Fixes" section (a table with File, Line, Current, Required, Convention), and the implementer has a "When Receiving a Review Report" section that parses that table and applies fixes in priority order (Critical → Warning).

See solution

Add to the reviewer:

### Actionable Fixes
| File | Line | Current | Required | Convention |

Add to the implementer:

## When Receiving a Review Report
1. Parse "Actionable Fixes" table
2. Prioritize: CRITICAL first, then WARNING
3. For each: read file, apply fix per convention, verify no breaks
4. Report each fix with before/after

Flow: "Use the reviewer to analyze src/" → "Use the implementer to fix these problems: [paste review]"

Exercise 6: Create a professional README.md (Hard)

Write a README.md for the plugin including: description, installation (claude plugins add and local path), agents (capabilities + usage example), skills, workflow (review → fix cycle), and requirements. Maximum 50 lines.

See solution

Include: title, one-liner description, Installation section with both methods, Agents section with a usage example per agent, Skills section with a description, Workflow section with the review→fix cycle, and Requirements (Claude Code + Node.js 18+).


Troubleshooting

Problem 1: "claude plugins add ./path gives a path error"

Symptom: An error indicating the path isn't a valid plugin.

Solution:

  1. Use an absolute path: claude plugins add /Users/you/plugins-workshop/my-plugin
  2. Verify that package.json exists at the root of the path
  3. Verify that claudeCodePlugin: true is present (not as a string "true")

Problem 2: "The plugin's agent doesn't receive the skill's context"

Symptom: The reviewer doesn't apply the api-conventions conventions when analyzing.

Solution:

  1. Verify that skills/ is in the package.json files field
  2. Verify that the skill has YAML frontmatter with name and description
  3. In the agent file, explicitly reference the skill in the system prompt

Problem 3: "After editing an agent file, the changes aren't reflected"

Symptom: You edited agents/reviewer.md but Claude Code uses the previous version.

Solution:

  1. Reinstall the plugin: claude plugins add ./path (overwrites the previous version)
  2. Start a new Claude Code session (plugins load at startup)
  3. Verify the reinstallation: claude plugins list

Summary

  • The process is linear: init → structure → agents → skills → local install → test → iterate
  • npm init -y + claudeCodePlugin: true is all you need for the basic manifest
  • Plugin agent files must be generic — no hardcoded paths, they discover the project via Glob and CLAUDE.md
  • claude plugins add ./path installs from a local directory — ideal for development
  • Testing before publishing is mandatory — verify that the agents load, that the skills preload, and that the reports have the expected format
  • The development cycle is: edit → reinstall → new session → test → repeat
  • A local plugin works identically to a published one — the difference is only the distribution mechanism
  • The manual alternative (setup script + copy) works when claude plugins isn't available

Additional Resources

  1. Claude Code Sub-Agents (Anthropic Docs) — Agent files and YAML frontmatter
  2. Create Custom Subagents — Agent file reference
  3. Claude Code CLI Reference — Plugin commands
  4. npm init Documentation — npm package initialization
  5. npm package.json Files Field — Controlling what gets distributed
  6. Claude Code Best Practices — Best practices for agent files
  7. Semantic Versioning — Plugin versioning
  8. Claude Code Settings — Configuration and permissions

Next capsule: In capsule 04 you'll learn how Claude Code loads plugins dynamically at the start of a session, how version pinning works with semver, how to publish to an npm registry (local and remote), and how to handle updates and breaking changes. Your local plugin becomes a distributable package.