Plugin cho phép bạn mở rộng Claude Code với chức năng tùy chỉnh có thể chia sẻ qua nhiều dự án. Qua Agent SDK, bạn có thể load plugin theo cách lập trình từ thư mục local để thêm skill, agent, hook, và MCP server vào agent session của mình.
Plugin là gì?
Phần tiêu đề “Plugin là gì?”Plugin là các gói mở rộng Claude Code có thể gồm:
- Skills: năng lực do model gọi mà Claude dùng tự động (cũng có thể gọi bằng
/skill-name) - Agents: subagent chuyên biệt cho tác vụ cụ thể
- Hooks: trình xử lý sự kiện phản hồi việc dùng tool và các sự kiện khác
- MCP servers: tích hợp tool bên ngoài qua Model Context Protocol
Để biết thông tin đầy đủ về cấu trúc plugin và cách tạo plugin, xem Plugins.
Load plugin
Phần tiêu đề “Load plugin”Load plugin bằng cách cung cấp đường dẫn filesystem local của chúng trong cấu hình tùy chọn. Trường type phải là "local", giá trị duy nhất SDK chấp nhận. SDK hỗ trợ load nhiều plugin từ các vị trí khác nhau.
Để dùng một plugin phân phối qua marketplace hay repository từ xa, hãy tải nó về trước và cung cấp đường dẫn thư mục local. Về cấu trúc thư mục mà một plugin cần, xem Tài liệu tham khảo cấu trúc plugin bên dưới.
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" } ] }})) { // Command, agent, và các tính năng khác của plugin giờ đã khả dụng}import asynciofrom 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"}, ] ), ): # Command, agent, và các tính năng khác của plugin giờ đã khả dụng pass
asyncio.run(main())Chỉ định đường dẫn
Phần tiêu đề “Chỉ định đường dẫn”Đường dẫn plugin có thể là:
- Đường dẫn tương đối: được resolve tương đối với thư mục làm việc hiện tại của bạn (ví dụ:
"./plugins/my-plugin") - Đường dẫn tuyệt đối: đường dẫn filesystem đầy đủ (ví dụ:
"/home/user/plugins/my-plugin")
Xác minh plugin đã cài
Phần tiêu đề “Xác minh plugin đã cài”Khi plugin load thành công, chúng xuất hiện trong system initialization message. Bạn có thể xác minh plugin của mình khả dụng:
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") { // Kiểm tra plugin đã load console.log("Plugins:", message.plugins); // Ví dụ: [{ name: "my-plugin", path: "/absolute/path/to/my-plugin" }]
// Skill của plugin xuất hiện với tiền tố tên plugin console.log("Skills:", message.skills); // Ví dụ: ["my-plugin:greet"]
// Command của plugin dùng cùng tiền tố, và skill cũng xuất hiện ở đây console.log("Commands:", message.slash_commands); // Ví dụ: ["compact", "context", "my-plugin:custom-command", "my-plugin:greet"] }}import asynciofrom 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": # Kiểm tra plugin đã load print("Plugins:", message.data.get("plugins")) # Ví dụ: [{"name": "my-plugin", "path": "/absolute/path/to/my-plugin"}]
# Skill của plugin xuất hiện với tiền tố tên plugin print("Skills:", message.data.get("skills")) # Ví dụ: ["my-plugin:greet"]
# Command của plugin dùng cùng tiền tố, và skill cũng xuất hiện ở đây print("Commands:", message.data.get("slash_commands")) # Ví dụ: ["compact", "context", "my-plugin:custom-command", "my-plugin:greet"]
asyncio.run(main())Dùng skill của plugin
Phần tiêu đề “Dùng skill của plugin”Skill từ plugin tự động được đặt namespace theo tên plugin để tránh xung đột. Để gọi trực tiếp một skill, gửi /plugin-name:skill-name làm prompt.
import { query } from "@anthropic-ai/claude-agent-sdk";
// Load một plugin có skill /greet tùy chỉnhfor await (const message of query({ prompt: "/my-plugin:greet", // Dùng skill của plugin kèm namespace options: { plugins: [{ type: "local", path: "./my-plugin" }] }})) { // Claude thực thi skill chào hỏi tùy chỉnh từ plugin if (message.type === "assistant") { console.log(message.message.content); }}import asynciofrom claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock
async def main(): # Load một plugin có skill /greet tùy chỉnh async for message in query( prompt="/my-plugin:greet", # Dùng skill của plugin kèm namespace options=ClaudeAgentOptions( plugins=[{"type": "local", "path": "./my-plugin"}] ), ): # Claude thực thi skill chào hỏi tùy chỉnh từ plugin if isinstance(message, AssistantMessage): for block in message.content: if isinstance(block, TextBlock): print(f"Claude: {block.text}")
asyncio.run(main())Ví dụ đầy đủ
Phần tiêu đề “Ví dụ đầy đủ”Đây là một ví dụ đầy đủ minh hoạ việc load và dùng plugin:
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);#!/usr/bin/env python3"""Ví dụ minh hoạ cách dùng plugin với Agent SDK."""
import asynciofrom pathlib import Path
from claude_agent_sdk import ( AssistantMessage, ClaudeAgentOptions, SystemMessage, TextBlock, query,)
async def run_with_plugin(): """Ví dụ dùng một plugin tùy chỉnh.""" 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())Tài liệu tham khảo cấu trúc plugin
Phần tiêu đề “Tài liệu tham khảo cấu trúc plugin”Một thư mục plugin thường chứa một file manifest .claude-plugin/plugin.json. Manifest là tùy chọn. Khi bỏ trống, Claude Code tự phát hiện các thành phần từ cấu trúc thư mục. Thư mục có thể gồm:
my-plugin/├── .claude-plugin/│ └── plugin.json # Manifest plugin (tùy chọn, thành phần được tự phát hiện nếu không có)├── skills/ # Agent Skills (gọi tự động hoặc qua /skill-name)│ └── my-skill/│ └── SKILL.md├── commands/ # Legacy: dùng skills/ thay vào đó│ └── custom-cmd.md├── agents/ # Agent tùy chỉnh│ └── specialist.md├── hooks/ # Trình xử lý sự kiện│ └── hooks.json└── .mcp.json # Định nghĩa MCP serverĐể biết thông tin chi tiết về tạo plugin, xem:
- Plugins - Hướng dẫn phát triển plugin đầy đủ
- Plugins reference - Đặc tả kỹ thuật và schema
Use case phổ biến
Phần tiêu đề “Use case phổ biến”Phát triển và kiểm thử
Phần tiêu đề “Phát triển và kiểm thử”Load plugin trong lúc phát triển mà không cần cài đặt toàn cục:
plugins: [{ type: "local", path: "./dev-plugins/my-plugin" }];Mở rộng riêng cho dự án
Phần tiêu đề “Mở rộng riêng cho dự án”Đưa plugin vào repository dự án của bạn để nhất quán trong toàn team:
plugins: [{ type: "local", path: "./project-plugins/team-workflows" }];Nhiều nguồn plugin
Phần tiêu đề “Nhiều nguồn plugin”Kết hợp plugin từ các vị trí khác nhau:
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") }];Xử lý sự cố
Phần tiêu đề “Xử lý sự cố”Plugin không load
Phần tiêu đề “Plugin không load”Nếu plugin của bạn không xuất hiện trong init message:
- Kiểm tra đường dẫn: đảm bảo đường dẫn trỏ tới thư mục gốc của plugin, thư mục cha của
skills/,agents/,hooks/,commands/(legacy), hay.claude-plugin/ - Xác thực plugin.json: nếu plugin của bạn gồm một manifest, đảm bảo nó có cú pháp JSON hợp lệ
- Kiểm tra quyền file: đảm bảo thư mục plugin có thể đọc được
- Xác nhận thư mục tồn tại: SDK bỏ qua một đường dẫn không tồn tại, và plugin sẽ không xuất hiện trong danh sách
pluginscủa init message
Skill không xuất hiện
Phần tiêu đề “Skill không xuất hiện”Nếu skill của plugin không hoạt động:
- Dùng namespace: gọi skill của plugin dưới dạng
/plugin-name:skill-name - Kiểm tra init message: xác minh skill xuất hiện trong danh sách
skillsvới namespace đúng - Xác thực file skill: đảm bảo mỗi skill có một file
SKILL.mdtrong thư mục con riêng dướiskills/, ví dụskills/my-skill/SKILL.md
Sự cố resolve đường dẫn
Phần tiêu đề “Sự cố resolve đường dẫn”Nếu đường dẫn tương đối không hoạt động:
- Kiểm tra thư mục làm việc: đường dẫn tương đối được resolve từ thư mục làm việc hiện tại của bạn
- Dùng đường dẫn tuyệt đối: để đáng tin cậy hơn, cân nhắc dùng đường dẫn tuyệt đối
- Chuẩn hoá đường dẫn: dùng path utility để dựng đường dẫn đúng cách
Xem thêm
Phần tiêu đề “Xem thêm”- Plugins - Hướng dẫn phát triển plugin đầy đủ
- Plugins reference - Đặc tả kỹ thuật
- Commands - Dùng command trong SDK
- Subagents - Làm việc với agent chuyên biệt
- Skills - Dùng Agent Skills
lượt xem