You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/customization/plugins.md
+89-49Lines changed: 89 additions & 49 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,36 +1,22 @@
1
1
# Plugins
2
2
3
-
Plugins package reusable Pythinker Code CLI capabilities into installable units — they can add [Agent Skills](./skills.md), agent profiles, output styles, MCP servers, and Language Server Protocol (LSP) servers that provide code intelligence. They are ideal for sharing workflows with a team, connecting to external services, or installing extensions from Pythinker and compatible Claude Code marketplaces.
3
+
Plugins package reusable Pythinker Code CLI capabilities into installable units. They can add [Agent Skills](./skills.md), [agent profiles](./agents.md), slash commands, system-prompt instructions, hooks, and MCP servers. Use them to share workflows with a teamor connect the agent to external services.
4
4
5
-
Pythinker Code CLI applies a conservative loading strategy for plugins: installing a plugin does not execute any Python, Node.js, shell, hook, or command scripts it contains.
5
+
Installing a plugin only validates and copies its files. Enabled hooks, commands, and MCP servers run only after the plugin is activated and the matching action occurs.
6
6
7
7
## Installation and management
8
8
9
-
Run `/plugins` in the terminal interface to open the plugin manager, where you can perform all routine operations. Common keys:
9
+
Run `/plugins` in the terminal interface. Use `Tab` or `Shift-Tab` to switch between **Installed**, **Official**, **Curated**, and **Custom**.
10
10
11
11
| Key | Action |
12
12
| --- | --- |
13
-
|`Enter`| Open the selected installed item, or install or update the selected marketplace plugin |
14
-
|`Space`| Enable or disable an installed plugin |
13
+
|`Enter`| View an installed plugin, install its update, or install the selected marketplace plugin |
14
+
|`Space`| Enable or disable the selected installed plugin |
15
+
|`D`| Remove the selected installed plugin |
15
16
|`M`| Manage MCP servers for the selected installed plugin |
16
-
| Type text | Search the current marketplace by plugin metadata and source |
17
-
|`PgUp` or `PgDn`| Move through marketplace pages |
18
-
|`←` or `Esc`| Go back to the previous level |
19
-
20
-
Each marketplace page shows up to four plugins and keeps the selected plugin's details visible. When a search is active, `Backspace` edits it and the first `Esc` clears it; press `Esc` again to leave the marketplace. An installed plugin with a newer version or revision shows `update <local> → <latest>`, an up-to-date one shows `installed` with its version when available, and an uninstalled one shows `install`. Entries that cannot be installed remain visible with an explanation.
21
-
22
-
Opening **Marketplace** without a source lets you choose **Pythinker**, **Anthropic**, or **Custom marketplace**. Pythinker loads the official and curated Pythinker catalog. Anthropic loads the official Claude Code plugin catalog. A custom source can be a local marketplace directory or JSON file, a direct JSON URL, a GitHub `owner/repository` shorthand, or a GitHub repository or tree URL.
23
-
24
-
You can also open a source directly:
25
-
26
-
```sh
27
-
/plugins marketplace pythinker
28
-
/plugins marketplace anthropic
29
-
/plugins marketplace ./example-marketplace
30
-
/plugins marketplace example-org/example-plugins
31
-
```
32
-
33
-
Pythinker marketplace JSON and Claude Code `.claude-plugin/marketplace.json` files are detected automatically. For a local directory or GitHub repository, Pythinker Code CLI reads `.claude-plugin/marketplace.json` from the marketplace root, so relative Claude plugin paths can resolve within that repository. A catalog-level `metadata.pluginRoot` is prepended to each relative plugin source. A direct remote JSON URL has no repository context; relative plugin entries in that catalog remain visible but unavailable. Claude `npm`, SSH, generic Git, and non-GitHub repository sources are also shown as unavailable instead of being silently omitted.
17
+
|`R`| Reload installed plugins and manifests |
18
+
|`I`| View details for the selected installed plugin |
19
+
|`Esc`| Close the plugin manager |
34
20
35
21
You can use slash commands for the remaining operations:
36
22
@@ -39,7 +25,7 @@ You can use slash commands for the remaining operations:
39
25
|`/plugins`| Open the interactive plugin manager |
40
26
|`/plugins list`| List installed plugins |
41
27
|`/plugins install <path-or-url>`| Install from a local directory, zip URL, or GitHub repository URL |
42
-
|`/plugins marketplace [source]`|Choose a marketplace or browse the supplied alias, path, JSON URL, or GitHub repository|
28
+
|`/plugins marketplace [source]`|Browse the default marketplace or a supplied local JSON path or URL|
43
29
|`/plugins info <id>`| View plugin details and diagnostics |
44
30
|`/plugins enable <id>`| Enable a plugin |
45
31
|`/plugins disable <id>`| Disable a plugin |
@@ -48,7 +34,7 @@ You can use slash commands for the remaining operations:
48
34
|`/plugins mcp enable <id> <server>`| Enable an MCP server declared by a plugin |
49
35
|`/plugins mcp disable <id> <server>`| Disable an MCP server declared by a plugin |
50
36
51
-
The plugin manager shows the installation source and a trust badge for each install: `pythinker-official` (from an official Pythinker address), `curated` (from a curated Pythinker address), or `third-party` (everything else). Marketplace ownership does not grant Pythinker trust, so plugins from Anthropic's official catalog still show `third-party` under Pythinker trust.
37
+
The CLI asks for confirmation before it installs any source that is not an official Pythinker plugin.
52
38
53
39
### Installing from GitHub
54
40
@@ -63,7 +49,7 @@ Network requests only go through `github.com` redirects and `codeload.github.com
63
49
64
50
### Notes
65
51
66
-
- Plugin changes only take effect for new sessions. After installing, enabling/disabling, or removing a plugin, run `/reload`to reload plugins or `/new` to start a new session; the current session will not update.
52
+
- Plugin changes apply after `/reload` or in a new session.
67
53
- Local installations are copied to `$PYTHINKER_CODE_HOME/plugins/managed/<id>/`, and the CLI always runs from this managed copy. Editing the original source directory after installation has no effect; you must reinstall.
68
54
- Removing a plugin only deletes the installation record; the managed copy and original source files remain on disk.
69
55
- Plugins are currently installed per-user and apply to all projects; project-level installation scope is not yet supported.
@@ -75,10 +61,9 @@ A direct directory, zip, or GitHub install needs a plugin manifest at one of the
75
61
```text
76
62
<plugin_root>/pythinker.plugin.json
77
63
<plugin_root>/.pythinker-plugin/plugin.json
78
-
<plugin_root>/.claude-plugin/plugin.json
79
64
```
80
65
81
-
When more than one exists, Pythinker Code CLI uses them in the order shown above and reports the lower-priority manifest as shadowed. A marketplace install may omit a manifest when its catalog entry supplies the plugin identity and component declarations. A Claude `.claude-plugin/plugin.json`manifest can use a top-level `displayName`; native Pythinker manifests use `interface.displayName`.
66
+
When both exist, Pythinker Code CLI uses `pythinker.plugin.json`and reports the other manifest as shadowed.
82
67
83
68
Example:
84
69
@@ -102,23 +87,30 @@ Supported fields:
102
87
103
88
| Field | Description |
104
89
| --- | --- |
105
-
|`name`| Required for direct installs; serves as the plugin id. A marketplace definition supplies this value instead. The id must match `[a-z0-9][a-z0-9_-]{0,63}`|
|`interface`| Fields shown in `/plugins`: `displayName`, `shortDescription`, `longDescription`, `developerName`, `websiteURL`|
108
-
|`defaultEnabled`| Initial enabled state on first install. Updating or reinstalling preserves the current enabled state |
109
93
|`skills`| One or more `./` directory paths containing Agent Skills |
110
-
|`agents`| One or more `./` Markdown files or directories containing agent profiles |
111
-
|`outputStyles`| One or more `./` Markdown files or directories containing output styles |
94
+
|`agents`| One or more `./` directory paths containing agent profiles |
112
95
|`sessionStart.skill`| Loads the specified plugin Skill into the main agent when a new or resumed session starts |
113
96
|`skillInstructions`| Additional instructions appended whenever a Skill from this plugin is loaded |
114
-
|`mcpServers`| Inline declarations, `./` JSON paths, or arrays of both. MCP servers are enabled by default and can be managed from `/plugins`|
115
-
|`lspServers`| Inline declarations, `./` JSON paths, or arrays of both for LSP servers |
97
+
|`systemPrompt`| Inline instructions added to the agent system prompt while the plugin is enabled |
98
+
|`systemPromptPath`| A `./` path to a UTF-8 file containing system-prompt instructions |
99
+
|`commands`| One or more `./` directory or Markdown-file paths that register slash commands |
100
+
|`hooks`| Hook rules that run on matching lifecycle events while the plugin is enabled |
101
+
|`mcpServers`| Inline MCP server declarations. Servers are enabled by default and can be managed from `/plugins`|
102
+
103
+
When `skills` is omitted, a root `SKILL.md` becomes the plugin's single Skill. When `agents` is omitted, an `agents/` directory is discovered automatically. Every declared path must start with `./` and remain inside the plugin root after symbolic-link resolution.
104
+
105
+
Fields such as `tools`, `apps`, `inject`, `configFile`, and `bootstrap` are not supported. They appear as compatibility diagnostics and are not run.
116
106
117
-
The conventional `skills/`, `agents/`, and `output-styles/` directories are discovered automatically. If neither `skills` nor `skills/` is present, a root `SKILL.md` is treated as one Skill root. Every discovered component must remain within the plugin root after symbolic link resolution. Explicit component paths must also start with `./` and point to the expected file or directory type.
107
+
### System-prompt instructions
118
108
119
-
Claude marketplace definitions can provide supported components even when the plugin has no manifest. By default, Pythinker Code CLI combines supported manifest and marketplace declarations. For an entry with `strict: false`, it uses only the marketplace's component declarations. The definition is retained with the installed plugin, so manifestless components remain available after restart. Updates preserve the plugin's enabled state and its per-server MCP choices.
109
+
Use `systemPrompt` for short inline instructions or `systemPromptPath` for a file inside the plugin root. If both are present, Pythinker Code CLI combines the inline text first and the file second.
120
110
121
-
Pythinker Code CLI loads the supported parts of Claude plugins: `skills`, `agents`, `outputStyles`, `mcpServers`, and `lspServers`. Runtime extensions such as `tools`, `commands`, `hooks`, `apps`, `workflows`, `monitors`, `themes`, and `channels` appear as compatibility diagnostics and are not run.
111
+
Each field has a 32 KB UTF-8 limit. One prompt build accepts up to 64 KB from all enabled plugins. Contributions above either limit are skipped with a diagnostic or warning.
112
+
113
+
Default agent templates include these instructions automatically. A custom `SYSTEM.md` or agent file can place them with `${plugin_sections}`. Do not add `${plugin_sections}` when `${base_prompt}` already includes the default plugin block. See [Custom agents and SYSTEM.md](./agents.md#overriding-the-main-agent-s-system-prompt-with-system-md).
122
114
123
115
## Skills and session start
124
116
@@ -136,11 +128,42 @@ my-plugin/
136
128
137
129
`sessionStart.skill` loads a plugin Skill into the main agent at session start, making it suitable for initialization instructions, workflow rules, or mapping terminology from other tools to Pythinker Code CLI. It only injects text; it does not execute code.
138
130
139
-
Regardless of how a Skill is loaded (`sessionStart.skill`, `/skill:<name>`, or automatic model invocation), `skillInstructions` appears alongside that plugin's Skill. Paths declared through `agents` add reusable [agent profiles](./agents.md), while `outputStyles` adds prompt-based output styles when the plugin is enabled.
131
+
Regardless of how a Skill is loaded (`sessionStart.skill`, `/skill:<name>`, or automatic model invocation), `skillInstructions` appears alongside that plugin's Skill.
132
+
133
+
## Plugin agents
134
+
135
+
Declare one or more `./` directories in `agents`, or add an `agents/` directory at the plugin root. Its Markdown files use the [custom agent format](./agents.md#custom-agents).
136
+
137
+
Plugin agents have the lowest file-source priority. User, extra, project, and `--agent-file` profiles win on name conflicts. Replacing a built-in profile still requires `override: true` in its frontmatter.
138
+
139
+
## Plugin slash commands
140
+
141
+
The `commands` field accepts a `./` directory, a Markdown file, or an array of either. Directories are scanned recursively for Markdown files.
142
+
143
+
```json
144
+
{
145
+
"name": "pythinker-finance",
146
+
"commands": "./commands/"
147
+
}
148
+
```
149
+
150
+
A command file contains optional frontmatter followed by the prompt body:
151
+
152
+
```markdown
153
+
---
154
+
description: Summarize a company's latest financials
155
+
---
156
+
157
+
Summarize the latest financials for $ARGUMENTS.
158
+
```
159
+
160
+
Commands use the plugin id as their namespace. The example registers `/pythinker-finance:<command-name>`. The `name` frontmatter field overrides the name derived from the file path. The `description` field falls back to the first non-empty body line.
161
+
162
+
Text after the command replaces every `$ARGUMENTS` token. If the body has no token, the CLI appends the text as `ARGUMENTS: <text>`.
140
163
141
164
## MCP servers in plugins
142
165
143
-
When a plugin needs real tool capabilities, it can declare `mcpServers` in its manifest or marketplace definition, reusing the [MCP](./mcp.md) schema.
166
+
When a plugin needs tool capabilities, it can declare `mcpServers` in its manifest, using the [MCP](./mcp.md) schema.
144
167
145
168
Stdio server (local command):
146
169
@@ -167,21 +190,36 @@ HTTP server (remote service):
167
190
}
168
191
```
169
192
170
-
When `mcpServers` is omitted, a root `.mcp.json` file is loaded automatically. The same rule applies to `lspServers` and `.lsp.json`. Each file may contain the server map directly or wrap it in an `mcpServers` or `lspServers` object.
193
+
For stdio servers, `command` can be a command on `PATH` or a path starting with `./` inside the plugin root. `cwd` must also stay inside the plugin root. Local server processes receive `PYTHINKER_CODE_HOME` and `PYTHINKER_PLUGIN_ROOT` in their environment.
171
194
172
-
For stdio servers, `command` can be a command on `PATH` or a path starting with `./` within the plugin root directory. `cwd` likewise must start with `./` and remain within the plugin root directory; otherwise the server is ignored. In MCP and LSP declarations, `${CLAUDE_PLUGIN_ROOT}` expands to the installed plugin root. Local server processes also receive `CLAUDE_PLUGIN_ROOT` and `PYTHINKER_PLUGIN_ROOT` in their environment; declarations containing any other unresolved placeholder are ignored.
173
-
174
-
Plugin MCP servers only start in new sessions. To enable or disable a server:
195
+
Plugin MCP servers start after `/reload` or in a new session. To enable or disable a server:
175
196
176
197
```sh
177
198
/plugins mcp disable pythinker-finance finance
178
-
/new
199
+
/reload
179
200
180
201
/plugins mcp enable pythinker-finance finance
181
-
/new
202
+
/reload
203
+
```
204
+
205
+
## Hooks in plugins
206
+
207
+
The `hooks` field accepts the same `event`, `matcher`, `command`, and `timeout` fields as a [`[[hooks]]` rule in `config.toml`](./hooks.md#configuration):
208
+
209
+
```json
210
+
{
211
+
"hooks": [
212
+
{
213
+
"event": "PreToolUse",
214
+
"matcher": "Bash",
215
+
"command": "node ./hooks/check-bash.mjs",
216
+
"timeout": 5
217
+
}
218
+
]
219
+
}
182
220
```
183
221
184
-
LSP servers are active in new sessions while their plugin is enabled.
222
+
Plugin hooks run only while the plugin is enabled. Each hook uses the plugin root as its working directory and receives `PYTHINKER_CODE_HOME` and `PYTHINKER_PLUGIN_ROOT`.
185
223
186
224
## Security model
187
225
@@ -190,11 +228,13 @@ Plugins have a limited loading scope:
190
228
- Installing a plugin does not run its scripts, hooks, commands, or tool runtimes
191
229
- Zip extraction rejects absolute paths, parent-directory traversal, and symbolic-link escapes
192
230
- Component, executable, working-directory, and repository-subdirectory paths must remain inside the plugin root
193
-
-MCP and LSP declarations must pass their configuration schemas before activation
194
-
- MCP and LSP servers from enabled plugins only start in new sessions; MCP servers can be disabled individually from `/plugins`
231
+
-Hook and MCP declarations must pass their configuration schemas before activation
232
+
- MCP servers from enabled plugins start after `/reload` or in a new session and can be disabled individually from `/plugins`
195
233
- Broken manifests, unsupported components, unsafe paths, and rejected placeholders appear in `/plugins info <id>` diagnostics and do not affect other sessions
196
234
197
235
## Next steps
198
236
199
237
-[Agent Skills](./skills.md) — File format and frontmatter field reference for Skills
238
+
-[Custom agents and SYSTEM.md](./agents.md) — Agent profile format and prompt variables
239
+
-[Hooks](./hooks.md) — Hook events and result handling
200
240
-[MCP](./mcp.md) — Full schema and permission configuration for plugin MCP servers
0 commit comments