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

# Plugins

A plugin is a directory in Qoder CLI that bundles commands, sub-agents, Skills, Hooks, MCP servers, and other extensions for installation, enable/disable management, and sharing. A plugin directory may contain one or more of these resources, and the CLI auto-discovers and loads them after installation.

## Quick Start

The following example creates a minimal plugin containing a single Skill and installs it from a local directory.

### 1. Create the plugin directory

```bash theme={null}
mkdir -p ~/my-plugin/.qoder-plugin
mkdir -p ~/my-plugin/skills/hello
```

### 2. Write the manifest

Declaring a `plugin.json` is recommended for every plugin so it has stable metadata; at minimum include `name` (see [Manifest Fields](#manifest-fields) below):

`~/my-plugin/.qoder-plugin/plugin.json`:

```json theme={null}
{
  "name": "my-plugin",
  "version": "0.1.0",
  "description": "My first plugin"
}
```

### 3. Add a Skill

`~/my-plugin/skills/hello/SKILL.md`:

```markdown theme={null}
---
name: hello
description: Greet the user. Use when the user says "say hi".
---

# Hello Skill

Greet the user warmly.
```

### 4. Install

```bash theme={null}
qodercli plugins install ~/my-plugin
```

After seeing `Plugin "my-plugin@local" installed successfully. Run /plugins reload to apply.`, restart the CLI or run `/plugins reload` in the TUI to start using the Skill.

## Plugin Directory Layout

`.qoder-plugin/plugin.json` is the recommended location for the manifest. When omitted, the CLI still loads the directory by convention and uses the directory name as the plugin name. Convention directories are **auto-discovered when present, otherwise ignored**.

```
my-plugin/
├── .qoder-plugin/
│   └── plugin.json        # Recommended: manifest (declares name/version/etc.)
├── commands/              # Custom commands (.md files or subdirectories)
├── agents/                # Custom sub-agents
├── skills/                # Custom Skills
├── hooks/
│   └── hooks.json         # Hook configuration
├── output-styles/         # Output styles
├── bin/                   # Plugin executables
└── .mcp.json              # MCP servers shipped with this plugin
```

Convention directory behavior:

| Directory / File   | Purpose                                                                                                                             |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| `commands/`        | Register custom slash commands; same structure as `~/.qoder/commands/`                                                              |
| `agents/`          | Register custom sub-agents                                                                                                          |
| `skills/`          | Register Skills; same structure as `~/.qoder/skills/`                                                                               |
| `hooks/hooks.json` | Hook configuration; uses the `{ "hooks": ... }` wrapper, where the inner `hooks` value matches the `hooks` field in `settings.json` |
| `output-styles/`   | Custom output styles                                                                                                                |
| `bin/`             | Plugin executables                                                                                                                  |
| `.mcp.json`        | MCP server declarations bundled with the plugin                                                                                     |

Agents shipped in `agents/` can also declare `isolation: worktree`, which is useful for implementation Subagents that should run in an isolated copy.

## Manifest Fields

Only `name` is required in `plugin.json`; other fields are optional.

| Field         | Required | Description                                                                                 |
| ------------- | -------- | ------------------------------------------------------------------------------------------- |
| `name`        | Yes      | Unique plugin identifier; cannot contain spaces; kebab-case recommended (e.g., `my-plugin`) |
| `version`     | No       | Semantic version (e.g., `1.0.0`)                                                            |
| `description` | No       | Brief description                                                                           |
| `author`      | No       | Author information                                                                          |
| `homepage`    | No       | Documentation or homepage URL                                                               |
| `repository`  | No       | Source repository URL                                                                       |
| `license`     | No       | SPDX license identifier (e.g., `MIT`)                                                       |
| `keywords`    | No       | Tags for discovery and categorization                                                       |

> Advanced: the manifest can also explicitly declare `commands` / `agents` / `skills` / `hooks` / `outputStyles` to override the default directory conventions or use inline content (note the manifest field uses camelCase `outputStyles`, while the convention directory remains `output-styles/`). When not declared, the CLI auto-discovers via the conventions above.

## Installation Scope

Plugins can be installed at three scopes:

| Scope     | Description                                                                                                             | Use case                              |
| --------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `user`    | Globally available; applies to all of the current user's projects (default)                                             | Personal frequently-used plugins      |
| `project` | Applies only to the current project; written to project-level `settings.json`, can be committed to git for team sharing | Team-shared, project-specific plugins |
| `local`   | Applies only to the current project; written to project-local `settings.local.json`, recommended to add to `.gitignore` | Local experimental plugins            |

## Commands

Plugin commands live under the `qodercli plugins` subcommand group, aliased as `plugin`.

### Install: `plugins install`

Install a plugin from a local directory path:

```bash theme={null}
qodercli plugins install ~/my-plugin
qodercli plugins install ./relative/path/to/plugin
qodercli plugins install /abs/path/to/plugin --scope project
```

| Argument / Option     | Description                                                  |
| --------------------- | ------------------------------------------------------------ |
| `<plugin>`            | Local plugin directory path (absolute, relative, or `~/...`) |
| `-s, --scope <scope>` | Installation scope: `user` (default), `project`, `local`     |

After installation, restart the CLI or run `/plugins reload` in the TUI to apply changes.

### Uninstall: `plugins uninstall`

```bash theme={null}
qodercli plugins uninstall my-plugin
qodercli plugins uninstall my-plugin --scope project --keep-data
```

Aliases: `remove` / `rm`.

| Argument / Option     | Description                                                   |
| --------------------- | ------------------------------------------------------------- |
| `<plugin>`            | Installed plugin name                                         |
| `-s, --scope <scope>` | Scope to uninstall from: `user` (default), `project`, `local` |
| `--keep-data`         | Preserve the plugin's data directory                          |

### Enable / Disable: `plugins enable` / `plugins disable`

```bash theme={null}
qodercli plugins enable my-plugin
qodercli plugins disable my-plugin
qodercli plugins enable my-plugin --scope project
qodercli plugins disable --all
```

| Argument / Option     | Description                                                      |
| --------------------- | ---------------------------------------------------------------- |
| `<plugin>`            | Installed plugin name                                            |
| `-s, --scope <scope>` | Scope to write to; auto-detected if omitted                      |
| `-a, --all`           | (`disable` only) Disable all enabled plugins in the chosen scope |

Enable / disable is implemented by updating the `enabledPlugins` field in the corresponding `settings.json`. Disabled plugins are not loaded in new sessions.

### List: `plugins list`

```bash theme={null}
qodercli plugins list
qodercli plugins list --json
qodercli plugins list --plugin-dir ./local-plugins ./more-plugins
```

| Option                         | Description                                                                  |
| ------------------------------ | ---------------------------------------------------------------------------- |
| `--json`                       | Output as JSON                                                               |
| `-o, --output-format <format>` | `text` or `json` (equivalent to `--json`)                                    |
| `--plugin-dir <dirs...>`       | Additional directories to scan and merge into the listing (does not install) |

### Validate: `plugins validate`

Validate that a local plugin directory matches the conventions; useful during development:

```bash theme={null}
qodercli plugins validate ~/my-plugin
```

The command lists the commands, Skills, Hooks, and other components it discovers, and prints a notice when no convention subdirectory exists. Note: `validate` does not fail in that case — but `plugins install` for a local plugin requires at least one recognizable component or resource (either a convention directory or a resource explicitly declared in the manifest).

> **Recommended**: always declare `name`, `version`, etc. in `.qoder-plugin/plugin.json`. This is the recommended way to organize a Qoder plugin — without it, the plugin can only be identified by its directory name in `plugins list`, `enabledPlugins`, and other places, which is fragile across environments.

## The `enabledPlugins` Setting

Enable / disable state is stored in the `enabledPlugins` field of `settings.json`:

```json theme={null}
{
  "enabledPlugins": {
    "my-plugin@local": true,
    "another-plugin@local": false
  }
}
```

* `true`: enables the plugin
* `false`: explicitly disables the plugin

> The configuration key must match the installed plugin ID exactly (locally installed plugins have IDs of the form `name@local`). Run `plugins list` to see each plugin's identifier.

Prefer `plugins enable` / `plugins disable` over hand-editing this field — the commands handle scope selection, dependency resolution, and other details for you.

## Writing Plugin Hooks

A plugin may declare its own Hooks in `hooks/hooks.json`. The file uses a **wrapped** shape: a top-level object with a `hooks` field whose value matches the `hooks` field in `settings.json`:

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"${QODER_PLUGIN_ROOT}\"/scripts/check.sh"
          }
        ]
      }
    ]
  }
}
```

> Note this differs from `settings.json`: `settings.json` uses the bare `hooks` field, while a plugin's `hooks/hooks.json` requires the extra `{ "hooks": ... }` wrapper.

When executed, plugin Hooks receive two extra environment variables:

| Variable            | Description                                                                                            |
| ------------------- | ------------------------------------------------------------------------------------------------------ |
| `QODER_PLUGIN_ROOT` | Installation root of the current plugin                                                                |
| `QODER_PLUGIN_DATA` | Data directory of the current plugin (separate from the install dir to preserve state across upgrades) |

See [Hooks](./hooks) for more on writing Hooks.

## Marketplace

A marketplace is a centralized distribution source for plugins. By adding a marketplace, you can browse and install published plugins without managing local directories manually.

### Add a Marketplace

Multiple source formats are supported:

```bash theme={null}
# Git repository (HTTPS / SSH)
qodercli plugins marketplace add https://git.example.com/org/my-marketplace.git
qodercli plugins marketplace add git@git.example.com:org/my-marketplace.git

# Owner/repo shorthand (for supported git hosts)
qodercli plugins marketplace add org/my-marketplace

# Local directory
qodercli plugins marketplace add /path/to/marketplace

# URL pointing to a marketplace.json
qodercli plugins marketplace add https://example.com/marketplace.json
```

### List Configured Marketplaces

```bash theme={null}
qodercli plugins marketplace list
qodercli plugins marketplace list --json
```

### Update a Marketplace

Refresh the plugin catalog from the source:

```bash theme={null}
# Update a specific marketplace
qodercli plugins marketplace update my-marketplace

# Update all marketplaces
qodercli plugins marketplace update
```

### Remove a Marketplace

```bash theme={null}
qodercli plugins marketplace remove my-marketplace
```

Removing a marketplace also uninstalls all plugins that were installed from it.

### Install Plugins from a Marketplace

Once a marketplace is added, install plugins by name:

```bash theme={null}
qodercli plugins install hello-world
```

The CLI searches all configured marketplaces and installs the plugin. The resulting plugin ID takes the form `name@marketplace-name`.

### List Available Plugins

```bash theme={null}
qodercli plugins list --available --json
```

Returns all plugins from configured marketplaces that are not yet installed.

### Update Installed Marketplace Plugins

```bash theme={null}
qodercli plugins update hello-world
```
