Follow Discord
Sweep 10 Nov 2026 · 02:18Z Build v2.1.322 539 read Stable v2.1.311 Latest v2.1.322 Next v2.1.322 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-docs

Plugin pre-submission checklist changedplugins/pre-submission-checklist

Nearest release: v2.1.319, published 2 hours after upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 5 Nov 2026 22:16 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 5 Nov 2026 22:37 UTC.

Upstream edited
Recorded here
Lines+5added
Lines−5removed
From line 81 where the diff opens
First seen 25 Sep 2026 this site's first read of the page
Recorded edits9to this page, all time

The whole hunk

from line 81, old and new numbered
/
lines
from line 81
8181| - | - | - |
8282| Submit a folder that contains `.claude-plugin/plugin.json` | Blocks, except that a folder with no `plugin.json` anywhere and at least one `skills/<name>/SKILL.md` passes with a note and is listed for Claude Code only | |
8383| Submit one plugin at a time. In a [marketplace repository](https://code.claude.com/docs/en/plugins/create-marketplace) with several plugins, validate and submit each plugin folder on its own. | Blocks | **Pick one plugin first**, when you select **Submit for review** |
84| Keep every file that a hook, an MCP server command, or a script uses inside the plugin folder, and point every component path in `plugin.json` inside it | Blocks for a `plugin.json` path that points outside the plugin folder | |
84| Keep every file that a hook, an MCP server command, or a script uses inside the plugin folder, and point every component path in `plugin.json` inside it | Blocks for a `plugin.json` path that points outside the plugin folder, and for a path in a command or script that climbs out of it with `..` | **Path climbs out of the plugin** for a `plugin.json` path with `..`. **Command reaches above the plugin folder** for a path in a command or script. |
8585| Commit regular files and folders for everything the plugin loads, not symbolic links, Git submodules, or Git LFS pointer files | Blocks where the plugin loads the entry. Warning elsewhere. | |
8686| Remove `.DS_Store`, `Thumbs.db`, `desktop.ini`, and `__MACOSX` entries from the plugin folder | Blocks | In validation, a message that begins "This is a macOS or Windows system file". After you submit, **Files in the repository the scanner won’t accept**. |
8787| Use file and folder names that are valid on both Windows and macOS: no colon, no trailing dot or space, no Windows device name such as `con.md` or `prn`, and no two names that differ only by capitalization | Validation stops | **Couldn’t validate that repository** |
from line 139
139139| Don't read a credential that is already set in the user's environment, such as `$GITHUB_TOKEN`, and send it to a server, even in a README example. Ask for it through `userConfig` instead. | Held for a reviewer. Blocks for an HTTP hook that sends the credential. | **Uses a credential from the user’s machine** when held |
140140| Make `.mcp.json` valid JSON in which every server entry matches the schema in the [MCP documentation](https://code.claude.com/docs/en/mcp) | Blocks | **.mcp.json can’t be parsed** for invalid JSON |
141141| Give each remote MCP server a `type` of `http`, `sse`, or `ws` and a `url` that is an absolute `https://` or `wss://` URL, a `${user_config.KEY}` reference, or `""` when the plugin has no fixed endpoint | Blocks | **MCP server URL is not https** for a URL with another scheme |
142| Start each local MCP server by running a file in the plugin with plain arguments, such as `node ${CLAUDE_PLUGIN_ROOT}/server.js`, not through a shell, an inline program such as `-c`, or a package-manager script such as `npm run` | Held for a reviewer | **MCP server command wasn’t read** |
143| In the command of a hook or an MCP server, write each path in full from `${CLAUDE_PLUGIN_ROOT}`, with no other variable, command substitution, wildcard, or inline program such as `python3 -c` | Blocks when the plugin folder is a subfolder of the repository | |
144| Keep launchers and package installs out of each script that a hook or an MCP server runs. When the plugin folder is a subfolder of the repository, also keep shell variables other than `${CLAUDE_PLUGIN_ROOT}`, command substitutions, and calls to other files in the plugin out of those scripts. | Held for a reviewer | **Scripts the validator couldn’t follow** |
142| Start each local MCP server by running a file in the plugin with plain arguments, such as `node ${CLAUDE_PLUGIN_ROOT}/server.js`, not through a shell or a package-manager script such as `npm run` | Held for a reviewer | **MCP server command wasn’t read** |
143| In the command of a hook or an MCP server, write each path in full from `${CLAUDE_PLUGIN_ROOT}`, with no other variable, command substitution, wildcard, or inline program such as `python3 -c` | Blocks for another variable, a command substitution, a wildcard, or an inline program | **Command path can’t be followed** |
144| Keep launchers, package installs, shell variables other than `${CLAUDE_PLUGIN_ROOT}`, command substitutions, and calls to other files in the plugin out of each script that a hook or an MCP server runs | Held for a reviewer | **Scripts the validator couldn’t follow** |
145145 
146146### Choices a reviewer always checks
147147 
from line 149
149149 
150150* **A package from a registry:** a launcher that runs a package pinned to an exact version, or `uv run` with `--locked` or `--frozen`, is still held, because the package's own dependencies resolve at install time. The finding is **Runs a pinned npx or uvx package**
151151* **A lockfile install:** `package.json` beside `package-lock.json`, `npm-shrinkwrap.json`, `bun.lock`, or `bun.lockb` in the root of the plugin folder is held, because Claude Code [installs the packages in that lockfile](https://code.claude.com/docs/en/plugins/loading#node-js-package-dependencies) when a user installs the plugin. The finding is **Dependencies install from a lockfile**
152* **A program the validator can't read through, when the plugin folder is a subfolder of the repository:** the validator follows only plain shell scripts. When a hook, an MCP or LSP server command, or a `` !`…` `` line in a skill or command runs a non-shell file from the plugin, passes a whole directory to an interpreter, or runs a shell script that itself runs another file, that file is held. A script that `SKILL.md` only tells Claude to run isn't part of this check. To avoid the hold, keep the plugin at the root of its own repository, or keep the logic a hook or server runs in shell scripts that name each path as `${CLAUDE_PLUGIN_ROOT}/<file>`. The finding is **Scripts the validator couldn’t follow**
152* **A program the validator can't read through:** the validator follows only plain shell scripts. When a hook, an MCP or LSP server command, or a `` !`…` `` line in a skill or command runs a non-shell file from the plugin, passes a whole directory to an interpreter, or runs a shell script that itself runs another file, that file is held. A script that `SKILL.md` only tells Claude to run isn't part of this check. To avoid the hold, keep the logic a hook or server runs in shell scripts that name each path as `${CLAUDE_PLUGIN_ROOT}/<file>`. The finding is **Scripts the validator couldn’t follow**
153153 
154154If you bundle a package's code into the plugin instead, the launcher or install finding no longer applies, and a reviewer hold can still apply. Validation and the scan check the bundled file like every other file in the plugin folder, including the 256 KiB limit in [Files in the plugin folder](#files-in-the-plugin-folder).
155155 
Feedback