Skip to content

通过 Agent SDK 加载本地插件,可以为 Claude Code 添加自定义技能、代理、钩子和 MCP 服务器。配置时需指定插件根目录路径(指向包含 .claude-plugin/plugin.json 的文件夹),type 固定为 "local"。加载成功后可在系统初始化消息中查看已加载插件和斜杠命令。技能调用使用 plugin-name:skill-name 命名空间格式;如果相对路径不生效,改用绝对路径。

Claude Code Agent SDK 插件加载与配置

通过 Agent SDK 加载自定义插件,扩展 Claude Code 的命令、代理、技能和钩子功能。

插件让你能为 Claude Code 添加可跨项目共享的自定义功能。通过 Agent SDK,你可以从本地目录加载插件,为会话添加自定义斜杠命令、代理、技能、钩子和 MCP 服务器。

插件包含什么

一个插件可以包含以下扩展:

  • 技能(Skills):Claude 自主调用的能力(也可用 /skill-name 调用)
  • 代理(Agents):用于特定任务的专用子代理
  • 钩子(Hooks):响应工具调用等事件的事件处理器
  • MCP 服务器:通过 Model Context Protocol 集成外部工具

commands/ 目录是遗留格式。新建插件请使用 skills/。Claude Code 仍兼容两种格式。

插件完整结构和创建方法见插件开发指南

怎么配置插件加载

在选项配置中提供本地文件系统路径来加载插件。type 字段必须为 "local",这是 SDK 唯一接受的值。如果要用市场或远程仓库分发的插件,先下载到本地,再提供路径。SDK 支持从不同位置加载多个插件。

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Hello",
  options: {
    plugins: [
      { type: "local", path: "./my-plugin" },
      { type: "local", path: "/absolute/path/to/another-plugin" }
    ]
  }
})) {
  // 插件提供的命令、代理等功能已可用
}
python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    async for message in query(
        prompt="Hello",
        options=ClaudeAgentOptions(
            plugins=[
                {"type": "local", "path": "./my-plugin"},
                {"type": "local", "path": "/absolute/path/to/another-plugin"},
            ]
        ),
    ):
        # 插件功能已可用
        pass

asyncio.run(main())

路径类型

插件路径可以是:

  • 相对路径:相对于当前工作目录解析(例如 "./plugins/my-plugin"
  • 绝对路径:完整的文件系统路径(例如 "/home/user/plugins/my-plugin"

路径应指向插件根目录(包含 .claude-plugin/plugin.json 的目录)。

怎么验证插件加载成功

插件加载成功后,会出现在系统初始化消息中。可以通过以下代码验证:

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Hello",
  options: {
    plugins: [{ type: "local", path: "./my-plugin" }]
  }
})) {
  if (message.type === "system" && message.subtype === "init") {
    console.log("已加载插件:", message.plugins);
    // 示例: [{ name: "my-plugin", path: "./my-plugin" }]

    console.log("可用命令:", message.slash_commands);
    // 示例: ["/help", "/compact", "my-plugin:custom-command"]
  }
}
python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage

async def main():
    async for message in query(
        prompt="Hello",
        options=ClaudeAgentOptions(
            plugins=[{"type": "local", "path": "./my-plugin"}]
        ),
    ):
        if isinstance(message, SystemMessage) and message.subtype == "init":
            print("Plugins:", message.data.get("plugins"))
            # 示例: [{"name": "my-plugin", "path": "./my-plugin"}]
            print("Commands:", message.data.get("slash_commands"))
            # 示例: ["/help", "/compact", "my-plugin:custom-command"]

asyncio.run(main())

怎么调用插件技能

插件的技能会自动加命名空间(插件名称),避免冲突。作为斜杠命令调用时,格式为 plugin-name:skill-name

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

// 加载一个包含自定义 /greet 技能的插件
for await (const message of query({
  prompt: "/my-plugin:greet", // 使用命名空间调用插件技能
  options: {
    plugins: [{ type: "local", path: "./my-plugin" }]
  }
})) {
  if (message.type === "assistant") {
    console.log(message.message.content);
  }
}
python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock

async def main():
    # 加载一个包含自定义 /greet 技能的插件
    async for message in query(
        prompt="/demo-plugin:greet",  # 使用命名空间调用插件技能
        options=ClaudeAgentOptions(
            plugins=[{"type": "local", path": "./plugins/demo-plugin"}]
        ),
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(f"Claude: {block.text}")

asyncio.run(main())

如果你通过 CLI 安装了插件(例如 /plugin install my-plugin@marketplace),可以在 SDK 中直接使用其安装路径。CLI 安装的插件通常在 ~/.claude/plugins/

完整示例

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";
import * as path from "path";

async function runWithPlugin() {
  const pluginPath = path.join(__dirname, "plugins", "my-plugin");

  console.log("Loading plugin from:", pluginPath);

  for await (const message of query({
    prompt: "What custom commands do you have available?",
    options: {
      plugins: [{ type: "local", path: pluginPath }],
      maxTurns: 3
    }
  })) {
    if (message.type === "system" && message.subtype === "init") {
      console.log("Loaded plugins:", message.plugins);
      console.log("Available commands:", message.slash_commands);
    }

    if (message.type === "assistant") {
      console.log("Assistant:", message.message.content);
    }
  }
}

runWithPlugin().catch(console.error);
python
#!/usr/bin/env python3
from pathlib import Path
import anyio
from claude_agent_sdk import (
    AssistantMessage,
    ClaudeAgentOptions,
    SystemMessage,
    TextBlock,
    query,
)

async def run_with_plugin():
    plugin_path = Path(__file__).parent / "plugins" / "demo-plugin"
    print(f"Loading plugin from: {plugin_path}")

    options = ClaudeAgentOptions(
        plugins=[{"type": "local", "path": str(plugin_path)}],
        max_turns=3,
    )

    async for message in query(
        prompt="What custom commands do you have available?", options=options
    ):
        if isinstance(message, SystemMessage) and message.subtype == "init":
            print(f"Loaded plugins: {message.data.get('plugins')}")
            print(f"Available commands: {message.data.get('slash_commands')}")

        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(f"Assistant: {block.text}")

if __name__ == "__main__":
    anyio.run(run_with_plugin)

插件目录结构参考

一个插件目录必须包含 .claude-plugin/plugin.json 清单文件。可选目录如下:

text
my-plugin/
├── .claude-plugin/
│   └── plugin.json          # 必需:插件清单
├── skills/                   # 技能(自主调用或 /skill-name 调用)
│   └── my-skill/
│       └── SKILL.md
├── commands/                 # 遗留:请改用 skills/
│   └── custom-cmd.md
├── agents/                   # 自定义代理
│   └── specialist.md
├── hooks/                    # 事件处理器
│   └── hooks.json
└── .mcp.json                # MCP 服务器定义

详细创建指南请参考:

常见使用场景

开发与测试

在开发阶段加载插件,无需全局安装:

typescript
plugins: [{ type: "local", path: "./dev-plugins/my-plugin" }];

项目专用扩展

将插件包含在项目仓库中,确保团队一致性:

typescript
plugins: [{ type: "local", path: "./project-plugins/team-workflows" }];

多插件来源

从不同位置组合加载插件:

typescript
plugins: [
  { type: "local", path: "./local-plugin" },
  { type: "local", path: "~/.claude/custom-plugins/shared-plugin" }
];

常见问题

插件加载后看不到技能怎么办?

检查技能是否出现在初始化消息的 slash_commands 中。插件技能必须以 plugin-name:skill-name 格式调用。确保每个技能文件位于 skills/ 下的独立子目录中,例如 skills/my-skill/SKILL.md

相对路径不生效怎么解决?

相对路径基于当前工作目录解析。确认工作目录是否正确。如果问题持续,改用绝对路径,或使用路径工具(如 path.join)正确构造路径。

插件加载失败时怎么排查?

检查路径是否指向包含 .claude-plugin/ 的根目录,验证 plugin.json 的 JSON 语法是否正确,并确认插件目录有读取权限。加载失败时不会报错,但技能不会出现在 slash_commands 中。

参见