feat(plugins): auto-discover project-scope plugins from <cwd>/.claude/plugins/
Summary
Claude Code 2.1.x requires every plugin to come from a registered marketplace.
Local-path installs (claude plugin install /abs/path/to/plugin) are rejected
with "not found in any configured marketplace". This forces consumers that
want to ship a project-scope plugin (one that lives inside the repo, version-
controlled with the project) to either:
(a) publish it to a remote marketplace just to install it locally, or
(b) build a wrapping marketplace at <repo>/.claude/<wrapping>/marketplace.json,
invoke claude plugin marketplace add/install/update on every apply, and
let CC own the materialized copy in its cache.
The wrapping-marketplace pattern is what claude-devkit (a Conventional Commits
- pnpm-workspace ParisGroup tool) currently does — it works, but the indirection
is operator-visible: claude plugin list shows baseline-filtered@devkit-managed-<slug>,
not the conceptually-cleaner baseline-filtered.
Proposal
Add project-scope plugin auto-discovery: when Claude Code starts up in a
working directory, walk up from <cwd> (same walk-up that locates<repo>/.claude/settings.json) and load every plugin found at<repo>/.claude/plugins/<plugin-name>/.claude-plugin/plugin.json.
Plugins discovered this way are:
- Implicit (no
claude plugin marketplace add/installrequired) - Project-scoped (only loaded when CC's
cwdis under that<repo>) - Lower-precedence than user-scope marketplace plugins (so an operator
can override a project plugin by installing the same name user-scope)
- Visible in
claude plugin listwith a clear origin marker (e.g.
(project) suffix), distinct from user-scope or marketplace-scope plugins
This is functionally equivalent to how <repo>/.claude/settings.json is
already loaded — same discovery, same scope, same precedence story —
extended to plugin manifests.
Use case
claude-devkit ships a managed view of the upstream pg-baseline plugin to<repo>/.claude/plugins/baseline-filtered/ based on the operator's<repo>/devkit.config.yaml (asset allowlist + per-repo overrides). Today,
the only way CC sees that view is the wrapping-marketplace dance described
above. With auto-discovery, the wrapping marketplace would become
unnecessary: devkit apply would write the view to <repo>/.claude/plugins/
and the next CC session would pick it up.
We expect this to be useful for any project-scope tooling that wants to
ship project-specific skills/commands/agents without pulling in a remote
marketplace as a deployment dependency.
Compatibility
- No breaking change. Existing marketplace-scope and user-scope plugins
continue to load identically. Auto-discovered project plugins only fill
the "no current way to ship a project plugin locally" gap.
- No CLI-flag change required. The discovery is implicit; the operator
doesn't run any new command. (If preferred, the behavior could be gated
on <repo>/.claude/settings.json having a "plugins.auto_discover": key, but the default-on case feels more aligned with how
true
settings.json is already discovered.)
- Precedence is deterministic. User-scope > marketplace > project.
An operator who wants to override a project plugin installs the same name
user-scope.
Alternatives considered (and why they fall short)
claude plugin install <local-path>accepting a directory path. Tried
in claude-devkit Plan 6 brainstorming; CC 2.1.138 rejects with
"not found in any configured marketplace". Would require new CLI surface
AND a runtime model that allows non-marketplace plugins to exist.
- Symlinking the project view into
~/.claude/plugins/cache/. Brittle —
CC re-resolves the cache on update and would overwrite the symlink.
- Wrapping marketplace (status quo). Works, but adds 1 marketplace per
project to claude marketplace list and introduces an
apply → marketplace add → install → update chain that has to handle
idempotency, error recovery, and version reconciliation on every run.
Auto-discovery removes the entire chain.
Acceptance criteria
<repo>/.claude/plugins/<name>/.claude-plugin/plugin.jsonis loaded
without any claude plugin marketplace or claude plugin install call
when claude is run with cwd under <repo>.
claude plugin listshows the plugin with a(project)orproject://
origin marker.
- A plugin of the same name installed at user scope overrides the
project-scope one (deterministic precedence).
- The walk-up stops at the first
.git/package.jsonancestor (same
walk-up as settings.json discovery).
- No regression in existing marketplace or user-scope plugin loading.
Background / context
This FR originates from claude-devkit Plan 6 (wrapping-marketplace
shipping, 2026-05-10) — the design doc surfaced four viable architectural
paths during B3-safety investigation. Option 1 (wrapping marketplace)
shipped because it's the only fully-in-tooling-scope solution; Option 3
(this FR — <cwd>/.claude/plugins/ auto-discovery from CC) was identified
as the cleanest design but requires upstream CC change, hence this issue.
Plan 6 design doc: docs/architecture/plan-6-wrapping-marketplace.md inparisgroup-ai/claude-devkit (private repo; happy to share excerpts if
useful).
Implementation notes (optional)
The walk-up is already implemented in CC for settings.json discovery
(see cwd → walk up until .git/package.json marker). Extending it toplugins/ should be additive: the same walk, the same marker, a separate
loader path.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗