writing-plugins

How to design and build plugins -- architecture decisions, component selection, file structure, manifest configuration, marketplace publishing. Primarily Claude Code (.claude-plugin/plugin.json); the same architecture maps to Codex CLI (.codex-plugin/plugin.json) and Antigravity extensions. Use when planning, creating, or reviewing a plugin.

10 stars

Best use case

writing-plugins is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

How to design and build plugins -- architecture decisions, component selection, file structure, manifest configuration, marketplace publishing. Primarily Claude Code (.claude-plugin/plugin.json); the same architecture maps to Codex CLI (.codex-plugin/plugin.json) and Antigravity extensions. Use when planning, creating, or reviewing a plugin.

Teams using writing-plugins should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/writing-plugins/SKILL.md --create-dirs "https://raw.githubusercontent.com/xiaolai/nlpm-for-claude/main/codex/skills/writing-plugins/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/writing-plugins/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How writing-plugins Compares

Feature / Agentwriting-pluginsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

How to design and build plugins -- architecture decisions, component selection, file structure, manifest configuration, marketplace publishing. Primarily Claude Code (.claude-plugin/plugin.json); the same architecture maps to Codex CLI (.codex-plugin/plugin.json) and Antigravity extensions. Use when planning, creating, or reviewing a plugin.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Writing Plugins

> Scope: covers plugin design and architecture. The examples use the **Claude Code** layout (`.claude-plugin/plugin.json` + auto-discovered `commands/`, `agents/`, `skills/`, `hooks/`). The same component-selection and architecture reasoning maps to the other tools — only the manifest path and packaging differ:
> - **Codex CLI**: `.codex-plugin/plugin.json` manifest + `.agents/plugins/marketplace.json`; skills live at `.agents/skills/`. See [[nlpm:conventions-codex]].
> - **Antigravity**: `gemini-extension.json` (becoming "Antigravity plugins"); skills at `.agent/skills/`. See [[nlpm:conventions-antigravity]].
> - **Cross-tool skills**: a `SKILL.md` collection with no plugin wrapper installs into any tool via `npx skills add`. See [[writing-skills]].
>
> For individual component authoring, see [[writing-skills]], [[writing-agents]], [[writing-hooks]], [[writing-rules]].

## 1. Plugin = Commands + Agents + Skills + Hooks

A plugin is a collection of NL artifacts that work together. Before writing anything, decide which components you need.

### Component Selection Guide

| User need | Component | Example |
|-----------|-----------|---------|
| User runs a slash command | Command | `/nlpm:score path/to/file.md` |
| AI works autonomously on a task | Agent | Security scanner dispatched by a command |
| Domain knowledge for agents/Claude | Skill | SKILL.md with patterns and decision tables |
| Something must happen automatically on events | Hook | Lint-on-save, block force push |
| External service integration | MCP server (`.mcp.json`) | GitHub API, Slack notifications |

### Minimum Viable Plugin

The smallest useful plugin has **one component**:

```
my-plugin/
  .claude-plugin/
    plugin.json
  commands/
    do-thing.md
```

Don't add agents, skills, or hooks until you need them. Each component adds maintenance burden.

## 2. Architecture Patterns

### Pattern: Single Command (simplest)

Command does everything itself. No agents, no orchestration.

```
Command receives input --> processes --> outputs result
```

**Use when**: task is simple, deterministic, single-step.
**Example**: `loc-guardian /scan` -- counts lines, checks limits, reports.

**File structure**:
```
my-plugin/
  .claude-plugin/plugin.json
  commands/do-thing.md
```

### Pattern: Command + Agent

Command parses input and dispatches one agent for heavy work.

```
Command parses input --> dispatches agent --> formats output
```

**Use when**: task requires AI judgment but has a clear entry point.
**Example**: `/nlpm:score` dispatches a scorer agent.

**File structure**:
```
my-plugin/
  .claude-plugin/plugin.json
  commands/analyze.md
  agents/analyzer.md
```

### Pattern: Command + Multiple Agents (parallel)

Command dispatches 2–6 agents in parallel, synthesizes results.

```
Command --> agent-1 (security)
        --> agent-2 (performance)    --> synthesize --> output
        --> agent-3 (architecture)
```

**Use when**: multiple independent analyses of the same input.
**Example**: grill dispatches 6 review agents in parallel.

**File structure**:
```
my-plugin/
  .claude-plugin/plugin.json
  commands/review.md
  agents/
    security-agent.md
    performance-agent.md
    architecture-agent.md
```

### Pattern: Command + Agent Pipeline (sequential)

Each agent feeds into the next. Stages have different model requirements.

```
Command --> parse (haiku) --> analyze (sonnet) --> QC (sonnet) --> output
```

**Use when**: multi-phase processing where each phase depends on the previous.
**Example**: reading-assistant's 4-phase pipeline.

**File structure**:
```
my-plugin/
  .claude-plugin/plugin.json
  commands/process.md
  agents/
    parser.md       # haiku
    analyzer.md     # sonnet
    qc-agent.md     # sonnet
```

### Pattern: Hooks Only (no commands)

Plugin enforces policy silently via hooks. No user-facing commands.

```
Event fires --> hook checks --> allow/deny/advise
```

**Use when**: enforcement should be automatic, not user-initiated.
**Example**: tdd-guardian's pre-commit quality gate.

**File structure**:
```
my-plugin/
  .claude-plugin/plugin.json
  hooks/hooks.json
  scripts/check.sh
```

### Pattern Selection Matrix

| Question | Yes --> | No --> |
|----------|---------|--------|
| Does the user explicitly trigger it? | Needs a command | Hooks only |
| Does it require AI judgment? | Needs agents | Command-only or hooks |
| Are there independent sub-analyses? | Parallel agents | Sequential or single agent |
| Does each step depend on the previous? | Sequential pipeline | Parallel or single |
| Should it run automatically on events? | Add hooks | Commands only |
| Does Claude need domain knowledge? | Add skills | No skills needed |

## 3. The plugin.json Manifest

### Required Fields

Only `name` is strictly required:

```json
{
  "name": "my-plugin"
}
```

### Recommended Fields

Ship with these for discoverability and marketplace listing:

```json
{
  "name": "my-plugin",
  "version": "0.1.0",
  "description": "What this plugin does in one sentence",
  "author": { "name": "your-name" },
  "license": "MIT",
  "keywords": ["relevant", "search", "terms"],
  "category": "developer-tools"
}
```

### Field Reference

| Field | Purpose | Example |
|-------|---------|---------|
| `name` | Unique identifier, used in slash commands | `"nlpm"` |
| `version` | Semver, used by marketplace and update checks | `"0.1.0"` |
| `description` | One-line summary for marketplace listing | `"NL programming quality tools"` |
| `author.name` | Creator attribution | `"xiaolai"` |
| `license` | Open source license | `"MIT"` |
| `keywords` | Search terms for marketplace discovery | `["linter", "quality"]` |
| `category` | Marketplace category | `"developer-tools"` |

## 4. File Structure

### Full Plugin Layout

```
my-plugin/
  .claude-plugin/
    plugin.json              # manifest (required)
    marketplace.json         # for marketplace publishing
  commands/                  # auto-discovered by Claude Code
    do-thing.md              # user-invocable: /plugin:do-thing
    advanced-thing.md
    shared/                  # non-invocable partials
      common-logic.md        # user-invocable: false
      format-output.md
  agents/                    # auto-discovered
    worker.md
    reviewer.md
  skills/                    # auto-discovered
    my-plugin/
      domain-knowledge/
        SKILL.md
      advanced-topic/
        SKILL.md
        references/
          deep-dive.md
  hooks/
    hooks.json               # hook definitions
  scripts/                   # hook scripts, utilities
    check.sh
    validate.sh
  CLAUDE.md                  # architecture guide (for Claude)
  README.md                  # user documentation (for humans)
  LICENSE
```

### Directory Conventions

| Directory | Auto-discovered? | What goes here |
|-----------|-----------------|----------------|
| `.claude-plugin/` | Yes (manifest) | Plugin metadata |
| `commands/` | Yes | Slash command definitions |
| `commands/shared/` | Yes (but not invocable) | Shared command logic |
| `agents/` | Yes | Agent definitions |
| `skills/` | Yes | Domain knowledge |
| `hooks/` | Yes (`hooks.json`) | Event hooks |
| `scripts/` | No | Shell scripts, utilities |

### Naming Conventions

| Component | File naming | Example |
|-----------|------------|---------|
| Commands | kebab-case, descriptive verb | `scan-files.md`, `generate-report.md` |
| Agents | kebab-case, role-noun | `security-reviewer.md`, `parser.md` |
| Skills | kebab-case directory, always `SKILL.md` | `skills/my-plugin/react-patterns/SKILL.md` |
| Hook scripts | kebab-case, descriptive | `check-loc.sh`, `validate-config.sh` |

## 5. Versioning

### Semver Rules

| Change type | Bump | Example |
|------------|------|---------|
| Bug fixes, typo corrections, penalty adjustments | Patch: 0.1.0 -> 0.1.1 | Fix scoring formula |
| New commands, new agents, new features | Minor: 0.1.0 -> 0.2.0 | Add `/plugin:export` command |
| Breaking changes (renamed commands, removed features) | Major: 0.1.0 -> 1.0.0 | Rename `/scan` to `/analyze` |

### Four-Place Update

When bumping version, update in **four** places:

| Location | File | Field |
|----------|------|-------|
| 1. Plugin manifest | `.claude-plugin/plugin.json` | `version` |
| 2. Plugin marketplace | `.claude-plugin/marketplace.json` | `version` in the plugin's entry |
| 3. Central marketplace manifest | `~/.claude/plugins/marketplaces/xiaolai/.claude-plugin/marketplace.json` | `version` |
| 4. Central marketplace README | `~/.claude/plugins/marketplaces/xiaolai/README.md` | Version in the table |

**Order**: push plugin repo first, then update central marketplace. The marketplace points to the repo -- if the repo isn't updated yet, users pull stale code.

## 6. CLAUDE.md for Plugins

Your plugin's CLAUDE.md is for **Claude** (the AI), not the user. It tells Claude how the plugin's components relate to each other.

### What to Include

```markdown
# my-plugin

## Architecture
Brief description of what the plugin does and how components interact.

## Components

### Commands
| Command | Purpose |
|---------|---------|
| /plugin:scan | Discovers and inventories files |
| /plugin:fix | Auto-fixes issues found by scan |

### Agents
| Agent | Model | Role |
|-------|-------|------|
| scanner | haiku | Mechanical file discovery |
| fixer | sonnet | AI-powered fix generation |

### Conventions
- All agents output findings in severity-tagged format
- Scanner runs before fixer (sequential dependency)
- Hook scripts use fail-open pattern
```

### What NOT to Include

- Installation instructions (those go in README.md)
- User-facing documentation (README.md)
- Changelog (CHANGELOG.md or git history)
- Contributing guidelines (CONTRIBUTING.md)

## 7. Shared Partials

Extract repeated logic into `commands/shared/*.md` with `user-invocable: false`.

### Partial Frontmatter

```yaml
---
user-invocable: false
description: "Shared config loading logic"
---
```

### Good Candidates for Extraction

| Partial | Content | When to extract |
|---------|---------|----------------|
| `shared/load-config.md` | Read and validate config file | 3+ commands need config |
| `shared/discover-files.md` | Find target files by pattern | 3+ commands scan files |
| `shared/validate-prereqs.md` | Check tool availability | 2+ commands need same tools |
| `shared/format-report.md` | Report header, footer, severity format | 3+ commands output reports |

### When NOT to Extract

- Logic used by only 1 command (premature abstraction)
- Simple logic under 10 lines (duplication is fine)
- Logic that differs slightly between commands (forced generalization adds complexity)

## 8. Testing Your Plugin

### Pre-Publish Checklist

| Check | How | Pass criteria |
|-------|-----|---------------|
| Structure validation | `claude plugin validate /path/to/plugin` | No errors |
| Command: no args | Run each command with no arguments | Helpful error or usage message |
| Command: normal args | Run each command with typical input | Correct output |
| Command: edge cases | Empty files, huge files, missing files | Graceful error handling |
| Agent triggering | Try queries that should and shouldn't trigger | Correct dispatch decisions |
| Hook scripts | `chmod +x` check, run with test JSON | Valid JSON output |
| Hook fail-open | Kill script mid-execution | Action is allowed |

### Testing Agent Triggers

For each agent, test with 3 types of queries:

| Query type | Expected | Example |
|-----------|----------|---------|
| Direct match | Agent triggers | "Scan this code for security issues" |
| Adjacent topic | Agent may or may not trigger | "Is this code okay?" |
| Unrelated | Agent does NOT trigger | "What's the weather?" |

## 9. Marketplace Publishing

1. Push your plugin repo to GitHub
2. Add entry to central `marketplace.json` (name, source, description, version, author, license, keywords, category)
3. Add row to central marketplace `README.md` version table
4. Commit and push the central marketplace repo
5. Verify: `claude plugin install my-plugin@xiaolai --scope project`

**Pre-publish checks**: `claude plugin validate .`, verify no hardcoded paths (`grep -r '/Users/' commands/ agents/ hooks/`), verify all scripts executable, verify version matches in all 4 locations.

## 10. Common Mistakes

| Mistake | Impact | Fix |
|---------|--------|-----|
| Commands that do too much | Hard to maintain, unreliable | Split into focused commands |
| Agents without examples | 40% trigger accuracy | Add 2-3 specific scenario examples |
| Skills over 500 lines | Context bloat, slow loading | Extract to references/ subdirectory |
| Hooks that block without explanation | Frustrating UX | Always include `permissionDecisionReason` |
| No CLAUDE.md | Claude doesn't understand plugin architecture | Add architecture overview |
| README documents internals | Users confused by implementation details | README = user guide, CLAUDE.md = internals |
| Hardcoded paths | Breaks on other machines | Use `${CLAUDE_PLUGIN_ROOT}` everywhere |
| No error handling in commands | Silent failures | Add explicit error cases |
| Version not updated in all 4 places | Marketplace shows wrong version | Use the four-place update checklist |
| Premature extraction into shared/ | Over-abstracted, harder to understand | Extract only when 3+ consumers exist |

Related Skills

We are still matching the closest adjacent skills for this page. In the meantime, continue through the full directory.