Plugin sources
Plugin sources tell Claude Code where to get each individual plugin listed in your marketplace. These are set in the source field of each plugin entry in marketplace.json.
Claude Code copies each installed plugin into the local versioned plugin cache at ~/.claude/plugins/cache, except for a command source in link mode, which Claude Code uses in place. Claude Code also installs the plugin's eligible Node.js package dependencies into the cached copy.
| Source | Type | Fields | Notes |
|---|---|---|---|
| Relative path | string (e.g. "./my-plugin") | none | Local directory within the marketplace repo. Must start with ./, unless you write a bare name under metadata.pluginRoot. Claude Code resolves the path relative to the marketplace root, not the .claude-plugin/ directory |
github | object | repo, ref?, sha? | |
url | object | url, ref?, sha? | Git URL source |
git-subdir | object | url, path, ref?, sha? | Subdirectory within a git repo. Clones sparsely to minimize bandwidth for monorepos |
npm | object | package, version?, registry? | Installed via npm install |
archive | object | url, sha256? | Zip archive downloaded over HTTPS. Works without git or npm on the user's machine. Requires Claude Code v2.1.224 or later |
command | object | command, timeout?, mode? | Plugin directory produced by running a local command, re-run once per session to pick up changes. Requires Claude Code v2.1.229 or later |
Marketplace sources vs plugin sources: These are different concepts that control different things.
- Marketplace source: where to fetch the
marketplace.jsoncatalog itself. Set when users run/plugin marketplace addor inextraKnownMarketplacessettings. Git-based marketplace sources supportref(branch/tag) but notsha. - Plugin source: where to fetch an individual plugin listed in the marketplace. Set in the
sourcefield of each plugin entry insidemarketplace.json. Git-based plugin sources support bothref(branch/tag) andsha(exact commit).
For example, a marketplace hosted at acme-corp/plugin-catalog (marketplace source) can list a plugin fetched from acme-corp/code-formatter (plugin source). The marketplace source and plugin source point to different repositories and are pinned independently.
The git-based source types below are github, url, and git-subdir. When both ref and sha are set on any of them, the sha is the effective pin. Claude Code fetches and checks out the pinned commit directly.
On most git hosts, including GitHub, GitLab, and Bitbucket, this means installation succeeds even if the branch or tag named by ref has since been deleted upstream, as long as the commit is still reachable from the repository. Some servers, such as AWS CodeCommit, don't support fetching commits by SHA. On those servers the ref must still exist and the pinned commit must be reachable from it.
If you distribute plugins through Organization settings > Plugins, only some source types are allowed. See Distribute through organization settings.
Relative paths
For plugins in the same repository, use a path starting with ./:
{
"name": "my-plugin",
"source": "./plugins/my-plugin"
}Paths resolve relative to the marketplace root, which is the directory containing .claude-plugin/. In the example above, ./plugins/my-plugin points to <repo>/plugins/my-plugin, even though marketplace.json lives at <repo>/.claude-plugin/marketplace.json. Don't use ../ to reference paths outside the marketplace root. On macOS and Linux, Claude Code refuses an entry path with a backslash anywhere past the leading ./, so write the separators as / on every platform.
A bare name is a single directory name with no /, such as "formatter". To write bare names instead of ./ paths, set metadata.pluginRoot to the directory they resolve under. With "pluginRoot": "./plugins", Claude Code resolves "source": "formatter" to ./plugins/formatter. Requires Claude Code v2.1.239 or later.
metadata.pluginRoot must itself be a relative path inside the marketplace. Claude Code ignores it for a source that already starts with ./. A source that contains a /, such as team-a/formatter, isn't a bare name and still needs the ./ prefix, even when metadata.pluginRoot is set.
Claude Code resolves relative paths against a local copy of the marketplace, so they work when users add your marketplace from a git source or a local directory. If users add your marketplace via a direct URL to the marketplace.json file, relative paths won't resolve, because Claude Code downloads only that file. For URL-based distribution, use any other plugin source instead. See Troubleshooting for details.
GitHub repositories
{
"name": "github-plugin",
"source": {
"source": "github",
"repo": "owner/plugin-repo"
}
}You can pin to a specific branch, tag, or commit:
{
"name": "github-plugin",
"source": {
"source": "github",
"repo": "owner/plugin-repo",
"ref": "v2.0.0",
"sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
}
}| Field | Type | Description |
|---|---|---|
repo | string | Required. GitHub repository in owner/repo format |
ref | string | Optional. Git branch or tag (defaults to repository default branch) |
sha | string | Optional. Full 40-character git commit SHA to pin to an exact version |
Git repositories
{
"name": "git-plugin",
"source": {
"source": "url",
"url": "https://gitlab.com/team/plugin.git"
}
}You can pin to a specific branch, tag, or commit:
{
"name": "git-plugin",
"source": {
"source": "url",
"url": "https://gitlab.com/team/plugin.git",
"ref": "main",
"sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
}
}| Field | Type | Description |
|---|---|---|
url | string | Required. Full git repository URL (https:// or git@). The .git suffix is optional, so Azure DevOps and AWS CodeCommit URLs without the suffix work |
ref | string | Optional. Git branch or tag (defaults to repository default branch) |
sha | string | Optional. Full 40-character git commit SHA to pin to an exact version |
Git subdirectories
Use git-subdir to point to a plugin that lives inside a subdirectory of a git repository. Claude Code uses a sparse, partial clone to fetch only the subdirectory, minimizing bandwidth for large monorepos.
{
"name": "my-plugin",
"source": {
"source": "git-subdir",
"url": "https://github.com/acme-corp/monorepo.git",
"path": "tools/claude-plugin"
}
}You can pin to a specific branch, tag, or commit:
{
"name": "my-plugin",
"source": {
"source": "git-subdir",
"url": "https://github.com/acme-corp/monorepo.git",
"path": "tools/claude-plugin",
"ref": "v2.0.0",
"sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
}
}The url field also accepts a GitHub shorthand (owner/repo) or SSH URLs (git@github.com:owner/repo.git).
| Field | Type | Description |
|---|---|---|
url | string | Required. Git repository URL, GitHub owner/repo shorthand, or SSH URL |
path | string | Required. Subdirectory path within the repo containing the plugin (for example, "tools/claude-plugin") |
ref | string | Optional. Git branch or tag (defaults to repository default branch) |
sha | string | Optional. Full 40-character git commit SHA to pin to an exact version |
npm packages
Plugins distributed as npm packages are installed using npm install. This works with any package on the public npm registry or a private registry your team hosts.
{
"name": "my-npm-plugin",
"source": {
"source": "npm",
"package": "@acme/claude-plugin"
}
}To pin to a specific version, add the version field:
{
"name": "my-npm-plugin",
"source": {
"source": "npm",
"package": "@acme/claude-plugin",
"version": "2.1.0"
}
}To install from a private or internal registry, add the registry field:
{
"name": "my-npm-plugin",
"source": {
"source": "npm",
"package": "@acme/claude-plugin",
"version": "^2.0.0",
"registry": "https://npm.example.com"
}
}| Field | Type | Description |
|---|---|---|
package | string | Required. Package name or scoped package (for example, @org/plugin) |
version | string | Optional. Version or version range (for example, 2.1.0, ^2.0.0, ~1.5.0) |
registry | string | Optional. Custom npm registry URL. Defaults to the system npm registry (typically npmjs.org) |
Zip archives
Use archive to distribute a plugin as a zip file that Claude Code downloads over HTTPS, so installs work without git or npm on the user's machine. Host the file on any static file server or artifact repository, such as an S3 bucket, an Artifactory generic repository, or nginx. Requires Claude Code v2.1.224 or later. On versions v2.1.120 through v2.1.223, installing the plugin fails with This plugin uses a source type your Claude Code version does not support. Update Claude Code and try again.; on older versions, a marketplace containing an archive entry fails to load entirely.
This entry installs the plugin from a zip file on an artifact server:
{
"name": "my-plugin",
"source": {
"source": "archive",
"url": "https://artifacts.example.com/claude-plugins/my-plugin-2.1.0.zip"
}
}When you build the zip, you can zip the plugin's contents directly or zip the plugin folder itself. Claude Code looks for .claude-plugin/ at the top of the archive, then inside a single top-level folder, so both layouts install:
my-plugin.zip my-plugin.zip
├── .claude-plugin/ └── my-plugin/
│ └── plugin.json ├── .claude-plugin/
└── commands/ │ └── plugin.json
└── commands/Claude Code doesn't look deeper than one folder, so a plugin nested further down fails to install. Claude Code refuses archives larger than 256 MiB.
To pin the exact file, add a sha256 field with the archive's digest:
{
"name": "my-plugin",
"source": {
"source": "archive",
"url": "https://artifacts.example.com/claude-plugins/my-plugin-2.1.0.zip",
"sha256": "6bfa50e3d2e00c052b46abe51fff89346ac803e45771f76dcf6df1ab74cca5e1"
}
}If the downloaded file doesn't match the pin, Claude Code refuses the install and reports Plugin archive integrity check failed.
Archive sources accept these fields:
| Field | Type | Description |
|---|---|---|
url | string | Required. HTTPS URL of the zip archive. Claude Code rejects http:// URLs, along with loopback, link-local, and cloud-metadata hosts. Every redirect hop must satisfy the same rules, or Claude Code refuses the download |
sha256 | string | Optional. SHA-256 digest of the archive as 64 hex characters, uppercase or lowercase. Claude Code verifies every download against it and refuses the install on a mismatch |
The sha256 digest also serves as the plugin's version when neither plugin.json nor the marketplace entry declares one. See Version management. If you declare a version, that version string is the update signal, so after changing the zip and its digest, bump the version too, or users keep the cached copy.
Authenticate archive downloads
To authenticate an archive download, such as a download from a private registry, set the HTTP headers Claude Code sends with it. Set headers on the url source you registered the marketplace from, such as an extraKnownMarketplaces entry. On Claude Code v2.1.238 or later, you can set it on the plugin's entry instead, beside source.
If the value you would put in headers is short-lived, such as a token your registry mints on request, set a headersHelper command in the same place instead. Claude Code runs the command and sends the JSON object it prints as that place's headers. Requires Claude Code v2.1.238 or later.
The place you choose decides which downloads get the headers and when Claude Code runs the command:
| Place | Downloads that get the headers | When Claude Code runs a headersHelper set there |
|---|---|---|
Marketplace url source | Archive downloads on the marketplace URL's origin, meaning the same scheme, host, and port | Before each fetch of the marketplace's marketplace.json and before each archive download on that origin. Claude Code reuses one run's output for up to 60 seconds |
| Plugin entry | That entry's download only | Only when a user installs or updates that one plugin by itself and accepts the command |
Where both places set a header of the same name, Claude Code sends the entry's value. Within one place, a header the command prints overrides a header of the same name listed in headers.
Add a headersHelper to a plugin entry
This entry sets headersHelper beside source. It also sets "strict": false, which Claude Code requires of a marketplace.json entry that sets headersHelper. With "strict": false, the marketplace entry is the plugin's entire definition, so a user can review what the plugin contains before accepting the command:
{
"name": "my-plugin",
"description": "Formatting commands for internal services",
"strict": false,
"commands": "./commands",
"source": {
"source": "archive",
"url": "https://registry.example.com/plugins/my-plugin-2.1.0.zip"
},
"headersHelper": "/opt/bin/mint-registry-token.sh"
}To check the entry, run claude plugin install my-plugin@your-marketplace. Claude Code shows you the command and the archive URL, and downloads the zip after you accept.
Before v2.1.238, Claude Code downloaded an entry's archive without its headers or headersHelper, so an install that relied on them failed with HTTP 401 while downloading plugin archive from, followed by the URL, with the registry's status code in place of 401.
Write the headersHelper command
Whether you set headersHelper on a marketplace's url source or on a plugin entry, write the command to meet these requirements:
- Command text: at most 500 characters of printable ASCII, with no run of four or more spaces.
- Output: print one JSON object of header names and string values on stdout, then exit 0 within 10 seconds.
- Shell and working directory: Claude Code runs the command through
sh, orcmd.exeon Windows, from the configuration directory,~/.claudeorCLAUDE_CONFIG_DIR. Give an absolute path or a command onPATH, because a relative path resolves against that directory, not the user's project. - Variables Claude Code removes: from the environment of a command set in a
marketplace.jsonentry or in a project's.claude/settings.jsonor.claude/settings.local.json, Claude Code removes every variable whose name contains a word such asTOKEN,SECRET,KEY, orAUTH, includingANTHROPIC_API_KEY. Claude Code doesn't apply this removal to a command set in user settings, a--settingsfile, or managed settings. - Variables Claude Code sets:
CLAUDE_CODE_MARKETPLACE_URLandCLAUDE_CODE_MARKETPLACE_NAMEfor aurlsource's command, andCLAUDE_CODE_PLUGIN_NAMEandCLAUDE_CODE_PLUGIN_ARCHIVE_URLfor an entry's command.CLAUDE_CODE_MARKETPLACE_NAMEis unset on the first fetch after a user adds a marketplace by URL, because that fetch is what supplies the name.
A command that mints a bearer token prints an object like this one:
{"Authorization": "Bearer eyJhbGciOiJSUzI1NiJ9"}When Claude Code skips a headersHelper command or drops its output
Claude Code doesn't run a headersHelper command, or drops headers that came from headers or from the command's output, in these situations:
- Command fails: if the command exits non-zero, runs past 10 seconds, or prints anything other than a JSON object of string values, Claude Code doesn't make the fetch or download it ran the command for.
- Marketplace URL doesn't start with
https://: Claude Code doesn't run thaturlsource's command and sends only the headers listed in itsheadersfield. - Redirect leaves the origin: when a download is redirected off the archive URL's origin, Claude Code drops the
headersvalues and command output of both the marketplaceurlsource and the plugin entry. - Entry sets a routing or identity header: Claude Code drops request-routing and client-identity names such as
Host,Cookie, andX-Forwarded-*from an entry'sheadersand command output, and keeps authentication names such asAuthorization. Claude Code filters everymarketplace.jsonentry this way, and an inline settings entry depending on which file declares it. - Command set in an
--add-dirdirectory's settings: Claude Code ignores it, on aurlsource and on an inline plugin entry alike, and sends only that file'sheaders. - Managed settings block the command: setting
disableCommandPluginSourcestotrueblocksheadersHelpercommands, andallowManagedHooksOnlyblocks them too unlessdisableCommandPluginSourcesis explicitlyfalse. Under either block, Claude Code still runs the command for a marketplace that managed settings themselves declare.
How users accept a headersHelper command
A user accepts a plugin entry's command each time they install or update that one plugin by itself, from the plugin's own view in /plugin or with claude plugin install or claude plugin update. Claude Code shows the command and the archive URL, and runs the command only after the user accepts. In a non-interactive shell, pass --yes to accept it.
Claude Code runs only the command it showed, for the archive URL it showed. If the entry's command or archive URL changed in between, Claude Code refuses the install or update. A change in the query string alone doesn't count.
Installs and updates that refuse the command instead of asking
On any operation other than a single-plugin install or update, Claude Code neither runs an entry's command nor downloads its archive, so the plugin stays at its installed version or stays uninstalled. What the user sees depends on the operation:
- Installing several plugins at once, from a plugin suggestion, or as another plugin's dependency: Claude Code refuses the plugin that has the command and points the user at that plugin's own view in
/plugin. The other plugins in a bulk install still install. A plugin that depends on the refused plugin fails to install until the user installs the refused plugin by itself. - Background auto-update, or session start for a plugin whose archive was never downloaded: Claude Code lists the plugin in the
/pluginErrors tab so the user knows to install or update it by hand. An auto-update that finds the entry still advertises the installed version lists nothing.
When a marketplace url source's command runs
A marketplace url source's headersHelper is declared in a settings file, such as an extraKnownMarketplaces entry, rather than in the catalog the marketplace publishes, so Claude Code doesn't ask the user to accept it on each install or update. The settings file that declares it decides when Claude Code runs it:
| Settings file | When Claude Code runs the command |
|---|---|
User settings, a --settings file, or a managed settings file on the machine | Without asking, including during a background marketplace refresh |
A project's .claude/settings.json or .claude/settings.local.json | Only after the user accepts the workspace trust dialog for that folder itself. A -p or SDK session doesn't count as accepting it, and neither does trust granted to a parent folder |
| Server-managed settings | Only after the user approves the delivered settings in the security approval dialog |
In a -p or SDK session, Claude Code can't show the security approval dialog. It applies the other delivered settings, but the marketplace fetch, and any archive download that needs the command, fails until a user has approved in an interactive session.
For an inline plugin entry in one of these files, Claude Code requires the same folder trust or settings approval as for a marketplace-level command in that file, and the user also accepts the entry's command on each install or update.
Command sources
Use command when a locally installed tool produces the plugin directory, such as an IDE that renders its plugin for the currently selected toolchain. Claude Code runs the command when the user installs the plugin and re-runs it in the background once per session, so your users pick up the tool's changed output without reinstalling. Requires Claude Code v2.1.229 or later. On v2.1.120 through v2.1.228, installing the plugin fails with This plugin uses a source type your Claude Code version does not support. Update Claude Code and try again., and on older versions the whole marketplace fails to load.
This entry installs the plugin from whatever directory the tool prints:
{
"name": "my-plugin",
"source": {
"source": "command",
"command": "my-tool claude-plugin-path"
}
}Claude Code runs the command through the platform shell, sh on macOS and Linux or cmd.exe on Windows, from the user's home directory. The command must print exactly one line on stdout and exit with code 0. That line is the absolute path of a directory that contains the complete plugin by the time the command exits, and the path may change between runs.
Claude Code stops a command that runs longer than timeout seconds, and the install or update fails. Claude Code also refuses the printed path in these cases, and the install or update fails the same way:
- The directory has no plugin content at its top level, such as a
.claude-plugin/directory or askills/,commands/,agents/, orhooks/directory - The directory is the one Claude Code was started in, or one of its parents
- On Windows, the path is a UNC path
Command sources accept these fields:
| Field | Type | Description |
|---|---|---|
command | string | Required. Shell command that prints the plugin directory's absolute path as a single line on stdout and exits 0. Must be printable ASCII, at most 500 characters, with no runs of four or more spaces, so users can review the whole command they're asked to accept |
timeout | number | Optional. Whole number of seconds to wait for the command before giving up (default: 60, maximum: 600) |
mode | string | Optional. "copy" (default) copies the printed directory into the plugin cache. "link" uses the printed directory in place. See Copy mode and link mode |
Copy mode and link mode
With the default "mode": "copy", Claude Code copies the printed directory into the versioned plugin cache and derives the plugin version from a hash of the directory's contents. Your tool can delete or rewrite the directory after the command exits, and a re-run that produces identical content counts as up to date. Claude Code refuses to install a directory larger than 256 MiB or containing more than 20,000 entries.
Set "mode": "link" for large plugin directories that shouldn't be copied, such as a rendered SDK export. Claude Code fills the plugin's cache entry with a link to each top-level entry of the printed directory and uses the files in place, so nothing is copied, file contents aren't hashed, and the size limits don't apply. The install fails if a top-level entry is a symlink that points outside the printed directory. Claude Code also skips the Node.js package dependency install for a link-mode plugin, so print a directory that already contains any node_modules the plugin needs.
Keep the printed directory in place for as long as the plugin stays installed, because Claude Code loads the plugin through those links at every startup. Claude Code derives the plugin version from the printed directory's real path and its top-level entries, not the files inside, so print a different path to signal new content. In a session started in the printed directory or anywhere below it, Claude Code doesn't load the plugin at all.
Claude Code doesn't support link mode on Windows and refuses to install a link-mode plugin there. Declare "mode": "copy" instead.
How users accept the command
Claude Code runs your command on the user's machine, so it binds every run to the user's explicit acceptance:
- When users install the plugin from its details screen in
/plugin, or install or update it withclaude plugin installorclaude plugin updatein an interactive terminal, Claude Code shows them the exact command string first and records the accepted command for that installation. Aclaude plugin updatethat can proceed on the recorded acceptance of the same command shows nothing. In a non-interactive shell, such as a provisioning script, pass--yestoclaude plugin installorclaude plugin updateto accept the command it prints. - Every other path runs only the command the user already accepted. This includes updates started from
/pluginand the background runs described in When Claude Code re-runs the command. When none was accepted, Claude Code refuses to run the command and tells the user how to review it. Claude Code never installs a command-sourced plugin as a dependency of another plugin, so users install it themselves first. - If you change the entry's
command, or switch itsmode, users keep the version they already have and Claude Code stops re-running the command. In interactive sessions, the/pluginErrors tab shows the new command until the user reviews and accepts it by runningclaude plugin update <plugin>@<marketplace>.
Administrators can block command sources across an organization with the managed setting disableCommandPluginSources. If an organization sets allowManagedHooksOnly, Claude Code blocks command sources by default.
When Claude Code re-runs the command
The printed directory reflects the tool's state at the time the command ran, so Claude Code runs the command again at these times:
- Every time the user installs or updates the plugin
- Once per session for each enabled command-sourced plugin, in the background, shortly after the session starts. This run doesn't go through marketplace auto-update, so it doesn't depend on the marketplace's auto-update setting
- At startup or on
/reload-plugins, when an enabled plugin's installed version is missing from the plugin cache
Claude Code skips the two background runs when the user sets CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC. Explicit installs and updates still run the command with that variable set.
When the command's hashed output has changed, Claude Code installs the result as a new version and reloads it in the running interactive session, switching the same components that /reload-plugins switches. The user sees a notification that the plugin was reloaded. If reloading in place would invalidate the session's prompt cache, Claude Code instead prompts the user to run /reload-plugins, which warns about the cache cost and applies when rerun with --force.
Advanced plugin entries
This example shows a plugin entry using many of the optional fields, including custom paths for commands, agents, hooks, and MCP servers:
{
"name": "enterprise-tools",
"source": {
"source": "github",
"repo": "company/enterprise-plugin"
},
"description": "Enterprise workflow automation tools",
"version": "2.1.0",
"author": {
"name": "Enterprise Team",
"email": "enterprise@example.com"
},
"homepage": "https://docs.example.com/plugins/enterprise-tools",
"repository": "https://github.com/company/enterprise-plugin",
"license": "MIT",
"keywords": ["enterprise", "workflow", "automation"],
"category": "productivity",
"commands": [
"./commands/core/",
"./commands/enterprise/",
"./commands/experimental/preview.md"
],
"agents": ["./agents/security-reviewer.md", "./agents/compliance-checker.md"],
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh"
}
]
}
]
},
"mcpServers": {
"enterprise-db": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"]
}
},
"strict": false
}Key things to notice:
commandsandagents: you can specify multiple directories or individual files. Paths are relative to the plugin root and must stay inside it.- Claude Code rejects a path that resolves outside the plugin directory, such as
./../shared.md, with apath escapes plugin directoryerror, and still loads the plugin without that component
- Claude Code rejects a path that resolves outside the plugin directory, such as
${CLAUDE_PLUGIN_ROOT}: use this variable in hook commands and MCP server configs to reference files within the plugin's installation directory.- See the substitution table for which config fields substitute it per server type
- For dependencies or state that should survive plugin updates, use
${CLAUDE_PLUGIN_DATA\}instead
strict: false: since this is set to false, the plugin doesn't need its ownplugin.json. The marketplace entry defines everything. See Strict mode below.
By default, a plugin's skills load from the skills/ directory under its source. Paths listed in the skills field add to that scan:
"skills": ["./skills/", "./extra-skills/"]When several plugin entries share one skills/ folder at the marketplace root (source: "./"), list specific subdirectories instead so each entry loads only its own skills:
"source": "./",
"skills": ["./skills/code-review", "./skills/docs"]With a marketplace-root source, the listed paths are the complete set for that entry, and other directories in the shared skills/ folder don't load. Listing ./skills/ itself, or the plugin root, keeps the full scan. If none of the listed paths exist, the default scan runs instead.
Strict mode
The strict field controls whether plugin.json is the authority for component definitions (skills, agents, hooks, MCP servers, output styles).
| Value | Behavior |
|---|---|
true (default) | plugin.json is the authority. The marketplace entry can supplement it with additional components, and both sources are merged. |
false | The marketplace entry is the entire definition. If the plugin also has a plugin.json that declares components, that's a conflict and the plugin fails to load. |
When to use each mode:
strict: true: the plugin has its ownplugin.jsonand manages its own components. The marketplace entry can add extra skills or hooks on top. This is the default and works for most plugins.strict: false: the marketplace operator wants full control. The plugin repo provides raw files, and the marketplace entry defines which of those files are exposed as skills, agents, hooks, etc. Useful when the marketplace restructures or curates a plugin's components differently than the plugin author intended.