> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pinework.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Plugin

> A plugin is one workspace install from a git repo, a marketplace or a device that adds read-only skills, MCP servers and commands. Marketplaces list plugins.

A plugin is one install that adds skills, MCP servers and commands to the whole workspace. Its id is `plug_` plus 16 base62 characters. A marketplace is a git repo whose index lists plugins, with id `mkt_…`. For why plugin parts are read-only, see [Plugins and skills](/concepts/plugins-and-skills).

## States

A plugin has no lifecycle status. Its one switch is `enabled`.

| State | Meaning | Ends here |
| - | - | - |
| On (`enabled: true`) | Its skills can reach runs, subject to each skill's own switch. | No |
| Off (`enabled: false`) | Its skills reach no run. An agent override cannot turn one on. | No |

| From | To | Trigger |
| - | - | - |
| On | Off | `pinework plugin update <plug_…> --enabled false` |
| Off | On | `pinework plugin update <plug_…> --enabled true` |

Uninstall deletes the plugin and every part it owns. There is no uninstalled state. A refresh replaces the parts in one step, so a run sees the old set or the new set.

Plugin parts are read-only. On a plugin skill you can change only `enabledByDefault`. On a plugin MCP server you can change only `enabled`, `connectionId`, `secretRef`, `authKind` and `headerName`. To change anything else, create your own standalone copy and turn the plugin's part off.

## Fields

<ResponseField name="object" type="string" required>Always `plugin`.</ResponseField>
<ResponseField name="id" type="string" required>`plug_…` id.</ResponseField>
<ResponseField name="slug" type="string" required>Stable name, unique in the workspace. For a marketplace plugin, the entry name.</ResponseField>
<ResponseField name="displayName" type="string" required>Readable name. You can change it.</ResponseField>
<ResponseField name="version" type="string">Version from the manifest. Null when the manifest has none.</ResponseField>
<ResponseField name="vendor" type="string" required>Manifest format: `anthropic`, `codex`, `cursor` or `agent-plugins`.</ResponseField>
<ResponseField name="marketplace" type="string">Marketplace it came from. Null for a direct install.</ResponseField>
<ResponseField name="sourceType" type="string">`github`, `git-url`, `git-subdir` or `local-device`. Null when unknown.</ResponseField>
<ResponseField name="enabled" type="boolean" required>Whether the plugin is on for the workspace.</ResponseField>
<ResponseField name="description" type="string">Description. Null when unset.</ResponseField>
<ResponseField name="homepage" type="string">Homepage URL. Null when unset.</ResponseField>

<ResponseField name="componentCounts" type="object" required>
  Count of each part kind the plugin declares. Pinework installs skills, MCP servers and commands. It records the other kinds without installing them.

  <Expandable title="componentCounts">
    <ResponseField name="skills" type="integer" required>Skills.</ResponseField>
    <ResponseField name="mcpServers" type="integer" required>MCP servers.</ResponseField>
    <ResponseField name="commands" type="integer" required>Commands.</ResponseField>
    <ResponseField name="hooks" type="integer" required>Hooks.</ResponseField>
    <ResponseField name="subagents" type="integer" required>Subagents.</ResponseField>
    <ResponseField name="lsp" type="integer" required>Language servers.</ResponseField>
    <ResponseField name="bin" type="integer" required>Executables.</ResponseField>
    <ResponseField name="outputStyles" type="integer" required>Output styles.</ResponseField>
    <ResponseField name="agentTemplates" type="integer" required>Agent templates.</ResponseField>
    <ResponseField name="teamTemplates" type="integer" required>Team templates.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="installedAt" type="string" required>Install time, ISO 8601.</ResponseField>
<ResponseField name="updatedAt" type="string" required>Last change time, ISO 8601.</ResponseField>
<ResponseField name="author" type="object">`name` and `email`, each null when unset. Detail only.</ResponseField>
<ResponseField name="source" type="object">`url`, `ref` and `sha` it was fetched at, each nullable. Detail only.</ResponseField>
<ResponseField name="warnings" type="object[]">Install and refresh only. Each has a `code`: `duplicate-within-bundle`, `mcp-name-taken` or `connection-dropped`.</ResponseField>

A marketplace object has these fields:

<ResponseField name="id" type="string" required>`mkt_…`, or the name for a built-in.</ResponseField>
<ResponseField name="name" type="string" required>The index's own name. `--marketplace` takes it.</ResponseField>
<ResponseField name="sourceUrl" type="string" required>The repo the index lives in.</ResponseField>
<ResponseField name="sourceRef" type="string" required>The ref it is read at. `HEAD` means the default branch.</ResponseField>
<ResponseField name="manifestPath" type="string" required>The index file that matched.</ResponseField>
<ResponseField name="entryCount" type="integer" required>Plugins you can install from it.</ResponseField>
<ResponseField name="skipped" type="object[]" required>Entries Pinework will not install, each with `name` and `reason`.</ResponseField>
<ResponseField name="builtIn" type="boolean" required>`true` for `claude-plugins-official` and `cursor-plugins`.</ResponseField>
<ResponseField name="lastRefreshedAt" type="string" required>When the index was last read.</ResponseField>

## CLI

| Command | Does |
| - | - |
| `pinework plugin list` | List plugins, newest install first. Filter by `--enabled`, `--marketplace`, `--source-type`, `--vendor` or `--q`. |
| `pinework plugin get <plug_…>` | Show one plugin with its source, author and part counts. |
| `pinework plugin install` | Install by `--marketplace` and `--plugin`, by `--source-type` and `--url`, or from a device. |
| `pinework plugin update <plug_…>` | Change `--name` or `--enabled`. |
| `pinework plugin refresh <plug_…>` | Fetch the plugin again from its recorded source and replace its parts. |
| `pinework plugin delete <plug_…>` | Uninstall it and remove every skill, MCP server, hook and grant it owns. |
| `pinework marketplace list` | List marketplaces, built-in first. |
| `pinework marketplace add <git-url>` | Add a marketplace. Takes `--ref`. |
| `pinework marketplace plugins <name or mkt_…>` | List the plugins it offers, plus skipped entries and why. |
| `pinework marketplace refresh <name or mkt_…>` | Read its index again. |
| `pinework marketplace remove <name or mkt_…>` | Remove it. Installed plugins stay. |

A device install takes `--source-type local-device`, `--device-id`, `--vendor` and `--manifest-path`. `refresh` fetches only plugins with a git source.

```bash theme={null}
pinework marketplace add https://github.com/acme/agent-plugins
pinework plugin install --marketplace acme-plugins --plugin release-tools
pinework plugin install --source-type github --url https://github.com/acme/release-tools --ref v1.4.0
pinework plugin update plug_8fK2mQx7Lp3RtV9a --enabled false
```

## API

| Method | Path | Does |
| - | - | - |
| GET | `/api/v1/companies/{workspaceId}/plugins` | List plugins. Query `vendor`, `marketplace`, `sourceType`, `enabled`, `q`, `limit`, `cursor`, `sort`. |
| POST | `/api/v1/companies/{workspaceId}/plugins` | Install from a source. Body `{source, components?}`. |
| POST | `/api/v1/companies/{workspaceId}/plugins/install-from-marketplace` | Install by name. Body `{marketplace, plugin, sha?}`. Returns 201, or 200 when it updates an installed plugin. |
| GET | `/api/v1/companies/{workspaceId}/plugins/{pluginId}` | Read one plugin. |
| PATCH | `/api/v1/companies/{workspaceId}/plugins/{pluginId}` | Change `displayName` or `enabled`. |
| DELETE | `/api/v1/companies/{workspaceId}/plugins/{pluginId}` | Uninstall. Returns 204. |
| POST | `/api/v1/companies/{workspaceId}/plugins/{pluginId}/refresh` | Refresh. Body `{sha?}` moves it to that commit. |
| GET | `/api/v1/companies/{workspaceId}/plugins/{pluginId}/{kind}` | List owned parts. `kind` is `skills`, `mcp-servers`, `commands`, `hooks`, `lsp`, `bin`, `subagents`, `agent-templates` or `team-templates`. |
| GET | `/api/v1/companies/{workspaceId}/plugins/outdated` | List marketplace plugins whose entry now pins a newer commit. |
| POST | `/api/v1/companies/{workspaceId}/install/parse` | Read a pasted install command and return what would install. It never runs the command. |
| GET | `/api/v1/plugins/catalog` | Browse the Anthropic catalog live. |
| GET | `/api/v1/companies/{workspaceId}/marketplaces` | List marketplaces. |
| POST | `/api/v1/companies/{workspaceId}/marketplaces` | Add one. Body `{url, ref?}`. |
| GET | `/api/v1/companies/{workspaceId}/marketplaces/{marketplace}/plugins` | List its plugins and skipped entries. |
| POST | `/api/v1/companies/{workspaceId}/marketplaces/{marketplace}/refresh` | Read its index again. |
| DELETE | `/api/v1/companies/{workspaceId}/marketplaces/{marketplace}` | Remove it. Returns 204. |

`{marketplace}` takes a `mkt_…` id or a name. An agent's install, update, refresh, uninstall, or marketplace change becomes an approval request. The call returns HTTP 202. A marketplace entry with an npm or command source is skipped. Pinework fetches plugin content from git only.

## Errors

| Code | HTTP | When | What to do |
| - | - | - | - |
| `plugin_not_found` | 404 | No plugin has that id, or the marketplace has no entry with that name. | Check with `plugin list` or `marketplace plugins`. |
| `duplicate_plugin_slug` | 409 | A plugin with this slug is installed already. | Refresh or delete the installed one. |
| `invalid_plugin_source` | 400 | The source URL is not one Pinework can fetch. | Pass a GitHub URL. |
| `plugin_source_not_found` | 422 | The repo or ref does not exist. | Check `--url` and `--ref`. |
| `plugin_path_not_found` | 422 | The subdir is not in the repo. | Check `--subdir`. |
| `plugin_source_rejected` | 422 | The archive failed the safety check, for example a link or a path outside the plugin folder. | Fix the repo. |
| `plugin_source_too_large` | 422 | The download is too large. | Use a smaller source or a subdir. |
| `plugin_source_unavailable` | 502 | GitHub failed or rate-limited the fetch. | Retry later. |
| `plugin_scan_empty` | 400, 422 | The scan found no parts. Nothing was installed. | Point at the folder with the manifest. |
| `plugin_component_limit_exceeded` | 400 | The manifest has more than 100 parts. | Split the plugin. |
| `plugin_raw_credential` | 400 | An MCP server carries a raw credential. | Reference a secret or a connection. |
| `plugin_refresh_conflict` | 409 | Another refresh is running, or the plugin changed. | Read it again and retry. |
| `plugin_cache_not_ready` | 202 | Installed, but the cache is not written yet. | Read the plugin again shortly. |
| `skill_replace_forbidden` | 409 | You edited a plugin skill beyond `enabledByDefault`. | Create your own copy. |
| `plugin_mcp_edit_forbidden` | 409 | You edited a plugin MCP server's definition. | Add your own MCP server. |
| `plugin_source_refused` | 422 | The marketplace entry's source kind is refused. | Install it from git by URL instead. |
| `marketplace_not_found` | 404 | No marketplace has that id or name. | Run `marketplace list`. |
| `invalid_marketplace_url` | 400 | The URL is not a GitHub repo, or the ref is unsafe. | Pass `https://github.com/owner/repo`. |
| `not_a_marketplace` | 422 | The repo has no index Pinework can read. | Add a marketplace index file. |
| `duplicate_marketplace` | 409 | A marketplace with that name exists, or it is built in. | Use the existing one. |
| `builtin_marketplace_not_refreshable` | 400 | You refreshed a built-in. It is read live. | Skip the refresh. |
| `builtin_marketplace_not_removable` | 400 | You removed a built-in. | Leave it. |

Shared codes are in [API errors](/reference/api#errors).

## Limits

* A plugin holds at most 100 parts.
* A plugin archive holds at most 10,000 entries and 256 MiB.
* A marketplace index file is read up to 4 MiB, with a 10-second timeout.
* A list page returns 25 plugins by default and 100 at most.
* The `q` search takes up to 100 characters.
* A pasted install command holds up to 8,192 characters.

Pinework looks for a marketplace index at `.agents/plugins/marketplace.json`, `.claude-plugin/marketplace.json` and `.cursor-plugin/marketplace.json`.

<CardGroup cols={2}>
  <Card title="Plugins and skills" href="/concepts/plugins-and-skills">
    Why plugin parts are read-only.
  </Card>

  <Card title="Install a plugin" href="/guides/install-a-plugin">
    Install from a marketplace and fork a part.
  </Card>

  <Card title="Skill" href="/reference/skill">
    The skills a plugin installs.
  </Card>

  <Card title="Connection" href="/reference/connection">
    Credentials for plugin MCP servers.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.