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

# Plugins

> Bundle skills, commands, agents, and integrations — install them with one source string.

A plugin is a self-contained bundle of agent capabilities. Where a [skill](/skills) is a single set of instructions, a plugin packages many things together — skills, slash commands, subagents, MCP servers, hooks, LLM providers, and helper executables — so you can install a whole capability set from one place and turn it on for your agents.

Dash plugins follow the **Claude Code plugin layout**, so a plugin published for Claude Code works in Dash unchanged.

## Quick start

Here's the whole journey, from an empty list to a working plugin — all from **Desktop → Settings → Plugins**:

<Steps>
  <Step title="Install a plugin">
    In the **Install Plugin** form, paste a **source** — a git repo (`git:owner/repo`), a download URL, or a path to a folder on your machine (`/path/to/plugin`) — and click **Install**. Leave **Name** blank to take the name from the plugin's manifest (or the source). See [Installing a plugin](#installing-a-plugin) for all three source forms.
  </Step>

  <Step title="See it in the list">
    The plugin appears with a **status badge** — *Loaded*, *Disabled*, or *Error* — and a row of **contribution** tags showing what it adds (such as skills, commands, agents, mcp, hooks, providers, bin). It lands **enabled but untrusted**: its skills and commands work right away; its code components wait for you to trust it.
  </Step>

  <Step title="Enable / disable it">
    Use the **Enable** / **Disable** button to turn the plugin's markdown components (skills, commands, subagents) on or off. A freshly installed plugin is already enabled.
  </Step>

  <Step title="Trust it (only if it ships code)">
    If the plugin includes code or credential components — MCP servers, hooks, `bin/` executables, or LLM providers — click **Trust**, review the confirmation listing exactly what will run, and confirm. A markdown-only plugin needs no trust. See the [Security model](#security-model).
  </Step>

  <Step title="Use it">
    Skills become loadable by any agent; commands and subagents are available as `/<plugin>:<command>` slash commands; trusted MCP servers and hooks wire in automatically; trusted providers show up on the [AI Providers](/ai-providers) screen once you add a key. See [Invoking each component](#invoking-each-component).
  </Step>
</Steps>

The rest of this page is the reference behind each of those steps. Prefer files over clicks? You can also drop a plugin directory under your HQ's plugins folder (`~/.dash/gateway/plugins/`) and edit `config.json` by hand — see [Where plugins live](#where-plugins-live), [Configuration → Plugins](/configuration#plugins), and the [complete example](#a-complete-example-plugin) below.

## Where plugins live

Installed plugins live in your HQ's managed plugins folder:

```
~/.dash/gateway/plugins/
├── config.json          # per-plugin state (enabled / trusted / source / installed)
└── <plugin-name>/       # one directory per plugin (its skills, commands, etc.)
```

This is the default. The HQ stores everything under `~/.dash` (overridable with `$DASH_HOME`), and its own data lives in `~/.dash/gateway` — so plugins land in `~/.dash/gateway/plugins/`. Running the HQ standalone with `--data-dir <path>` puts them in `<path>/plugins/` instead. See the [data directory layout](/configuration#data-directory) for the full picture.

You rarely need to touch this folder — Desktop's **Plugins** screen and the management API manage it for you. But it's there if you want to drop in a plugin by hand or inspect `config.json` directly.

## What's in a plugin

A plugin is a directory with an optional `.claude-plugin/plugin.json` manifest plus any of these components:

| Component          | What it adds                                     | Loads when              |
| ------------------ | ------------------------------------------------ | ----------------------- |
| `skills/`          | Reusable [skills](/skills) (`SKILL.md` files)    | Enabled                 |
| `commands/`        | Slash commands — `/<plugin>:<command>`           | Enabled                 |
| `agents/`          | Sub-agent types an agent can launch              | Enabled                 |
| `.mcp.json`        | MCP servers (extra [tools](/tools))              | Enabled **and** trusted |
| `hooks/hooks.json` | Shell commands that run at key points in a run   | Enabled **and** trusted |
| `providers/`       | LLM provider catalogs that add selectable models | Enabled **and** trusted |
| `bin/`             | Executables added to the HQ's `PATH`             | Enabled **and** trusted |

The first three components are **markdown** — they only contribute instructions, so an enabled plugin loads them right away. The last four **run code or carry credentials**, so they stay inert until you explicitly *trust* the plugin (see [Security model](#security-model)).

The `.claude-plugin/plugin.json` manifest is optional. When present it can set `name`, `displayName`, `description`, and `version`; when absent, the install name comes from the source (or the directory name).

<Tip>
  Already comfortable with skills? A plugin is the next step up: instead of installing skills one at a time, you install a curated bundle and get its commands, subagents, and integrations alongside them.
</Tip>

## Installing a plugin

You install a plugin **by source** from **Settings → Plugins** in Desktop — fill in the **Install Plugin** form and click **Install** — or, if you're scripting, by calling the management API's `POST /plugins/install` endpoint directly. Either way the installer fetches the plugin, scans it, and drops it into your HQ's managed plugins directory at `~/.dash/gateway/plugins/<name>` — no restart needed; the HQ hot-reloads.

A plugin install takes a single `source` string in one of three forms:

| Source form | Example                                       | What it means                                                     |
| ----------- | --------------------------------------------- | ----------------------------------------------------------------- |
| **Git**     | `git:owner/repo[/subpath][@ref]`              | A GitHub repo (optionally a subdirectory and a pinned ref)        |
| **URL**     | `https://example.com/my-plugin.tar.gz`        | A direct link to a `.tar.gz` archive (`http://` is also accepted) |
| **Local**   | `/path/to/plugin` or `/path/to/plugin.tar.gz` | A folder or archive already on the HQ host                        |

For example, installing from git:

```json theme={null}
POST /plugins/install
{ "source": "git:acme/dash-plugins/research@v1.2.0" }
```

On success you get back the installed plugin's `name`, on-disk `location`, and the `source` it came from. The plugin lands **enabled but untrusted** — its skills and commands work immediately; its code components wait for you to trust it.

Pass an optional `name` to override the install name. The manifest's `name` still wins when one is present.

### Pinning a version

For git sources, append `@ref` to pin the plugin to a branch, tag, or commit:

```
git:acme/dash-plugins/research@main          # a branch (moves over time)
git:acme/dash-plugins/research@v1.2.0         # a tag
git:acme/dash-plugins/research@9f2c1ab…       # a full commit SHA (recommended)
```

A **full commit SHA** is the safest choice — it pins to exact bytes that can't change underneath you. A branch like `@main` always installs the latest, which is convenient but means a later reinstall can bring in different code.

## Managing plugins in Desktop

Desktop's **Settings → Plugins** screen is where you install, inspect, enable, trust, and remove plugins without touching a config file. Changes take effect immediately; the HQ hot-reloads as you go.

**Install Plugin form.** At the top of the screen, a **Source** field takes any install source (git, URL, or local path — see [Installing a plugin](#installing-a-plugin)) and an optional **Name** field overrides the install name (the manifest's `name` still wins when one is present). Click **Install** to fetch, scan, and load the plugin. If the scan flags the plugin as *suspicious* or *dangerous*, the screen shows the verdict so you can decide whether to keep it.

**The plugin list.** Each installed plugin is a card showing its name, version, a **status badge**, and its contributions:

| Status badge | Meaning                                                          |
| ------------ | ---------------------------------------------------------------- |
| **Loaded**   | The plugin is enabled and loaded its components without error.   |
| **Disabled** | The plugin is installed but turned off — it contributes nothing. |
| **Error**    | The plugin failed to load; the card shows the failure message.   |

Below the badge, **contribution tags** show which component types the plugin ships. A tag is shown **activated** (green) when that component is actually running, or **noop** (greyed out, struck through) when it's present but not active yet — for example, a code component on an untrusted plugin, which stays inert until you trust it.

**Per-plugin controls.** Each card has:

* **Enable / Disable** — toggles the plugin's markdown components (skills, commands, subagents) on or off.
* **Trust / Revoke Trust** — shown **only when the plugin is enabled**. *Trust* opens a confirmation (below); *Revoke Trust* immediately stops the plugin's code components from running.
* **Remove** — deletes the plugin's directory from your machine, after a confirmation prompt.

### The trust confirmation

Clicking **Trust** opens a confirmation dialog before any code runs. It carries a high-contrast warning — **"This code will run on your machine."** — and lists the exact code component types that will activate once you trust the plugin: any of `bin`, `hooks`, `mcp`, and `providers` the plugin ships. Confirm with **Trust Plugin**, or cancel to leave the plugin untrusted.

<Note>
  The **Trust Plugin** button is disabled until the plugin is **enabled** — you enable a plugin first, then trust it. Trust is a deliberate, separate action; nothing trusts a plugin on your behalf. See the [Security model](#security-model) for why.
</Note>

## Security model

Installing a plugin brings someone else's instructions — and potentially their code — onto your HQ. Dash treats every install as **untrusted by default** and layers several defenses:

1. **Untrusted on arrival.** A freshly installed plugin is `enabled` but **not** `trusted`. Its markdown components (skills, commands, subagents) load, but its **code components stay inert** — MCP servers, hooks, `bin/` executables, and provider catalogs do nothing until you trust the plugin. Nothing a plugin ships can execute on your HQ from the install alone.

2. **Trust is a separate, deliberate action.** Marking a plugin `trusted` is a distinct step you take *after* you've reviewed it — never something an install, a marketplace entry, or the plugin itself can do on your behalf. Only trust plugins whose code you've read and are willing to run inside the HQ process.

3. **A heuristic scan, fail-closed.** Before a plugin is installed, its manifest and code payloads (`bin/`, `hooks/hooks.json`, `.mcp.json`, `providers/`) are scanned for **dangerous** patterns — downloads piped into a shell, destructive deletes, prompt-injection, secret exfiltration, and embedded private keys. A plugin the scan flags as **dangerous is refused** (the install fails; nothing lands on disk), and the scan is fail-closed: if it can't complete, the install is rejected rather than waved through. Softer **suspicious** signals — reading environment variables, base64 decoding, or prototype-pollution keys in a config file — are noted but do **not** block the install; treat them as a prompt to review the plugin before you trust it.

4. **Path-traversal (zip-slip) protection.** Archives are extracted with hard guards: any entry whose path would escape the destination — via `../`, an absolute path, or a symlink pointing outside — is rejected and the whole install fails. A malicious archive can't write files outside its own plugin directory.

<Warning>
  Trusting a plugin lets its hooks, MCP servers, `bin/` executables, and provider catalogs run inside the HQ with its privileges. Review a plugin before you trust it — especially anything installed from a source you don't control.
</Warning>

## Provider credentials

Some plugins ship **LLM provider catalogs** (`providers/*.json`) that add extra AI providers — your company's internal model HQ, a regional endpoint, or any OpenAI-compatible service. When you've **trusted** a plugin that ships one, its providers appear automatically on the **Settings → AI Providers** screen in Desktop ([AI Providers](/ai-providers)), listed right alongside the built-in ones (Claude, OpenAI, Google, Kimi, OpenRouter).

Adding a key works exactly like a built-in provider: open **AI Providers**, pick the plugin's provider, and paste your key. Each provider needs its own API key.

**Multiple named keys.** A provider can hold more than one key — a `default` plus extras like `backup` — so you can keep an alternate credential ready. Keys are stored in the same encrypted credential store as your built-in providers, under slots named:

```
<provider-id>-api-key:<key-name>
```

For example, a provider with id `myprov` stores its primary key under `myprov-api-key:default` and a second under `myprov-api-key:backup`.

<Note>
  A plugin's providers only show up if the plugin is **trusted**. An untrusted plugin's provider catalog is withheld — its providers won't appear on the AI Providers screen, and there's nowhere to add a key for them — until you trust the plugin (see [Security model](#security-model)). This is the same trust gate that holds back MCP servers, hooks, and `bin/` executables.
</Note>

A plugin can't shadow a built-in provider: if a plugin's provider id collides with one of the built-ins (`anthropic`, `openai`, `google`, `moonshotai`, `openrouter`), that provider is dropped and never offered, even from a trusted plugin.

## Invoking each component

Once a plugin is loaded (and trusted, where needed), its components show up in different places. Here's how each one is reached:

| Component                | How you use it                                                                                                   | Needs trust? |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------- | ------------ |
| **Skills**               | Auto-discovered into the agent's skill index; the agent loads one on demand with its `load_skill` tool.          | No           |
| **Commands**             | A `/<plugin>:<command>` slash command.                                                                           | No           |
| **Subagents**            | A `/<plugin>:<agent>` slash command, or loaded by the agent via `load_skill`.                                    | No           |
| **MCP servers**          | Register automatically at startup; their tools become available to the agent — no explicit invocation.           | Yes          |
| **Hooks**                | Run transparently at events during a run (session start, before/after tools, and so on).                         | Yes          |
| **LLM providers**        | Appear in the agent's model picker once trusted and a key is added.                                              | Yes          |
| **Executables (`bin/`)** | Prepended to the HQ's `PATH`, so they resolve when a command, hook, or the agent's shell tools run them by name. | Yes          |

### Skills

A plugin's `skills/<name>/SKILL.md` files join the agent's **skill index** — the compact list of available skills the agent sees in its system prompt. The agent loads a skill's full instructions on demand with its `load_skill` tool, so the agent needs `load_skill` in its tool list (it's there by default whenever skills are configured). See [Skills](/skills) for the format and how discovery works.

### Commands and subagents

A plugin's `commands/<name>.md` becomes a slash command **`/<plugin>:<command>`** — a plugin named `research` with `commands/triage.md` exposes `/research:triage`. A plugin's `agents/<name>.md` (Claude Code subagent format) becomes a **sub-agent type** named `<plugin>:<agent>`, which an agent launches with the [`agent` tool](/tools#sub-agents). Both are **markdown**, so they work on `enabled` alone — no trust needed. The plugin name namespaces them, so neither can clash with anything else.

<Note>
  **Plugin sub-agents run in their own context**, not in the main session. Their `tools` and `model` frontmatter is **enforced** — earlier releases loaded these files into the current conversation and treated `tools` as advisory. A sub-agent still never receives a tool or MCP server its parent lacks. See [Configuration → Plugin sub-agent types](/configuration#plugin-sub-agent-types).
</Note>

### MCP servers, hooks, and executables

These are **trusted** code components, and none of them is invoked by a slash command — they wire in behind the scenes:

* **MCP servers** (`.mcp.json`) register with the HQ at startup. Their tools become part of the agent's toolset; registration is fail-isolated, so a server that won't start is logged and skipped without taking down the HQ.
* **Hooks** (`hooks/hooks.json`) run automatically at key points in a run — session start, before and after tools, and run completion. You don't call them; they fire on events. For the full event list and behavior see [Hooks in the configuration reference](/configuration#hooks).
* **Executables** (`bin/`) are prepended to the HQ's `PATH`, so a plugin's tools resolve ahead of system binaries when a command, hook, or the agent's shell tools invoke them by name.

### LLM providers

A trusted plugin's `providers/*.json` catalogs add selectable models. Once the plugin is trusted **and** you've added a key (see [Provider credentials](#provider-credentials)), the provider's models appear in the agent's model picker as `<id>/<model-id>`, exactly like the built-in providers — point any agent at one the same way.

## Choosing plugins per agent

By default, **every agent sees every loaded plugin**. You can scope an individual agent to a subset from its configuration:

<Steps>
  <Step title="Open the agent's config">
    In Desktop, go to **Squad**, open the squad member, and switch to its **Config** tab.
  </Step>

  <Step title="Open the Plugins card">
    Expand the **Plugins** card. When no plugins are selected it reads **"All plugins (default)"** — the agent sees every loaded plugin.
  </Step>

  <Step title="Select the plugins this agent should see">
    Use **Add plugin...** to pick from the **loaded** plugins. Each one you add appears as a chip; remove a chip with its **×** button. As soon as you select at least one, the agent is scoped to exactly those plugins. Clear all the chips to return to the **all-plugins** default.
  </Step>
</Steps>

<Note>
  Per-agent selection controls **visibility only — it does not trust a plugin**. Trust is HQ-wide: selecting a plugin for an agent never makes its code run if the plugin isn't trusted, and a trusted plugin stays trusted regardless of which agents are scoped to it. Only **loaded** plugins are offered in the picker — a disabled or errored plugin contributes nothing to route.
</Note>

## Choosing AI providers per agent

Alongside the Plugins card, each agent's **Config** tab also has a **Providers** card. By default it reads **"All providers (default)"** — the agent can use models from every available AI provider. Add one or more providers to restrict the agent to just those: its model dropdown immediately narrows to the allowed providers, and if the agent's current model belongs to a provider you removed, it stays visible marked **"(not allowed)"** so you can pick a replacement. An agent that tries to run on a disallowed provider gets a clear error instead of a response. Clear all the chips to return to the all-providers default.

This is useful when an agent must only ever talk to a specific vendor — for example, keeping a customer-facing agent on Anthropic models only, regardless of which other providers are configured on the HQ.

## Marketplaces

A **marketplace** is a published catalog of plugins you can browse and install by name. You point Dash at a marketplace source — a local path, a URL, or a git repo — and Dash reads its `marketplace.json` to list the plugins it offers.

A `marketplace.json` looks like this:

```json theme={null}
{
  "name": "Acme Plugins",
  "owner": "acme",
  "description": "Internal plugins for the Acme team",
  "plugins": [
    {
      "name": "research",
      "source": "git:acme/dash-plugins/research@v1.2.0",
      "description": "Web research and citation tools"
    },
    {
      "name": "triage",
      "source": "https://plugins.acme.com/triage.tar.gz",
      "description": "Support-ticket triage commands"
    }
  ]
}
```

| Field                   | Required | Description                                |
| ----------------------- | -------- | ------------------------------------------ |
| `name`                  | No       | Marketplace display name                   |
| `owner`                 | No       | Who publishes the marketplace              |
| `description`           | No       | What the marketplace offers                |
| `plugins`               | Yes      | The list of advertised plugins             |
| `plugins[].name`        | Yes      | The name you install by                    |
| `plugins[].source`      | Yes      | A plugin source string (git / URL / local) |
| `plugins[].description` | No       | What the plugin does                       |

Each entry's `source` is just an ordinary install source. When you install a marketplace plugin, Dash resolves the name to its source and runs the **same untrusted, scanned install path** as a direct install — a marketplace listing is never a shortcut to trust. Installing from a marketplace is exactly as safe as installing the source by hand.

## Config flags

Each plugin has an entry in `~/.dash/gateway/plugins/config.json` describing its state. You may see these fields:

| Flag        | Meaning                                                                                                                                                |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `enabled`   | The plugin's skills and commands load. Set `true` on install.                                                                                          |
| `trusted`   | The plugin's code components (MCP, hooks, `bin/`, providers) are allowed to run. Defaults to off — set deliberately after review.                      |
| `source`    | Where the plugin was installed from, recorded for reinstall/update.                                                                                    |
| `installed` | `true` when the management API installed the plugin into `~/.dash/gateway/plugins/<name>`. Determines whether uninstalling also deletes the directory. |

For the full config-file format — directory layout, manual enabling, loading a plugin from an arbitrary `path`, and per-component details — see [Configuration → Plugins](/configuration#plugins).

## A complete example plugin

Here's a minimal but realistic plugin you can copy and install from a local folder. It bundles a skill, a slash command, and — optionally — an LLM provider and a hook.

**Directory layout:**

```
my-plugin/
├── .claude-plugin/
│   └── plugin.json
├── skills/
│   └── summarize/
│       └── SKILL.md
├── commands/
│   └── triage.md
├── providers/                  (optional — needs trust)
│   └── myprov.json
└── hooks/                      (optional — needs trust)
    └── hooks.json
```

**`.claude-plugin/plugin.json`** — the manifest. Only `name` is meaningful-required (and must be kebab-case); the rest is metadata.

```json theme={null}
{
  "name": "my-plugin",
  "displayName": "My Plugin",
  "description": "A summarize skill and a triage command",
  "version": "1.0.0"
}
```

**`skills/summarize/SKILL.md`** — a skill. Markdown, so it loads on `enabled` alone.

```markdown theme={null}
---
name: summarize
description: Summarize any text concisely
---
Summarize the provided text in three sentences or fewer.
```

**`commands/triage.md`** — a slash command, reachable as `/my-plugin:triage`. Optional frontmatter (`name`, `description`) overrides the command name and supplies a description.

```markdown theme={null}
---
description: Triage an incoming support ticket
---
Read the ticket below and assign a priority (P1–P4) with a one-line reason.
```

**`providers/myprov.json`** *(optional — a code/credential component, so it only runs once the plugin is trusted)*. The `credentialPrefix` must equal `<id>-api-key`, and `models` must list at least one model.

```json theme={null}
{
  "id": "myprov",
  "label": "My Provider",
  "credentialPrefix": "myprov-api-key",
  "baseUrl": "https://api.myprov.example/v1",
  "api": "openai-completions",
  "models": [
    { "id": "my-fast", "name": "My Fast", "contextWindow": 128000, "maxTokens": 8192 }
  ]
}
```

**`hooks/hooks.json`** *(optional — also trust-gated)*. Claude Code hooks format; `${CLAUDE_PLUGIN_ROOT}` resolves to the plugin's own directory.

```json theme={null}
{
  "PreToolUse": [
    {
      "matcher": "bash",
      "hooks": [
        { "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/scripts/guard.sh" }
      ]
    }
  ]
}
```

**Install it.** From Desktop's **Settings → Plugins** screen, put the folder's path in the **Source** field (for example `/Users/you/plugins/my-plugin`) and click **Install**. The plugin lands **enabled but untrusted** — the `summarize` skill and `/my-plugin:triage` command work right away. To turn on the provider and hook, click **Trust** and confirm. Then add a key for the provider on the **Settings → AI Providers** screen, and its `myprov/my-fast` model becomes selectable for any agent.

## What the errors mean

If an install fails, the response code tells you why:

| Code  | Meaning                                                                                                                                                 | What to do                                                                     |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `404` | Source or marketplace entry **not found** — a missing repo, a dead URL, an unknown plugin name                                                          | Check the source string and that the plugin exists                             |
| `409` | A plugin with that name is **already installed**                                                                                                        | Uninstall the existing one first, or install under a different `name`          |
| `422` | The plugin is **invalid, corrupt, dangerous, or failed the scan** — a bad manifest, a broken archive, a zip-slip attempt, or a payload the scan flagged | Inspect the source; this usually means the plugin shouldn't be installed as-is |

## Not yet supported

A couple of capabilities are planned but not available yet, so you know not to rely on them:

* **Signature verification** — installs are scanned heuristically but not cryptographically verified against a publisher signature.
* **npm / registry sources** — plugins install from git, URL, and local sources only; there's no `npm:`-style package registry source yet.
