pluginConfigs lookup for --plugin-dir-loaded plugins doesn't resolve to their marketplace-keyed userConfig
Problem
When a plugin is loaded via claude --plugin-dir <path> instead of through a marketplace, hook/MCP ${user_config.<key>} template substitution fails with:
Hook failed to run (Stop): Plugin option "autoregen" isn't set. Open /plugin manage to configure it, or check that the plugin's userConfig schema declares "autoregen".
This happens even when the same plugin, installed through a marketplace, already has that userConfig key set to a real value — and the plugin's userConfig schema is well-formed (verified with a valid default and no typos).
Root cause hypothesis
~/.claude/settings.json's pluginConfigs stores marketplace installs keyed as <name>@<marketplace> (e.g. claude-prospector@glitchwerks). A plugin loaded via --plugin-dir instead registers under the bare name (claude-prospector, no @marketplace suffix). The ${user_config.*} substitution used by hook/MCP definitions appears to look up the config under whichever plugin identity the harness resolved for the running instance — under --plugin-dir that's the bare name, which has no corresponding pluginConfigs entry, so the lookup misses even though a value exists under the marketplace-keyed identity for the same plugin content.
Corroborating observation: /plugin (list) shows the --plugin-dir-loaded plugin as "inline" but visually linked back to the marketplace entry (same displayed name/version), and /plugin reconfigure <name> inside a --plugin-dir session does not surface the marketplace install's already-configured fields at all. This suggests display-identity unification and config-key resolution are two separate code paths that disagree: the UI treats the --plugin-dir load as "the same plugin" for display purposes, but the userConfig storage/lookup key is not unified across the two identities.
Repro
- Install a plugin through a marketplace and set a
userConfigvalue for it (e.g. a boolean flag consumed by a hook via${user_config.<key>}). - Confirm the hook works correctly under the marketplace install.
- Load the same plugin source via
claude --plugin-dir <local-path-to-plugin>in a fresh session (bypassing the marketplace entirely). - Trigger the hook that reads
${user_config.<key>}.
Expected: the hook resolves the configured value (or the schema's declared default).
Actual: Hook failed to run: Plugin option "<key>" isn't set, even though the schema is valid and a value is set under the marketplace-keyed install.
Related but distinct: #86936
#86936 ("lspServers ${user_config.*} interpolation ignores declared userConfig defaults") is adjacent — same user-facing error string (Plugin option "X" isn't set) — but a different mechanism: that issue is about the LSP code path not merging the schema's declared default before interpolation (unlike the MCP path, which does merge defaults). This report is about identity/key resolution across install sources (--plugin-dir vs marketplace) for the same plugin, independent of whether a default is declared. A plugin with an explicit value already set under its marketplace identity still fails when the identical source is loaded via --plugin-dir, which #86936's default-merging fix would not address.
Ask
- Confirm whether
pluginConfigslookup for--plugin-dir-loaded plugins should fall back to (or merge with) a matching marketplace-keyed entry for the same plugin, or whether--plugin-dirsessions need their own documented way to seeduserConfig(e.g. does/plugin reconfiguresupport this today, and if not, should it?). - Not blocking for real installs —
--plugin-diris a local-dev-only path; the supported install path is the marketplace. This affects local plugin development/testing workflows.
Origin
Originally reported and investigated in glitchwerks/claude-prospector#277 while verifying that repo's local-dev --plugin-dir workflow (issue #102 / PR #276).
🤖 _Generated by Claude Code on behalf of @cbeaulieu-gt_