# CodeBuddy Plugin Reference

> A complete technical reference for the CodeBuddy plugin system, covering component specifications, CLI commands, and development tools.

A **plugin** is a self-contained component directory that extends CodeBuddy with custom functionality. Plugin components include Skills, Agents, Hooks, MCP servers, and LSP servers.

name: agent-name
description: The agent's expertise and when to invoke it
model: sonnet
effort: medium
maxTurns: 20
disallowedTools: Write, Edit
---

Detailed system prompt for the agent, describing its role, expertise, and behavior.
```

Plugin agents support the following frontmatter fields: `name`, `description`, `model`, `effort`, `maxTurns`, `tools`, `disallowedTools`, `skills`, `memory`, `background`, and `isolation`. The only valid value for `isolation` is `"worktree"`. For security reasons, plugin agents do not support the `hooks`, `mcpServers`, or `permissionMode` fields.

**Integration**:

- Agents appear in the `/agents` UI.
- The AI assistant can auto-invoke agents based on task context.
- Users can also invoke agents manually.
- Plugin agents cooperate with built-in agents.

See [Subagents](sub-agents.md) for details.

### 3. Hooks

Plugins can provide event handlers that respond to CodeBuddy events automatically.

**Location**: `hooks/hooks.json` under the plugin root, or inline configuration in `plugin.json`.

**Format**: JSON configuration containing event matchers and actions.

**Configuration example**:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CODEBUDDY_PLUGIN_ROOT}/scripts/format-code.sh"
          }
        ]
      }
    ]
  }
}
```

**Available events**:

Plugin hooks respond to the same lifecycle events as user-defined hooks:

| Event | Trigger |
|------|---------|
| `SessionStart` | Session starts or resumes |
| `UserPromptSubmit` | User submits a prompt, before AI processing |
| `PreToolUse` | Before tool execution; can block |
| `PermissionRequest` | When the permission dialog appears |
| `PermissionDenied` | When a tool call is denied by the auto-mode classifier. Return `{retry: true}` to tell the model it can retry |
| `PostToolUse` | After a tool call succeeds |
| `PostToolUseFailure` | After a tool call fails |
| `Notification` | When CodeBuddy sends a notification |
| `SubagentStart` | When a sub-agent starts |
| `SubagentStop` | When a sub-agent finishes |
| `TaskCreated` | When a task is created via `TaskCreate` |
| `TaskCompleted` | When a task is marked completed |
| `Stop` | When the AI finishes its response |
| `StopFailure` | When the turn ends due to an API error. Output and exit code are ignored |
| `TeammateIdle` | When a teammate is about to go idle |
| `InstructionsLoaded` | When CODEBUDDY.md or `.codebuddy/rules/*.md` files are loaded into context |
| `ConfigChange` | When a configuration file changes during the session |
| `CwdChanged` | When the working directory changes (e.g., the AI runs `cd`) |
| `FileChanged` | When a watched file changes on disk. The `matcher` field specifies the filename to watch |
| `WorktreeCreate` | When a worktree is created via `--worktree` or `isolation: "worktree"` |
| `WorktreeRemove` | When a worktree is removed (session exit or sub-agent completion) |
| `PreCompact` | Before context compaction |
| `PostCompact` | After context compaction completes |
| `Elicitation` | When an MCP server requests user input during a tool call |
| `ElicitationResult` | After the user responds to an MCP elicitation, before the response is sent back to the server |
| `SessionEnd` | When the session terminates |

**Hook types**:

- `command`: Executes a shell command or script.
- `http`: Sends the event JSON as a POST request to a URL.
- `prompt`: Uses an LLM to evaluate a prompt (use the `$ARGUMENTS` placeholder for context).
- `agent`: Runs an agent validator with tools, for complex validation tasks.

**Differences from Skill / Agent frontmatter hooks**:

A plugin can carry hooks via two distinct paths:

| Path | Scope | Safety gate |
| --- | --- | --- |
| `hooks/hooks.json` (described in this section) | Entire session (while the plugin is enabled) | Not subject to `allowUntrustedFrontmatterHooks`; takes effect as soon as the plugin is enabled |
| `hooks` frontmatter in `agents/*.md` or `skills/SKILL.md` | Only within that subagent / fork skill lifecycle | Subject to the `allowUntrustedFrontmatterHooks` gate, denied by default; users must explicitly enable it in `settings.json` |

Because frontmatter hooks are intercepted by the safety gate, plugin-distributed Skills / Agents that rely on frontmatter hooks to function correctly should clearly notify users in the plugin README to enable the `allowUntrustedFrontmatterHooks` setting. See [Hook Reference Guide - Frontmatter Hooks](./hooks.md#agent--skill-frontmatter-hooks) for details.

### 4. MCP Servers

Plugins can bundle Model Context Protocol (MCP) servers to connect CodeBuddy with external tools and services.

**Location**: `.mcp.json` under the plugin root, or inline configuration in `plugin.json`.

**Format**: Standard MCP server configuration.

**Configuration example**:

```json
{
  "mcpServers": {
    "plugin-database": {
      "command": "${CODEBUDDY_PLUGIN_ROOT}/servers/db-server",
      "args": ["--config", "${CODEBUDDY_PLUGIN_ROOT}/config.json"],
      "env": {
        "DB_PATH": "${CODEBUDDY_PLUGIN_ROOT}/data"
      }
    },
    "plugin-api-client": {
      "command": "npx",
      "args": ["@company/mcp-server", "--plugin-mode"],
      "cwd": "${CODEBUDDY_PLUGIN_ROOT}"
    }
  }
}
```

**Integration behavior**:

- MCP servers start automatically when the plugin is enabled.
- Servers appear as standard MCP tools in the toolkit.
- Server functionality integrates seamlessly with existing tools.
- Plugin servers can be configured independently of user-level MCP servers.

### 5. LSP Servers

> **Tip**: Need an LSP plugin? You can install one from the official marketplace — search for "lsp" in the `/plugin` Discover tab. This section covers how to create LSP plugins for languages not provided by the official marketplace.

Plugins can provide [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (LSP) servers to give the AI assistant real-time code intelligence while working on a codebase.

LSP integration provides:

* **Instant diagnostics**: The AI assistant sees errors and warnings immediately after each edit.
* **Code navigation**: Go to definition, find references, and hover information.
* **Language awareness**: Type information and documentation for code symbols.

**Location**: An `.lsp.json` file under the plugin root, or inline configuration in `plugin.json`.

**Format**: JSON configuration mapping language server names to their configurations.

**`.lsp.json` file format**:

```json
{
  "go": {
    "command": "gopls",
    "args": ["serve"],
    "extensionToLanguage": {
      ".go": "go"
    }
  }
}
```

**Inline configuration in `plugin.json`**:

```json
{
  "name": "my-plugin",
  "lspServers": {
    "go": {
      "command": "gopls",
      "args": ["serve"],
      "extensionToLanguage": {
        ".go": "go"
      }
    }
  }
}
```

**Required fields**:

| Field | Description |
| :--- | :--- |
| `command` | LSP binary to execute (must be on PATH) |
| `extensionToLanguage` | Maps file extensions to language identifiers |

**Optional fields**:

| Field | Description |
| :--- | :--- |
| `args` | Command-line arguments for the LSP server |
| `transport` | Communication transport: `stdio` (default) or `socket` |
| `env` | Environment variables to set when starting the server |
| `initializationOptions` | Options passed to the server during initialization |
| `settings` | Settings passed via `workspace/didChangeConfiguration` |
| `workspaceFolder` | Workspace folder path for the server |
| `startupTimeout` | Maximum time (ms) to wait for server startup |
| `shutdownTimeout` | Maximum time (ms) to wait for graceful shutdown |
| `restartOnCrash` | Whether to automatically restart after a crash |
| `maxRestarts` | Maximum restart attempts before giving up |

> **Warning**: **You must install the language server binary separately.** LSP plugins configure how CodeBuddy connects to a language server but do not include the server itself. If you see an `Executable not found in $PATH` error in the `/plugin` Errors tab, install the binary for your language.

**Available LSP plugins**:

| Plugin | Language Server | Install Command |
| :--- | :--- | :--- |
| `pyright-lsp` | Pyright (Python) | `pip install pyright` or `npm install -g pyright` |
| `typescript-lsp` | TypeScript Language Server | `npm install -g typescript-language-server typescript` |
| `rust-lsp` | rust-analyzer | [See rust-analyzer installation](https://rust-analyzer.github.io/manual.html#installation) |

Install the language server first, then install the plugin from the marketplace.

---

## II. Plugin Installation Scopes

When installing a plugin, choose a **scope** that determines where the plugin is available:

| Scope | Settings file | Use case |
| :--- | :--- | :--- |
| `user` | `~/.codebuddy/settings.json` | Personal plugin, available in all projects (default) |
| `project` | `.codebuddy/settings.json` | Team plugin, shared via version control |
| `local` | `.codebuddy/settings.local.json` | Project-specific plugin, gitignored |
| `managed` | Managed settings | Managed plugins (read-only; updates only) |

Plugins use the same scoping system as other CodeBuddy configuration. See [Settings](settings.md) for details.

---

## III. Plugin Manifest Schema (plugin.json)

The `.codebuddy-plugin/plugin.json` file (or `.workbuddy-plugin/plugin.json`, `.claude-plugin/plugin.json`) defines plugin metadata and configuration. This section documents all supported fields and options.

The manifest is optional. If omitted, CodeBuddy auto-discovers components in the [default locations](#file-location-reference) and derives the plugin name from the directory name. Use a manifest when you need to provide metadata or customize component paths.

### Complete Schema Example

```json
{
  "name": "plugin-name",
  "version": "1.2.0",
  "description": "Brief plugin description",
  "author": {
    "name": "Author name",
    "email": "[email protected]",
    "url": "https://github.com/author"
  },
  "homepage": "https://docs.example.com/plugin",
  "repository": "https://github.com/author/plugin",
  "license": "MIT",
  "keywords": ["keyword1", "keyword2"],
  "commands": ["./custom/commands/special.md"],
  "agents": "./custom/agents/",
  "skills": "./custom/skills/",
  "hooks": "./config/hooks.json",
  "mcpServers": "./mcp-config.json",
  "outputStyles": "./styles/",
  "lspServers": "./.lsp.json"
}
```

### Required Fields

If a manifest is included, `name` is the only required field.

| Field | Type | Description | Example |
|------|------|------|------|
| `name` | string | Unique identifier (kebab-case, no spaces) | `"deployment-tools"` |

This name is used for component namespacing. For example, in the UI, the agent `agent-creator` from plugin `plugin-dev` will appear as `plugin-dev:agent-creator`.

### Metadata Fields

| Field | Type | Description | Example |
|------|------|------|------|
| `version` | string | Semantic version. If set in both the marketplace entry and `plugin.json`, `plugin.json` wins. Set in only one place. | `"2.1.0"` |
| `description` | string | Short description of the plugin's purpose | `"Deployment automation tools"` |
| `author` | object | Author information | `{"name": "Dev Team", "email": "[email protected]"}` |
| `homepage` | string | Documentation URL | `"https://docs.example.com"` |
| `repository` | string | Source code URL | `"https://github.com/user/plugin"` |
| `license` | string | License identifier | `"MIT"`, `"Apache-2.0"` |
| `keywords` | array | Discovery tags | `["deployment", "ci-cd"]` |

### Component Path Fields

| Field | Type | Description | Example |
|------|------|------|------|
| `commands` | string \| array | Custom command file/directory (replaces default `commands/`) | `"./custom/cmd.md"` or `["./cmd1.md"]` |
| `agents` | string \| array | Custom agent files (replaces default `agents/`) | `"./custom/agents/reviewer.md"` |
| `skills` | string \| array | Custom skill directories (replaces default `skills/`) | `"./custom/skills/"` |
| `hooks` | string \| array \| object | Hook configuration path or inline configuration | `"./my-extra-hooks.json"` |
| `mcpServers` | string \| array \| object | MCP configuration path or inline configuration | `"./my-extra-mcp-config.json"` |
| `outputStyles` | string \| array | Custom output style files/directories (replaces default `output-styles/`) | `"./styles/"` |
| `lspServers` | string \| array \| object | LSP configuration path or inline configuration | `"./.lsp.json"` |
| `userConfig` | object | Values CodeBuddy prompts the user to provide when enabling the plugin. See [User Configuration](#user-configuration) | See below |
| `channels` | array | Channel declarations for message injection. See [Channels](#channels) | See below |

### User Configuration

The `userConfig` field declares values that CodeBuddy prompts the user to provide when the plugin is enabled. Use this instead of asking users to edit `settings.json` manually.

```json
{
  "userConfig": {
    "api_endpoint": {
      "description": "Your team's API endpoint",
      "sensitive": false
    },
    "api_token": {
      "description": "API authentication token",
      "sensitive": true
    }
  }
}
```

Keys must be valid identifiers. Each value can be substituted as `${user_config.KEY}` in MCP and LSP server configs and hook commands, and (for non-sensitive values only) inside skill and agent content. Values are also exported as `CODEBUDDY_PLUGIN_OPTION_<KEY>` environment variables to plugin child processes.

Non-sensitive values are stored in `pluginConfigs[<plugin-id>].options` in `settings.json`. Sensitive values are stored in the system keychain (or in `~/.codebuddy/.credentials.json` if the keychain is unavailable). Keychain storage is shared with OAuth tokens and has a total limit of around 2 KB, so sensitive values should be kept small.

### Channels

The `channels` field lets a plugin declare one or more message channels used to inject content into the conversation. Each channel binds to an MCP server provided by the plugin.

```json
{
  "channels": [
    {
      "server": "telegram",
      "userConfig": {
        "bot_token": { "description": "Telegram bot token", "sensitive": true },
        "owner_id": { "description": "Your Telegram user ID", "sensitive": false }
      }
    }
  ]
}
```

The `server` field is required and must match a key in the plugin's `mcpServers`. The optional per-channel `userConfig` uses the same schema as the top-level one, letting you prompt for a bot token or owner ID when the plugin is enabled.

### Path Behavior Rules

For `commands`, `agents`, `skills`, and `outputStyles`, a custom path **replaces** the default directory. If the manifest specifies `commands`, the default `commands/` directory is not scanned. Hooks, MCP servers, and LSP servers have different semantics for handling multiple sources.

- All paths must be relative to the plugin root and start with `./`.
- Components under custom paths follow the same naming and namespacing rules.
- Multiple paths can be specified as an array.
- To keep the default directory and add more paths, include the default in the array: `"commands": ["./commands/", "./extras/deploy.md"]`.

**Path examples**:

```json
{
  "commands": [
    "./specialized/deploy.md",
    "./utilities/batch-process.md"
  ],
  "agents": [
    "./custom-agents/reviewer.md",
    "./custom-agents/tester.md"
  ]
}
```

### Environment Variables

CodeBuddy provides two variables for referencing plugin paths. Both are substituted inline anywhere in skill content, agent content, hook commands, and MCP or LSP server configuration. Both are also exported as environment variables to hook processes and MCP/LSP server child processes.

**`${CODEBUDDY_PLUGIN_ROOT}`**: Absolute path to the plugin installation directory. Use it to reference scripts, binaries, and configuration files bundled with the plugin. This path changes when the plugin is updated, so files written here do not persist across updates.

**Compatibility**: The `${CLAUDE_PLUGIN_ROOT}` variable name is also supported for compatibility with Claude Code plugins.

**`${CODEBUDDY_PLUGIN_DATA}`**: A persistent directory for plugin state that survives updates. Use it for installed dependencies (such as `node_modules` or Python virtual environments), generated code, caches, and any files that need to persist across plugin versions. The directory is created automatically on first reference.

**Compatibility**: The `${CLAUDE_PLUGIN_DATA}` variable name is also supported.

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CODEBUDDY_PLUGIN_ROOT}/scripts/process.sh"
          }
        ]
      }
    ]
  }
}
```

#### Persistent Data Directory

The `${CODEBUDDY_PLUGIN_DATA}` directory resolves to `~/.codebuddy/plugins/data/{id}/`, where `{id}` is the plugin identifier with characters outside `a-z`, `A-Z`, `0-9`, `_`, and `-` replaced by `-`. For example, a plugin installed as `formatter@my-marketplace` uses the directory `~/.codebuddy/plugins/data/formatter-my-marketplace/`.

A common use is to install language dependencies once and reuse them across sessions and plugin updates. Because the data directory's lifetime outlasts any single plugin version, simply checking for directory existence does not detect when an update has changed the plugin's dependency manifest. The recommended pattern is to compare the bundled manifest with a copy in the data directory and reinstall when they differ.

The following `SessionStart` hook installs `node_modules` on first run, and reinstalls them whenever a plugin update includes a changed `package.json`:

```json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "diff -q \"${CODEBUDDY_PLUGIN_ROOT}/package.json\" \"${CODEBUDDY_PLUGIN_DATA}/package.json\" >/dev/null 2>&1 || (cd \"${CODEBUDDY_PLUGIN_DATA}\" && cp \"${CODEBUDDY_PLUGIN_ROOT}/package.json\" . && npm install) || rm -f \"${CODEBUDDY_PLUGIN_DATA}/package.json\""
          }
        ]
      }
    ]
  }
}
```

`diff` exits non-zero whenever the stored copy is missing or differs from the bundled copy, covering both the first run and dependency-changing updates. If `npm install` fails, the trailing `rm` removes the copied manifest so the next session retries.

Scripts bundled under `${CODEBUDDY_PLUGIN_ROOT}` can run against the persisted `node_modules`:

```json
{
  "mcpServers": {
    "routines": {
      "command": "node",
      "args": ["${CODEBUDDY_PLUGIN_ROOT}/server.js"],
      "env": {
        "NODE_PATH": "${CODEBUDDY_PLUGIN_DATA}/node_modules"
      }
    }
  }
}
```

When a plugin is uninstalled (from its last installation scope), the data directory is deleted automatically. The `/plugin` UI shows the directory size and prompts before deletion. The CLI deletes it by default; pass `--keep-data` to retain it.

---

## IV. Plugin Cache and File Resolution

Plugins can be specified in two ways:

- Via `codebuddy --plugin-dir`, valid for the current session only.
- Via marketplace installation, valid for future sessions.

For security and validation, CodeBuddy copies **marketplace** plugins to the user's local **plugin cache** (`~/.codebuddy/plugins/cache`) rather than using them in place. Understanding this behavior is important when developing plugins that reference external files.

### Path Traversal Restrictions

Installed plugins cannot reference files outside their own directory. Paths that traverse outside the plugin root (like `../shared-utils`) do not work after installation because those external files are not copied into the cache.

### Using External Dependencies

If a plugin needs access to files outside its directory, you can create symlinks inside the plugin directory that point to external files. Symlinks are preserved during the copy:

```bash
# Inside the plugin directory
ln -s /path/to/shared-utils ./shared-utils
```

The contents of the symlink are copied into the plugin cache. This provides flexibility while preserving the security benefits of the cache system.

---

## V. Plugin Directory Structure

### Standard Plugin Layout

A complete plugin follows this structure:

```
enterprise-plugin/
├── .codebuddy-plugin/        # Metadata directory (optional)
│   └── plugin.json             # Plugin manifest
├── commands/                 # Default commands location
│   ├── status.md
│   └── logs.md
├── agents/                   # Default agents location
│   ├── security-reviewer.md
│   ├── performance-tester.md
│   └── compliance-checker.md
├── skills/                   # Agent skills
│   ├── code-reviewer/
│   │   └── SKILL.md
│   └── pdf-processor/
│       ├── SKILL.md
│       └── scripts/
├── output-styles/            # Output style definitions
│   └── terse.md
├── hooks/                    # Hook configuration
│   ├── hooks.json            # Primary hook configuration
│   └── security-hooks.json   # Additional hooks
├── bin/                      # Plugin executables, added to PATH
│   └── my-tool               # Callable as a bare command in the Bash tool
├── settings.json             # Plugin default settings
├── .mcp.json                 # MCP server definitions
├── .lsp.json                 # LSP server configuration
├── scripts/                  # Hook and utility scripts
│   ├── security-scan.sh
│   ├── format-code.py
│   └── deploy.js
├── LICENSE                   # License file
└── CHANGELOG.md              # Version history
```

> **Important**: The `.codebuddy-plugin/` directory contains the `plugin.json` file. All other directories (`commands/`, `agents/`, `skills/`, `output-styles/`, `hooks/`) must live at the plugin root, not inside `.codebuddy-plugin/`. The `.workbuddy-plugin/` and `.claude-plugin/` directories are also supported for compatibility.

### File Location Reference

| Component | Default location | Purpose |
|------|----------|------|
| **Manifest** | `.codebuddy-plugin/plugin.json` | Plugin metadata and configuration (optional) |
| **Commands** | `commands/` | Skill Markdown files (legacy; new skills use `skills/`) |
| **Agents** | `agents/` | Sub-agent Markdown files |
| **Skills** | `skills/` | Skills following the `<name>/SKILL.md` structure |
| **Output styles** | `output-styles/` | Output style definitions |
| **Hooks** | `hooks/hooks.json` | Hook configuration |
| **MCP servers** | `.mcp.json` | MCP server definitions |
| **LSP servers** | `.lsp.json` | Language server configuration |
| **Executables** | `bin/` | Executables added to the Bash tool PATH. When the plugin is enabled, files in this directory can be invoked as bare commands in any Bash tool call |
| **Settings** | `settings.json` | Default configuration applied when the plugin is enabled. Currently only [agent](sub-agents.md) settings are supported |

---

## VI. CLI Command Reference

CodeBuddy provides CLI commands for non-interactive plugin management, suitable for scripting and automation.

### plugin install

Install a plugin from an available marketplace.

```bash
codebuddy plugin install <plugin> [options]
```

**Arguments**:

- `<plugin>`: Plugin name, or `plugin-name@marketplace-name` to specify a particular marketplace.

**Options**:

| Option | Description | Default |
|------|------|------|
| `-s, --scope <scope>` | Install scope: `user`, `project`, or `local` | `user` |
| `-h, --help` | Show command help | |

The scope determines which settings file the installed plugin is added to. For example, `--scope project` writes to `enabledPlugins` in `.codebuddy/settings.json`, making the plugin available to everyone who clones the project repository.

**Examples**:

```bash
# Install at user scope (default)
codebuddy plugin install formatter@my-marketplace

# Install at project scope (shared with team)
codebuddy plugin install formatter@my-marketplace --scope project

# Install at local scope (gitignored)
codebuddy plugin install formatter@my-marketplace --scope local
```

### plugin uninstall

Remove an installed plugin.

```bash
codebuddy plugin uninstall <plugin> [options]
```

**Arguments**:

- `<plugin>`: Plugin name, or `plugin-name@marketplace-name`.

**Options**:

| Option | Description | Default |
|------|------|------|
| `-s, --scope <scope>` | Uninstall from scope: `user`, `project`, or `local` | `user` |
| `--keep-data` | Preserve the plugin's [persistent data directory](#persistent-data-directory) | |
| `-h, --help` | Show command help | |

**Aliases**: `remove`, `rm`

By default, uninstalling from the last remaining scope also deletes the plugin's `${CODEBUDDY_PLUGIN_DATA}` directory. Use `--keep-data` to preserve it — for example, when reinstalling after testing a new version.

### plugin enable

Enable a disabled plugin.

```bash
codebuddy plugin enable <plugin> [options]
```

**Arguments**:

- `<plugin>`: Plugin name, or `plugin-name@marketplace-name`.

**Options**:

| Option | Description | Default |
|------|------|------|
| `-s, --scope <scope>` | Enable scope: `user`, `project`, or `local` | `user` |
| `-h, --help` | Show command help | |

### plugin disable

Disable a plugin without uninstalling it.

```bash
codebuddy plugin disable <plugin> [options]
```

**Arguments**:

- `<plugin>`: Plugin name, or `plugin-name@marketplace-name`.

**Options**:

| Option | Description | Default |
|------|------|------|
| `-s, --scope <scope>` | Disable scope: `user`, `project`, or `local` | `user` |
| `-h, --help` | Show command help | |

### plugin update

Update a plugin to the latest version.

```bash
codebuddy plugin update <plugin> [options]
```

**Arguments**:

- `<plugin>`: Plugin name, or `plugin-name@marketplace-name`.

**Options**:

| Option | Description | Default |
|------|------|------|
| `-s, --scope <scope>` | Update scope: `user`, `project`, `local`, or `managed` | `user` |
| `-h, --help` | Show command help | |

### Marketplace Management

```bash
# Add a marketplace
codebuddy plugin marketplace add <source> [--name <name>]

# List marketplaces
codebuddy plugin marketplace list

# Update a marketplace
codebuddy plugin marketplace update <name>

# Remove a marketplace
codebuddy plugin marketplace remove <name>
```

**Marketplace source formats**:

```bash
# Local directory
codebuddy plugin marketplace add /path/to/marketplace

# GitHub shorthand
codebuddy plugin marketplace add owner/repo

# Git URL
codebuddy plugin marketplace add https://github.com/owner/repo.git

# HTTP URL (marketplace.json)
codebuddy plugin marketplace add https://example.com/marketplace.json
```

---

## VII. Debugging and Development Tools

### Debug Commands

Use `codebuddy --debug` to see plugin loading details:

**What it shows**:

- Which plugins are being loaded.
- Any errors in plugin manifests.
- Command, agent, and hook registration.
- MCP server initialization.

### Common Troubleshooting

| Issue | Cause | Solution |
|------|------|----------|
| Plugin not loaded | Invalid `plugin.json` | Run `codebuddy plugin validate` or `/plugin validate` to check `plugin.json`, skill/agent/command frontmatter, and `hooks/hooks.json` for syntax and schema errors |
| Command not appearing | Wrong directory structure | Ensure `commands/` is at the plugin root, not inside `.codebuddy-plugin/` |
| Hook not firing | Script not executable | Run `chmod +x script.sh` |
| MCP server fails | Missing `${CODEBUDDY_PLUGIN_ROOT}` | Use this variable for all plugin paths |
| Path errors | Using absolute paths | All paths must be relative and start with `./` |
| LSP `Executable not found in $PATH` | Language server not installed | Install the binary (e.g., `npm install -g typescript-language-server typescript`) |

### Common Error Messages

**Manifest validation errors**:

- `Invalid JSON syntax: Unexpected token } in JSON at position 142`: Check for missing commas, trailing commas, or unquoted strings.
- `Plugin has an invalid manifest file at .codebuddy-plugin/plugin.json. Validation errors: name: Required`: Missing required field.
- `Plugin has a corrupt manifest file at .codebuddy-plugin/plugin.json. JSON parse error: ...`: JSON syntax error.

**Plugin loading errors**:

- `Warning: No commands found in plugin my-plugin custom directory: ./cmds. Expected .md files or SKILL.md in subdirectories.`: The command path exists but contains no valid command files.
- `Plugin directory not found at path: ./plugins/my-plugin. Check that the marketplace entry has the correct path.`: The `source` path in `marketplace.json` points to a non-existent directory.
- `Plugin my-plugin has conflicting manifests: both plugin.json and marketplace entry specify components.`: Remove duplicate component definitions, or remove `strict: false` from the marketplace entry.

### Hook Troubleshooting

**Hook script not executing**:

1. Verify the script is executable: `chmod +x ./scripts/your-script.sh`.
2. Check the shebang line: the first line should be `#!/bin/bash` or `#!/usr/bin/env bash`.
3. Confirm the path uses `${CODEBUDDY_PLUGIN_ROOT}`: `"command": "${CODEBUDDY_PLUGIN_ROOT}/scripts/your-script.sh"`.
4. Test the script manually: `./scripts/your-script.sh`.

**Hook not firing on the expected event**:

1. Verify the event name (case-sensitive): `PostToolUse`, not `postToolUse`.
2. Check the matcher pattern matches the target tool: `"matcher": "Write|Edit"` for file operations.
3. Confirm the hook type is valid: `command`, `http`, `prompt`, or `agent`.

### MCP Server Troubleshooting

**Server does not start**:

1. Check that the command exists and is executable.
2. Verify all paths use the `${CODEBUDDY_PLUGIN_ROOT}` variable.
3. Check MCP server logs: `codebuddy --debug` shows initialization errors.
4. Test the server manually outside of CodeBuddy.

**Server tools do not appear**:

1. Ensure the server is correctly configured in `.mcp.json` or `plugin.json`.
2. Verify that the server correctly implements the MCP protocol.
3. Check for connection timeouts in the debug output.

### Directory Structure Errors

**Symptom**: The plugin loads but components (commands, agents, hooks) are missing.

**Correct structure**: Components must be at the plugin root, not inside `.codebuddy-plugin/`. Only `plugin.json` belongs in `.codebuddy-plugin/`.

```
my-plugin/
├── .codebuddy-plugin/
│   └── plugin.json      <- Only the manifest lives here
├── commands/             <- At root level
├── agents/               <- At root level
└── hooks/                <- At root level
```

If components are inside `.codebuddy-plugin/`, move them up to the plugin root.

**Debug checklist**:

1. Run `codebuddy --debug` and look for "loading plugin" messages.
2. Verify that each component directory is listed in the debug output.
3. Confirm that file permissions allow reading the plugin files.

---

## VIII. Version Management Reference

### Semantic Versioning

Follow semantic versioning for plugin releases:

```json
{
  "name": "my-plugin",
  "version": "2.1.0"
}
```

**Version format**: `MAJOR.MINOR.PATCH`

- **MAJOR**: Incompatible API changes.
- **MINOR**: Backwards-compatible feature additions.
- **PATCH**: Backwards-compatible bug fixes.

**Best practices**:

- Start the first stable release at `1.0.0`.
- Update the version in `plugin.json` before distributing changes.
- Record changes in a `CHANGELOG.md` file.
- Use pre-release versions (e.g., `2.0.0-beta.1`) for testing.

> **Note**: CodeBuddy uses the version to decide whether a plugin needs updating. If you change plugin code without bumping the version in `plugin.json`, existing users will not see the change due to caching.
>
> If the plugin is in a [marketplace](plugin-marketplaces.md) directory, you can manage versions via `marketplace.json` and omit the `version` field from `plugin.json`.

---

## IX. Compatibility with Claude Code

The CodeBuddy plugin system is designed to be compatible with the Claude Code plugin specification, with the following differences:

### Naming Differences

| Concept | Claude Code | CodeBuddy |
|------|-------------|-----------|
| Metadata directory | `.claude-plugin/` | `.codebuddy-plugin/` (priority), `.workbuddy-plugin/`, or `.claude-plugin/` (compatible) |
| Environment variable | `${CLAUDE_PLUGIN_ROOT}` | `${CODEBUDDY_PLUGIN_ROOT}` (priority) or `${CLAUDE_PLUGIN_ROOT}` (compatible) |
| Data directory variable | `${CLAUDE_PLUGIN_DATA}` | `${CODEBUDDY_PLUGIN_DATA}` (priority) or `${CLAUDE_PLUGIN_DATA}` (compatible) |

### Migration Guide

Migrating from Claude Code to CodeBuddy:

1. Optionally rename `.claude-plugin/` to `.codebuddy-plugin/`.
2. Optionally replace `${CLAUDE_PLUGIN_ROOT}` with `${CODEBUDDY_PLUGIN_ROOT}` in scripts.
3. Optionally replace `${CLAUDE_PLUGIN_DATA}` with `${CODEBUDDY_PLUGIN_DATA}`.

**Note**: Keeping the original names is fully compatible — CodeBuddy recognizes them automatically.

---

## Related Resources

- [Plugins](plugins.md) – Tutorial and practical guide
- [Plugin Marketplaces](plugin-marketplaces.md) – Creating and managing marketplaces
- [Skills](skills.md) – Skill development details
- [Subagents](sub-agents.md) – Agent configuration and capabilities
- [Hooks](hooks.md) – Event handling and automation
- [MCP](mcp.md) – External tool integration
- [Settings](settings.md) – Plugin configuration options
