How does Claude Code discover, validate, load, and invoke a user plugin from the .claude/plugins directory, including manifest parsing, capability check, and registration into the tool set

en
100.0% sentence pass·18/18 cited·19/19 citations valid·112 fn·0 dec·825 sem
Plugin & Skill EcosystemCommand SystemTool FrameworkApplication Bootstrap & EntrypointsMCP Integration

Plugin discovery, load, and registration

Overview

The whitelisted source does not contain a .claude/plugins directory scanner, manifest parser, capability gate, or tool-registration path for user plugins . What is visible is marketplace-entry loading, MCPB bundle loading, and delisted-plugin cleanup, which together only cover part of the question .

Steps

  1. Plugin discovery in this codebase is driven by marketplace entries rather than a raw .claude/plugins directory walk, with loadPluginFromMarketplaceEntry resolving each entry's source to a concrete pluginPath . Local string sources are validated via pathExists and then copied into a versioned cache, while external sources (npm, github, url, pip) route through cachePlugin .
  2. cachePlugin creates the plugin cache directory with mkdir, generates a temp name via generateTemporaryCacheNameForPlugin, and dispatches on source kind to installFromLocal, installFromNpm, installFromGitHub, installFromGit, or installFromGitSubdir . Git-based installs go through validateGitUrl and gitClone, running git via execFileNoThrow .
  3. installFromLocal verifies the source with pathExists, uses copyDir to stage files, and strips the nested .git directory via rm . installFromNpm invokes npm install through execFileNoThrow into a shared npm cache and then copyDirs the package .
  4. For MCPB-packaged plugins, loadMcpbFile reads or extracts the archive, parses manifest.json, and — if manifest.user_config is non-empty — checks saved config via validateUserConfig, returning a needs-config result when required fields are missing . On success it produces an McpbLoadResult carrying manifest, generated mcpConfig, and extractedPath .
  5. The UI-side save path in ManagePlugins re-invokes loadMcpbFile with the user-supplied UserConfigValues to complete the capability/config gate before the plugin becomes usable . Uninstall flows go through doUninstalluninstallPluginOp, and delisted plugins are swept by detectAndUninstallDelistedPlugins .
  6. At runtime, deferred plugin installation is awaited inside run (bounded by CLAUDE_CODE_SYNC_PLUGIN_INSTALL_TIMEOUT_MS), after which a refreshPluginState call makes new commands, agents, and hooks visible — this is the closest thing to "registration into the tool set" in the whitelist . Plugin-sourced slash commands are then resolved per-turn by getCommand/findCommand against context.options.commands and dispatched via processSlashCommandgetMessagesForSlashCommand .
  7. Plugin identity for telemetry and marketplace scoping is parsed by parsePluginIdentifier and classified via isOfficialMarketplaceName, with buildPluginCommandTelemetryFields attaching fields when a plugin-sourced command is invoked .
  8. The precise steps for scanning .claude/plugins, validating a plugin manifest schema, checking declared capabilities, and inserting the plugin's tools into the active Tools array are not present in the whitelisted source, so the exact discovery→capability-check→tool-registration chain cannot be cited here .

State touched

  • — filesystem operations used by mkdir, rm, stat during install

Decisions

None of the whitelisted decision tokens apply to this flow .