# Plugins (/agent/plugins)

A plugin is a set of [skills](/agent/skills) installed from a git repository. Any repo that
looks like a skill collection - or is a single skill - can be installed with one command, without
copying files by hand or trusting a download step. A plugin can also package commands, agent
definitions, and optional MCP server declarations. Installing a plugin never runs its code: the
install step only clones and moves files, and it does not start a declared MCP server. Enabling one
is a separate, explicit setup action that can run local code or contact a remote service. A plugin
that declares [tools or hooks](/agent/hooks) runs commands later, once a session uses it.

## Where they live [#where-they-live]

```
~/.jan/projects/<slug>/plugins/
└── release-tools/
    ├── plugin.toml              # optional TOML metadata
    ├── .claude-plugin/
    │   └── plugin.json          # Claude-compatible metadata
    ├── skills/
    │   └── prepare/
    │       └── SKILL.md
    └── ...
```

A plugin's payload is discovered conventionally, so a repo needs no manifest to be installable:

- `skills/` - the same layout as project skills: folder skills (`<name>/SKILL.md`) and flat
  `<name>.md`
- `SKILL.md` at the repo root - a repo that is itself one skill
- `commands/` - slash-invocable prompt templates (`<name>.md`, nested directories included)
- `agents/` - dispatchable subagent definitions (`<name>.md`, nested directories included)
- `hooks/hooks.json` - optional [lifecycle hooks](/agent/hooks)
- `plugin.toml` or `.claude-plugin/plugin.json` - optional metadata: `name`, `description`, `version`,
  and `repo`. The directory name is the plugin's identity; the manifest's `name` is what
  `plugin list` shows when present.

Jan discovers these conventional directories in Claude Code-style plugin repositories,
including `anthropics/claude-plugins-official`. Installation does not guarantee runtime
compatibility: external commands, credentials, and provider approval may still be required.

## Installing [#installing]

From the command line:

```bash
jan plugin install <git-url>
jan plugin install <git-url>#<ref>        # install a specific branch or tag
jan plugin install <github-tree-url>      # install a plugin from a repo subdirectory
jan plugin install <marketplace-name>     # resolve a name through your marketplace
jan plugin list
jan plugin remove <name>
jan plugin search [query]
```

Inside the interactive agent, the equivalent commands are:

```
/plugin install <git-url>
/plugin list
/plugin remove <name>
/plugin search <query>
```

GitHub tree URLs such as
`https://github.com/anthropics/claude-plugins-official/tree/main/plugins/claude-code-setup`
are cloned from the repository root and install only the selected subdirectory.

The plugin is cloned (`--depth 1`), validated to contain a plugin manifest, `skills/`, `commands/`,
`agents/`, `.mcp.json`, or a root `SKILL.md`, and moved into place under its final name.
Reinstalling an existing plugin is refused (remove it first). Specs with shell metacharacters are
rejected outright - a plugin name is a name, not a command.

In the TUI, installation continues directly into setup. Jan reads the plugin's
`.mcp.json` or inline `mcpServers` declarations, collects required keys in a masked
field, and offers **Enable and connect** for each server. Nothing is enabled or
executed until you confirm. For providers that accept Jan's OAuth client registration,
setup offers browser sign-in and reconnects after successful authorization.

Choose **Not now** or press Esc to keep the plugin installed without completing
its connections. Resume with `/plugin setup <name>`, or use `/plugin setup` to
choose one installed plugin. Type or paste to filter by name and description
(case-insensitive); Backspace edits the search, Up/Down selects, Enter opens setup,
and Esc cancels. Rows identify the installation directory and also show the manifest
name when it differs. Opening the picker does not run setup for every plugin or enable
any servers. No separate terminal command or Jan restart is needed. Plugins without
keys or MCP servers need no connection setup.

Imported MCP servers use names such as `figma:figma` to avoid collisions. Existing
servers with different settings are not overwritten; review them in `/mcp`.
Stored key references such as `${API_KEY}` and `${CLAUDE_PLUGIN_ROOT}` are resolved
from the plugin's key store and installed directory. Key files and generated MCP
configuration are owner-only (`0600`) on Unix.
Shell credential injection is scoped to the project that registered the keys;
starting a run in another project does not replace that project's shell credentials.

OAuth browser sign-in requires successful client registration. If the provider
rejects registration, Jan shows the endpoint, HTTP status, and rejection detail
in the TUI instead of opening a consent page with a placeholder client ID.
[Figma restricts its remote MCP server to approved clients](https://developers.figma.com/docs/figma-mcp-server/remote-server-installation/).
**Remote Figma sign-in is currently blocked for Jan:** registration returns HTTP 403.
Installing the Figma plugin does not grant approval, and retrying setup does not remove
that restriction. Jan does not currently accept pre-registered OAuth client credentials.

MCP connections already enabled in Jan remain in its user-owned configuration.
Skipping setup does not disable them, and removing a plugin does not remove its imported
MCP entries. Use `/mcp`, select the server, then **Disable** or **Remove server**.
This also applies to placeholder servers declared by example plugins.

A plugin installed or edited outside the running session (another terminal, `git pull`, a hand
edit) is picked up with `/reload plugin`, which re-scans and reports what was added, removed, or
changed without restarting.

## Invoking plugin skills [#invoking-plugin-skills]

Plugin skills are qualified with their plugin name: `release-tools:prepare`.

| You type | What happens |
| --- | --- |
| `/prepare` | The plugin skill, when the name is unambiguous |
| `/skill:release-tools:prepare` | The exact plugin skill, always |
| `/release-tools:prepare` | Same as the explicit form |

Precedence: a project skill always wins its short name, and a plain name shared by two plugins is
ambiguous, so only the explicit forms work. The slash popup applies the same rules - it offers the
short form when unambiguous and the qualified form otherwise. Plugin skills flow through the same
invocation mechanics as project skills, including the `[skills].enabled` whitelist: enable a plugin
name (`release-tools`), one qualified skill (`release-tools:prepare`), or a plain name.

## Plugin commands [#plugin-commands]

A plugin's `commands/` directory is discovered as slash commands. Each markdown file is a prompt
template: the frontmatter `description` feeds the slash popup, and the body is loaded into the
conversation when you run the command. `$ARGUMENTS` is replaced with everything you typed after the
command name, and `$1`..`$9` with the individual whitespace-separated words. A missing positional
becomes empty, and `$10`-style tokens (and `$ARGUMENTATION`) are left literal so a body can talk
about dollars; the popup only advertises placeholders that will actually be filled:

```bash
/feature-dev add user authentication     # $ARGUMENTS = "add user authentication", $1 = "add"
```

Precedence in the slash namespace is built-in command, then plugin command, then skill, so a plugin
command named `resume` never shadows the built-in `/resume` (the explicit `/command:<plugin>:<name>`
form always works). Like skills, commands honor the `[skills].enabled` whitelist: a command disabled
there is not offered and cannot be fired, even by typing its name directly. The transcript shows one
compact `[command:<name>]` row with your arguments.

## Plugin agents [#plugin-agents]

A plugin's `agents/` directory is discovered as dispatchable subagents: the markdown frontmatter
`name` and `description` become the subagent's identity, and the body becomes its system prompt, so
a plugin can fan work out to specialized agents exactly as it does in Claude Code. Claude-runtime
metadata is handled honestly:

- `model` and `color` are ignored - the agent always runs on the session's model
- `tools` is mapped onto Jan's tool names (`Read` -> `read`, `Glob` -> `glob`, `Grep` -> `grep`,
  `WebSearch` -> `web_search`, `WebFetch` -> `web_fetch`, `TodoWrite` -> `todo`, and so on);
  names with no Jan equivalent are dropped, and an agent listing only unknown tools inherits the
  parent's full tool policy
- `skill_list` and `skill_read` stay available even when `tools` maps to a narrow set - a plugin
  agent can always load the skills its procedure references, matching Claude Code (see
  [Subagents](/agent/subagents#tool-permissions))

Plugin agents are read-only: `create_subagent` refuses the plugin scope, and a subagent defined in
the project's `subagents/` shadows a plugin agent of the same name.

## Managing [#managing]

Interactive commands:

```
/plugin list                  # one compact summary line per plugin
/plugin list release-tools    # description and skill names for one plugin
/plugin remove release-tools  # uninstall
/plugin setup release-tools   # resume API-key or MCP connection setup
/plugin search prepare        # search the marketplace (name/description)
```

The compact list shows each plugin's name, version, and payload counts (skills, commands, agents).
Descriptions and artifact names are shown only when a plugin name is requested. Interrupted
`.installing-*` staging directories are omitted from listings.

The headless CLI uses the same compact table by default:

```bash
jan plugin list --project ~/code/app
```

Use `--json` when complete plugin metadata or machine-readable output is needed:

```bash
jan plugin list --project ~/code/app --json
```

Install and search continue to print JSON results:

```bash
jan plugin install https://github.com/acme/release-tools --project ~/code/app
jan plugin search prepare --project ~/code/app
```

Removal is a directory delete under the same name guard as everything else in the agent: a name
can never escape the plugins directory.

## Plugin tools and hooks [#plugin-tools-and-hooks]

Beyond instructions, a plugin can carry two executable payloads. Both are covered in full on the
[hooks](/agent/hooks) page; the short form:

- `[[tools]]` in `plugin.toml` declares a tool. Each entry names a `description`, a JSON Schema in
  `[tools.parameters]`, and a `command`. The model calls it as `plugin__<plugin>__<tool>`, the
  arguments arrive on the command's stdin as JSON, and its stdout becomes the tool result. Plugin
  tools are gated like MCP tools: prompted rather than auto-approved, and withheld in Plan mode.
- `hooks/hooks.json` declares [lifecycle hooks](/agent/hooks) - commands that run before and
  after tool calls, at prompt submit, at session start and end, and before a compaction. A
  `PreToolUse` hook can deny a call outright.

Both are on by default and both switch off in `agent.toml` without uninstalling the plugin:

```toml
[plugins]
hooks = false
tools = false
```

<Callout type="warning">
Installing a plugin that ships hooks means a third party's commands run on your tool calls, with
whatever access the run has. Read its `hooks/hooks.json` and `[[tools]]` before installing, or turn
them off and keep only its skills.
</Callout>

## Marketplace [#marketplace]

Point `[plugins] marketplace` in `agent.toml` at a JSON index to install by name and search:

```toml
[plugins]
marketplace = "https://example.com/jan-plugins/index.json"
```

```json
[
  { "name": "release-tools", "description": "Release automation", "repo": "https://github.com/acme/release-tools" },
  { "name": "triage", "description": "Issue triage helpers", "repo": "https://github.com/acme/triage", "ref": "main" }
]
```

`repo` is cloned with an optional pinned `ref` (branch or tag). Without a configured marketplace,
`install <name>` and `search` report the missing config - direct git URLs always work.

<Callout type="info">
Plugins are shared with Jan Desktop - the same project files, through the same directory. The
desktop agent exposes `agent_plugin_list`, `agent_plugin_install`, `agent_plugin_remove`, and
`agent_plugin_search` for UI integration.
</Callout>
