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> Добавляйте skills, 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
405Плагин Claude Code строится из компонентов, таких как skills, agents, hooks и MCP серверы. Каждый компонент имеет папку по умолчанию в плагине, необязательный ключ манифеста в `.claude-plugin/plugin.json`, который заменяет или добавляет к этой папке, и имя, которое видит пользователь. Для полной таблицы полей каждого ключа см. [справочник манифеста](/docs/ru/plugins/manifest-reference#fields).
406
407Используйте эту страницу для добавления компонента в плагин, который уже загружается.
408
409После добавления компонента запустите `/reload-plugins` в работающей сессии или начните новую, чтобы Claude Code загрузил его. Чтобы проверить файл компонента перед загрузкой, запустите [`claude plugin validate .`](/docs/ru/plugins/cli-reference#plugin-validate) в вашей оболочке из директории плагина.
410
411<Note>
412 Эти случаи рассматриваются на других страницах:
413
414 * **Создание вашего первого плагина**: начните с [Create a plugin](/docs/ru/plugins/create)
415 * **Установка плагина кого-то другого**: см. [Install plugins](/docs/ru/plugins/install)
416 * **Ваши пользователи плагина находятся на claude.ai или в Cowork**: там загружается другой набор компонентов. См. [Plugins on claude.ai and in 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* Subagent для проверки безопасности
427* Hook, который форматирует файлы после редактирования Claude, и папку `scripts/`, которую он вызывает
428* Монитор логов
429* Стиль вывода и цветовую тему
430* Workflow для аудита маршрутов
431* Исполняемый файл `hello-plugin`
432* Параметры по умолчанию
433* Локальный MCP сервер и языковой сервер Go
434
435Каждый файл — это наименьший допустимый пример своего формата, предназначенный для демонстрации структуры, а не для практического использования: реальный skill или agent содержит полные инструкции и часто вспомогательные файлы, а реальный hook или монитор выполняет реальную работу. Разделы после обозревателя используют те же файлы в качестве примеров и ссылаются на более полные версии. Выберите файл или папку, чтобы прочитать, для чего она нужна, увидеть, что в ней содержится, и найти раздел, который её описывает.
436
437<PluginExplorer>
438 <Piece id="manifest">
439 [Манифест](/docs/ru/plugins/manifest-reference) — это файл `plugin.json` в директории `.claude-plugin/` плагина. Он содержит метаданные плагина и значения `userConfig`, которые Claude Code запрашивает у пользователя. Обязателен только `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/ru/skills) — это файл `SKILL.md`. Сохраняйте каждый skill в отдельной директории в папке `skills/`. Claude читает `description` каждого skill, и когда то, что просит пользователь, совпадает с ней, например, когда пользователь просит Claude проверить pull request, 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` и принимает тот же frontmatter, что и skill:
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 [Subagent](/docs/ru/sub-agents) — это отдельный помощник с собственными инструкциями и собственным контекстным окном, которому Claude может делегировать задачу и получить результат. Каждый файл Markdown в папке `agents/` определяет один: frontmatter называет его и говорит, когда его использовать, а тело — это его системный prompt. Этот назван `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/ru/hooks-guide) запускает что-то автоматически в точке жизненного цикла Claude Code, например, после каждого редактирования файла: команду shell, HTTP запрос, вызов инструмента MCP, prompt к модели или subagent. Сохраняйте hooks плагина в `hooks/hooks.json` в корне плагина. Этот запускает `scripts/format.sh` плагина после того, как Claude записывает или редактирует файл:
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/ru/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/ru/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 Плагин может включать [цветовые темы](/docs/ru/terminal-config#create-a-custom-theme) для интерфейса Claude Code. Сохраняйте каждую тему как `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/ru/workflows) `.js`: блок `meta`, затем тело скрипта, которое координирует несколько subagents. Этот запускается как `/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 помещает эту папку в `PATH` shell, в котором он запускает команды, поэтому 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 Hook в `hooks/hooks.json` запускает скрипт, и эта папка — это место, где пример его хранит. Имя `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/ru/settings-reference), которые применяются, пока плагин включен, поэтому плагин может изменить поведение сеанса и не только добавить компоненты. Только два ключа действуют из плагина, [`agent`](/docs/ru/settings-reference#agent) и [`subagentStatusLine`](/docs/ru/settings-reference#subagentstatusline); все остальные ключи отбрасываются. См. [Параметры по умолчанию](#default-settings).
594
595 Этот устанавливает `agent`, который запускает основной поток сеанса как собственный agent `security-reviewer` плагина, поэтому системный prompt этого agent, ограничения инструментов и модель применяются ко всему сеансу:
596
597 ```json theme={null}
598 {
599 "agent": "security-reviewer"
600 }
601 ```
602 </Piece>
603
604 <Piece id="mcp">
605 [MCP сервер](/docs/ru/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/ru/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Каждый раздел ниже охватывает один вид компонента: где его файлы находятся в плагине, пример, который проходит валидацию, что видит пользователь после загрузки плагина, и ключ манифеста, который изменяет расположение по умолчанию. Добавляйте те, которые нужны вашему плагину; ни один не требуется.
641
642<h3 id="skills">
643 Skills
644</h3>
645
646[Skill](/docs/ru/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>`, поэтому `skills/review/SKILL.md` в `my-plugin` — это `/my-plugin:review`. Если вы установите `name` в frontmatter, он заменит последний сегмент, и префикс плагина остаётся. См. [как skill получает имя команды](/docs/ru/skills#how-a-skill-gets-its-command-name)
670* **Кто вызывает**: Claude, пользователь или оба, контролируется frontmatter. См. [Control who invokes a skill](/docs/ru/skills#control-who-invokes-a-skill)
671
672Вы также можете разместить skills вне директории по умолчанию `skills/`:
673
674* **Дополнительные директории**: перечислите их в ключе манифеста `skills`. Они добавляются к сканированию по умолчанию `skills/`, а не заменяют его, в отличие от `commands` и `agents`
675* **Один skill в корне плагина**: без директории `skills/` и без ключа манифеста `skills`, `SKILL.md` в корне плагина загружается как один skill. Установите `name` в его frontmatter, потому что иначе установка из marketplace назовёт skill по его [директории кэша](/docs/ru/plugins/loading#find-plugins-on-disk), а не по вашему плагину
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/ru/skills).
680
681<h3 id="commands">
682 Команды
683</h3>
684
685Команда — это один файл Markdown, который пользователь запускает по имени, например `/my-plugin:about`.
686
687<Note>
688 Команды — это более старый формат, и [skills](#skills) их заменяют для новой работы. Skill запускается по имени таким же образом, и он также может содержать вспомогательные файлы в своей директории. Сохраняйте `commands/` для файлов, которые вы переносите из `.claude/commands/`.
689</Note>
690
691Сохраняйте команду в `commands/<file>.md` и она становится `/<plugin>:<file>`. Подпапка добавляет сегмент, поэтому `commands/db/migrate.md` — это `/my-plugin:db:migrate`.
692
693Файлы команд принимают тот же frontmatter, что и skills.
694
695<h4 id="define-commands-in-the-manifest">
696 Определение команд в манифесте
697</h4>
698
699Это нужно только, если вы хотите сохранить файлы команд где-то в другом месте, чем `commands/`, или определить короткую команду внутри `plugin.json` без отдельного файла Markdown. Установите ключ манифеста `commands`, и Claude Code читает его вместо сканирования `commands/`. Ключ принимает путь, массив путей или объект, который отображает каждое имя команды либо на файл `source`, либо на встроенное `content`.
700
701Этот манифест определяет `/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/ru/plugins/manifest-reference#commands).
718
719<h3 id="agents">
720 Агенты
721</h3>
722
723[Подагент](/docs/ru/sub-agents) — это отдельный помощник с собственными инструкциями и окном контекста, которому Claude может делегировать задачу. Каждый файл Markdown под `agents/` определяет один:
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Этот агент назван `my-plugin:security-reviewer`, и пользователь может [вызвать его явно](/docs/ru/sub-agents#invoke-subagents-explicitly) с помощью `@agent-my-plugin:security-reviewer`. Форма имени — `<plugin>:<name>`, где `<name>` берётся из frontmatter или из имени файла, когда его нет.
736
737Ключ `agents` манифеста заменяет сканирование `agents/`.
738
739<h4 id="organize-agents-in-subfolders">
740 Организация агентов в подпапках
741</h4>
742
743Вы можете поместить файлы агентов плагина в подпапки `agents/`. Claude Code [загружает их рекурсивно](/docs/ru/sub-agents#choose-the-subagent-scope) и объединяет имя плагина, каждое имя подпапки и имя файла с двоеточиями, чтобы сформировать имя агента с областью видимости. Например, `agents/review/security.md` в плагине с именем `my-plugin` загружается как `my-plugin:review:security`. Два параметра изменяют это имя:
744
745* Frontmatter `name`: он заменяет только имя файла, поэтому `name: audit` в `agents/review/security.md` загружается как `my-plugin:review:audit`
746* Манифест [`agents`](/docs/ru/plugins/manifest-reference#fields) поле: файл, который вы там перечислите, загружается без имён подпапок, поэтому `"agents": "./custom/review/security.md"` загружается как `my-plugin:security`
747
748<h4 id="frontmatter-fields-in-plugin-agents">
749 Поля frontmatter в агентах плагина
750</h4>
751
752Frontmatter агента плагина следует этим правилам:
753
754* **Поддерживаемые поля**: `name`, `description`, `model`, `effort`, `maxTurns`, `tools`, `disallowedTools`, `skills`, `memory`, `background`, `omitClaudeMd`, `isolation`, `color` и ключ `cacheTtl` из `experimental`. Единственное допустимое значение `isolation` — это `"worktree"`. См. [поддерживаемые поля frontmatter](/docs/ru/sub-agents#supported-frontmatter-fields) для того, что делает каждое
755* **Игнорируемые поля**: `permissionMode`, `hooks`, `mcpServers` и `initialPrompt`. Файл агента не может добавлять hooks или MCP серверы самостоятельно, поэтому добавляйте их как плагин [hooks](#hooks) и [MCP серверы](#mcp-servers) вместо этого
756* **Frontmatter, который не парсится**: агент всё ещё загружается со всеми полями, игнорируемыми. Он назван по имени файла, и его описание читается как `Agent from my-plugin plugin`. Запустите [`claude plugin validate`](/docs/ru/plugins/cli-reference#plugin-validate) в вашей оболочке, чтобы найти эти файлы
757
758Для того, что делает каждое поле и правила приоритета, см. [Subagents](/docs/ru/sub-agents#supported-frontmatter-fields).
759
760<h3 id="hooks">
761 Hooks
762</h3>
763
764[Hook](/docs/ru/hooks-guide) запускает что-то автоматически в точке жизненного цикла Claude Code, например, после каждого редактирования файла: команду оболочки, HTTP запрос, вызов инструмента MCP, prompt к модели или подагента. Сохраняйте hooks плагина в `hooks/hooks.json` в корне плагина, под верхним уровнем ключа `"hooks"`, в той же форме, что и объект `hooks` в `settings.json`. Это позволяет вам скопировать существующий 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 отредактировать файл. Hook `PostToolUse`, который выходит с кодом 0, ничего не показывает в транскрипте, поэтому подтвердите, что он запустился с помощью [debug logging](/docs/ru/hooks#debug-hooks) или по тому, что сам скрипт изменяет.
789
790Hooks в `hooks/hooks.json` и в ключе манифеста `hooks` оба загружаются. Для каждого события и его payload см. [Hook events](/docs/ru/hooks#hook-events).
791
792<h4 id="when-plugin-hooks-fire">
793 Когда запускаются hooks плагина
794</h4>
795
796Hooks плагина не ждут использования одного из skills или команд плагина. Claude Code регистрирует их, когда сессия загружает плагин, и они запускаются на своих событиях с этого момента. Чтобы ограничить, когда запускается hook, сузьте его `matcher`.
797
798Если hook никогда не запускается, см. [hooks that don't fire](/docs/ru/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
804Окружение hook, кавычки `${CLAUDE_PLUGIN_ROOT}` и matchers для собственных инструментов MCP плагина работают следующим образом:
805
806* **Окружение**: каждый процесс hook получает `CLAUDE_PLUGIN_ROOT` и `CLAUDE_PLUGIN_DATA` в своём окружении, плюс `CLAUDE_PLUGIN_OPTION_<KEY>` для каждого значения [конфигурации пользователя](#user-configuration), поэтому ваш скрипт может читать их оттуда
807* **Кавычки**: когда `command` не имеет `args`, он запускается через оболочку, поэтому оберните путь `${CLAUDE_PLUGIN_ROOT}` в двойные кавычки, как пример `hooks/hooks.json` под [Hooks](#hooks) делает, чтобы сохранить развёрнутый путь одним словом оболочки. Когда вы передаёте `args` вместо этого, каждый элемент передаётся как один аргумент без оболочки и не нуждается в кавычках. См. [exec form and shell form](/docs/ru/hooks#exec-form-and-shell-form)
808* **Соответствие собственным инструментам MCP плагина**: инструмент из [MCP сервера, который объявляет этот плагин](#mcp-servers), назван `mcp__plugin_<plugin>_<server>__<tool>`, поэтому напишите это полное имя в matcher. Matcher только на имя сервера никогда не запускается. См. [Match MCP tools](/docs/ru/hooks#match-mcp-tools)
809
810<h3 id="mcp-servers">
811 MCP серверы
812</h3>
813
814MCP сервер предоставляет Claude инструменты из внешней системы. Объявите его в `.mcp.json` в корне плагина, в той же форме, что и [проект `.mcp.json`](/docs/ru/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 servers that don't start](/docs/ru/plugins/troubleshooting#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start).
834
835Ключ манифеста `mcpServers` принимает встроенную карту сервера, путь к файлу JSON или массив этих. Когда сервер манифеста имеет то же имя, что и один в `.mcp.json`, сервер манифеста заменяет его.
836
837<h4 id="reach-users-on-claude-ai-and-cowork">
838 Достижение пользователей на claude.ai и Cowork
839</h4>
840
841Локальный сервер stdio, такой как сервер `db` под [MCP servers](#mcp-servers), работает в Claude Code и в сессии Cowork, которая работает на вашей машине в приложении Claude Desktop, но не на claude.ai. Чтобы достичь пользователей там тоже, ссылайтесь на удалённый сервер по его URL `https://`, который claude.ai и Cowork предлагают пользователю как соединитель.
842
843<h4 id="server-names-tool-names-and-reloads">
844 Имена серверов, имена инструментов и перезагрузки
845</h4>
846
847Имена сервера, подстановка переменных и поведение перезагрузки следуют этим правилам:
848
849* **Имя сервера**: `plugin:<plugin>:<server>`, поэтому сервер `db` в `my-plugin` — это `plugin:my-plugin:db` в `/mcp`. Используйте ту же форму для именования сервера в [hook `mcp_tool`](/docs/ru/hooks#mcp-tool-hook-fields)
850* **Имена инструментов**: `mcp__plugin_<plugin>_<server>__<tool>`, поэтому инструмент `query` на том сервере `db` — это `mcp__plugin_my-plugin_db__query`. Это имя, которое нужно использовать в [правилах разрешений](/docs/ru/permissions) и [matchers hook](#hooks)
851* **Подстановка**: `${CLAUDE_PLUGIN_ROOT}` и другие [переменные пути](#path-variables-and-persistent-data) подставляются в `command`, `args` и `env`. Кавычки не нужны в `args`, потому что каждый элемент передаётся как один аргумент
852* **Перезагрузка**: когда пользователь запускает `/reload-plugins` и [перезагрузка применяется](/docs/ru/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`. Укажите ключ на файл, как путь внутри плагина или URL `https://`:
859
860```json .claude-plugin/plugin.json theme={null}
861{
862 "name": "my-plugin",
863 "mcpServers": "./servers/db.mcpb"
864}
865```
866
867Сервер берёт своё имя из `name` в манифесте пакета.
868
869Для транспортов и аутентификации см. [MCP](/docs/ru/mcp#plugin-provided-mcp-servers).
870
871<h3 id="lsp-servers">
872 LSP серверы
873</h3>
874
875LSP сервер предоставляет Claude диагностику и навигацию по коду для языка. Если [официальный плагин code intelligence](/docs/ru/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"` появляется на вкладке **Errors** в `/plugin`.
892
893Ваш плагин конфигурирует соединение, но не устанавливает двоичный файл сервера, и каждое расширение файла получает один сервер:
894
895* **Отсутствующий двоичный файл**: Claude Code запускает `command` по имени из `PATH` пользователя. Когда двоичный файл там не находится, сервер не запускается и `claude --debug` логирует `LSP server <name> failed to start`
896* **Конфликты расширений**: когда два включённых сервера претендуют на одно и то же расширение, первый зарегистрированный обрабатывает эти файлы, а другой не используется для них, независимо от того, поступают ли серверы из одного плагина или двух. Вкладка **Errors** в `/plugin` показывает предупреждение `LSP server "<name>" is not used for <ext> files`
897
898Ключ манифеста `lspServers` принимает ту же карту встроенной, путь к файлу JSON или массив этих, и его серверы добавляются к тем, что в `.lsp.json`. Когда сервер манифеста имеет то же имя, что и один в `.lsp.json`, сервер манифеста заменяет его.
899
900Для `transport`, timeouts, restarts и других полей см. [`lspServers`](/docs/ru/plugins/manifest-reference#lspservers).
901
902Отправляйте вывод логов в stderr, а не stdout. Claude Code читает stdout сервера только как сообщения протокола и принимает заголовки сообщений до 64 КиБ и тело сообщения до 32 МиБ.
903
904Claude Code отключает сервер, который превышает любой лимит или пишет вывод, не являющийся протоколом, в stdout, и считает отключение сбоем для `restartOnCrash` и `maxRestarts`. Когда вы запускаете с `--debug`, Claude Code пишет ошибку, называющую причину, в журнал отладки.
905
906<h3 id="executables">
907 Исполняемые файлы
908</h3>
909
910Файлы в `bin/` в корне плагина находятся на `PATH` оболочки инструмента Bash, пока плагин включен, поэтому 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/ru/plugins/host-marketplace#distribute-through-organization-settings).
922
923<h3 id="default-settings">
924 Параметры по умолчанию
925</h3>
926
927Чтобы установить значения по умолчанию, которые применяются, пока плагин включен, добавьте `settings.json` в корень плагина или поместите тот же объект встроенным в ключ манифеста `settings`. Два ключа вступают в силу, `agent` и `subagentStatusLine`, и все остальные ключи отбрасываются.
928
929Установите `agent` для запуска одного из собственных агентов плагина как основного потока:
930
931```json settings.json theme={null}
932{
933 "agent": "security-reviewer"
934}
935```
936
937Загрузите плагин и начните сессию. Claude затем отвечает в основном разговоре с системным prompt и моделью агента `security-reviewer`.
938
939Для всего, что контролирует ключ, см. [параметр `agent`](/docs/ru/settings-reference#agent).
940
941Когда один и тот же ключ установлен в более чем одном месте, эти правила решают, какое значение применяется:
942
943* **Файл над манифестом**: когда оба существуют и `settings.json` устанавливает по крайней мере один поддерживаемый ключ, `settings.json` применяется и `settings` манифеста игнорируется
944* **Параметры пользователя над значениями по умолчанию плагина**: во всех источниках параметров значения по умолчанию плагина — это самый низкий уровень, поэтому собственный `agent` пользователя в `~/.claude/settings.json` переопределяет ваш
945* **Два плагина устанавливают один и тот же ключ**: значение из плагина, загруженного последним, применяется, и `claude --debug` логирует `overrides setting`
946
947Для формы `subagentStatusLine` см. [subagent status lines](/docs/ru/statusline#subagent-status-lines).
948
949<h3 id="themes-and-output-styles">
950 Темы и стили вывода
951</h3>
952
953Плагин может включать цветовые темы и стили вывода. Оба появляются в тех же выборщиках, что и собственные пользователя. Для любого из них установка ключа манифеста заменяет сканирование папки.
954
955| Компонент | Сохраняйте как | Формат | Появляется в | Ключ манифеста |
956| :----------- | :------------------------ | :--------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------- | :-------------------- |
957| Тема | `themes/<slug>.json` | Формат [пользовательского файла темы](/docs/ru/terminal-config#create-a-custom-theme), который пользователи пишут в `~/.claude/themes/` | `/theme`, под `name` файла | `experimental.themes` |
958| Стиль вывода | `output-styles/<name>.md` | Формат [пользовательского стиля вывода](/docs/ru/output-styles#create-a-custom-output-style), с frontmatter `name` и `description` | `/output-style`, как `<plugin>:<name>` | `outputStyles` |
959
960Темы плагина доступны только для чтения, поэтому когда пользователь редактирует одну в `/theme`, редактирование сохраняется как копия в их собственной директории тем.
961
962Эта тема перекрашивает акцент prompt и текст ошибки на тёмном предустановке:
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/ru/channels) позволяет внешней системе, такой как приложение чата, отправлять сообщения в сессию. В плагине канал — это один из MCP серверов плюс запись `channels`, которая привязывает к нему и может запросить собственную конфигурацию. Этот манифест привязывает канал к серверу `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`. Per-channel `userConfig` принимает ту же форму, что и [верхний уровень ключа `userConfig`](#user-configuration).
1008
1009Для того, что должен реализовать сервер и как пользователи включают плагин канала, см. [Package as a plugin](/docs/ru/channels-reference#package-as-a-plugin) в справочнике каналов. Для таблицы полей см. [`channels`](/docs/ru/plugins/manifest-reference#channels).
1010
1011<h3 id="monitors">
1012 Мониторы
1013</h3>
1014
1015Монитор — это команда оболочки, которая работает в фоне для всей сессии. То, что она выводит, достигает 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Команда запускается в оболочке, в рабочей директории, в которой сессия началась.
1028
1029Команда монитора ограничена в том, где она запускается и на что может ссылаться:
1030
1031* **Только интерактивные сессии**: мониторы плагина запускаются в интерактивной сессии и никогда в неинтерактивном режиме с флагом `-p`. Они также запускаются только там, где доступен [инструмент Monitor](/docs/ru/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` принимает тот же массив встроенным или путь к файлу JSON и читается вместо `monitors/monitors.json`.
1036
1037Для триггера `when` и других полей см. [`monitors`](/docs/ru/plugins/manifest-reference#monitors).
1038
1039<h2 id="user-configuration">
1040 Запрос значений конфигурации у пользователя
1041</h2>
1042
1043Объявите значения, которые ваш плагин нужен от пользователя, в ключе манифеста `userConfig`, чтобы пользователи не редактировали `settings.json` сами. Каждый вариант появляется в диалоге с его `title` как метка и его `description` под ней.
1044
1045Установите `"sensitive": true` для токена или пароля. Диалог затем маскирует ввод, и значение хранится в защищённом хранилище, а не в `settings.json`.
1046
1047Этот манифест запрашивает конечную точку и токен:
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* Включает плагин из вкладки **Installed** в `/plugin`
1077
1078Чтобы открыть тот же диалог в любое время, пользователь запускает `/plugin configure <plugin>@<marketplace>`.
1079
1080Команда оболочки `claude plugin install` никогда не запрашивает значения `userConfig`. Чтобы установить значения из оболочки, передайте каждое как `--config KEY=VALUE`. Когда варианты остаются неустановленными, команда выводит строку `userConfig options not yet set`, которая называет оба способа их установки. [The `userConfig` dialog never appears](/docs/ru/plugins/troubleshooting#the-userconfig-dialog-never-appears) цитирует строку.
1081
1082Для полей варианта, где хранится каждое значение, как компонент ссылается на сохранённое значение и какие поля отклоняют `${user_config.*}`, см. [User configuration](/docs/ru/plugins/manifest-reference#user-configuration).
1083
1084<h2 id="path-variables-and-persistent-data">
1085 Ссылка на пути плагина и хранение данных
1086</h2>
1087
1088Вы не знаете, где будет установлен ваш плагин, поэтому ссылайтесь на его файлы и данные через эти переменные, а не через фиксированные пути. Они подставляются в содержимое skill, команды и агента, в команды hook и монитора, а также в конфигурации MCP и LSP сервера. Они также экспортируются в процессы hook, MCP и LSP:
1089
1090* **`${CLAUDE_PLUGIN_ROOT}`**: директория установки плагина. Каждая версия имеет свою собственную [директорию кэша](/docs/ru/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 подставленные пути используют прямые слэши, поэтому оболочка не читает обратные слэши как экранирование.
1097
1098<h3 id="install-dependencies-into-the-data-directory">
1099 Установка зависимостей в директорию данных
1100</h3>
1101
1102Для плагина, установленного из marketplace, Claude Code автоматически устанавливает подходящие [зависимости пакета Node.js](/docs/ru/plugins/loading#node-js-package-dependencies) при кэшировании плагина, поэтому вам может не потребоваться устанавливать их самостоятельно. Когда вам нужно, этот hook `SessionStart` устанавливает `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 сервер может затем установить `NODE_PATH` в `${CLAUDE_PLUGIN_DATA}/node_modules` в его `env`. Для того, какие поля подставляют какую переменную, см. [Environment variables](/docs/ru/plugins/manifest-reference#environment-variables).
1122
1123<h2 id="next-steps">
1124 Следующие шаги
1125</h2>
1126
1127* [Plugin manifest reference](/docs/ru/plugins/manifest-reference): поля `plugin.json`, правила пути и стандартная раскладка
1128* [Test plugins with evals](/docs/ru/plugin-evals): проверьте, что компоненты, которые вы добавили, изменяют поведение Claude так, как вы намеревались
1129* [Publish and distribute a plugin](/docs/ru/plugins/publish): версионируйте плагин и поместите его в marketplace
1130* [Troubleshoot plugins](/docs/ru/plugins/troubleshooting): что делать, когда компонент не загружается или hook не запускается