Skip to content

Commit 192ae6b

Browse files
committed
docs: 添加 Claude Agent SDK plugin 文档
记录 SDK 中 plugin 机制的实现细节
1 parent 29bcb05 commit 192ae6b

1 file changed

Lines changed: 346 additions & 0 deletions

File tree

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
# Plugins in the SDK
2+
3+
Load custom plugins to extend Claude Code with commands, agents, skills, and hooks through the Agent SDK
4+
5+
---
6+
7+
Plugins allow you to extend Claude Code with custom functionality that can be shared across projects. Through the Agent SDK, you can programmatically load plugins from local directories to add custom slash commands, agents, skills, hooks, and MCP servers to your agent sessions.
8+
9+
## What are plugins?
10+
11+
Plugins are packages of Claude Code extensions that can include:
12+
- **Commands**: Custom slash commands
13+
- **Agents**: Specialized subagents for specific tasks
14+
- **Skills**: Model-invoked capabilities that Claude uses autonomously
15+
- **Hooks**: Event handlers that respond to tool use and other events
16+
- **MCP servers**: External tool integrations via Model Context Protocol
17+
18+
For complete information on plugin structure and how to create plugins, see [Plugins](https://code.claude.com/docs/en/plugins).
19+
20+
## Loading plugins
21+
22+
Load plugins by providing their local file system paths in your options configuration. The SDK supports loading multiple plugins from different locations.
23+
24+
<CodeGroup>
25+
26+
```typescript TypeScript
27+
import { query } from "@anthropic-ai/claude-agent-sdk";
28+
29+
for await (const message of query({
30+
prompt: "Hello",
31+
options: {
32+
plugins: [
33+
{ type: "local", path: "./my-plugin" },
34+
{ type: "local", path: "/absolute/path/to/another-plugin" }
35+
]
36+
}
37+
})) {
38+
// Plugin commands, agents, and other features are now available
39+
}
40+
```
41+
42+
```python Python
43+
import asyncio
44+
from claude_agent_sdk import query
45+
46+
async def main():
47+
async for message in query(
48+
prompt="Hello",
49+
options={
50+
"plugins": [
51+
{"type": "local", "path": "./my-plugin"},
52+
{"type": "local", "path": "/absolute/path/to/another-plugin"}
53+
]
54+
}
55+
):
56+
# Plugin commands, agents, and other features are now available
57+
pass
58+
59+
asyncio.run(main())
60+
```
61+
62+
</CodeGroup>
63+
64+
### Path specifications
65+
66+
Plugin paths can be:
67+
- **Relative paths**: Resolved relative to your current working directory (e.g., `"./plugins/my-plugin"`)
68+
- **Absolute paths**: Full file system paths (e.g., `"/home/user/plugins/my-plugin"`)
69+
70+
<Note>
71+
The path should point to the plugin's root directory (the directory containing `.claude-plugin/plugin.json`).
72+
</Note>
73+
74+
## Verifying plugin installation
75+
76+
When plugins load successfully, they appear in the system initialization message. You can verify that your plugins are available:
77+
78+
<CodeGroup>
79+
80+
```typescript TypeScript
81+
import { query } from "@anthropic-ai/claude-agent-sdk";
82+
83+
for await (const message of query({
84+
prompt: "Hello",
85+
options: {
86+
plugins: [{ type: "local", path: "./my-plugin" }]
87+
}
88+
})) {
89+
if (message.type === "system" && message.subtype === "init") {
90+
// Check loaded plugins
91+
console.log("Plugins:", message.plugins);
92+
// Example: [{ name: "my-plugin", path: "./my-plugin" }]
93+
94+
// Check available commands from plugins
95+
console.log("Commands:", message.slash_commands);
96+
// Example: ["/help", "/compact", "my-plugin:custom-command"]
97+
}
98+
}
99+
```
100+
101+
```python Python
102+
import asyncio
103+
from claude_agent_sdk import query
104+
105+
async def main():
106+
async for message in query(
107+
prompt="Hello",
108+
options={"plugins": [{"type": "local", "path": "./my-plugin"}]}
109+
):
110+
if message.type == "system" and message.subtype == "init":
111+
# Check loaded plugins
112+
print("Plugins:", message.data.get("plugins"))
113+
# Example: [{"name": "my-plugin", "path": "./my-plugin"}]
114+
115+
# Check available commands from plugins
116+
print("Commands:", message.data.get("slash_commands"))
117+
# Example: ["/help", "/compact", "my-plugin:custom-command"]
118+
119+
asyncio.run(main())
120+
```
121+
122+
</CodeGroup>
123+
124+
## Using plugin commands
125+
126+
Commands from plugins are automatically namespaced with the plugin name to avoid conflicts. The format is `plugin-name:command-name`.
127+
128+
<CodeGroup>
129+
130+
```typescript TypeScript
131+
import { query } from "@anthropic-ai/claude-agent-sdk";
132+
133+
// Load a plugin with a custom /greet command
134+
for await (const message of query({
135+
prompt: "/my-plugin:greet", // Use plugin command with namespace
136+
options: {
137+
plugins: [{ type: "local", path: "./my-plugin" }]
138+
}
139+
})) {
140+
// Claude executes the custom greeting command from the plugin
141+
if (message.type === "assistant") {
142+
console.log(message.content);
143+
}
144+
}
145+
```
146+
147+
```python Python
148+
import asyncio
149+
from claude_agent_sdk import query, AssistantMessage, TextBlock
150+
151+
async def main():
152+
# Load a plugin with a custom /greet command
153+
async for message in query(
154+
prompt="/demo-plugin:greet", # Use plugin command with namespace
155+
options={"plugins": [{"type": "local", "path": "./plugins/demo-plugin"}]}
156+
):
157+
# Claude executes the custom greeting command from the plugin
158+
if isinstance(message, AssistantMessage):
159+
for block in message.content:
160+
if isinstance(block, TextBlock):
161+
print(f"Claude: {block.text}")
162+
163+
asyncio.run(main())
164+
```
165+
166+
</CodeGroup>
167+
168+
<Note>
169+
If you installed a plugin via the CLI (e.g., `/plugin install my-plugin@marketplace`), you can still use it in the SDK by providing its installation path. Check `~/.claude/plugins/` for CLI-installed plugins.
170+
</Note>
171+
172+
## Complete example
173+
174+
Here's a full example demonstrating plugin loading and usage:
175+
176+
<CodeGroup>
177+
178+
```typescript TypeScript
179+
import { query } from "@anthropic-ai/claude-agent-sdk";
180+
import * as path from "path";
181+
182+
async function runWithPlugin() {
183+
const pluginPath = path.join(__dirname, "plugins", "my-plugin");
184+
185+
console.log("Loading plugin from:", pluginPath);
186+
187+
for await (const message of query({
188+
prompt: "What custom commands do you have available?",
189+
options: {
190+
plugins: [
191+
{ type: "local", path: pluginPath }
192+
],
193+
maxTurns: 3
194+
}
195+
})) {
196+
if (message.type === "system" && message.subtype === "init") {
197+
console.log("Loaded plugins:", message.plugins);
198+
console.log("Available commands:", message.slash_commands);
199+
}
200+
201+
if (message.type === "assistant") {
202+
console.log("Assistant:", message.content);
203+
}
204+
}
205+
}
206+
207+
runWithPlugin().catch(console.error);
208+
```
209+
210+
```python Python
211+
#!/usr/bin/env python3
212+
"""Example demonstrating how to use plugins with the Agent SDK."""
213+
214+
from pathlib import Path
215+
import anyio
216+
from claude_agent_sdk import (
217+
AssistantMessage,
218+
ClaudeAgentOptions,
219+
TextBlock,
220+
query,
221+
)
222+
223+
224+
async def run_with_plugin():
225+
"""Example using a custom plugin."""
226+
plugin_path = Path(__file__).parent / "plugins" / "demo-plugin"
227+
228+
print(f"Loading plugin from: {plugin_path}")
229+
230+
options = ClaudeAgentOptions(
231+
plugins=[
232+
{"type": "local", "path": str(plugin_path)}
233+
],
234+
max_turns=3,
235+
)
236+
237+
async for message in query(
238+
prompt="What custom commands do you have available?",
239+
options=options
240+
):
241+
if message.type == "system" and message.subtype == "init":
242+
print(f"Loaded plugins: {message.data.get('plugins')}")
243+
print(f"Available commands: {message.data.get('slash_commands')}")
244+
245+
if isinstance(message, AssistantMessage):
246+
for block in message.content:
247+
if isinstance(block, TextBlock):
248+
print(f"Assistant: {block.text}")
249+
250+
251+
if __name__ == "__main__":
252+
anyio.run(run_with_plugin)
253+
```
254+
255+
</CodeGroup>
256+
257+
## Plugin structure reference
258+
259+
A plugin directory must contain a `.claude-plugin/plugin.json` manifest file. It can optionally include:
260+
261+
```
262+
my-plugin/
263+
├── .claude-plugin/
264+
│ └── plugin.json # Required: plugin manifest
265+
├── commands/ # Custom slash commands
266+
│ └── custom-cmd.md
267+
├── agents/ # Custom agents
268+
│ └── specialist.md
269+
├── skills/ # Agent Skills
270+
│ └── my-skill/
271+
│ └── SKILL.md
272+
├── hooks/ # Event handlers
273+
│ └── hooks.json
274+
└── .mcp.json # MCP server definitions
275+
```
276+
277+
For detailed information on creating plugins, see:
278+
- [Plugins](https://code.claude.com/docs/en/plugins) - Complete plugin development guide
279+
- [Plugins reference](https://code.claude.com/docs/en/plugins-reference) - Technical specifications and schemas
280+
281+
## Common use cases
282+
283+
### Development and testing
284+
285+
Load plugins during development without installing them globally:
286+
287+
```typescript
288+
plugins: [
289+
{ type: "local", path: "./dev-plugins/my-plugin" }
290+
]
291+
```
292+
293+
### Project-specific extensions
294+
295+
Include plugins in your project repository for team-wide consistency:
296+
297+
```typescript
298+
plugins: [
299+
{ type: "local", path: "./project-plugins/team-workflows" }
300+
]
301+
```
302+
303+
### Multiple plugin sources
304+
305+
Combine plugins from different locations:
306+
307+
```typescript
308+
plugins: [
309+
{ type: "local", path: "./local-plugin" },
310+
{ type: "local", path: "~/.claude/custom-plugins/shared-plugin" }
311+
]
312+
```
313+
314+
## Troubleshooting
315+
316+
### Plugin not loading
317+
318+
If your plugin doesn't appear in the init message:
319+
320+
1. **Check the path**: Ensure the path points to the plugin root directory (containing `.claude-plugin/`)
321+
2. **Validate plugin.json**: Ensure your manifest file has valid JSON syntax
322+
3. **Check file permissions**: Ensure the plugin directory is readable
323+
324+
### Commands not available
325+
326+
If plugin commands don't work:
327+
328+
1. **Use the namespace**: Plugin commands require the `plugin-name:command-name` format
329+
2. **Check init message**: Verify the command appears in `slash_commands` with the correct namespace
330+
3. **Validate command files**: Ensure command markdown files are in the `commands/` directory
331+
332+
### Path resolution issues
333+
334+
If relative paths don't work:
335+
336+
1. **Check working directory**: Relative paths are resolved from your current working directory
337+
2. **Use absolute paths**: For reliability, consider using absolute paths
338+
3. **Normalize paths**: Use path utilities to construct paths correctly
339+
340+
## See also
341+
342+
- [Plugins](https://code.claude.com/docs/en/plugins) - Complete plugin development guide
343+
- [Plugins reference](https://code.claude.com/docs/en/plugins-reference) - Technical specifications
344+
- [Slash Commands](/docs/en/agent-sdk/slash-commands) - Using slash commands in the SDK
345+
- [Subagents](/docs/en/agent-sdk/subagents) - Working with specialized agents
346+
- [Skills](/docs/en/agent-sdk/skills) - Using Agent Skills

0 commit comments

Comments
 (0)