Manage plugins for your organisation
Use managed settings to pre-install, require, restrict and update Claude Code plugins across every machine in your organisation.
When you are responsible for a fleet of Claude Code installs, you usually want three things from plugins: everyone has the ones the business relies on, nobody installs from sources you have not vetted, and updates arrive predictably. All of that is done through managed settings, which users cannot override. Almost every key on this page only has teeth when it comes from a managed source.
This page is for administrators and is about Claude Code specifically. A few related jobs live elsewhere:
- Installing plugins for yourself: Install plugins.
- The Organization settings > Plugins & skills page on claude.ai turns plugins on for members' claude.ai accounts. Those reach Claude Code as synced plugins (see How plugins load), and that page does not set any of the keys described here.
- Mods, the plugins that run JavaScript inside Claude Code, have their own controls: Manage mods for your organisation.
A typical rollout goes: require plugins, seed containers and CI, lock down sources, set update policy, then audit. The sections follow that order, and the control matrix summarises every key in one place.
Getting plugins onto every machine
A marketplace is a catalogue Claude Code fetches from git, a URL or a local path. Two managed keys work together to roll plugins out:
extraKnownMarketplacesregisters a marketplace on every machine.enabledPluginsnames the plugins to install and switch on from it.
Delivery mechanisms
Managed settings arrive in one of three ways:
| Mechanism | How | Best for |
|---|---|---|
| Server-managed settings | Paste JSON at Organization settings > Claude Code > Managed settings on claude.ai. Requires the Owner role. Cloud sessions wait for these before installing plugins | Team and Enterprise organisations whose devices are not all under MDM |
| MDM policy | A macOS plist whose top-level keys are the settings keys, or on Windows the full JSON stored as a string in a registry value | Fleets already managed by MDM |
| Managed settings file | managed-settings.json at the platform's system path, optionally with extra files in a managed-settings.d/ drop-in folder | Fleets managed by config management or images |
Exact paths, plist domains and registry keys are on Managed settings, and Server-managed settings discusses the trade-off.
Only one source wins (by default)
Claude Code checks server-managed settings first, then MDM, then the file, and uses the first that delivers any policy key at all. That means if the admin console delivers even one unrelated key, plugin keys in an MDM profile or managed file on that machine are ignored (apart from a short list of keys read from every source). To combine all sources instead, set managedSourcesBehavior to "merge". The full precedence rules are on Managed settings.
Requiring a marketplace and its plugins
Key the extraKnownMarketplaces entry by the marketplace's own name (from its marketplace.json), and list plugins in enabledPlugins as plugin@marketplace:
{
"extraKnownMarketplaces": {
"acme-plugins": {
"source": { "source": "github", "repo": "acme/claude-plugins" },
"autoUpdate": true
}
},
"enabledPlugins": {
"deploy-guard@acme-plugins": true,
"incident-notes@acme-plugins": true
}
}
Once this reaches a machine, the next session registers acme-plugins and installs both plugins. Users see them in /plugin, and disabling them in their own settings does nothing, because managed settings outrank every other scope. Setting a plugin to false in managed enabledPlugins does the opposite: it is blocked everywhere and hidden from the listing.
Adjust two fields for your situation:
autoUpdate:truekeeps the marketplace and its plugins refreshing in the background;falseturns that off. See update policy.source:githubis one option. Usegitwith aurlfor GitLab or an internal host, orurlfor a hostedmarketplace.json. Every shape is in the marketplace reference.
For a private git repository, each user needs read access. Cloning runs with the user's own git and stored credentials, without prompting. For people with no git-host account, use a seed.
A managed entry also beats same-named alternatives. A managed marketplace entry replaces a lower-precedence entry of the same name outright (fields are not merged), and for how a --plugin-dir copy with a matching name is handled, see name conflicts on How plugins load.
Anthropic's claude-plugins-official is a special case: enabling any of its plugins with name@claude-plugins-official: true declares the marketplace by itself, so no extraKnownMarketplaces entry is needed. If you want it registered without enabling anything, add an explicit entry, as in the lockdown example.
Requiring plugins for one repository
To target the contributors of a single repository rather than the whole fleet, put the same two keys in that repo's committed .claude/settings.json. The marketplace entries only take effect in folders the contributor trusts, and are silently ignored otherwise:
- In interactive sessions, after the contributor accepts the workspace trust dialog for that folder (see Permissions).
- In non-interactive
-pruns, only where trust was already accepted interactively, or where you sethasTrustDialogAcceptedfor the folder in~/.claude.json.
Plugins listed by relative path in the marketplace then load straight from the marketplace copy. Plugins whose entries point somewhere external (their own GitHub repo, say) do not install from repository settings alone: each contributor sees Plugin "<name>" is enabled in project settings but isn't installed until they run claude plugin install <name>@<marketplace> --scope project.
Local directory or file sources with a relative path resolve against the repository's main checkout, so every git worktree shares the same marketplace location.
To roll out a group of related plugins, enable a bundle plugin that depends on them; see Plugin dependencies.
When each surface applies the keys
| Surface | From managed settings | From a repo's .claude/settings.json |
|---|---|---|
| Interactive terminal | At session start on every machine that has the policy | Marketplaces after trust; enabledPlugins at session start |
-p and CI | At session start; installs happen in the background | Marketplaces only in trusted folders; enabledPlugins applied |
| Cloud sessions | In Anthropic-hosted environments only server-managed settings arrive, and the session waits for them before installing. MDM and local files stay on the user's machine | Covered on Install plugins |
Because -p installs run in the background, a plugin may be missing on the first turn. Set CLAUDE_CODE_SYNC_PLUGIN_INSTALL=1 to make the run wait for installation first.
Checking it worked
- Interactively: start Claude Code and open
/plugin; the marketplace and plugins should be listed. - In CI: run
claude -pwith--output-format stream-json --verbose. Theinitevent includes apluginsarray of what loaded.
Seeding containers and CI
Container images and CI runners often cannot clone at runtime. For those, build a plugins directory into the image and point CLAUDE_CODE_PLUGIN_SEED_DIR at it. Claude Code registers the seed's marketplaces at start-up and loads plugin caches from it in place, with no cloning. Seeds also help users who lack a git-host account.
Note: In CI, configure a git credential helper before installing from private repositories. On GitHub Actions, export a token that can read the marketplace repo as
GH_TOKENand rungh auth setup-git. The default workflow token can only see its own repository, so a marketplace elsewhere needs a personal access token or an app token.
Build a seed in three steps:
-
Install into the seed path at build time. Point
CLAUDE_CODE_PLUGIN_CACHE_DIRat the seed so installs land there instead of~/.claude/plugins:ENV CLAUDE_CODE_PLUGIN_CACHE_DIR=/srv/claude-plugins RUN claude plugin marketplace add acme/claude-plugins \ && claude plugin install deploy-guard@acme-pluginsThe resulting layout mirrors
~/.claude/plugins:known_marketplaces.json,marketplaces/<name>/andcache/<marketplace>/<plugin>/<version>/. You may mount it at a different path at runtime. -
Tell the runtime where it is. Set
CLAUDE_CODE_PLUGIN_SEED_DIR=/srv/claude-plugins. Several seeds can be listed, separated by:on Unix or;on Windows; the first one containing a given marketplace or cache wins. -
Enable the plugins. Seeded plugins are not switched on automatically. List them in
enabledPlugins, in managed settings or the repo's.claude/settings.json.
To verify, run claude -p --output-format stream-json --verbose in the image and check that each plugin's path in the init event sits under the seed directory.
Seeds behave differently from normal marketplaces:
- Read-only. Claude Code never writes to a seed and forces
autoUpdateoff for its marketplaces. - Seed wins. On every start-up, a seed's marketplace overwrites a user entry of the same name. Users opt out of a seeded plugin with
claude plugin disable, not by removing the marketplace. - Update and remove fail.
claude plugin marketplace update <name>, andremovewithout--scope, fail with a message naming the seed directory. - Policy still applies. Allowlists and blocklists check the seed marketplace's recorded source, so allow the source you built from.
For fleets with no outbound git at all, pair a seed with directory or file marketplace sources on a shared mount, and set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 (which also turns off plugin auto-update). If a proxy exists, Network configuration lists the variables.
Restricting sources
Two managed lists govern which marketplace sources plugins can come from: the strictKnownMarketplaces allowlist and the blockedMarketplaces blocklist. Both match the marketplace's source (the repo, URL or path it is fetched from), not the source of an individual plugin entry inside it.
They are enforced twice:
- Before downloading: when a marketplace is added, and on every install, update, refresh and auto-update.
- At session start: against already-installed plugins, so a plugin whose marketplace no longer qualifies does not load.
/pluginshowsMarketplace "<name>" is not in the allowed marketplace listorMarketplace "<name>" is blocked by enterprise policy.
Where the lists are enforced depends on where you set them:
- From the claude.ai admin console: Claude Code enforces them in sessions that read server-managed settings. claude.ai also checks them when anyone in the organisation adds a git-hosted marketplace on claude.ai or from Customize in the desktop app outside its Code tab, whether for their own account or for the whole organisation. It does not re-check marketplaces added before the lists existed, and does not check uploaded plugins.
- From an MDM policy or managed file: enforced only by Claude Code on machines that read that source.
While any allowlist is set, or the blocklist names anything other than skills-dir, a plugin whose marketplace cannot be found will not load. /plugin shows a policy error rather than "not found". The usual culprit is a stale enabledPlugins entry for a marketplace nobody registered.
Control matrix
| Key | What it enforces | What it does not do |
|---|---|---|
strictKnownMarketplaces (alias allowedMarketplaces) | Allowlist of marketplace sources. [] blocks everything, the official marketplace included | Does not register marketplaces, filter plugins inside an allowed one, or block --plugin-dir |
blockedMarketplaces | Blocklist of sources, evaluated before the allowlist | Does not affect a marketplace already registered from a source it does not match |
enabledPlugins | true forces a plugin on; false blocks and hides it at every scope | Cannot install a plugin whose marketplace is unregistered or disallowed |
syncClaudeAiPlugins | false stops Claude Code downloading and loading plugins synced from users' claude.ai accounts. Needs v2.1.273 or later | Cannot target one synced plugin; use "<name>@synced": false in enabledPlugins for that |
disableSideloadFlags | Rejects --plugin-dir, --plugin-url, --agents, the Agent SDK plugins option and non-SDK --mcp-config at start-up, plus folders listed in CLAUDE_CODE_PLUGIN_DIRS | Does not restrict .mcp.json, claude mcp add or SDK-supplied servers. Pair with allowedMcpServers (Managed MCP) |
disableCommandPluginSources | Blocks plugins with a command source from installing, updating or loading. Defaults to the value of allowManagedHooksOnly | No effect on other source types |
allowManagedHooksOnly | Limits which hooks may run | Does not trust hooks from plugins users enable themselves |
strictPluginOnlyCustomization | Blocks skills, agents, hooks and MCP servers that do not come from a plugin, managed settings or the built-ins. true covers all four; an array such as ["skills", "mcp"] covers some | Does not limit which plugins can be installed; pair with strictKnownMarketplaces |
pluginSuggestionMarketplaces | Marketplaces allowed to produce install suggestions (relevance) | No effect on built-in tips |
pluginTrustMessage | Appends your own text to the trust warning shown before install | Cannot change the warning itself |
allowedChannelPlugins | Replaces the default list of plugins allowed to push channel messages. Requires channelsEnabled: true | See Channels |
CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL=1 | Stops interactive terminal sessions auto-registering the official marketplace | Does not remove it if already registered. Once a machine starts with it set, auto-registration does not resume after you unset it |
allowManagedModsOnly | Stops mods that do not count as your organisation's from running their hooks | Does not stop a plugin containing a mod from installing |
All of these are managed-only keys, with four exceptions. enabledPlugins works at any scope, with managed settings locking it. syncClaudeAiPlugins can also be set by a user in user or local settings. CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL is an environment variable, delivered via the managed env block. allowManagedModsOnly is an option on a built-in plugin, set under pluginConfigs; see mods admin. Each settings key has an entry in the settings reference.
The aliases allowedMarketplaces (for strictKnownMarketplaces) and additionalMarketplaces (for extraKnownMarketplaces) need v2.1.232 or later and are ignored by older clients, so stick to the canonical names for mixed fleets. If a file sets both spellings, the canonical one applies.
Allowlist entry types
strictKnownMarketplaces is an array of source objects:
| Entry | Example | Matching |
|---|---|---|
github | { "source": "github", "repo": "acme/claude-plugins" } (optional ref, path) | Exact |
github owner wildcard | { "source": "github", "repo": "acme/*" } | Any repo under that owner. * must be the entire repo name; */x or acme/tools-* are invalid and match nothing. Needs v2.1.223 or later |
git | { "source": "git", "url": "https://gitlab.acme.internal/tools/plugins.git" } (optional ref, path) | Exact |
url | { "source": "url", "url": "https://plugins.acme.dev/marketplace.json" } (optional headers) | Exact on url; headers are not compared |
file / directory | { "source": "directory", "path": "/srv/plugins" } | Exact, absolute paths |
hostPattern | { "source": "hostPattern", "hostPattern": "^git\\.acme\\.internal$" } | Regex against the host of github, git and url sources (github always counts as github.com). Anchor with ^ and $ |
pathPattern | { "source": "pathPattern", "pathPattern": "^/srv/approved/" } | Regex against file and directory paths. ".*" allows every local path |
skills-dir | { "source": "skills-dir" } | Matches no marketplace; keeps skills-directory plugins loading |
hostPattern is the right tool for a GitHub Enterprise Server or GitLab host where developers create their own marketplaces; GitHub Enterprise Server has a worked example.
Exact matching is strict
For github and git entries, the repo or URL, the ref and the path must all match or all be absent. So an entry without ref does not cover a source with ref: "main"; a github entry does not cover a git URL for the same repo; and a trailing slash, .git suffix or ssh:// scheme each count as a different value. If a marketplace can be cloned by several URLs, use hostPattern. Owner wildcards obey the same ref rules, match any path unless pinned, and are case-sensitive on the allowlist.
Skills-directory plugins
These are plugins people keep under ~/.claude/skills/ or a project's .claude/skills/ in folders with a .claude-plugin/plugin.json. Any allowlist without a { "source": "skills-dir" } entry stops them loading. Plain skills (just a SKILL.md) are unaffected.
Marketplaces hosted on claude.ai
Allow or block these by adding a hostPattern entry matching claude.ai. On the allowlist, that admits your organisation's claude.ai marketplaces and the claude.ai defaults, but not a marketplace built from a member's own uploads or one whose scope claude.ai did not state. Needs v2.1.273 or later.
Total lockdown
"strictKnownMarketplaces": [] blocks every marketplace source including the official one. It does not affect plugins synced from claude.ai accounts; to stop those too, set syncClaudeAiPlugins to false in managed settings or turn off Skills for the organisation on claude.ai.
Blocklist behaviour
blockedMarketplaces takes the same entry types and is checked first, so anything on both lists is blocked. Its matching is deliberately looser:
- Git URLs are canonicalised, so
git@andhttps://forms,.gitsuffixes and trailing slashes for one github.com repo all match one entry. - A
githubentry also blocks the equivalentgitURL, and vice versa. - Owner wildcards compare the owner case-insensitively.
- An entry with no
reforpathblocks every ref and path.
{
"blockedMarketplaces": [
{ "source": "github", "repo": "sketchy-plugins/*" },
{ "source": "url", "url": "https://gitlab.com/someone/unvetted-marketplace" }
]
}
url entries also stop users adding an https:// repository URL that Claude Code clones rather than fetches (a bare github.com or gitlab.com repo URL, for example), ignoring .git and any #ref. That needs v2.1.232 or later.
{ "source": "skills-dir" } on the blocklist stops skills-directory plugins from both ~/.claude/skills/ and project .claude/skills/. A blocklist containing only that entry does not count as an active restriction for the "unknown marketplace" rule above.
Allowing the official marketplace and your own
This is the policy most organisations end up with:
{
"strictKnownMarketplaces": [
{ "source": "github", "repo": "anthropics/claude-plugins-official" },
{ "source": "github", "repo": "acme/*" },
{ "source": "skills-dir" }
],
"extraKnownMarketplaces": {
"claude-plugins-official": {
"source": { "source": "github", "repo": "anthropics/claude-plugins-official" }
},
"acme-plugins": {
"source": { "source": "github", "repo": "acme/claude-plugins" }
}
},
"enabledPlugins": {
"deploy-guard@acme-plugins": true
},
"disableSideloadFlags": true
}
Under this policy, adding any other source fails with a message containing is blocked by enterprise policy and the allowed list, and claude --plugin-dir ./foo exits naming disableSideloadFlags. Drop the skills-dir entry if you want skills-directory plugins blocked too.
Register both marketplaces explicitly rather than relying on the allowlist or on self-registration, because:
- The allowlist never registers anything.
extraKnownMarketplacesdoes, and its entries must themselves pass the allowlist. - The official marketplace only self-registers in interactive terminal sessions (and only when allowed).
-pruns and terminals attached to cloud sessions never do it. - A blocked registration attempt is remembered. A machine that once ran under a policy blocking the official marketplace (an
[]lockdown, say) will not try again by itself; it needs anextraKnownMarketplacesentry, anenabledPluginsentry for one of its plugins, or a manual add.
Update policy
Per marketplace
Set "autoUpdate": true or false on a managed extraKnownMarketplaces entry to decide for the fleet. If set, users who try the /plugin toggle get an error beginning Auto-update for '<name>' is set by. If left unset, users' own toggles stick. Defaults per marketplace are covered on How plugins load.
Fleet-wide off switch
{
"env": {
"DISABLE_AUTOUPDATER": "1"
}
}
That stops plugin auto-update for every marketplace and also Claude Code's own self-updates. To keep plugin updates while freezing the CLI, add "FORCE_AUTOUPDATE_PLUGINS": "1" alongside it. It does not cover command sources, which re-run their command every session and install changed output; How plugins load explains what stops those.
Release channels per group
Host a stable and a preview marketplace pointing at different refs (see Host a marketplace), then give each user group a different extraKnownMarketplaces entry. Server-managed settings apply to everyone in the organisation, so they cannot do this. Use either:
- separate endpoint-managed settings (files or MDM profiles) per group, checking how they combine with any organisation-wide source; or
- one Claude apps gateway policy per group, ordered so each user hits the right one first. A policy's
extraKnownMarketplacesdoes not merge with any other policy's, so list every marketplace the group needs. See Claude apps gateway configuration.
Recommending plugins
Marketplace owners can add relevance signals so Claude Code suggests a plugin when a project matches. For suggestions to show, the marketplace must be registered on the machine, named in managed pluginSuggestionMarketplaces, and have its source declared in the same policy (as an extraKnownMarketplaces entry or an allowlist entry). The official marketplace needs only its name. Details are on Suggest plugins by relevance.
Auditing
Before approving a marketplace, read Plugin security for what a plugin can do on a machine.
OpenTelemetry. claude_code.plugin_installed fires on each install and claude_code.plugin_loaded for each enabled plugin at session start. Third-party plugin and marketplace names are redacted or omitted unless OTEL_LOG_TOOL_DETAILS=1 is set. Field lists are on Monitoring usage, and Measure plugin usage covers the redaction.
Analytics API. On Enterprise, GET /v1/organizations/analytics/plugins returns per-plugin, per-day install and invocation counts across Claude Code and Cowork, groupable by user or RBAC group. Activity without a plugin name is rolled into one third-party row. See Analytics for access.
Gaps and workarounds
Security reviews often ask for controls that do not exist as keys. Nearest equivalents:
- Different policy per user or group: every key applies to everyone who receives the settings. Use per-group endpoint settings or gateway policies.
- Blocking one plugin from an allowed marketplace: set it to
falsein managedenabledPlugins. - Hiding
/plugin: not possible. Combine an allowlist with only your marketplace, managedenabledPlugins, anddisableSideloadFlags. - Gating
--plugin-dirvia the allowlist: the allowlist ignores it;disableSideloadFlagshandles it. - Enforcing claude.ai plugin toggles through these keys: they are separate. Those arrive as synced plugins with their own controls.
Troubleshooting policy
- Claude Code refuses to start and names
managed-settings.json: the file is not valid JSON. A file that parses but has one bad entry keeps the rest; see Errors and Managed settings. - The policy seems ignored: run
/statusand look forEnterprise managed settingsinSetting sources. If it is absent, the source did not load. - A user reports
blocked by enterprise policy: the message names the marketplace or source and, for an allowlist, the permitted sources. User-side guidance is on Plugin troubleshooting. - A plugin the user disabled still loads: another source (usually managed
enabledPlugins) re-enables it./pluginandclaude plugin listshowDisabled in ~/.claude/settings.json but still loadsalong with the source responsible.