Claude Code 学习站

Agent SDK 插件加载指南(TypeScript / Python)

介绍如何通过 Claude Agent SDK 以编程方式从本地目录加载插件,启用 Skills、Agents、Hooks 与 MCP 服务器。

本页目录14
AI 摘要 · 已核查整理于 2026-08-04原文:Plugins in the SDK(Anthropic)Agent SDK插件TypeScriptPython
要点速览
  • 插件通过 options.plugins 数组加载,每项必须是 { type: "local", path: "..." },type 目前只支持 "local"
  • path 需指向插件根目录,即 skills/、agents/、hooks/、commands/ 或 .claude-plugin/ 的父目录;支持相对路径和绝对路径,但不支持 ~ 展开
  • 插件的 Skills 会自动以插件名为前缀命名空间,直接调用需发送 /plugin-name:skill-name
  • 可在 system 初始化消息(subtype为 init)中通过 message.plugins、message.skills、message.slash_commands 字段验证插件是否加载成功
  • 若路径不存在,SDK 会跳过该插件并继续会话,不会报错中断,需要自行检查 init 消息中的 plugins 列表来确认
  • plugin.json 清单文件是可选的,省略时 Claude Code 会根据目录结构自动发现组件

本文是对官方 Agent SDK 某页的中文整理,完整与最新内容以原文为准:https://code.claude.com/docs/en/agent-sdk/plugins

概述

插件(Plugins)允许你用可跨项目共享的自定义功能扩展 Claude Code。通过 Agent SDK,你可以以编程方式从本地目录加载插件,为 agent 会话增加能力。一个插件可以包含:

  • Skills(技能):Claude 在相关时自主调用的能力,也可以通过 /plugin-name:skill-name 直接调用某个插件技能
  • Agents(智能体):用于特定任务的专用子智能体
  • Hooks(钩子):响应工具使用等事件的事件处理器
  • MCP servers(MCP 服务器):通过 Model Context Protocol 集成的外部工具

关于插件结构与如何创建插件的完整信息,参见官方 Plugins 文档。

加载插件

在 options 配置中提供插件的本地文件系统路径来加载插件。type 字段必须为 "local",这是 SDK 目前唯一接受的值。SDK 支持从不同位置加载多个插件。

如果要使用通过 marketplace 或远程仓库分发的插件,需要先下载后再提供本地目录路径。插件所需的目录结构见下文「插件结构参考」。

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" }
    ]
  }
})) {
  // Plugin commands, agents, and other features are now available
}

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"},
            ]
        ),
    ):
        # Plugin commands, agents, and other features are now available
        pass


asyncio.run(main())

路径规范

插件路径可以是:

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

注:该路径应指向插件的根目录,即 skills/agents/hooks/commands/.claude-plugin/ 的父目录。

plugins 选项字段

字段类型默认值说明
typestring(仅 "local"插件来源类型,目前只接受 "local"
pathstring插件根目录的本地文件系统路径,可为相对路径或绝对路径

验证插件安装

插件加载成功后,会出现在系统初始化(init)消息中。可以通过检查该消息来确认插件是否可用:

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") {
    // Check loaded plugins
    console.log("Plugins:", message.plugins);
    // Example: [{ name: "my-plugin", path: "/absolute/path/to/my-plugin" }]

    // Plugin skills appear with the plugin name as a prefix
    console.log("Skills:", message.skills);
    // Example: ["my-plugin:greet"]

    // Plugin commands use the same prefix, and skills appear here too
    console.log("Commands:", message.slash_commands);
    // Example: ["compact", "context", "my-plugin:custom-command", "my-plugin:greet"]
  }
}

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":
            # Check loaded plugins
            print("Plugins:", message.data.get("plugins"))
            # Example: [{"name": "my-plugin", "path": "/absolute/path/to/my-plugin"}]

            # Plugin skills appear with the plugin name as a prefix
            print("Skills:", message.data.get("skills"))
            # Example: ["my-plugin:greet"]

            # Plugin commands use the same prefix, and skills appear here too
            print("Commands:", message.data.get("slash_commands"))
            # Example: ["compact", "context", "my-plugin:custom-command", "my-plugin:greet"]


asyncio.run(main())

init 消息中与插件相关的字段

字段类型默认值说明
pluginsarray已加载插件列表,元素形如 { name: "my-plugin", path: "/absolute/path/to/my-plugin" }
skillsarray<string>已加载的技能列表,插件技能带插件名前缀,如 "my-plugin:greet"
slash_commandsarray<string>可用的斜杠命令列表,同样带插件名前缀,技能也会出现在此列表中

使用插件技能(skills)

来自插件的 Skills 会自动以插件名做命名空间以避免冲突。要直接调用某个技能,将 /plugin-name:skill-name 作为 prompt 发送即可。

TypeScript

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

// Load a plugin with a custom /greet skill
for await (const message of query({
  prompt: "/my-plugin:greet", // Use plugin skill with namespace
  options: {
    plugins: [{ type: "local", path: "./my-plugin" }]
  }
})) {
  // Claude executes the custom greeting skill from the 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():
    # Load a plugin with a custom /greet skill
    async for message in query(
        prompt="/my-plugin:greet",  # Use plugin skill with namespace
        options=ClaudeAgentOptions(
            plugins=[{"type": "local", "path": "./my-plugin"}]
        ),
    ):
        # Claude executes the custom greeting skill from the 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 { fileURLToPath } from "node:url";

async function runWithPlugin() {
  const pluginPath = fileURLToPath(new URL("./plugins/my-plugin", import.meta.url));

  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 skills:", message.skills);
      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
"""Example demonstrating how to use plugins with the Agent SDK."""

import asyncio
from pathlib import Path

from claude_agent_sdk import (
    AssistantMessage,
    ClaudeAgentOptions,
    SystemMessage,
    TextBlock,
    query,
)


async def run_with_plugin():
    """Example using a custom plugin."""
    plugin_path = Path(__file__).parent / "plugins" / "my-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 skills: {message.data.get('skills')}")
            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__":
    asyncio.run(run_with_plugin())

插件结构参考

插件目录通常包含一个 .claude-plugin/plugin.json 清单文件。该清单是可选的——省略时 Claude Code 会根据目录结构自动发现组件。目录可包含以下内容:

my-plugin/
├── .claude-plugin/
│   └── plugin.json          # Plugin manifest (optional, components auto-discovered without it)
├── skills/                   # Agent Skills (invoked autonomously or via /plugin-name:skill-name)
│   └── my-skill/
│       └── SKILL.md
├── commands/                 # Skills as flat .md files
│   └── custom-cmd.md
├── agents/                   # Custom agents
│   └── specialist.md
├── hooks/                    # Event handlers
│   └── hooks.json
└── .mcp.json                # MCP server definitions

注:commands/ 目录存放以扁平 Markdown 文件形式存在的技能。新插件应使用 skills/。Claude Code 同时支持这两种位置。

多个插件来源

可以组合来自不同位置的插件:

import * as os from "node:os";
import * as path from "node:path";

plugins: [
  { type: "local", path: "./local-plugin" },
  {
    type: "local",
    path: path.join(os.homedir(), ".claude", "custom-plugins", "shared-plugin")
  }
];

注:SDK 不会展开 ~/plugins 这类 tilde 路径。如果某个插件路径不存在,SDK 会跳过该插件,会话继续正常运行,因此应检查 init 消息中的 plugins 列表以确认每个插件是否成功加载。

故障排查

插件未加载

如果插件没有出现在 init 消息中:

  1. 检查路径:确保路径指向插件根目录,即 skills/agents/hooks/commands/.claude-plugin/ 的父目录
  2. 验证 plugin.json:如果插件包含清单文件,确保其 JSON 语法有效
  3. 检查文件权限:确保插件目录可读
  4. 确认目录存在:SDK 会跳过不存在的路径,该插件不会出现在 init 消息的 plugins 列表中

技能未出现

如果插件技能不起作用:

  1. 使用命名空间:以 /plugin-name:skill-name 形式调用插件技能
  2. 检查 init 消息:确认该技能以正确的命名空间出现在 skills 列表中
  3. 验证技能文件:确保每个技能在 skills/ 下有自己的子目录,且其中包含 SKILL.md 文件,例如 skills/my-skill/SKILL.md

另请参阅