Skip to main content

Plugins on your machines

A plugin bundles slash commands, subagents, skills, hooks and local MCP servers. Save one on the gateway and each enrolled machine installs it, with nobody opening a settings page.
Hooks and MCP servers run on every enrolled machine

A plugin's hooks and MCP servers are commands. Review them like code before you save a plugin. Saving or removing one needs the orgplugins:manage capability (security_admin and the admin token), so an operator can still write Skills but not plugins.

Save a plugin​

1
Lay out the plugin

Use the standard folders. Only .claude-plugin/plugin.json is required.

PathHolds
.claude-plugin/plugin.jsonA JSON object. name is the plugin id and version is its version
commands/*.md, agents/*.mdSlash commands and subagents
skills/<folder>/SKILL.mdSkills, each with a name and a description in its front matter
hooks/hooks.jsonHooks, in Claude Code's hook shape
.mcp.jsonLocal (stdio) MCP servers
2
Send it

The body is one JSON object: the id, a display name, a description, the version, "kind": "plugin", and files, a map of path to text.

Save review-kit
curl -X PUT https://<your-anyray-gateway>/admin/v1/desktop-plugins \
-H "Authorization: Bearer $ANYRAY_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d @review-kit.json
review-kit.json
{
"id": "review-kit",
"name": "Review kit",
"description": "Review helpers for the platform team.",
"version": "1.0.0",
"kind": "plugin",
"files": {
".claude-plugin/plugin.json": "{\"name\":\"review-kit\",\"version\":\"1.0.0\"}",
"commands/review.md": "---\ndescription: Review a diff\n---\nReview the diff."
}
}

Admin API keys cannot save or remove plugins, whatever scopes they hold. Use a signed-in admin or the admin token.

3
Confirm it arrived

Machines pick the plugin up on their next sync. See check it arrived for the Claude Code and Claude Desktop checks, which read the same marketplace.

The gateway answers 400 with the reason when the plugin breaks a rule below, 403 without orgplugins:manage, and 409 when a skill in the plugin would take the id of another item.

Which machines get what​

Claude Code and Claude Desktop install the whole plugin from the gateway's marketplace. Other tools that Connect writes skills for (Codex, Cursor and the rest) get the skills only: each skills/<folder>/SKILL.md lands as a skill named <plugin>-<folder>, and a root SKILL.md lands under the plugin id.

What the gateway checks on a save
  • name in plugin.json equals the id, and version equals the item version.
  • hooks and mcpServers in plugin.json are inline or absent. A path to another file is refused.
  • hooks/hooks.json holds a hooks map of events to groups. Each group lists hooks that have a type, and a command hook has a command.
  • An id keeps its kind. Saving a Skill or Guidance item under a plugin's id, or a plugin under theirs, answers 409. Remove the old item first.
  • Item ids that differ only in letter case, or a skill folder that matches another item's id, are refused.
  • Every .mcp.json server is stdio. A url or a type other than stdio is refused: add remote MCP servers under Connectors, where they get credentials and governance.
  • Every skills/<folder>/SKILL.md opens with front matter that sets a name and a description. Folder names use letters, digits, dots, underscores and hyphens.
  • Files are text, up to 256 KB per plugin and 2 MB for all Skills, Guidance and plugins together.
  • Marketplace and archive URLs are public, so a value shaped like a key or token is refused. In plugin.json, hooks.json and .mcp.json that includes a key such as API_KEY or password with a literal value. Reference an environment variable instead, like ${API_KEY}.
  • The archive stores every file without the execute bit. Start scripts through their interpreter, like sh scripts/start.sh.
Machines that lock Claude Code hooks

When a machine's managed Claude Code settings set allowManagedHooksOnly, plugin hooks run only if the managed enabledPlugins lists the plugin. Without that entry the plugin installs and its hooks stay off.