SpecMatter field notes

Claude Code / plugin loading field notes

Claude Code Plugins: install, validate, and load one safely

Short answer: a Claude Code plugin is one directory that can package skills, subagents, hooks, MCP servers, and commands. Its usual identity lives in .claude-plugin/plugin.json. Install a shared plugin from a marketplace when you want updates and a persistent scope; use --plugin-dir when you are testing a local copy for one session. Validate the directory first, then inspect what it adds before enabling it broadly.

On this Windows machine, Claude Code 2.1.283 accepted a minimal local plugin, rejected broken JSON, rejected a directory with no manifest, and loaded one skill from the valid fixture with --plugin-dir. The test made no model request and installed nothing persistently.

A local plugin folder passes validation, loads for one session, and exposes one skill while bad JSON and a missing manifest fail
The tested path: validate a local directory, load it once, and verify discovery in the debug log.

Local test: Windows 11, Claude Code 2.1.283, 2026-09-28. No Claude login, API key, marketplace install, model request, or charge.

What a plugin changes

ComponentWhat the plugin can addWhat to review
SkillInstructions that load when relevant or run as a namespaced commandName, description, trigger breadth, and full instructions
SubagentA delegated role with its own prompt and tool policyAllowed tools, model choice, and write authority
HookA handler that runs on lifecycle eventsEvent, matcher, executable, arguments, and failure behavior
MCP serverExternal tools and data connections available to sessionsProcess, network access, credentials, and tool descriptions
CommandA repeatable workflow exposed under the plugin namespaceArguments, side effects, and files it may change

The practical difference from a standalone component is packaging. A single local skill can live on its own. A plugin becomes useful when several related components should travel together, share a release, or be installed consistently across projects.

The three installation scopes

ScopeWhere it appliesSettings recordUse it when
UserEvery project for one user on this machine~/.claude/settings.jsonYou personally use the plugin everywhere
ProjectEveryone working in one repository.claude/settings.jsonThe repository depends on a shared workflow
LocalOne user in one repository.claude/settings.local.jsonYou are evaluating it without changing team settings
One sessionOnly the current launchNo persistent installYou are developing or auditing a local copy
claude plugin install <plugin>@<marketplace> --scope local
claude --plugin-dir .\path\to\plugin

The first command installs and records a scope. The second loads a path for one launch. That distinction matters when you are testing an unknown manifest or iterating on a plugin you own.

A local validation test with three fixtures

The valid fixture contained one manifest and one skill:

valid/
├── .claude-plugin/
│   └── plugin.json
└── skills/
    └── evidence-check/
        └── SKILL.md

The same Claude Code binary checked that fixture, a manifest with broken JSON, and a directory with no manifest:

claude plugin validate .\valid --json
claude plugin validate .\invalid-json --json
claude plugin validate .\missing-manifest --json
FixtureExitObserved resultWhat it proves
Minimal valid plugin0success: true; warning that author metadata was absentThe manifest parsed and passed non-strict validation
Broken JSON1Invalid JSON syntax: JSON Parse error: Expected '}'Manifest parsing stops before component discovery
No manifest1Expected .claude-plugin/marketplace.json or .claude-plugin/plugin.jsonA plain directory is not accepted as this plugin fixture

Download the validation observations (CSV)

What one-session loading actually showed

claude --init-only \
  --plugin-dir .\valid \
  --debug-file .\plugin-load-debug.log

The process exited 0. Its debug log recorded these checkpoints:

--plugin-dir ...\valid is one plugin
Loaded inline plugin from path: specmatter-plugin-lab
Loaded 1 directory-loaded plugins
Loaded 1 skills from plugin specmatter-plugin-lab default directory
Total plugin skills loaded: 1
Claim boundary: this proves manifest validation, directory discovery, and skill discovery in one unauthenticated initialization. It does not prove that the skill was invoked, that a hook fired, that an MCP server connected, or that a marketplace installation would behave identically.

A short audit before installation

  1. Read .claude-plugin/plugin.json and identify every declared component and dependency.
  2. Open hooks and MCP configuration before running the plugin. Those components can start processes or connect to external systems.
  3. Run claude plugin validate <path> --strict when warnings should fail a CI check.
  4. Use --plugin-dir for a local copy and save the debug log when you need proof of discovery.
  5. Choose the narrowest persistent scope that matches the actual audience.
  6. After installation, use claude plugin details <name> to inspect component inventory and projected context cost.

An enabled plugin can contribute names and descriptions to every turn, run hooks at lifecycle events, and start plugin MCP servers. The review should cover both visible commands and background behavior.

FAQ

Does a Claude Code plugin require a marketplace?

No. A marketplace is the normal distribution catalog, but a local plugin can be loaded for one session with --plugin-dir.

Is a plugin the same thing as an MCP server?

No. An MCP server is one possible plugin component. A plugin can package MCP together with skills, agents, hooks, or commands.

Did this test install or run a third-party plugin?

No. It used a small local fixture written for this test. Nothing was installed persistently, and no model request was sent.

Was plugin invocation tested?

No. Discovery was tested. Invocation remains untested because there was no authenticated model session.

Sources and related field notes

Official documentation checked 2026-09-28. Local observations were produced with Claude Code 2.1.283. SpecMatter is not affiliated with Anthropic.