CDF Plugin Manifest
A plugin's plugin.json, read from .claude-plugin/plugin.json. Models every key the Claude Code plugin manifest and marketplace references, read 2026-10-05 document, with the same meaning, so a Claude Code plugin validates here; unknown top-level keys pass through, as Claude Code strips them with a warning. Two keys are CDF's own: the optional cdf block, which declares what the harness alone understands, and plugin-level category, which Claude Code documents only on a marketplace entry — what the plugin contributes, what its own code asks to be allowed, and who vouches for the declaration. name is the only required key, which is Claude Code's rule and not a relaxation of ours: a manifest that named nothing could not be addressed, and everything else has a defensible default. A declaration is not an installation: reading this file tells the loader what a plugin says about itself, never that it may run.
- Schema
plugin-manifest.schema.json, served as JSON at its$id: https://cognitive-delivery.github.io/contract/1.x/plugin-manifest.schema.json- Dialect
http://json-schema.org/draft-07/schema#- Root
- object, open (additional properties are carried)
required:name - Stability
- none stated at the root; every declared property carries its own
- Properties
- 168 declared: 34 under the root, 134 in definitions
Properties
Every declared property under the root, in the schema's own order. [] is an array's items, .* the shape of every unnamed member, #name a definition. Objects carry additional properties unless a row says otherwise.
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
name | string | yes | The plugin id: letters, digits, ., _ and -, starting with a letter or digit, as Claude Code accepts (it recommends kebab-case and warns otherwise). The only required key, and the one a decision record is keyed to. Claude Code plugin manifest and marketplace references, read 2026-10-05. | pattern ^[A-Za-z0-9][A-Za-z0-9._-]*$ | stable |
description | string | stable | |||
version | string | The plugin's own version. An open string: a plugin is free to version itself however it likes, and a marketplace may pin a different one. | stable | ||
author | string | object #author | Who publishes the plugin. An object is the documented form; a bare string is accepted because marketplaces in the wild carry one, and a reader that refused it would refuse a real plugin. | stable | ||
displayName | string | A human label for a listing. name remains the identity. | stable | ||
homepage | string | stable | |||
repository | string | object #repository | The source repository, as a URL string or as an object carrying one. | stable | ||
license | string | stable | |||
keywords | array | stable | |||
keywords[] | string | min length 1 | |||
category | string | Free-form category. A CDF extension on the manifest: Claude Code documents category on a marketplace entry only, and strips it from plugin.json with a warning. Kept because CDF's decision records key on it; the README names it as not a Claude Code key. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
metadata | object | Free-form publisher metadata. Carried, never interpreted. | stable | ||
defaultEnabled | boolean | Whether a host that installs this plugin enables it by default. A hint to the host, never an approval: presence is not approval, and neither is this. | stable | ||
skills | string | array #componentPath | A component directory or file, or a list of them. Claude Code accepts a single string or an array of strings for skills, commands, agents, outputStyles, workflows and experimental.themes, and scans the default folder when the key is absent, so an absent key is not an empty contribution. Every path starts with ./ (skills also accepts "."). Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
commands | string | array | object #commands | Flat .md command files, directories of them, or an object map of command name to source or content. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
agents | string | array #componentPath | A component directory or file, or a list of them. Claude Code accepts a single string or an array of strings for skills, commands, agents, outputStyles, workflows and experimental.themes, and scans the default folder when the key is absent, so an absent key is not an empty contribution. Every path starts with ./ (skills also accepts "."). Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
hooks | object | string | array #hooksSource | Hooks declared inline as the event map, as a path to a .json file that declares them (wrapped in a top-level hooks key), or as an array mixing both. Claude Code accepts all three. | stable | ||
mcpServers | object | string | array #mcpServersSource | MCP servers declared inline keyed by name, as a path to a .json config, an .mcpb or .dxt bundle path, an https:// bundle URL, or an array mixing these. Claude Code accepts all of them. | stable | ||
lspServers | string | object | array #lspServers | .json LSP config files, an inline map of server name to config, or an array of either. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
$schema | string | JSON Schema URL for editor autocomplete. Ignored at load time. | stable | ||
icon | string | Path of an image inside the plugin for its listing in Anthropic's directory. Claude Code plugin manifest and marketplace references, read 2026-10-05. | min length 1 must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\ | stable | |
documentationUrl | string | Read by Anthropic's directory from plugin.json only; Claude Code ignores it at load time and warns when it appears in a marketplace entry. Claude Code plugin manifest and marketplace references, read 2026-10-05. | pattern ^https:// | stable | |
supportUrl | string | Read by Anthropic's directory from plugin.json only; Claude Code ignores it at load time and warns when it appears in a marketplace entry. Claude Code plugin manifest and marketplace references, read 2026-10-05. | pattern ^https:// | stable | |
privacyPolicyUrl | string | Read by Anthropic's directory from plugin.json only; Claude Code ignores it at load time and warns when it appears in a marketplace entry. Claude Code plugin manifest and marketplace references, read 2026-10-05. | pattern ^https:// | stable | |
termsOfServiceUrl | string | Read by Anthropic's directory from plugin.json only; Claude Code ignores it at load time and warns when it appears in a marketplace entry. Claude Code plugin manifest and marketplace references, read 2026-10-05. | pattern ^https:// | stable | |
dependencies | array #dependencies | Plugins that must be enabled for this one to work. Each entry is "name", "name@marketplace", or an object with name, marketplace and version. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
settings | object | Settings applied while the plugin is enabled; Claude Code honours agent and subagentStatusLine and drops the rest. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
userConfig | object #userConfig | Values Claude Code prompts the user for when the plugin is enabled. Keys are identifiers of letters, digits and underscores not starting with a digit. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
types | string | A .d.ts file declaring a mod's $.state values and $ nouns. Claude Code plugin manifest and marketplace references, read 2026-10-05. | min length 1 must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\ | stable | |
channels | array | stable | |||
channels[] | object #channel | A message channel bound to one of the plugin's MCP servers. A STRICT object in Claude Code. Claude Code plugin manifest and marketplace references, read 2026-10-05. | |||
outputStyles | string | array #componentPath | A component directory or file, or a list of them. Claude Code accepts a single string or an array of strings for skills, commands, agents, outputStyles, workflows and experimental.themes, and scans the default folder when the key is absent, so an absent key is not an empty contribution. Every path starts with ./ (skills also accepts "."). Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
workflows | string | array #componentPath | A component directory or file, or a list of them. Claude Code accepts a single string or an array of strings for skills, commands, agents, outputStyles, workflows and experimental.themes, and scans the default folder when the key is absent, so an absent key is not an empty contribution. Every path starts with ./ (skills also accepts "."). Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
themes | string | array | Theme files or directories at the top level. Claude Code still loads this key but warns; experimental.themes is the documented place. Claude Code plugin manifest and marketplace references, read 2026-10-05. | any of: (1) string, min length 1; (2) array, of string, min length 1 | stable | |
themes[]anyOf branch 2 of 2 | string | min length 1 | |||
experimental | object #experimental | Container for themes, monitors and evals, whose manifest shape Claude Code says may still change. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
cdf | object #cdf | The additive CDF block. Absent in a plain Claude Code plugin, and its absence is not a defect: such a plugin contributes its skills, commands, agents, hooks and MCP servers and declares nothing further. | stable |
Definitions
The named shapes this schema refers to as #name. A row above that links here is not expanded in place; its constraints are the definition's.
#attestation
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#attestation | object | Who vouches for the declaration. Optional: a plugin published without a key has nothing to sign with, and the harness records that honestly rather than claiming a signature it does not have. The issuer vocabulary is the lease manifest's, so one reader understands both. | |||
#attestation.issuer | string | yes | Which party produced the declaration. | one of "agent", "bridge", "harness", "plugin" | stable |
#attestation.signature | string | Lower-case hex signature over the canonical bytes of the manifest, when the issuer can sign. | pattern ^[0-9a-f]+$ | stable | |
#attestation.key_fingerprint | string | Fingerprint of the key that produced signature. Never the key. | min length 1 | stable |
#author
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#author | string | object | Who publishes the plugin. An object is the documented form; a bare string is accepted because marketplaces in the wild carry one, and a reader that refused it would refuse a real plugin. | any of: (1) string, min length 1; (2) object, with name, email, url, requires name | ||
#author.nameanyOf branch 2 of 2 | string | yes | min length 1 | stable | |
#author.emailanyOf branch 2 of 2 | string | stable | |||
#author.urlanyOf branch 2 of 2 | string | stable |
#capabilities
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#capabilities | object | What the plugin's own code asks to be allowed when the harness runs it out of process. This is the lease manifest's allow shape, property for property, because a plugin worker's lease is generated from it and narrowed against the workspace root policy. It is deliberately NOT the store-listing interface.capabilities vocabulary a plugin may also carry: that is a shelf label, this is an authorisation request. Every list is optional here — an absent list is a plugin that asks for nothing, which is the correct default — whereas the granted manifest requires all five. | |||
#capabilities.tools | array | Governed tool names the agent may call. | stable | ||
#capabilities.tools[] | string | A governed tool name the plugin asks to call. At most 128 characters of letters, digits, _, ., :, / and -, so a governed cdf_ name and a <server>/<tool> pair both fit. * is refused: a lease that names every tool has not named one, and SPEC §5.2 R2 exists because a grant must say what it opens. Whitespace is refused. | pattern ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$min length 1 | ||
#capabilities.read_paths | array | Workspace-relative POSIX globs the agent may read. Refused here, without lookahead so any RE2-based validator can load the rule: a leading /, any .. segment, a leading ~, a drive-letter prefix and any backslash. The registry re-checks the resolved path against the workspace root. | stable | ||
#capabilities.read_paths[] | string | min length 1 must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\ | |||
#capabilities.write_paths | array | Workspace-relative POSIX globs the agent may change. Refused here, without lookahead: a leading /, any .. segment, a leading ~, a drive-letter prefix and any backslash. The registry re-checks the resolved path against the workspace root, and a change outside the granted set is a scope violation that revokes the lease. | stable | ||
#capabilities.write_paths[] | string | min length 1 must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\ | |||
#capabilities.hosts | array | Hostnames the agent may reach, with an optional leading wildcard label (*.example.com). Enforced by the egress proxy once it keys off the lease. | stable | ||
#capabilities.hosts[] | string | A host the plugin asks to reach. A lower-case DNS name of one or more labels, an IPv4 literal or localhost (both are DNS-name shaped), with an optional single leading *. label, or the bare *. Refused by the pattern, which uses no lookahead or backreference and compiles under RE2: a scheme, a port, a path, whitespace, upper case, a trailing dot and a wildcard anywhere but the first label. A port is not a host: the egress proxy matches hostnames, and a rule nothing enforces is a claim. IP literals are admitted because a local model provider (Ollama, LM Studio) lives at 127.0.0.1 and the root policy derives its hosts from provider URLs. | pattern ^(\*|(\*\.)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*)$min length 1 max length 253 | ||
#capabilities.commands | array | Executable names the agent may run. | stable | ||
#capabilities.commands[] | string | An executable the plugin asks to run. The basename of the executable, at most 128 characters: letters, digits, ., _, +, -. No path separator (identity is the resolved executable's basename, not where it was found), no whitespace (an argument is not part of the name) and no shell operator. | pattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$min length 1 | ||
#capabilities.tool_args | object | DECLARED argument constraints per tool a plugin asks for, as in the lease manifest it becomes (schema set 1.2, development stability): tool name to a JSON Schema the agent proposes for its own calls to that tool, after Progent's argument-schema policies. A declaration, not a grant: in 1.x an issuer MAY omit it from the granted manifest and MUST NOT treat it as granted authority, because the reference gate does not yet evaluate argument schemas and a narrowing rule without an enforcing gate is a claim the corpus cannot test. The vector tool-args-dropped shows the reference dropping it. It becomes a rule when a gate enforces it. | keys must match ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$additional properties: see #capabilities.tool_args.* | development a declaration an issuer MAY omit from the grant (SPEC 4.4); becomes a rule when a gate enforces it | |
#capabilities.tool_args.* | object | A JSON Schema. Not validated as one here: draft-07 cannot validate a schema as data without a meta-schema $ref, which the self-contained rule forbids. |
#cdf
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#cdf | object | The additive CDF block. Absent in a plain Claude Code plugin, and its absence is not a defect: such a plugin contributes its skills, commands, agents, hooks and MCP servers and declares nothing further. | |||
#cdf.schemaVersion | string | yes | Contract version this block was written against. | one of "1.0" | stable |
#cdf.contributes | object #contributes | What the plugin adds to the harness as DATA the kernel reads. Every list is optional. Nothing here is code the kernel executes: a contributed check names a worker the harness spawns, and a contributed provider names a host the egress policy must already permit. | stable | ||
#cdf.capabilities | object #capabilities | What the plugin's own code asks to be allowed when the harness runs it out of process. This is the lease manifest's allow shape, property for property, because a plugin worker's lease is generated from it and narrowed against the workspace root policy. It is deliberately NOT the store-listing interface.capabilities vocabulary a plugin may also carry: that is a shelf label, this is an authorisation request. Every list is optional here — an absent list is a plugin that asks for nothing, which is the correct default — whereas the granted manifest requires all five. | stable | ||
#cdf.attestation | object #attestation | Who vouches for the declaration. Optional: a plugin published without a key has nothing to sign with, and the harness records that honestly rather than claiming a signature it does not have. The issuer vocabulary is the lease manifest's, so one reader understands both. | stable |
#check
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#check | object | A data or delivery check the plugin implements. worker is a path inside the plugin; the harness runs it out of process, never in the kernel. | |||
#check.id | string | yes | min length 1 | stable | |
#check.worker | string | yes | min length 1 must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\ | stable |
#componentPath
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#componentPath | string | array | A component directory or file, or a list of them. Claude Code accepts a single string or an array of strings for skills, commands, agents, outputStyles, workflows and experimental.themes, and scans the default folder when the key is absent, so an absent key is not an empty contribution. Every path starts with ./ (skills also accepts "."). Claude Code plugin manifest and marketplace references, read 2026-10-05. | any of: (1) string, min length 1; (2) array, of string, min length 1 | ||
#componentPath[]anyOf branch 2 of 2 | string | min length 1 |
#contributes
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#contributes | object | What the plugin adds to the harness as DATA the kernel reads. Every list is optional. Nothing here is code the kernel executes: a contributed check names a worker the harness spawns, and a contributed provider names a host the egress policy must already permit. | |||
#contributes.providers | array | Model providers the plugin adds to the registry. | stable | ||
#contributes.providers[] | object #provider | A model provider the plugin contributes. kind is the closed set of wire protocols the harness speaks; a provider whose protocol is neither is not a provider the harness can drive. | |||
#contributes.trackers | array | Tracker strategies the plugin adds to the mirror. | stable | ||
#contributes.trackers[] | object #tracker | A tracker strategy the plugin contributes. The action ids name integration actions; an id the host does not know is reported, never invented. | |||
#contributes.docPacks | array | Paths inside the plugin to document packs it contributes. | stable | ||
#contributes.docPacks[] | string | min length 1 must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\ | |||
#contributes.checks | array | Checks the plugin implements. | stable | ||
#contributes.checks[] | object #check | A data or delivery check the plugin implements. worker is a path inside the plugin; the harness runs it out of process, never in the kernel. |
#prices
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#prices | object | Declared unit prices, for budget accounting. Advisory: the harness records what it spent, not what it was told it would cost. | |||
#prices.input_per_million | number | min 0 | stable | ||
#prices.output_per_million | number | min 0 | stable |
#provider
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#provider | object | A model provider the plugin contributes. kind is the closed set of wire protocols the harness speaks; a provider whose protocol is neither is not a provider the harness can drive. | |||
#provider.id | string | yes | min length 1 | stable | |
#provider.kind | string | yes | The wire protocol. Closed: the harness has exactly these two clients. | one of "openai-compatible", "anthropic" | stable |
#provider.baseUrl | string | Where the provider is reached: https://, or http:// to loopback only (127.0.0.1, localhost, [::1]), because a local model provider such as Ollama or LM Studio lives there and a plain-http remote provider would carry a key in the clear. | min length 1 any of: (1) pattern ^https://; (2) pattern ^http://(127\.0\.0\.1|localhost|\[::1\])(:[0-9]{1,5})?(/|$) | stable | |
#provider.model | string | min length 1 | stable | ||
#provider.prices | object #prices | Declared unit prices, for budget accounting. Advisory: the harness records what it spent, not what it was told it would cost. | stable | ||
#provider.extraHosts | array | Hostnames beyond the base URL's own that this provider reaches. They must still be permitted by the lease. | stable | ||
#provider.extraHosts[] | string | min length 1 |
#repository
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#repository | string | object | The source repository, as a URL string or as an object carrying one. | any of: (1) string, min length 1; (2) object |
#tracker
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#tracker | object | A tracker strategy the plugin contributes. The action ids name integration actions; an id the host does not know is reported, never invented. | |||
#tracker.id | string | yes | min length 1 | stable | |
#tracker.label | string | yes | min length 1 | stable | |
#tracker.readAction | string | yes | min length 1 | stable | |
#tracker.commentAction | string | min length 1 | stable | ||
#tracker.transitionAction | string | min length 1 | stable | ||
#tracker.createAction | string | min length 1 | stable | ||
#tracker.externalIdLabel | string | min length 1 | stable | ||
#tracker.externalIdPlaceholder | string | min length 1 | stable |
#dependencies
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#dependencies | array | Plugins that must be enabled for this one to work. Each entry is "name", "name@marketplace", or an object with name, marketplace and version. Claude Code plugin manifest and marketplace references, read 2026-10-05. | |||
#dependencies[] | string | object | any of: (1) string, min length 1; (2) object, with name, marketplace, version, requires name | |||
#dependencies[].nameanyOf branch 2 of 2 | string | yes | min length 1 | stable | |
#dependencies[].marketplaceanyOf branch 2 of 2 | string | stable | |||
#dependencies[].versionanyOf branch 2 of 2 | string | stable |
#userConfigOption
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#userConfigOption | object | One user-configuration option. A STRICT object in Claude Code: an unknown key stops the plugin loading, so the contract refuses it too, which is the one place the contract closes a content model to mean what Claude Code means. Claude Code plugin manifest and marketplace references, read 2026-10-05. | no additional properties | ||
#userConfigOption.type | string | yes | one of "string", "number", "boolean", "directory", "file" | stable | |
#userConfigOption.title | string | yes | min length 1 | stable | |
#userConfigOption.description | string | yes | stable | ||
#userConfigOption.required | boolean | stable | |||
#userConfigOption.default | string | number | boolean | array | any of: (1) string; (2) number; (3) boolean; (4) array, of string | stable | ||
#userConfigOption.default[]anyOf branch 4 of 4 | string | ||||
#userConfigOption.options | array | stable | |||
#userConfigOption.options[] | string | min length 1 max length 64 | |||
#userConfigOption.multiple | boolean | stable | |||
#userConfigOption.sensitive | boolean | stable | |||
#userConfigOption.min | number | stable | |||
#userConfigOption.max | number | stable |
#userConfig
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#userConfig | object | Values Claude Code prompts the user for when the plugin is enabled. Keys are identifiers of letters, digits and underscores not starting with a digit. Claude Code plugin manifest and marketplace references, read 2026-10-05. | keys must match ^[A-Za-z_][A-Za-z0-9_]*$additional properties: see #userConfig.* | ||
#userConfig.* | object #userConfigOption | One user-configuration option. A STRICT object in Claude Code: an unknown key stops the plugin loading, so the contract refuses it too, which is the one place the contract closes a content model to mean what Claude Code means. Claude Code plugin manifest and marketplace references, read 2026-10-05. |
#channel
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#channel | object | A message channel bound to one of the plugin's MCP servers. A STRICT object in Claude Code. Claude Code plugin manifest and marketplace references, read 2026-10-05. | no additional properties | ||
#channel.server | string | yes | min length 1 | stable | |
#channel.displayName | string | stable | |||
#channel.userConfig | object #userConfig | Values Claude Code prompts the user for when the plugin is enabled. Keys are identifiers of letters, digits and underscores not starting with a digit. Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable |
#lspServer
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#lspServer | object | One language server. A STRICT object in Claude Code: command and extensionToLanguage are required and an unknown key fails validation. Claude Code plugin manifest and marketplace references, read 2026-10-05. | no additional properties | ||
#lspServer.command | string | yes | min length 1 | stable | |
#lspServer.extensionToLanguage | object | yes | min properties 1 keys must match ^\.additional properties: see #lspServer.extensionToLanguage.* | stable | |
#lspServer.extensionToLanguage.* | string | min length 1 | |||
#lspServer.args | array | stable | |||
#lspServer.args[] | string | ||||
#lspServer.transport | string | one of "stdio", "socket" | stable | ||
#lspServer.env | object | additional properties: see #lspServer.env.* | stable | ||
#lspServer.env.* | string | ||||
#lspServer.initializationOptions | object | stable | |||
#lspServer.settings | object | stable | |||
#lspServer.workspaceFolder | string | stable | |||
#lspServer.startupTimeout | integer | min 1 max 9007199254740991 | stable | ||
#lspServer.shutdownTimeout | integer | min 1 max 9007199254740991 | stable | ||
#lspServer.requestTimeout | integer | min 1 max 9007199254740991 | stable | ||
#lspServer.restartOnCrash | boolean | stable | |||
#lspServer.maxRestarts | integer | min 0 max 9007199254740991 | stable | ||
#lspServer.diagnostics | boolean | stable |
#lspServers
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#lspServers | string | object | array | .json LSP config files, an inline map of server name to config, or an array of either. Claude Code plugin manifest and marketplace references, read 2026-10-05. | any of: (1) string, min length 1; (2) object, additional properties #lspServer; (3) array, of string | object, any of 2 branches | ||
#lspServers.*anyOf branch 2 of 3 | object #lspServer | One language server. A STRICT object in Claude Code: command and extensionToLanguage are required and an unknown key fails validation. Claude Code plugin manifest and marketplace references, read 2026-10-05. | |||
#lspServers[]anyOf branch 3 of 3 | string | object | any of: (1) string, min length 1; (2) object, additional properties #lspServer | |||
#lspServers[].*anyOf branch 3 of 3; anyOf branch 2 of 2 | object #lspServer | One language server. A STRICT object in Claude Code: command and extensionToLanguage are required and an unknown key fails validation. Claude Code plugin manifest and marketplace references, read 2026-10-05. |
#commandEntry
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#commandEntry | object | One command in the commands object map. Exactly one of source (a path) or content (inline Markdown) is set. Claude Code plugin manifest and marketplace references, read 2026-10-05. | exactly one of: (1) requires source; (2) requires content | ||
#commandEntry.source | string | min length 1 | stable | ||
#commandEntry.content | string | stable | |||
#commandEntry.description | string | stable | |||
#commandEntry.argumentHint | string | stable | |||
#commandEntry.model | string | stable | |||
#commandEntry.allowedTools | array | stable | |||
#commandEntry.allowedTools[] | string | min length 1 |
#commands
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#commands | string | array | object | Flat .md command files, directories of them, or an object map of command name to source or content. Claude Code plugin manifest and marketplace references, read 2026-10-05. | any of: (1) string, min length 1; (2) array, of string, min length 1; (3) object, additional properties #commandEntry | ||
#commands[]anyOf branch 2 of 3 | string | min length 1 | |||
#commands.*anyOf branch 3 of 3 | object #commandEntry | One command in the commands object map. Exactly one of source (a path) or content (inline Markdown) is set. Claude Code plugin manifest and marketplace references, read 2026-10-05. |
#monitor
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#monitor | object | One background monitor. A STRICT object in Claude Code. Claude Code plugin manifest and marketplace references, read 2026-10-05. | no additional properties | ||
#monitor.name | string | yes | min length 1 | stable | |
#monitor.command | string | yes | min length 1 | stable | |
#monitor.description | string | yes | min length 1 | stable | |
#monitor.when | string | stable |
#experimental
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#experimental | object | Container for themes, monitors and evals, whose manifest shape Claude Code says may still change. Claude Code plugin manifest and marketplace references, read 2026-10-05. | |||
#experimental.themes | string | array #componentPath | A component directory or file, or a list of them. Claude Code accepts a single string or an array of strings for skills, commands, agents, outputStyles, workflows and experimental.themes, and scans the default folder when the key is absent, so an absent key is not an empty contribution. Every path starts with ./ (skills also accepts "."). Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable | ||
#experimental.monitors | string | array | any of: (1) string, min length 1; (2) array, of #monitor | stable | ||
#experimental.monitors[]anyOf branch 2 of 2 | object #monitor | One background monitor. A STRICT object in Claude Code. Claude Code plugin manifest and marketplace references, read 2026-10-05. | |||
#experimental.evals | string | array #componentPath | A component directory or file, or a list of them. Claude Code accepts a single string or an array of strings for skills, commands, agents, outputStyles, workflows and experimental.themes, and scans the default folder when the key is absent, so an absent key is not an empty contribution. Every path starts with ./ (skills also accepts "."). Claude Code plugin manifest and marketplace references, read 2026-10-05. | stable |
#credentialFree
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#credentialFree | string | A string that is not a credential. Refuses the seven shapes the reference evidence sanitiser refuses (a private key block, an AWS access key id, a GitHub token, an OpenAI key, a Slack token, a literal bearer token and a JWT), each a pattern without lookahead or word boundaries, which RE2 compiles. A detector, not a guarantee: it catches these shapes and nothing else, and the documented route for a secret remains the host's own environment ($VAR interpolation) or headersHelper. | must not match -----BEGIN [A-Z0-9 ]*PRIVATE KEY-----, (^|[^A-Za-z0-9])AKIA[0-9A-Z]{16}([^A-Za-z0-9]|$), (^|[^A-Za-z0-9])gh[pousr]_[A-Za-z0-9]{36,}, (^|[^A-Za-z0-9])sk-[A-Za-z0-9_-]{20,}, (^|[^A-Za-z0-9])xox[baprs]-[A-Za-z0-9-]{10,}, Bearer +[A-Za-z0-9._~+/-]{16,}, eyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,} |
#hookHandler
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#hookHandler | object | One hook, discriminated by type, after the Claude Code settings schema on SchemaStore (read 2026-10-05). The five types are closed because a handler of unknown type is one the harness cannot vet; each type's own fields stay open because Claude Code adds fields between releases and a plugin that uses one must not stop validating here. | any of: (1) object, with type = "command", command, args, async, asyncRewake, shell one of "bash", "powershell", timeout, if, statusMessage, once, requires type, command, Runs a command.; (2) object, with type = "prompt", prompt, model, continueOnBlock, timeout, if, statusMessage, once, requires type, prompt, Asks the model a single-turn question.; (3) object, with type = "agent", prompt, model, timeout, if, statusMessage, once, requires type, prompt, Runs a subagent with tools.; (4) object, with type = "http", url, headers, allowedEnvVars, timeout, if, statusMessage, once, requires type, url, POSTs the hook input to a URL.; (5) object, with type = "mcp_tool", server, tool, input, timeout, if, statusMessage, once, requires type, server, tool, Calls a tool on a connected MCP server. | ||
#hookHandler.typeanyOf branch 1 of 5: Runs a command. | string | yes | one of "command" | stable | |
#hookHandler.commandanyOf branch 1 of 5: Runs a command. | string | yes | A shell command, or with args an executable run without a shell. | min length 1 | stable |
#hookHandler.argsanyOf branch 1 of 5: Runs a command. | array | stable | |||
#hookHandler.args[]anyOf branch 1 of 5: Runs a command. | string | ||||
#hookHandler.asyncanyOf branch 1 of 5: Runs a command. | boolean | stable | |||
#hookHandler.asyncRewakeanyOf branch 1 of 5: Runs a command. | boolean | stable | |||
#hookHandler.shellanyOf branch 1 of 5: Runs a command. | string | one of "bash", "powershell" | stable | ||
#hookHandler.timeoutanyOf branch 1 of 5: Runs a command. | number | Seconds. | greater than 0 | stable | |
#hookHandler.ifanyOf branch 1 of 5: Runs a command. | string | A permission-rule filter; the hook runs only when it matches. | stable | ||
#hookHandler.statusMessageanyOf branch 1 of 5: Runs a command. | string | stable | |||
#hookHandler.onceanyOf branch 1 of 5: Runs a command. | boolean | stable | |||
#hookHandler.typeanyOf branch 2 of 5: Asks the model a single-turn question. | string | yes | one of "prompt" | stable | |
#hookHandler.promptanyOf branch 2 of 5: Asks the model a single-turn question. | string | yes | min length 1 | stable | |
#hookHandler.modelanyOf branch 2 of 5: Asks the model a single-turn question. | string | stable | |||
#hookHandler.continueOnBlockanyOf branch 2 of 5: Asks the model a single-turn question. | boolean | stable | |||
#hookHandler.timeoutanyOf branch 2 of 5: Asks the model a single-turn question. | number | Seconds. | greater than 0 | stable | |
#hookHandler.ifanyOf branch 2 of 5: Asks the model a single-turn question. | string | A permission-rule filter; the hook runs only when it matches. | stable | ||
#hookHandler.statusMessageanyOf branch 2 of 5: Asks the model a single-turn question. | string | stable | |||
#hookHandler.onceanyOf branch 2 of 5: Asks the model a single-turn question. | boolean | stable | |||
#hookHandler.typeanyOf branch 3 of 5: Runs a subagent with tools. | string | yes | one of "agent" | stable | |
#hookHandler.promptanyOf branch 3 of 5: Runs a subagent with tools. | string | yes | min length 1 | stable | |
#hookHandler.modelanyOf branch 3 of 5: Runs a subagent with tools. | string | stable | |||
#hookHandler.timeoutanyOf branch 3 of 5: Runs a subagent with tools. | number | Seconds. | greater than 0 | stable | |
#hookHandler.ifanyOf branch 3 of 5: Runs a subagent with tools. | string | A permission-rule filter; the hook runs only when it matches. | stable | ||
#hookHandler.statusMessageanyOf branch 3 of 5: Runs a subagent with tools. | string | stable | |||
#hookHandler.onceanyOf branch 3 of 5: Runs a subagent with tools. | boolean | stable | |||
#hookHandler.typeanyOf branch 4 of 5: POSTs the hook input to a URL. | string | yes | one of "http" | stable | |
#hookHandler.urlanyOf branch 4 of 5: POSTs the hook input to a URL. | string | yes | Where the hook input is POSTed. | min length 1 | stable |
#hookHandler.headersanyOf branch 4 of 5: POSTs the hook input to a URL. | object | Request headers. Values may interpolate $VAR from allowedEnvVars; a literal credential is refused. | additional properties: see #hookHandler.headers.* | stable | |
#hookHandler.headers.*anyOf branch 4 of 5: POSTs the hook input to a URL. | string #credentialFree | A string that is not a credential. Refuses the seven shapes the reference evidence sanitiser refuses (a private key block, an AWS access key id, a GitHub token, an OpenAI key, a Slack token, a literal bearer token and a JWT), each a pattern without lookahead or word boundaries, which RE2 compiles. A detector, not a guarantee: it catches these shapes and nothing else, and the documented route for a secret remains the host's own environment ($VAR interpolation) or headersHelper. | |||
#hookHandler.allowedEnvVarsanyOf branch 4 of 5: POSTs the hook input to a URL. | array | stable | |||
#hookHandler.allowedEnvVars[]anyOf branch 4 of 5: POSTs the hook input to a URL. | string | ||||
#hookHandler.timeoutanyOf branch 4 of 5: POSTs the hook input to a URL. | number | Seconds. | greater than 0 | stable | |
#hookHandler.ifanyOf branch 4 of 5: POSTs the hook input to a URL. | string | A permission-rule filter; the hook runs only when it matches. | stable | ||
#hookHandler.statusMessageanyOf branch 4 of 5: POSTs the hook input to a URL. | string | stable | |||
#hookHandler.onceanyOf branch 4 of 5: POSTs the hook input to a URL. | boolean | stable | |||
#hookHandler.typeanyOf branch 5 of 5: Calls a tool on a connected MCP server. | string | yes | one of "mcp_tool" | stable | |
#hookHandler.serveranyOf branch 5 of 5: Calls a tool on a connected MCP server. | string | yes | A configured MCP server. | min length 1 | stable |
#hookHandler.toolanyOf branch 5 of 5: Calls a tool on a connected MCP server. | string | yes | min length 1 | stable | |
#hookHandler.inputanyOf branch 5 of 5: Calls a tool on a connected MCP server. | object | stable | |||
#hookHandler.timeoutanyOf branch 5 of 5: Calls a tool on a connected MCP server. | number | Seconds. | greater than 0 | stable | |
#hookHandler.ifanyOf branch 5 of 5: Calls a tool on a connected MCP server. | string | A permission-rule filter; the hook runs only when it matches. | stable | ||
#hookHandler.statusMessageanyOf branch 5 of 5: Calls a tool on a connected MCP server. | string | stable | |||
#hookHandler.onceanyOf branch 5 of 5: Calls a tool on a connected MCP server. | boolean | stable |
#hookMatcher
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#hookMatcher | object | ||||
#hookMatcher.matcher | string | A pattern matched against the event context; absent means every occurrence. | stable | ||
#hookMatcher.hooks | array | yes | stable | ||
#hookMatcher.hooks[] | object #hookHandler | One hook, discriminated by type, after the Claude Code settings schema on SchemaStore (read 2026-10-05). The five types are closed because a handler of unknown type is one the harness cannot vet; each type's own fields stay open because Claude Code adds fields between releases and a plugin that uses one must not stop validating here. |
#hooksMap
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#hooksMap | object | The event map: event name to matchers. The event names are the thirty-three the Claude Code hooks reference lists (read 2026-10-05); an unknown event is refused because nothing would ever fire it. | keys one of 33 values all 33"PreToolUse", "PostToolUse", "PostToolUseFailure", "PermissionRequest", "Notification", "UserPromptSubmit", "Stop", "StopFailure", "SubagentStart", "SubagentStop", "PreCompact", "PostCompact", "Elicitation", "ElicitationResult", "TeammateIdle", "TaskCompleted", "Setup", "InstructionsLoaded", "CwdChanged", "FileChanged", "ConfigChange", "WorktreeCreate", "WorktreeRemove", "SessionStart", "SessionEnd", "PostToolBatch", "TaskCreated", "PermissionDenied", "UserPromptExpansion", "MessageDisplay", "DirectoryAdded", "PreModelSwitch", "PostModelSwitch"additional properties: see #hooksMap.* | ||
#hooksMap.* | array | ||||
#hooksMap.*[] | object #hookMatcher |
#hooksSource
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#hooksSource | object | string | array | Hooks declared inline as the event map, as a path to a .json file that declares them (wrapped in a top-level hooks key), or as an array mixing both. Claude Code accepts all three. | any of: (1) #hooksMap; (2) string, min length 1; (3) array, of object | string, any of 2 branches | ||
#hooksSource[]anyOf branch 3 of 3 | object | string | any of: (1) #hooksMap; (2) string, min length 1 |
#mcpServer
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#mcpServer | object | One MCP server config, keyed by name in mcpServers, after the Claude Code .mcp.json reference (read 2026-10-05). stdio needs command; http, sse, ws and streamable-http need url; an entry with no type is left as the reference leaves it. env and headers values are credential-free: a literal secret in a plugin manifest ships to everyone who installs it, and ${VAR} interpolation or headersHelper is the route. | conditional requirements (below) | ||
#mcpServer.type | string | one of "stdio", "http", "sse", "ws", "streamable-http" | stable | ||
#mcpServer.command | string | when type is "stdio" | min length 1 | stable | |
#mcpServer.args | array | stable | |||
#mcpServer.args[] | string | ||||
#mcpServer.env | object | additional properties: see #mcpServer.env.* | stable | ||
#mcpServer.env.* | string #credentialFree | A string that is not a credential. Refuses the seven shapes the reference evidence sanitiser refuses (a private key block, an AWS access key id, a GitHub token, an OpenAI key, a Slack token, a literal bearer token and a JWT), each a pattern without lookahead or word boundaries, which RE2 compiles. A detector, not a guarantee: it catches these shapes and nothing else, and the documented route for a secret remains the host's own environment ($VAR interpolation) or headersHelper. | |||
#mcpServer.url | string | when type is "http", "sse", "ws" or "streamable-http" | min length 1 | stable | |
#mcpServer.headers | object | additional properties: see #mcpServer.headers.* | stable | ||
#mcpServer.headers.* | string #credentialFree | A string that is not a credential. Refuses the seven shapes the reference evidence sanitiser refuses (a private key block, an AWS access key id, a GitHub token, an OpenAI key, a Slack token, a literal bearer token and a JWT), each a pattern without lookahead or word boundaries, which RE2 compiles. A detector, not a guarantee: it catches these shapes and nothing else, and the documented route for a secret remains the host's own environment ($VAR interpolation) or headersHelper. | |||
#mcpServer.headersHelper | string | stable | |||
#mcpServer.timeout | integer | min 0 max 9007199254740991 | stable | ||
#mcpServer.alwaysLoad | boolean | stable | |||
#mcpServer.oauth | object | stable |
#mcpServersMap
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#mcpServersMap | object | Server name to config. | additional properties: see #mcpServersMap.* | ||
#mcpServersMap.* | object #mcpServer | One MCP server config, keyed by name in mcpServers, after the Claude Code .mcp.json reference (read 2026-10-05). stdio needs command; http, sse, ws and streamable-http need url; an entry with no type is left as the reference leaves it. env and headers values are credential-free: a literal secret in a plugin manifest ships to everyone who installs it, and ${VAR} interpolation or headersHelper is the route. |
#mcpServersSource
| Path | Type | Required | Description | Constraints | Stability |
|---|---|---|---|---|---|
#mcpServersSource | object | string | array | MCP servers declared inline keyed by name, as a path to a .json config, an .mcpb or .dxt bundle path, an https:// bundle URL, or an array mixing these. Claude Code accepts all of them. | any of: (1) #mcpServersMap; (2) string, min length 1; (3) array, of object | string, any of 2 branches | ||
#mcpServersSource[]anyOf branch 3 of 3 | object | string | any of: (1) #mcpServersMap; (2) string, min length 1 |
Conditional requirements
What an if/then clause makes required, one line per property and condition value; the same text appears in the Required column above.
| Property | Required | Where |
|---|---|---|
command | when type is "stdio" | #mcpServer |
url | when type is "http" | #mcpServer |
url | when type is "sse" | #mcpServer |
url | when type is "ws" | #mcpServer |
url | when type is "streamable-http" | #mcpServer |