1> ## Documentation Index
2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
3> Use this file to discover all available pages before exploring further.
4
5# 新增元件至外掛程式
6
7> 新增技能、hooks、MCP 伺服器及其他所有元件類型至 Claude Code 外掛程式,並提供每種元件的驗證範例。
8
9export const Piece = ({id, children}) => <div className="pe-piece" data-piece={id}>{children}</div>;
10
11export const PluginExplorer = ({children}) => {
12 const PIECES = [{
13 id: 'manifest',
14 name: 'Manifest',
15 path: '.claude-plugin/plugin.json',
16 required: "Required by Anthropic's directory",
17 lines: [{
18 depth: 0,
19 kind: 'folder',
20 text: '.claude-plugin/'
21 }, {
22 depth: 1,
23 kind: 'file',
24 text: 'plugin.json'
25 }],
26 href: '/en/plugins/manifest-reference#manifest-file',
27 linkText: 'Go to the manifest reference'
28 }, {
29 id: 'skills',
30 name: 'Skills',
31 path: 'skills/review/SKILL.md',
32 lines: [{
33 depth: 0,
34 kind: 'folder',
35 text: 'skills/'
36 }, {
37 depth: 1,
38 kind: 'folder',
39 text: 'review/'
40 }, {
41 depth: 2,
42 kind: 'file',
43 text: 'SKILL.md'
44 }],
45 href: '/en/plugins/components#skills',
46 linkText: 'Go to the Skills section'
47 }, {
48 id: 'commands',
49 name: 'Commands',
50 path: 'commands/about.md',
51 lines: [{
52 depth: 0,
53 kind: 'folder',
54 text: 'commands/'
55 }, {
56 depth: 1,
57 kind: 'file',
58 text: 'about.md'
59 }],
60 href: '/en/plugins/components#commands',
61 linkText: 'Go to the Commands section'
62 }, {
63 id: 'agents',
64 name: 'Agents',
65 path: 'agents/security-reviewer.md',
66 lines: [{
67 depth: 0,
68 kind: 'folder',
69 text: 'agents/'
70 }, {
71 depth: 1,
72 kind: 'file',
73 text: 'security-reviewer.md'
74 }],
75 href: '/en/plugins/components#agents',
76 linkText: 'Go to the Agents section'
77 }, {
78 id: 'hooks',
79 name: 'Hooks',
80 path: 'hooks/hooks.json',
81 lines: [{
82 depth: 0,
83 kind: 'folder',
84 text: 'hooks/'
85 }, {
86 depth: 1,
87 kind: 'file',
88 text: 'hooks.json'
89 }],
90 href: '/en/plugins/components#hooks',
91 linkText: 'Go to the Hooks section'
92 }, {
93 id: 'monitors',
94 name: 'Monitors',
95 path: 'monitors/monitors.json',
96 lines: [{
97 depth: 0,
98 kind: 'folder',
99 text: 'monitors/'
100 }, {
101 depth: 1,
102 kind: 'file',
103 text: 'monitors.json'
104 }],
105 href: '/en/plugins/components#monitors',
106 linkText: 'Go to the Monitors section'
107 }, {
108 id: 'output-styles',
109 name: 'Output styles',
110 path: 'output-styles/terse.md',
111 lines: [{
112 depth: 0,
113 kind: 'folder',
114 text: 'output-styles/'
115 }, {
116 depth: 1,
117 kind: 'file',
118 text: 'terse.md'
119 }],
120 href: '/en/plugins/components#themes-and-output-styles',
121 linkText: 'Go to the Themes and output styles section'
122 }, {
123 id: 'themes',
124 name: 'Themes',
125 path: 'themes/dracula.json',
126 lines: [{
127 depth: 0,
128 kind: 'folder',
129 text: 'themes/'
130 }, {
131 depth: 1,
132 kind: 'file',
133 text: 'dracula.json'
134 }],
135 href: '/en/plugins/components#themes-and-output-styles',
136 linkText: 'Go to the Themes and output styles section'
137 }, {
138 id: 'workflows',
139 name: 'Workflows',
140 path: 'workflows/audit-routes.js',
141 lines: [{
142 depth: 0,
143 kind: 'folder',
144 text: 'workflows/'
145 }, {
146 depth: 1,
147 kind: 'file',
148 text: 'audit-routes.js'
149 }],
150 href: '/en/workflows#distribute-a-workflow-in-a-plugin',
151 linkText: 'Go to Distribute a workflow in a plugin'
152 }, {
153 id: 'bin',
154 name: 'Executables',
155 path: 'bin/hello-plugin',
156 lines: [{
157 depth: 0,
158 kind: 'folder',
159 text: 'bin/'
160 }, {
161 depth: 1,
162 kind: 'file',
163 text: 'hello-plugin'
164 }],
165 href: '/en/plugins/components#executables',
166 linkText: 'Go to the Executables section'
167 }, {
168 id: 'scripts',
169 name: 'Scripts',
170 path: 'scripts/format.sh',
171 lines: [{
172 depth: 0,
173 kind: 'folder',
174 text: 'scripts/'
175 }, {
176 depth: 1,
177 kind: 'file',
178 text: 'format.sh'
179 }],
180 href: '/en/plugins/components#hooks',
181 linkText: 'Go to the Hooks section'
182 }, {
183 id: 'settings',
184 name: 'Default settings',
185 path: 'settings.json',
186 lines: [{
187 depth: 0,
188 kind: 'file',
189 text: 'settings.json'
190 }],
191 href: '/en/plugins/components#default-settings',
192 linkText: 'Go to the Default settings section'
193 }, {
194 id: 'mcp',
195 name: 'MCP servers',
196 path: '.mcp.json',
197 lines: [{
198 depth: 0,
199 kind: 'file',
200 text: '.mcp.json'
201 }],
202 href: '/en/plugins/components#mcp-servers',
203 linkText: 'Go to the MCP servers section'
204 }, {
205 id: 'lsp',
206 name: 'LSP servers',
207 path: '.lsp.json',
208 lines: [{
209 depth: 0,
210 kind: 'file',
211 text: '.lsp.json'
212 }],
213 href: '/en/plugins/components#lsp-servers',
214 linkText: 'Go to the LSP servers section'
215 }];
216 const [selectedId, setSelectedId] = useState('manifest');
217 const [isFullscreen, setIsFullscreen] = useState(false);
218 const rootRef = useRef(null);
219 useEffect(() => {
220 const onFsChange = () => setIsFullscreen(!!document.fullscreenElement);
221 document.addEventListener('fullscreenchange', onFsChange);
222 return () => document.removeEventListener('fullscreenchange', onFsChange);
223 }, []);
224 const toggleFullscreen = () => {
225 if (!rootRef.current) return;
226 if (document.fullscreenElement) document.exitFullscreen(); else rootRef.current.requestFullscreen().catch(() => {});
227 };
228 const selected = PIECES.find(p => p.id === selectedId) || PIECES[0];
229 const onTreeKeyDown = e => {
230 const keys = ['ArrowDown', 'ArrowUp', 'Home', 'End'];
231 if (keys.indexOf(e.key) === -1) return;
232 const i = PIECES.findIndex(p => p.id === selectedId);
233 let next = i;
234 if (e.key === 'ArrowDown') next = Math.min(PIECES.length - 1, i + 1);
235 if (e.key === 'ArrowUp') next = Math.max(0, i - 1);
236 if (e.key === 'Home') next = 0;
237 if (e.key === 'End') next = PIECES.length - 1;
238 e.preventDefault();
239 if (next === i) return;
240 const id = PIECES[next].id;
241 setSelectedId(id);
242 const el = document.getElementById('pe-node-' + id);
243 if (el) el.focus();
244 };
245 const FolderIcon = () => <svg className="pe-icon" width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" aria-hidden="true">
246 <path d="M1.5 4.5a1 1 0 0 1 1-1h3.2l1.3 1.5h6a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1h-10.5a1 1 0 0 1-1-1z" />
247 </svg>;
248 const FileIcon = () => <svg className="pe-icon" width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" aria-hidden="true">
249 <path d="M4 1.5h5.5L13 5v9.5H4z" />
250 <path d="M9.5 1.5V5H13" />
251 </svg>;
252 return <div ref={rootRef} className={isFullscreen ? 'pe-root pe-fullscreen not-prose' : 'pe-root not-prose'} data-selected={selected.id}>
253 <style>{`
254 .pe-root {
255 --pe-mono: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
256 --pe-accent: #D97757;
257 --pe-accent-text: #A8502F;
258 --pe-accent-bg: rgba(217,119,87,0.10);
259 --pe-bg: #FFFFFF;
260 --pe-surface: #FAFAF7;
261 --pe-hover: #F0EEE6;
262 --pe-border: #E8E6DC;
263 --pe-text: #141413;
264 --pe-text-2: #3D3D3A;
265 --pe-text-3: #5E5D59;
266 font-family: inherit;
267 background: var(--pe-bg);
268 color: var(--pe-text);
269 border: 1px solid var(--pe-border);
270 border-radius: 12px;
271 margin: 1.5rem 0;
272 overflow: hidden;
273 box-sizing: border-box;
274 }
275 .dark .pe-root {
276 --pe-accent-text: #EBA98F;
277 --pe-accent-bg: rgba(217,119,87,0.18);
278 --pe-bg: #1A1918;
279 --pe-surface: #232221;
280 --pe-hover: #2E2D2B;
281 --pe-border: #3A3936;
282 --pe-text: #F1EFE9;
283 --pe-text-2: #D6D4CA;
284 --pe-text-3: #B8B5AD;
285 }
286 .pe-root *, .pe-root *::before, .pe-root *::after { box-sizing: border-box; }
287 .pe-head { display: flex; align-items: flex-start; gap: 12px; padding: 18px 24px 16px; border-bottom: 1px solid var(--pe-border); }
288 .pe-head-text { flex: 1; min-width: 0; }
289 .pe-fs-btn { flex-shrink: 0; width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--pe-border); border-radius: 6px; background: var(--pe-surface); color: var(--pe-text-2); font-size: 15px; line-height: 1; cursor: pointer; }
290 .pe-fs-btn:hover { background: var(--pe-hover); }
291 .pe-fs-btn:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: 2px; }
292 .pe-fullscreen { border-radius: 0; height: 100vh; display: flex; flex-direction: column; overflow: auto; }
293 .pe-fullscreen .pe-body { flex: 1; }
294 .pe-title { font-size: 19px; font-weight: 600; line-height: 1.3; color: var(--pe-text); margin: 0; }
295 .pe-sub { font-size: 15px; line-height: 1.5; color: var(--pe-text-3); margin: 4px 0 0; }
296 .pe-sub code { font-family: var(--pe-mono); font-size: 0.88em; padding: 1px 5px; border-radius: 4px; background: var(--pe-surface); border: 1px solid var(--pe-border); }
297 .pe-body { display: flex; align-items: stretch; }
298 .pe-tree-pane { width: 270px; flex-shrink: 0; background: var(--pe-surface); border-right: 1px solid var(--pe-border); padding: 16px 0 12px; }
299 .pe-panel { flex: 1; min-width: 0; padding: 16px 24px 24px; }
300 .pe-caption { font-size: 13px; font-weight: 600; color: var(--pe-text-3); margin: 0 0 10px; }
301 .pe-tree-pane .pe-caption { padding: 0 16px; }
302 .pe-rootline { display: flex; align-items: center; gap: 7px; padding: 3px 16px; font-family: var(--pe-mono); font-size: 13.5px; color: var(--pe-text-3); }
303 .pe-node {
304 display: block; width: 100%; margin: 0; padding: 3px 16px 3px 30px; text-align: left; cursor: pointer;
305 background: transparent; color: var(--pe-text-2);
306 border: none; border-left: 3px solid transparent;
307 font-family: var(--pe-mono); font-size: 13.5px; line-height: 1.4;
308 }
309 .pe-node:hover { background: var(--pe-hover); }
310 .pe-node:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: -2px; }
311 .pe-node[aria-pressed="true"] { background: var(--pe-accent-bg); border-left-color: var(--pe-accent); color: var(--pe-accent-text); font-weight: 600; }
312 .pe-line { display: flex; align-items: center; gap: 7px; padding: 2px 0; }
313 .pe-line-tree { flex-wrap: wrap; }
314 .pe-line-tree .pe-req { flex-basis: 100%; margin: 2px 0 0 22px; white-space: normal; width: fit-content; max-width: calc(100% - 22px); }
315 .pe-line span { overflow-wrap: anywhere; }
316 .pe-piece { display: none; font-size: 16px; line-height: 1.6; color: var(--pe-text-2); }
317 .pe-root[data-selected="manifest"] .pe-piece[data-piece="manifest"],
318 .pe-root[data-selected="skills"] .pe-piece[data-piece="skills"],
319 .pe-root[data-selected="commands"] .pe-piece[data-piece="commands"],
320 .pe-root[data-selected="agents"] .pe-piece[data-piece="agents"],
321 .pe-root[data-selected="hooks"] .pe-piece[data-piece="hooks"],
322 .pe-root[data-selected="monitors"] .pe-piece[data-piece="monitors"],
323 .pe-root[data-selected="output-styles"] .pe-piece[data-piece="output-styles"],
324 .pe-root[data-selected="themes"] .pe-piece[data-piece="themes"],
325 .pe-root[data-selected="workflows"] .pe-piece[data-piece="workflows"],
326 .pe-root[data-selected="bin"] .pe-piece[data-piece="bin"],
327 .pe-root[data-selected="scripts"] .pe-piece[data-piece="scripts"],
328 .pe-root[data-selected="settings"] .pe-piece[data-piece="settings"],
329 .pe-root[data-selected="mcp"] .pe-piece[data-piece="mcp"],
330 .pe-root[data-selected="lsp"] .pe-piece[data-piece="lsp"] { display: block; }
331 .pe-piece p { margin: 0 0 10px; }
332 .pe-piece p:last-child { margin-bottom: 0; }
333 .pe-piece code { font-family: var(--pe-mono); font-size: 0.88em; padding: 1px 5px; border-radius: 4px; background: var(--pe-surface); border: 1px solid var(--pe-border); }
334 .pe-piece .code-block { margin: 12px 0 0; }
335 .pe-piece pre code { padding: 0; border: none; background: none; }
336 .pe-piece a { color: var(--pe-accent-text); }
337 .pe-line-compact { display: none; }
338 .pe-icon { flex-shrink: 0; }
339 .pe-req { margin-left: 8px; padding: 0 6px; border-radius: 999px; font-size: 11px; line-height: 18px; letter-spacing: .02em; color: var(--pe-accent-text); border: 1px solid var(--pe-border); background: var(--pe-surface); white-space: nowrap; font-weight: 500; vertical-align: middle; }
340 .pe-name { font-size: 22px; font-weight: 600; line-height: 1.25; letter-spacing: -0.2px; color: var(--pe-text); margin: 0; }
341 .pe-path { font-family: var(--pe-mono); font-size: 13.5px; color: var(--pe-accent-text); margin: 4px 0 0; overflow-wrap: anywhere; }
342 .pe-block { margin: 20px 0 0; }
343 .pe-link {
344 display: inline-block; margin: 24px 0 0; padding: 8px 14px; border-radius: 8px;
345 font-size: 14.5px; font-weight: 600; text-decoration: none;
346 color: var(--pe-accent-text); background: var(--pe-accent-bg); border: 1px solid var(--pe-accent);
347 }
348 .pe-link:hover { filter: brightness(0.97); }
349 .pe-link:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: 2px; }
350 @media (max-width: 700px) {
351 .pe-head { padding: 16px 16px 14px; }
352 .pe-body { flex-direction: column; }
353 .pe-tree-pane { width: 100%; border-right: none; border-bottom: 1px solid var(--pe-border); }
354 .pe-line-tree { display: none; }
355 .pe-line-compact { display: flex; }
356 .pe-panel { padding: 16px 16px 20px; }
357 }
358 `}</style>
359
360 <div className="pe-head">
361 <div className="pe-head-text">
362 <div className="pe-title">What goes in a plugin</div>
363 <div className="pe-sub">This example plugin, <code>my-plugin</code>, has one of every kind of component, each in its default location. Select a file or folder to read what it’s for and see what goes in it.</div>
364 </div>
365 <button type="button" className="pe-fs-btn" onClick={toggleFullscreen} aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'} title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}>
366 {isFullscreen ? '⤡' : '⛶'}
367 </button>
368 </div>
369
370 <div className="pe-body">
371 <div className="pe-tree-pane">
372 <div className="pe-caption" id="pe-tree-caption">Plugin directory</div>
373 <div role="group" aria-labelledby="pe-tree-caption" onKeyDown={onTreeKeyDown}>
374 <div className="pe-rootline"><FolderIcon /><span>my-plugin/</span></div>
375 {PIECES.map(p => <button key={p.id} id={'pe-node-' + p.id} type="button" className="pe-node" aria-pressed={p.id === selected.id} aria-label={p.name + ', ' + p.path} onClick={() => setSelectedId(p.id)}>
376 {p.lines.map((line, i) => <span key={i} className="pe-line pe-line-tree" style={{
377 paddingLeft: line.depth * 18 + 'px'
378 }}>
379 {line.kind === 'folder' ? <FolderIcon /> : <FileIcon />}
380 <span>{line.text}</span>
381 {p.required && i === p.lines.length - 1 ? <span className="pe-req">{p.required}</span> : null}
382 </span>)}
383 <span className="pe-line pe-line-compact">
384 <FileIcon />
385 <span>{p.path}</span>
386 {p.required ? <span className="pe-req">{p.required}</span> : null}
387 </span>
388 </button>)}
389 </div>
390 </div>
391
392 <div className="pe-panel" role="region" aria-labelledby="pe-panel-caption" aria-live="polite" aria-atomic="true">
393 <div className="pe-caption" id="pe-panel-caption">Selected piece</div>
394 <div className="pe-name">{selected.name}{selected.required ? <span className="pe-req">{selected.required}</span> : null}</div>
395 <div className="pe-path">{selected.path}</div>
396
397 <div className="pe-block">{children}</div>
398
399 <a className="pe-link" href={selected.href}>{selected.linkText}</a>
400 </div>
401 </div>
402 </div>;
403};
404
405Claude Code 外掛程式由多個元件組成,例如技能、代理、hooks 和 MCP 伺服器。每個元件在外掛程式中都有一個預設資料夾、`.claude-plugin/plugin.json` 中的選用資訊清單鍵(用於取代或新增至該資料夾),以及使用者看到的名稱。如需每個鍵的完整欄位表,請參閱[資訊清單參考](/docs/zh-TW/plugins/manifest-reference#fields)。
406
407使用此頁面將元件新增至已載入的外掛程式。
408
409新增元件後,在執行中的工作階段中執行 `/reload-plugins`,或啟動新的工作階段,以便 Claude Code 載入該元件。若要在載入前檢查元件的檔案,請從外掛程式目錄在您的殼層中執行 [`claude plugin validate .`](/docs/zh-TW/plugins/cli-reference#plugin-validate)。
410
411<Note>
412 這些情況涵蓋在其他頁面上:
413
414 * **建立您的第一個外掛程式**:從[建立外掛程式](/docs/zh-TW/plugins/create)開始
415 * **安裝他人的外掛程式**:請參閱[安裝外掛程式](/docs/zh-TW/plugins/install)
416 * **您的外掛程式使用者在 claude.ai 或 Cowork 上**:那裡會載入不同的元件集合。請參閱[claude.ai 和 Cowork 上的外掛程式](https://claude.com/docs/plugins/overview)
417</Note>
418
419<h2 id="explore-the-plugin-directory">
420 探索外掛程式目錄
421</h2>
422
423探索工具顯示一個範例外掛程式 `my-plugin`,其在預設位置具有每種元件:
424
425* 一個審查 skill 和一個 `about` 命令
426* 一個安全審查子代理
427* 一個在 Claude 編輯檔案後格式化檔案的 hook,以及它呼叫的 `scripts/` 資料夾
428* 一個日誌監視器
429* 一個輸出樣式和一個色彩主題
430* 一個路由審計工作流程
431* 一個 `hello-plugin` 可執行檔
432* 預設設定
433* 一個本機 MCP 伺服器和一個 Go 語言伺服器
434
435每個檔案都是其格式的最小有效範例,目的是展示形狀而不是有用:真實的 skill 或 agent 包含完整的指示,通常還有支援檔案,真實的 hook 或監視器執行真實的工作。探索工具後的章節使用與探索工具相同的檔案作為範例,並連結至更完整的檔案。選擇檔案或資料夾以讀取其用途、查看其內容,並找到涵蓋它的章節。
436
437<PluginExplorer>
438 <Piece id="manifest">
439 [manifest](/docs/zh-TW/plugins/manifest-reference) 是外掛程式 `.claude-plugin/` 目錄中的 `plugin.json` 檔案。它包含外掛程式的中繼資料和 Claude Code 提示使用者的 `userConfig` 值。只有 `name` 是必需的。在這個中,`description` 是使用者在 `/plugin` 中看到的外掛程式文字,`version` 會讓使用者保持在該版本,直到您變更它:
440
441 ```json theme={null}
442 {
443 "name": "my-plugin",
444 "version": "1.0.0",
445 "description": "Review, formatting, and database tools for this team"
446 }
447 ```
448 </Piece>
449
450 <Piece id="skills">
451 [skill](/docs/zh-TW/skills) 是一個 `SKILL.md` 檔案。將每個 skill 儲存在 `skills/` 下的自己的目錄中。Claude 讀取每個 skill 的 `description`,當使用者要求的內容與其相符時(例如要求 Claude 審查此處的提取請求),Claude 會載入 skill 的指示並遵循它們。使用者也可以直接執行它作為 `/my-plugin:review`:
452
453 ```markdown theme={null}
454 ---
455 description: Reviews a pull request for style and test coverage. Use when asked to review code.
456 ---
457
458 Review the changed files. Report style problems first, then missing tests.
459 ```
460 </Piece>
461
462 <Piece id="commands">
463 命令是使用者按名稱執行的單一 Markdown 檔案。命令是較舊的格式:skill 按名稱執行的方式相同,也可以在自己的目錄中攜帶支援檔案,因此將新的寫成 skills,並為您已有的檔案保留 `commands/`。此檔案變成 `/my-plugin:about`,並採用與 skill 相同的 frontmatter:
464
465 ```markdown theme={null}
466 ---
467 description: Summarize the repository
468 ---
469
470 Summarize what this repository does in three sentences.
471 ```
472 </Piece>
473
474 <Piece id="agents">
475 [子代理](/docs/zh-TW/sub-agents) 是一個單獨的助手,具有自己的指示和自己的內容視窗,Claude 可以將任務委派給它並取回結果。`agents/` 下的每個 Markdown 檔案定義一個:frontmatter 命名它並說明何時使用它,正文是其系統提示。這個命名為 `my-plugin:security-reviewer`,使用者可以使用 `@agent-my-plugin:security-reviewer` 叫用它:
476
477 ```markdown theme={null}
478 ---
479 name: security-reviewer
480 description: Reviews code changes for security issues. Use after edits to authentication or input handling.
481 model: sonnet
482 ---
483
484 You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.
485 ```
486 </Piece>
487
488 <Piece id="hooks">
489 [hook](/docs/zh-TW/hooks-guide) 在 Claude Code 生命週期中的某個點自動執行某些操作,例如在每次檔案編輯後:shell 命令、HTTP 請求、MCP 工具呼叫、對模型的提示或子代理。將外掛程式的 hooks 儲存在外掛程式根目錄的 `hooks/hooks.json` 中。這個在 Claude 寫入或編輯檔案後執行外掛程式的 `scripts/format.sh`:
490
491 ```json theme={null}
492 {
493 "hooks": {
494 "PostToolUse": [
495 {
496 "matcher": "Write|Edit",
497 "hooks": [
498 {
499 "type": "command",
500 "command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/format.sh\""
501 }
502 ]
503 }
504 ]
505 }
506 }
507 ```
508 </Piece>
509
510 <Piece id="monitors">
511 監視器是一個 shell 命令,Claude Code 在工作階段啟動時在背景啟動,並保持執行直到工作階段結束,使用 [Monitor 工具](/docs/zh-TW/tools-reference#monitor-tool)。它列印的內容作為通知到達 Claude。`when` 欄位可以改為在命名 skill 首次執行時啟動它。這個尾部一個錯誤日誌:
512
513 ```json theme={null}
514 [
515 {
516 "name": "error-log",
517 "command": "tail -F ./logs/error.log",
518 "description": "Application error log"
519 }
520 ]
521 ```
522 </Piece>
523
524 <Piece id="output-styles">
525 外掛程式可以包含 [輸出樣式](/docs/zh-TW/output-styles),這會改變 Claude 格式化和措辭其回覆的方式。將每個輸出樣式儲存為 `output-styles/<name>.md`。這個在 `/output-style` 中顯示為 `my-plugin:terse`:
526
527 ```markdown theme={null}
528 ---
529 name: terse
530 description: Answer in as few words as possible
531 keep-coding-instructions: true
532 ---
533
534 Keep every reply short. Skip preambles and summaries.
535 ```
536 </Piece>
537
538 <Piece id="themes">
539 外掛程式可以包含 [Claude Code 介面的色彩主題](/docs/zh-TW/terminal-config#create-a-custom-theme)。將每個主題儲存為 `themes/<slug>.json`。這個在 `/theme` 中顯示為 `Dracula`,標記為來自 `my-plugin`:
540
541 ```json theme={null}
542 {
543 "name": "Dracula",
544 "base": "dark",
545 "overrides": {
546 "claude": "#bd93f9",
547 "error": "#ff5555"
548 }
549 }
550 ```
551 </Piece>
552
553 <Piece id="workflows">
554 `workflows/` 資料夾包含 [workflow](/docs/zh-TW/workflows) `.js` 檔案:一個 `meta` 區塊,然後是協調多個子代理的指令碼正文。這個執行為 `/my-plugin:audit-routes`:
555
556 ```javascript theme={null}
557 export const meta = {
558 name: 'audit-routes',
559 description: 'Audit every route handler for missing auth checks',
560 }
561
562 const found = await agent('List every .ts file under src/routes/.', {
563 schema: { type: 'object', required: ['files'], properties: { files: { type: 'array', items: { type: 'string' } } } },
564 })
565
566 const audits = await pipeline(found.files, file =>
567 agent(`Audit ${file} for missing authentication checks.`, { label: file }),
568 )
569
570 return audits.filter(Boolean)
571 ```
572 </Piece>
573
574 <Piece id="bin">
575 `bin/` 是外掛程式如何提供命令列工具的方式。啟用外掛程式時,Claude Code 將此資料夾放在它執行命令的 shell 的 `PATH` 上,因此 Claude 或 skill 的指示可以按名稱執行工具,而無需使用者安裝任何東西。有了這個 [可執行檔](#executables),`hello-plugin` 是 Claude 可以執行的命令:
576
577 ```bash theme={null}
578 #!/bin/bash
579 echo "hello from my-plugin"
580 ```
581 </Piece>
582
583 <Piece id="scripts">
584 `hooks/hooks.json` 中的 hook 執行指令碼,此資料夾是範例保留它的位置。名稱 `scripts/` 是一個慣例,不是 Claude Code 尋找的東西:hook 按其路徑指向檔案,`${CLAUDE_PLUGIN_ROOT}/scripts/format.sh`。格式化指令碼可能看起來像這樣:
585
586 ```bash theme={null}
587 #!/bin/bash
588 npx prettier --write .
589 ```
590 </Piece>
591
592 <Piece id="settings">
593 外掛程式根目錄的 `settings.json` 包含在啟用外掛程式時適用的 [設定](/docs/zh-TW/settings-reference),因此外掛程式可以改變工作階段的行為方式,而不僅僅是新增元件。只有兩個鍵從外掛程式生效,[`agent`](/docs/zh-TW/settings-reference#agent) 和 [`subagentStatusLine`](/docs/zh-TW/settings-reference#subagentstatusline);所有其他鍵都被丟棄。請參閱 [預設設定](#default-settings)。
594
595 這個設定 `agent`,它執行工作階段的主執行緒作為外掛程式自己的 `security-reviewer` agent,因此該 agent 的系統提示、工具限制和模型適用於整個工作階段:
596
597 ```json theme={null}
598 {
599 "agent": "security-reviewer"
600 }
601 ```
602 </Piece>
603
604 <Piece id="mcp">
605 [MCP 伺服器](/docs/zh-TW/mcp) 從外部系統為 Claude 提供工具。在外掛程式根目錄的 `.mcp.json` 中宣告它。這個啟動外掛程式內指令碼中的本機伺服器,並在 `/mcp` 中顯示為 `plugin:my-plugin:db`:
606
607 ```json theme={null}
608 {
609 "mcpServers": {
610 "db": {
611 "command": "node",
612 "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"]
613 }
614 }
615 }
616 ```
617 </Piece>
618
619 <Piece id="lsp">
620 LSP 伺服器為 Claude 提供 [診斷和程式碼導航](/docs/zh-TW/plugins/code-intelligence) 用於語言。在外掛程式根目錄的 `.lsp.json` 中宣告伺服器。這個連接 Go 語言伺服器用於 `.go` 檔案:
621
622 ```json theme={null}
623 {
624 "gopls": {
625 "command": "gopls",
626 "args": ["serve"],
627 "extensionToLanguage": {
628 ".go": "go"
629 }
630 }
631 }
632 ```
633 </Piece>
634</PluginExplorer>
635
636<h2 id="add-each-kind-of-component">
637 新增每種元件
638</h2>
639
640下面的每個章節涵蓋一種元件:其檔案在外掛程式中的位置、驗證的範例、外掛程式載入後使用者看到的內容,以及改變預設位置的 manifest 鍵。新增您的外掛程式需要的;沒有任何是必需的。
641
642<h3 id="skills">
643 Skills
644</h3>
645
646[skill](/docs/zh-TW/skills) 是一個 `SKILL.md` 檔案,當其描述與任務相符時 Claude 可以載入。使用者也可以將其作為命令執行。將每個 skill 儲存在 `skills/` 下的自己的目錄中:
647
648```text theme={null}
649my-plugin/
650├── .claude-plugin/
651│ └── plugin.json
652└── skills/
653 └── review/
654 └── SKILL.md
655```
656
657給 `SKILL.md` 一個 `description`,以便 Claude 知道何時使用它:
658
659```markdown skills/review/SKILL.md theme={null}
660---
661description: Reviews a pull request for style and test coverage. Use when asked to review code.
662---
663
664Review the changed files. Report style problems first, then missing tests.
665```
666
667載入外掛程式後,`/my-plugin:review` 執行 skill。命令名稱和誰可以叫用它遵循這些規則:
668
669* **命令名稱**:`/<plugin>:<directory>`,所以 `my-plugin` 中的 `skills/review/SKILL.md` 是 `/my-plugin:review`。如果您在 frontmatter 中設定 `name`,它會取代最後一個區段,外掛程式前綴保持不變。請參閱 [skill 如何獲得其命令名稱](/docs/zh-TW/skills#how-a-skill-gets-its-command-name)
670* **誰叫用它**:Claude、使用者或兩者,由 frontmatter 控制。請參閱 [控制誰叫用 skill](/docs/zh-TW/skills#control-who-invokes-a-skill)
671
672您也可以將 skills 放在預設 `skills/` 目錄之外:
673
674* **其他目錄**:在 `skills` manifest 鍵中列出它們。它們新增至預設 `skills/` 掃描,而不是取代它,不像 `commands` 和 `agents`
675* **外掛程式根目錄的單一 skill**:沒有 `skills/` 目錄且沒有 `skills` manifest 鍵,外掛程式根目錄的 `SKILL.md` 載入為一個 skill。在其 frontmatter 中設定 `name`,因為否則市場安裝會在其 [快取目錄](/docs/zh-TW/plugins/loading#find-plugins-on-disk) 之後命名 skill,而不是您的外掛程式
676
677若要在外掛程式中包含指示,將其寫成 skill。Claude Code 不會載入外掛程式根目錄的 `CLAUDE.md`,`claude plugin validate` 會警告 `CLAUDE.md at the plugin root is not loaded as project context`。
678
679如需 frontmatter 欄位和支援檔案,請參閱 [Skills](/docs/zh-TW/skills)。
680
681<h3 id="commands">
682 命令
683</h3>
684
685命令是使用者按名稱執行的單一 Markdown 檔案,例如 `/my-plugin:about`。
686
687<Note>
688 命令是較舊的格式,[skills](#skills) 對新工作已取代它們。skill 按名稱執行的方式相同,它也可以在其目錄中攜帶支援檔案。為您從 `.claude/commands/` 移動的檔案保留 `commands/`。
689</Note>
690
691將命令儲存在 `commands/<file>.md`,它變成 `/<plugin>:<file>`。子目錄新增一個區段,所以 `commands/db/migrate.md` 是 `/my-plugin:db:migrate`。
692
693命令檔案採用與 skills 相同的 frontmatter。
694
695<h4 id="define-commands-in-the-manifest">
696 在 manifest 中定義命令
697</h4>
698
699只有當您想將命令檔案保留在 `commands/` 以外的地方,或在 `plugin.json` 中定義短命令而不需要單獨的 Markdown 檔案時,您才需要這個。設定 `commands` manifest 鍵,Claude Code 會讀取它而不是掃描 `commands/`。鍵採用路徑、路徑陣列或將每個命令名稱對應到 `source` 檔案或內嵌 `content` 的物件。
700
701此 manifest 內嵌定義 `/my-plugin:about`,沒有 Markdown 檔案:
702
703```json .claude-plugin/plugin.json theme={null}
704{
705 "name": "my-plugin",
706 "commands": {
707 "about": {
708 "content": "Summarize what this repository does in three sentences.",
709 "description": "Summarize the repository"
710 }
711 }
712}
713```
714
715載入外掛程式並在工作階段中執行 `/my-plugin:about` 以確認它已載入。
716
717如需完整的鍵語法,請參閱 [`commands`](/docs/zh-TW/plugins/manifest-reference#commands)。
718
719<h3 id="agents">
720 Agents
721</h3>
722
723[子代理](/docs/zh-TW/sub-agents) 是一個單獨的助手,具有自己的指示和內容視窗,Claude 可以將任務委派給它。`agents/` 下的每個 Markdown 檔案定義一個:
724
725```markdown agents/security-reviewer.md theme={null}
726---
727name: security-reviewer
728description: Reviews code changes for security issues. Use after edits to authentication or input handling.
729model: sonnet
730---
731
732You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.
733```
734
735此 agent 命名為 `my-plugin:security-reviewer`,使用者可以使用 `@agent-my-plugin:security-reviewer` [明確叫用它](/docs/zh-TW/sub-agents#invoke-subagents-explicitly)。名稱形式是 `<plugin>:<name>`,其中 `<name>` 來自 frontmatter,或沒有時來自檔案名稱。
736
737`agents` manifest 鍵取代 `agents/` 掃描。
738
739<h4 id="organize-agents-in-subfolders">
740 在子資料夾中組織 agents
741</h4>
742
743您可以將外掛程式 agent 檔案放在 `agents/` 的子資料夾中。Claude Code [遞迴載入它們](/docs/zh-TW/sub-agents#choose-the-subagent-scope),並使用冒號連接外掛程式名稱、每個子資料夾名稱和檔案名稱以形成 agent 的範圍名稱。例如,`my-plugin` 中的 `agents/review/security.md` 載入為 `my-plugin:review:security`。兩個設定改變該名稱:
744
745* Frontmatter `name`:它只取代檔案名稱,所以 `agents/review/security.md` 中的 `name: audit` 載入為 `my-plugin:review:audit`
746* Manifest [`agents`](/docs/zh-TW/plugins/manifest-reference#fields) 欄位:您在那裡列出的檔案載入時沒有子資料夾名稱,所以 `"agents": "./custom/review/security.md"` 載入為 `my-plugin:security`
747
748<h4 id="frontmatter-fields-in-plugin-agents">
749 外掛程式 agents 中的 Frontmatter 欄位
750</h4>
751
752外掛程式 agent 的 frontmatter 遵循這些規則:
753
754* **支援的欄位**:`name`、`description`、`model`、`effort`、`maxTurns`、`tools`、`disallowedTools`、`skills`、`memory`、`background`、`omitClaudeMd`、`isolation`、`color` 和 `experimental` 的 `cacheTtl` 鍵。唯一有效的 `isolation` 值是 `"worktree"`。請參閱 [支援的 frontmatter 欄位](/docs/zh-TW/sub-agents#supported-frontmatter-fields) 以了解每個欄位的作用
755* **忽略的欄位**:`permissionMode`、`hooks`、`mcpServers` 和 `initialPrompt`。agent 檔案無法自行新增 hooks 或 MCP 伺服器,因此改為將這些新增為外掛程式 [hooks](#hooks) 和 [MCP 伺服器](#mcp-servers)
756* **無法解析的 Frontmatter**:agent 仍然載入,每個欄位都被忽略。它以檔案命名,其描述讀取 `Agent from my-plugin plugin`。在您的 shell 中執行 [`claude plugin validate`](/docs/zh-TW/plugins/cli-reference#plugin-validate) 以找到這些檔案
757
758如需每個欄位的作用和優先順序規則,請參閱 [子代理](/docs/zh-TW/sub-agents#supported-frontmatter-fields)。
759
760<h3 id="hooks">
761 Hooks
762</h3>
763
764[hook](/docs/zh-TW/hooks-guide) 在 Claude Code 生命週期中的某個點自動執行某些操作,例如在每次檔案編輯後:shell 命令、HTTP 請求、MCP 工具呼叫、對模型的提示或子代理。將外掛程式的 hooks 儲存在外掛程式根目錄的 `hooks/hooks.json` 中,在頂層 `"hooks"` 鍵下,形狀與 `settings.json` 中的 `hooks` 物件相同。這讓您可以複製現有的設定 hook 而不變更。
765
766此 hook 在每個 `Write` 或 `Edit` 後執行捆綁的指令碼:
767
768```json hooks/hooks.json theme={null}
769{
770 "hooks": {
771 "PostToolUse": [
772 {
773 "matcher": "Write|Edit",
774 "hooks": [
775 {
776 "type": "command",
777 "command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/format.sh\""
778 }
779 ]
780 }
781 ]
782 }
783}
784```
785
786將指令碼儲存在 `scripts/format.sh` 並使其可執行。
787
788載入外掛程式並要求 Claude 編輯檔案。退出 0 的 `PostToolUse` hook 在文字記錄中不顯示任何內容,因此使用 [偵錯日誌](/docs/zh-TW/hooks#debug-hooks) 或指令碼本身所做的更改來確認它執行。
789
790`hooks/hooks.json` 和 `hooks` manifest 鍵中的 Hooks 都會載入。如需每個事件及其承載,請參閱 [Hook 事件](/docs/zh-TW/hooks#hook-events)。
791
792<h4 id="when-plugin-hooks-fire">
793 外掛程式 hooks 何時觸發
794</h4>
795
796外掛程式的 hooks 不會等待使用外掛程式的 skills 或命令之一。Claude Code 在工作階段載入外掛程式時註冊它們,從那時起它們在其事件上觸發。若要限制 hook 執行的時間,縮小其 `matcher`。
797
798如果 hook 從不觸發,請參閱 [不觸發的 hooks](/docs/zh-TW/plugins/troubleshooting#failed-to-load-hooks-from-and-hooks-that-dont-fire)。
799
800<h4 id="environment-quoting-and-matching-mcp-tools">
801 環境、引號和匹配 MCP 工具
802</h4>
803
804hook 的環境、`${CLAUDE_PLUGIN_ROOT}` 的引號和外掛程式自己的 MCP 工具的匹配器工作如下:
805
806* **環境**:每個 hook 程序在其環境中接收 `CLAUDE_PLUGIN_ROOT` 和 `CLAUDE_PLUGIN_DATA`,加上每個 [使用者設定](#user-configuration) 值的 `CLAUDE_PLUGIN_OPTION_<KEY>`,因此您的指令碼可以從那裡讀取它們
807* **引號**:當 `command` 沒有 `args` 時,它通過 shell 執行,因此將 `${CLAUDE_PLUGIN_ROOT}` 路徑包裝在雙引號中,如 [Hooks](#hooks) 下的 `hooks/hooks.json` 範例所做,以保持展開的路徑為一個 shell 單詞。當您改為傳遞 `args` 時,每個元素作為一個引數傳遞,沒有 shell,不需要引號。請參閱 [exec 形式和 shell 形式](/docs/zh-TW/hooks#exec-form-and-shell-form)
808* **匹配外掛程式自己的 MCP 工具**:來自此外掛程式宣告的 [MCP 伺服器](#mcp-servers) 的工具命名為 `mcp__plugin_<plugin>_<server>__<tool>`,因此在匹配器中寫入該完整名稱。僅在伺服器名稱上的匹配器從不觸發。請參閱 [匹配 MCP 工具](/docs/zh-TW/hooks#match-mcp-tools)
809
810<h3 id="mcp-servers">
811 MCP 伺服器
812</h3>
813
814MCP 伺服器從外部系統為 Claude 提供工具。在外掛程式根目錄的 `.mcp.json` 中宣告它,形狀與 [專案 `.mcp.json`](/docs/zh-TW/mcp#project-scope) 相同。此 `.mcp.json` 宣告一個命名為 `db` 的伺服器:
815
816```json .mcp.json theme={null}
817{
818 "mcpServers": {
819 "db": {
820 "command": "node",
821 "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"]
822 }
823 }
824}
825```
826
827您也可以省略 `mcpServers` 包裝器,將 `db` 放在檔案的頂層。
828
829載入外掛程式並執行 `/mcp` 以確認伺服器顯示為 `plugin:my-plugin:db`。
830
831`claude plugin validate` 檢查 `.mcp.json` 並報告 Claude Code 在載入時會丟棄的伺服器項目作為錯誤。需要 Claude Code v2.1.281 或更新版本。
832
833如需壞項目在載入時顯示的位置,請參閱 [不啟動的 MCP 伺服器](/docs/zh-TW/plugins/troubleshooting#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start)。
834
835`mcpServers` manifest 鍵採用內嵌伺服器對應、JSON 檔案的路徑或這些的陣列。當 manifest 伺服器與 `.mcp.json` 中的伺服器同名時,manifest 伺服器取代它。
836
837<h4 id="reach-users-on-claude-ai-and-cowork">
838 到達 claude.ai 和 Cowork 上的使用者
839</h4>
840
841本機 stdio 伺服器(例如 [MCP 伺服器](#mcp-servers) 下的 `db` 伺服器)在 Claude Code 和在 Claude Desktop 應用程式中在您的機器上執行的 Cowork 工作階段中執行,但不在 claude.ai 上。若要到達那裡的使用者,請透過其 `https://` URL 參考遠端伺服器,claude.ai 和 Cowork 將其作為連接器提供給使用者。
842
843<h4 id="server-names-tool-names-and-reloads">
844 伺服器名稱、工具名稱和重新載入
845</h4>
846
847伺服器的名稱、變數替換和重新載入行為遵循這些規則:
848
849* **伺服器名稱**:`plugin:<plugin>:<server>`,所以 `my-plugin` 中的 `db` 伺服器在 `/mcp` 中是 `plugin:my-plugin:db`。使用相同的形式在 [`mcp_tool` hook](/docs/zh-TW/hooks#mcp-tool-hook-fields) 中命名伺服器
850* **工具名稱**:`mcp__plugin_<plugin>_<server>__<tool>`,所以該 `db` 伺服器上的 `query` 工具是 `mcp__plugin_my-plugin_db__query`。這是在 [權限規則](/docs/zh-TW/permissions) 和 [hook 匹配器](#hooks) 中使用的名稱
851* **替換**:`${CLAUDE_PLUGIN_ROOT}` 和其他 [路徑變數](#path-variables-and-persistent-data) 在 `command`、`args` 和 `env` 中被替換。`args` 中不需要引號,因為每個元素作為一個引數傳遞
852* **重新載入**:當使用者執行 `/reload-plugins` 且 [重新載入適用](/docs/zh-TW/plugins/cli-reference#reloads-that-change-mcp-tools) 時,配置未變更的伺服器保持其連接。配置已變更的伺服器重新連接,您移除的伺服器斷開連接
853
854<h4 id="include-a-packaged-mcpb-server">
855 包含打包的 MCPB 伺服器
856</h4>
857
858`mcpServers` 鍵也接受打包的伺服器作為 [MCPB 檔案](https://github.com/modelcontextprotocol/mcpb),其副檔名為 `.mcpb` 或較舊的 `.dxt`。將鍵指向檔案,作為外掛程式內的路徑或 `https://` URL:
859
860```json .claude-plugin/plugin.json theme={null}
861{
862 "name": "my-plugin",
863 "mcpServers": "./servers/db.mcpb"
864}
865```
866
867伺服器從捆綁的 manifest 中的 `name` 獲取其名稱。
868
869如需傳輸和驗證,請參閱 [MCP](/docs/zh-TW/mcp#plugin-provided-mcp-servers)。
870
871<h3 id="lsp-servers">
872 LSP 伺服器
873</h3>
874
875LSP 伺服器為 Claude 提供語言的診斷和程式碼導航。如果 [官方程式碼智慧外掛程式](/docs/zh-TW/plugins/code-intelligence) 已涵蓋您的語言,請安裝該外掛程式而不是寫一個。否則在外掛程式根目錄的 `.lsp.json` 中宣告伺服器:
876
877```json .lsp.json theme={null}
878{
879 "gopls": {
880 "command": "gopls",
881 "args": ["serve"],
882 "extensionToLanguage": {
883 ".go": "go"
884 }
885 }
886}
887```
888
889檔案直接將每個伺服器名稱對應到其配置,在對應周圍沒有包裝物件。`command` 是二進位檔的名稱,其引數在 `args` 中。`extensionToLanguage` 需要至少一個副檔名,每個以 `.` 開頭。
890
891`claude plugin validate` 不讀取此檔案。當任何項目無效時,整個檔案在載入時被跳過,`Invalid LSP server config for ".lsp.json"` 出現在 `/plugin` **Errors** 標籤中。
892
893您的外掛程式配置連接但不安裝伺服器二進位檔,每個檔案副檔名獲得一個伺服器:
894
895* **缺少二進位檔**:Claude Code 從使用者的 `PATH` 按名稱啟動 `command`。當二進位檔不存在時,伺服器無法啟動,`claude --debug` 記錄 `LSP server <name> failed to start`
896* **副檔名衝突**:當兩個啟用的伺服器聲稱相同的副檔名時,首先註冊的處理這些檔案,另一個不用於它們,無論伺服器來自一個外掛程式還是兩個。`/plugin` **Errors** 標籤顯示警告 `LSP server "<name>" is not used for <ext> files`
897
898`lspServers` manifest 鍵採用相同的對應內嵌、JSON 檔案的路徑或這些的陣列,其伺服器新增至 `.lsp.json` 中的伺服器。當 manifest 伺服器與 `.lsp.json` 中的伺服器同名時,manifest 伺服器取代它。
899
900如需 `transport`、逾時、重新啟動和其他欄位,請參閱 [`lspServers`](/docs/zh-TW/plugins/manifest-reference#lspservers)。
901
902將日誌輸出傳送至 stderr,而不是 stdout。Claude Code 僅將伺服器的 stdout 讀取為協議訊息,並接受最多 64 KiB 的訊息標頭和最多 32 MiB 的訊息正文。
903
904Claude Code 斷開超過任一限制或將非協議輸出寫入 stdout 的伺服器,並將斷開連接計為 `restartOnCrash` 和 `maxRestarts` 的當機。當您使用 `--debug` 執行時,Claude Code 將命名原因的錯誤寫入偵錯日誌。
905
906<h3 id="executables">
907 可執行檔
908</h3>
909
910外掛程式根目錄的 `bin/` 中的檔案在啟用外掛程式時位於 Bash 工具的 shell 的 `PATH` 上,因此 Claude 可以將它們作為裸命令執行。新增可執行指令碼:
911
912```bash bin/hello-plugin theme={null}
913#!/bin/bash
914echo "hello from my-plugin"
915```
916
917使用 `chmod +x bin/hello-plugin` 使其可執行並載入外掛程式。當您要求 Claude 執行 `hello-plugin` 時,Bash 工具結果顯示指令碼的輸出。
918
919外掛程式 `bin/` 目錄位於使用者自己的 `PATH` 項目之後,因此外掛程式無法遮蔽 `git`、`ls` 或其他系統命令。
920
921claude.ai 和 Cowork 不安裝具有頂層 `bin/` 目錄的外掛程式,包括您 [透過 claude.ai 組織設定分發](/docs/zh-TW/plugins/host-marketplace#distribute-through-organization-settings) 的外掛程式。
922
923<h3 id="default-settings">
924 預設設定
925</h3>
926
927若要設定在啟用外掛程式時適用的預設值,在外掛程式根目錄新增 `settings.json`,或將相同的物件內嵌放在 `settings` manifest 鍵中。兩個鍵生效,`agent` 和 `subagentStatusLine`,所有其他鍵都被丟棄。
928
929設定 `agent` 以執行外掛程式自己的一個 agents 作為主執行緒:
930
931```json settings.json theme={null}
932{
933 "agent": "security-reviewer"
934}
935```
936
937載入外掛程式並啟動工作階段。Claude 然後使用 `security-reviewer` agent 的系統提示和模型在主對話中回答。
938
939如需鍵控制的所有內容,請參閱 [`agent` 設定](/docs/zh-TW/settings-reference#agent)。
940
941當相同的鍵在多個位置設定時,這些規則決定哪個值適用:
942
943* **檔案優於 manifest**:當兩者都存在且 `settings.json` 設定至少一個支援的鍵時,`settings.json` 適用,manifest 的 `settings` 被忽略
944* **使用者設定優於外掛程式預設值**:在設定來源中,外掛程式預設值是最低層,因此使用者自己在 `~/.claude/settings.json` 中的 `agent` 覆蓋您的
945* **兩個外掛程式設定相同的鍵**:來自最後載入的外掛程式的值適用,`claude --debug` 記錄 `overrides setting`
946
947如需 `subagentStatusLine` 形狀,請參閱 [子代理狀態行](/docs/zh-TW/statusline#subagent-status-lines)。
948
949<h3 id="themes-and-output-styles">
950 主題和輸出樣式
951</h3>
952
953外掛程式可以包含色彩主題和輸出樣式。兩者都出現在與使用者自己相同的選擇器中。對於任一個,設定 manifest 鍵取代資料夾掃描。
954
955| 元件 | 儲存為 | 格式 | 出現在 | Manifest 鍵 |
956| :--- | :------------------------ | :--------------------------------------------------------------------------------------------------- | :----------------------------------- | :-------------------- |
957| 主題 | `themes/<slug>.json` | 使用者在 `~/.claude/themes/` 中寫入的 [自訂主題檔案](/docs/zh-TW/terminal-config#create-a-custom-theme) 格式 | `/theme`,在檔案的 `name` 下 | `experimental.themes` |
958| 輸出樣式 | `output-styles/<name>.md` | [自訂輸出樣式](/docs/zh-TW/output-styles#create-a-custom-output-style) 格式,具有 `name` 和 `description` frontmatter | `/output-style`,作為 `<plugin>:<name>` | `outputStyles` |
959
960外掛程式主題是唯讀的,因此當使用者在 `/theme` 中編輯一個時,編輯會儲存為其自己的主題目錄中的副本。
961
962此主題在深色預設上重新著色提示符號重點和錯誤文字:
963
964```json themes/dracula.json theme={null}
965{
966 "name": "Dracula",
967 "base": "dark",
968 "overrides": {
969 "claude": "#bd93f9",
970 "error": "#ff5555"
971 }
972}
973```
974
975<h3 id="channels">
976 頻道
977</h3>
978
979[頻道](/docs/zh-TW/channels) 讓外部系統(例如聊天應用程式)將訊息傳送到工作階段。在外掛程式中,頻道是 MCP 伺服器之一加上 `channels` 項目,該項目綁定到它並可以提示其自己的配置。此 manifest 將頻道綁定到 `telegram` 伺服器並要求機器人令牌:
980
981```json .claude-plugin/plugin.json theme={null}
982{
983 "name": "my-plugin",
984 "mcpServers": {
985 "telegram": {
986 "command": "node",
987 "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"],
988 "env": { "BOT_TOKEN": "${user_config.bot_token}" }
989 }
990 },
991 "channels": [
992 {
993 "server": "telegram",
994 "userConfig": {
995 "bot_token": {
996 "type": "string",
997 "title": "Bot token",
998 "description": "Telegram bot token",
999 "sensitive": true
1000 }
1001 }
1002 }
1003 ]
1004}
1005```
1006
1007`server` 必須符合 `mcpServers` 中的鍵。每個頻道的 `userConfig` 採用與 [頂層 `userConfig` 鍵](#user-configuration) 相同的形狀。
1008
1009如需伺服器必須實現的內容以及使用者如何啟用頻道外掛程式,請參閱頻道參考中的 [打包為外掛程式](/docs/zh-TW/channels-reference#package-as-a-plugin)。如需欄位表,請參閱 [`channels`](/docs/zh-TW/plugins/manifest-reference#channels)。
1010
1011<h3 id="monitors">
1012 監視器
1013</h3>
1014
1015監視器是在整個工作階段的背景中執行的 shell 命令。它列印的內容作為通知到達 Claude,因此 Claude 可以對日誌或狀態變更做出反應,而無需被要求監視它。將項目儲存在 `monitors/monitors.json` 中:
1016
1017```json monitors/monitors.json theme={null}
1018[
1019 {
1020 "name": "error-log",
1021 "command": "tail -F ./logs/error.log",
1022 "description": "Application error log"
1023 }
1024]
1025```
1026
1027命令在 shell 中執行,在工作階段啟動的工作目錄中。
1028
1029監視器的命令在其啟動位置和可以參考的內容方面受到限制:
1030
1031* **僅互動式工作階段**:外掛程式監視器在互動式工作階段中啟動,從不在使用 `-p` 旗標的非互動式模式中。它們也只在 [Monitor 工具](/docs/zh-TW/tools-reference#monitor-tool) 可用的地方啟動
1032* **無使用者設定**:`command` 從環境中獲取 [路徑變數](#path-variables-and-persistent-data) 和 `${ENV_VAR}`,但從不獲取 `${user_config.*}`。參考一個的監視器不啟動,監視器程序也不接收 `CLAUDE_PLUGIN_OPTION_<KEY>`
1033* **中途停用**:如果您在工作階段中途停用外掛程式,Claude Code 不會停止已執行的監視器。它們在工作階段結束時停止
1034
1035`experimental.monitors` manifest 鍵採用相同的陣列內嵌或 JSON 檔案的路徑,並代替 `monitors/monitors.json` 讀取。
1036
1037如需 `when` 觸發器和其他欄位,請參閱 [`monitors`](/docs/zh-TW/plugins/manifest-reference#monitors)。
1038
1039<h2 id="user-configuration">
1040 要求使用者提供設定值
1041</h2>
1042
1043在 `userConfig` manifest 鍵中宣告您的外掛程式需要的使用者值,以便使用者不會自行編輯 `settings.json`。每個選項在對話方塊中顯示,其 `title` 作為標籤,其 `description` 在下方。
1044
1045為令牌或密碼設定 `"sensitive": true`。對話方塊然後遮蔽輸入,值儲存在安全儲存中,而不是 `settings.json`。
1046
1047此 manifest 要求端點和令牌:
1048
1049```json .claude-plugin/plugin.json theme={null}
1050{
1051 "name": "my-plugin",
1052 "userConfig": {
1053 "api_url": {
1054 "type": "string",
1055 "title": "API URL",
1056 "description": "Base URL of your team's API"
1057 },
1058 "api_token": {
1059 "type": "string",
1060 "title": "API token",
1061 "description": "Token for your team's API",
1062 "sensitive": true
1063 }
1064 }
1065}
1066```
1067
1068<h3 id="when-the-configuration-dialog-appears">
1069 設定對話方塊何時出現
1070</h3>
1071
1072對話方塊僅在互動式 `/plugin` 介面中出現。當使用者執行以下任何操作時,它會為任何尚未設定的選項開啟:
1073
1074* 在 `/plugin` 中安裝外掛程式
1075* 在工作階段內執行 `/plugin install <plugin>@<marketplace>`
1076* 從 `/plugin` 中的 **Installed** 標籤啟用外掛程式
1077
1078若要在任何時間開啟相同的對話方塊,使用者執行 `/plugin configure <plugin>@<marketplace>`。
1079
1080`claude plugin install` shell 命令從不提示 `userConfig` 值。若要從 shell 設定值,將每個值作為 `--config KEY=VALUE` 傳遞。當選項保持未設定時,命令列印 `userConfig options not yet set` 行,命名兩種設定方式。[`userConfig` 對話方塊從不出現](/docs/zh-TW/plugins/troubleshooting#the-userconfig-dialog-never-appears) 引用該行。
1081
1082如需選項欄位、每個值儲存的位置、元件如何參考已儲存的值以及哪些欄位拒絕 `${user_config.*}`,請參閱 [使用者設定](/docs/zh-TW/plugins/manifest-reference#user-configuration)。
1083
1084<h2 id="path-variables-and-persistent-data">
1085 參考外掛程式路徑和儲存資料
1086</h2>
1087
1088您不知道您的外掛程式將安裝在哪裡,因此透過這些變數而不是固定路徑參考其檔案和資料。它們在 skill、命令和 agent 內容、hook 和監視器命令以及 MCP 和 LSP 伺服器配置中被替換。它們也被匯出到 hook、MCP 和 LSP 程序:
1089
1090* **`${CLAUDE_PLUGIN_ROOT}`**:外掛程式的安裝目錄。每個版本都有自己的 [快取目錄](/docs/zh-TW/plugins/loading#find-plugins-on-disk),因此當外掛程式更新時路徑會變更。不要在那裡寫入狀態
1091* **`${CLAUDE_PLUGIN_DATA}`**:一個在更新中倖存的目錄,用於 `node_modules`、虛擬環境和快取。它解析為 `~/.claude/plugins/data/<id>/`,並在首次參考時建立
1092* **`${CLAUDE_PROJECT_DIR}`**:專案根目錄,hooks 接收的相同值
1093
1094在資料目錄路徑中,`<id>` 是外掛程式識別碼,每個字元除了字母、數字、`_` 和 `-` 外都被 `-` 取代,因此 `my-plugin@my-marketplace` 變成 `my-plugin-my-marketplace`。
1095
1096在 Windows 上,替換的路徑使用正斜杠,因此 shell 不會將反斜杠讀取為逸出。
1097
1098<h3 id="install-dependencies-into-the-data-directory">
1099 將相依性安裝到資料目錄
1100</h3>
1101
1102對於市場安裝的外掛程式,Claude Code 在快取外掛程式時自動安裝符合條件的 [Node.js 套件相依性](/docs/zh-TW/plugins/loading#node-js-package-dependencies),因此您可能不需要自行安裝它們。當您執行時,此 `SessionStart` hook 在首次執行時將 `node_modules` 安裝到 `${CLAUDE_PLUGIN_DATA}` 中,並在更新變更 `package.json` 後再次安裝:
1103
1104```json hooks/hooks.json theme={null}
1105{
1106 "hooks": {
1107 "SessionStart": [
1108 {
1109 "hooks": [
1110 {
1111 "type": "command",
1112 "command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/package.json\" \"${CLAUDE_PLUGIN_DATA}/package.json\" >/dev/null 2>&1 || (cd \"${CLAUDE_PLUGIN_DATA}\" && cp \"${CLAUDE_PLUGIN_ROOT}/package.json\" . && npm install) || rm -f \"${CLAUDE_PLUGIN_DATA}/package.json\""
1113 }
1114 ]
1115 }
1116 ]
1117 }
1118}
1119```
1120
1121在第一個工作階段後,`~/.claude/plugins/data/<id>/node_modules` 存在。MCP 伺服器然後可以在其 `env` 中設定 `NODE_PATH` 為 `${CLAUDE_PLUGIN_DATA}/node_modules`。如需哪些欄位替換哪個變數,請參閱 [環境變數](/docs/zh-TW/plugins/manifest-reference#environment-variables)。
1122
1123<h2 id="next-steps">
1124 後續步驟
1125</h2>
1126
1127* [外掛程式 manifest 參考](/docs/zh-TW/plugins/manifest-reference):`plugin.json` 欄位、路徑規則和標準配置
1128* [使用 evals 測試外掛程式](/docs/zh-TW/plugin-evals):檢查您新增的元件以您的意圖改變 Claude 的行為
1129* [發佈和分發外掛程式](/docs/zh-TW/plugins/publish):版本化外掛程式並將其放在市場中
1130* [疑難排解外掛程式](/docs/zh-TW/plugins/troubleshooting):當元件無法載入或 hook 無法觸發時該怎麼辦