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# Ajouter des composants à un plugin
6
7> Ajoutez des skills, des hooks, des serveurs MCP et tous les autres types de composants à un plugin Claude Code, avec un exemple qui valide chacun.
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
405Un plugin Claude Code est construit à partir de composants, tels que des skills, des agents, des hooks et des serveurs MCP. Chaque composant a un dossier par défaut dans le plugin, une clé de manifeste optionnelle dans `.claude-plugin/plugin.json` qui remplace ou ajoute à ce dossier, et un nom que l'utilisateur voit. Pour chaque tableau complet des champs de clé, consultez la [référence du manifeste](/docs/fr/plugins/manifest-reference#fields).
406
407Utilisez cette page pour ajouter un composant à un plugin qui charge déjà.
408
409Après avoir ajouté un composant, exécutez `/reload-plugins` dans une session en cours ou démarrez une nouvelle session pour que Claude Code le charge. Pour vérifier le fichier du composant avant de le charger, exécutez [`claude plugin validate .`](/docs/fr/plugins/cli-reference#plugin-validate) dans votre shell à partir du répertoire du plugin.
410
411<Note>
412 Ces cas sont couverts sur d'autres pages :
413
414 * **Construire votre premier plugin** : commencez par [Créer un plugin](/docs/fr/plugins/create)
415 * **Installer le plugin de quelqu'un d'autre** : consultez [Installer des plugins](/docs/fr/plugins/install)
416 * **Les utilisateurs de votre plugin sont sur claude.ai ou dans Cowork** : un ensemble différent de composants se charge là. Consultez [Plugins sur claude.ai et dans Cowork](https://claude.com/docs/plugins/overview)
417</Note>
418
419<h2 id="explore-the-plugin-directory">
420 Explorez le répertoire du plugin
421</h2>
422
423L'explorateur montre un exemple de plugin, `my-plugin`, qui a un de chaque type de composant à son emplacement par défaut :
424
425* Une skill de révision et une commande `about`
426* Un sous-agent de révision de sécurité
427* Un hook qui formate les fichiers après que Claude les édite, et le dossier `scripts/` qu'il appelle
428* Un moniteur de journal
429* Un style de sortie et un thème de couleur
430* Un workflow d'audit de route
431* Un exécutable `hello-plugin`
432* Les paramètres par défaut
433* Un serveur MCP local et un serveur de langage Go
434
435Chaque fichier est le plus petit exemple valide de son format, là pour montrer la forme plutôt que d'être utile : une skill ou un agent réel porte des instructions complètes et souvent des fichiers de support, et un hook ou un moniteur réel fait un vrai travail. Les sections après l'explorateur utilisent les mêmes fichiers que leurs exemples et renvoient à des versions plus complètes. Sélectionnez un fichier ou un dossier pour lire à quoi il sert, voir ce qu'il contient, et trouver la section qui le couvre.
436
437<PluginExplorer>
438 <Piece id="manifest">
439 Le [manifeste](/docs/fr/plugins/manifest-reference) est le fichier `plugin.json` dans le répertoire `.claude-plugin/` d'un plugin. Il contient les métadonnées du plugin et les valeurs `userConfig` que Claude Code demande à l'utilisateur. Seul `name` est requis. Dans celui-ci, `description` est le texte que les utilisateurs voient pour le plugin dans `/plugin`, et `version` garde les utilisateurs sur cette version jusqu'à ce que vous la changiez :
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 Une [skill](/docs/fr/skills) est un fichier `SKILL.md`. Enregistrez chaque skill dans son propre répertoire sous `skills/`. Claude lit la `description` de chaque skill, et quand ce que l'utilisateur demande correspond, comme demander à Claude de réviser une pull request ici, Claude charge les instructions de la skill et les suit. L'utilisateur peut aussi l'exécuter directement comme `/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 Une commande est un seul fichier Markdown que l'utilisateur exécute par nom. Les commandes sont le format plus ancien : une skill s'exécute par nom de la même manière et peut aussi porter des fichiers de support dans son propre répertoire, donc écrivez les nouvelles comme des skills et gardez `commands/` pour les fichiers que vous avez déjà. Ce fichier devient `/my-plugin:about` et prend le même frontmatter qu'une 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 Un [sous-agent](/docs/fr/sub-agents) est un assistant séparé, avec ses propres instructions et sa propre fenêtre de contexte, que Claude peut déléguer une tâche et obtenir un résultat. Chaque fichier Markdown sous `agents/` en définit un : le frontmatter le nomme et dit quand l'utiliser, et le corps est son invite système. Celui-ci est nommé `my-plugin:security-reviewer`, et l'utilisateur peut l'invoquer avec `@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 Un [hook](/docs/fr/hooks-guide) exécute quelque chose automatiquement à un point du cycle de vie de Claude Code, comme après chaque édition de fichier : une commande shell, une requête HTTP, un appel d'outil MCP, une invite à un modèle, ou un sous-agent. Enregistrez les hooks du plugin dans `hooks/hooks.json` à la racine du plugin. Celui-ci exécute le `scripts/format.sh` du plugin après que Claude écrit ou édite un fichier :
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 Un moniteur est une commande shell que Claude Code démarre en arrière-plan quand la session démarre et continue à exécuter jusqu'à ce qu'elle se termine, en utilisant l'[outil Monitor](/docs/fr/tools-reference#monitor-tool). Ce qu'il imprime atteint Claude comme des notifications. Un champ `when` peut à la place le démarrer la première fois qu'une skill nommée s'exécute. Celui-ci suit un journal d'erreurs :
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 Un plugin peut inclure des [styles de sortie](/docs/fr/output-styles), qui changent la façon dont Claude formate et formule ses réponses. Enregistrez chaque style de sortie comme `output-styles/<name>.md`. Celui-ci apparaît dans `/output-style` comme `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 Un plugin peut inclure des [thèmes de couleur](/docs/fr/terminal-config#create-a-custom-theme) pour l'interface Claude Code. Enregistrez chaque thème comme `themes/<slug>.json`. Celui-ci apparaît dans `/theme` comme `Dracula`, marqué comme provenant de `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 Le dossier `workflows/` contient des fichiers [workflow](/docs/fr/workflows) `.js` : un bloc `meta`, puis un corps de script qui orchestre plusieurs sous-agents. Celui-ci s'exécute comme `/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/` est la façon dont un plugin expédie un outil en ligne de commande. Tant que le plugin est activé, Claude Code met ce dossier sur le `PATH` du shell dans lequel il exécute les commandes, donc Claude, ou les instructions d'une skill, peuvent exécuter l'outil par nom sans que l'utilisateur n'installe rien. Avec cet [exécutable](#executables) en place, `hello-plugin` est une commande que Claude peut exécuter :
576
577 ```bash theme={null}
578 #!/bin/bash
579 echo "hello from my-plugin"
580 ```
581 </Piece>
582
583 <Piece id="scripts">
584 Le hook dans `hooks/hooks.json` exécute un script, et ce dossier est l'endroit où l'exemple le garde. Le nom `scripts/` est une convention, pas quelque chose que Claude Code recherche : le hook pointe vers le fichier par son chemin, `${CLAUDE_PLUGIN_ROOT}/scripts/format.sh`. Un script de formatage pourrait ressembler à ceci :
585
586 ```bash theme={null}
587 #!/bin/bash
588 npx prettier --write .
589 ```
590 </Piece>
591
592 <Piece id="settings">
593 Un `settings.json` à la racine du plugin contient des [paramètres](/docs/fr/settings-reference) qui s'appliquent tant que le plugin est activé, donc un plugin peut changer le comportement de la session et non seulement ajouter des composants. Seules deux clés prennent effet à partir d'un plugin, [`agent`](/docs/fr/settings-reference#agent) et [`subagentStatusLine`](/docs/fr/settings-reference#subagentstatusline) ; toute autre clé est supprimée. Consultez [Paramètres par défaut](#default-settings).
594
595 Celui-ci définit `agent`, qui exécute le fil principal de la session comme le propre agent `security-reviewer` du plugin, donc l'invite système, les restrictions d'outils et le modèle de cet agent s'appliquent à toute la session :
596
597 ```json theme={null}
598 {
599 "agent": "security-reviewer"
600 }
601 ```
602 </Piece>
603
604 <Piece id="mcp">
605 Un [serveur MCP](/docs/fr/mcp) donne à Claude des outils d'un système externe. Déclarez-le dans `.mcp.json` à la racine du plugin. Celui-ci démarre un serveur local à partir d'un script à l'intérieur du plugin, et apparaît dans `/mcp` comme `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 Un serveur LSP donne à Claude des [diagnostics et une navigation de code](/docs/fr/plugins/code-intelligence) pour une langue. Déclarez le serveur dans `.lsp.json` à la racine du plugin. Celui-ci connecte le serveur de langage Go pour les fichiers `.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 Ajouter chaque type de composant
638</h2>
639
640Chaque section ci-dessous couvre un type de composant : où ses fichiers vont dans le plugin, un exemple qui valide, ce que l'utilisateur voit une fois que le plugin charge, et la clé de manifeste qui change l'emplacement par défaut. Ajoutez ceux dont votre plugin a besoin ; aucun n'est requis.
641
642<h3 id="skills">
643 Skills
644</h3>
645
646Une [skill](/docs/fr/skills) est un fichier `SKILL.md` que Claude peut charger quand sa description correspond à la tâche. L'utilisateur peut aussi l'exécuter comme une commande. Enregistrez chaque skill dans son propre répertoire sous `skills/` :
647
648```text theme={null}
649my-plugin/
650├── .claude-plugin/
651│ └── plugin.json
652└── skills/
653 └── review/
654 └── SKILL.md
655```
656
657Donnez au `SKILL.md` une `description` pour que Claude sache quand l'utiliser :
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
667Après avoir chargé le plugin, `/my-plugin:review` exécute la skill. Le nom de la commande et qui peut l'invoquer suivent ces règles :
668
669* **Nom de la commande** : `/<plugin>:<directory>`, donc `skills/review/SKILL.md` dans `my-plugin` est `/my-plugin:review`. Si vous définissez `name` dans le frontmatter, il remplace le dernier segment et le préfixe du plugin reste. Consultez [comment une skill obtient son nom de commande](/docs/fr/skills#how-a-skill-gets-its-command-name)
670* **Qui l'invoque** : Claude, l'utilisateur, ou les deux, contrôlé par le frontmatter. Consultez [Contrôler qui invoque une skill](/docs/fr/skills#control-who-invokes-a-skill)
671
672Vous pouvez aussi placer des skills en dehors du répertoire par défaut `skills/` :
673
674* **Répertoires supplémentaires** : listez-les dans la clé de manifeste `skills`. Ils s'ajoutent au scan `skills/` par défaut plutôt que de le remplacer, contrairement à `commands` et `agents`
675* **Une seule skill à la racine du plugin** : sans répertoire `skills/` et sans clé de manifeste `skills`, un `SKILL.md` à la racine du plugin charge comme une skill. Définissez `name` dans son frontmatter, car sinon une installation marketplace nomme la skill d'après son [répertoire de cache](/docs/fr/plugins/loading#find-plugins-on-disk) plutôt que votre plugin
676
677Pour inclure des instructions dans un plugin, écrivez-les comme une skill. Claude Code ne charge pas un `CLAUDE.md` à la racine du plugin, et `claude plugin validate` avertit `CLAUDE.md at the plugin root is not loaded as project context`.
678
679Pour les champs de frontmatter et les fichiers de support, consultez [Skills](/docs/fr/skills).
680
681<h3 id="commands">
682 Commandes
683</h3>
684
685Une commande est un seul fichier Markdown que l'utilisateur exécute par nom, comme `/my-plugin:about`.
686
687<Note>
688 Les commandes sont le format plus ancien, et les [skills](#skills) les remplacent pour les nouveaux travaux. Une skill s'exécute par nom de la même manière, et elle peut aussi porter des fichiers de support dans son répertoire. Gardez `commands/` pour les fichiers que vous migrez depuis `.claude/commands/`.
689</Note>
690
691Enregistrez une commande à `commands/<file>.md` et elle devient `/<plugin>:<file>`. Un sous-répertoire ajoute un segment, donc `commands/db/migrate.md` est `/my-plugin:db:migrate`.
692
693Les fichiers de commande prennent le même frontmatter que les skills.
694
695<h4 id="define-commands-in-the-manifest">
696 Définir les commandes dans le manifeste
697</h4>
698
699Vous n'en avez besoin que si vous voulez garder les fichiers de commande quelque part d'autre que `commands/`, ou pour définir une commande courte dans `plugin.json` sans fichier Markdown séparé. Définissez la clé de manifeste `commands`, et Claude Code la lit à la place de scanner `commands/`. La clé prend un chemin, un tableau de chemins, ou un objet qui mappe chaque nom de commande à soit un fichier `source` soit un `content` en ligne.
700
701Ce manifeste définit `/my-plugin:about` en ligne, sans fichier 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
715Chargez le plugin et exécutez `/my-plugin:about` dans la session pour confirmer qu'il a chargé.
716
717Pour la syntaxe complète de la clé, consultez [`commands`](/docs/fr/plugins/manifest-reference#commands).
718
719<h3 id="agents">
720 Agents
721</h3>
722
723Un [sous-agent](/docs/fr/sub-agents) est un assistant séparé, avec ses propres instructions et fenêtre de contexte, que Claude peut déléguer une tâche. Chaque fichier Markdown sous `agents/` en définit un :
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
735Cet agent est nommé `my-plugin:security-reviewer`, et l'utilisateur peut l'[invoquer explicitement](/docs/fr/sub-agents#invoke-subagents-explicitly) avec `@agent-my-plugin:security-reviewer`. La forme du nom est `<plugin>:<name>`, où `<name>` provient du frontmatter, ou du nom du fichier quand il n'y en a pas.
736
737La clé de manifeste `agents` remplace le scan `agents/`.
738
739<h4 id="organize-agents-in-subfolders">
740 Organiser les agents dans des sous-dossiers
741</h4>
742
743Vous pouvez mettre les fichiers d'agent du plugin dans des sous-dossiers de `agents/`. Claude Code les [charge récursivement](/docs/fr/sub-agents#choose-the-subagent-scope) et joint le nom du plugin, chaque nom de sous-dossier, et le nom du fichier avec des deux-points pour former le nom d'agent scopé. Par exemple, `agents/review/security.md` dans un plugin nommé `my-plugin` charge comme `my-plugin:review:security`. Deux paramètres changent ce nom :
744
745* Frontmatter `name` : il remplace seulement le nom du fichier, donc `name: audit` dans `agents/review/security.md` charge comme `my-plugin:review:audit`
746* Champ de manifeste [`agents`](/docs/fr/plugins/manifest-reference#fields) : un fichier que vous listez là charge sans noms de sous-dossier, donc `"agents": "./custom/review/security.md"` charge comme `my-plugin:security`
747
748<h4 id="frontmatter-fields-in-plugin-agents">
749 Champs de frontmatter dans les agents du plugin
750</h4>
751
752Le frontmatter d'un agent du plugin suit ces règles :
753
754* **Champs supportés** : `name`, `description`, `model`, `effort`, `maxTurns`, `tools`, `disallowedTools`, `skills`, `memory`, `background`, `omitClaudeMd`, `isolation`, `color`, et la clé `cacheTtl` de `experimental`. La seule valeur `isolation` valide est `"worktree"`. Consultez [champs de frontmatter supportés](/docs/fr/sub-agents#supported-frontmatter-fields) pour ce que chacun fait
755* **Champs ignorés** : `permissionMode`, `hooks`, `mcpServers`, et `initialPrompt`. Un fichier d'agent ne peut pas ajouter des hooks ou des serveurs MCP par lui-même, donc ajoutez-les comme plugin [hooks](#hooks) et [serveurs MCP](#mcp-servers) à la place
756* **Frontmatter qui ne s'analyse pas** : l'agent charge quand même avec chaque champ ignoré. Il est nommé d'après le fichier, et sa description lit `Agent from my-plugin plugin`. Exécutez [`claude plugin validate`](/docs/fr/plugins/cli-reference#plugin-validate) dans votre shell pour trouver ces fichiers
757
758Pour ce que chaque champ fait et les règles de précédence, consultez [Sous-agents](/docs/fr/sub-agents#supported-frontmatter-fields).
759
760<h3 id="hooks">
761 Hooks
762</h3>
763
764Un [hook](/docs/fr/hooks-guide) exécute quelque chose automatiquement à un point du cycle de vie de Claude Code, comme après chaque édition de fichier : une commande shell, une requête HTTP, un appel d'outil MCP, une invite à un modèle, ou un sous-agent. Enregistrez les hooks du plugin dans `hooks/hooks.json` à la racine du plugin, sous une clé `"hooks"` de niveau supérieur, dans la même forme que l'objet `hooks` dans `settings.json`. Cela vous permet de copier un hook de paramètres existant inchangé.
765
766Ce hook exécute un script groupé après chaque `Write` ou `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
786Enregistrez le script à `scripts/format.sh` et rendez-le exécutable.
787
788Chargez le plugin et demandez à Claude d'éditer un fichier. Un hook `PostToolUse` qui sort 0 ne montre rien dans la transcription, donc confirmez qu'il a exécuté avec [journalisation de débogage](/docs/fr/hooks#debug-hooks) ou par ce que le script lui-même change.
789
790Les hooks dans `hooks/hooks.json` et dans la clé de manifeste `hooks` chargent tous les deux. Pour chaque événement et sa charge utile, consultez [Événements de hook](/docs/fr/hooks#hook-events).
791
792<h4 id="when-plugin-hooks-fire">
793 Quand les hooks du plugin se déclenchent
794</h4>
795
796Les hooks d'un plugin n'attendent pas qu'une des skills ou commandes du plugin soit utilisée. Claude Code les enregistre quand une session charge le plugin, et ils se déclenchent sur leurs événements à partir de là. Pour limiter quand un hook s'exécute, réduisez son `matcher`.
797
798Si un hook ne se déclenche jamais, consultez [hooks qui ne se déclenchent pas](/docs/fr/plugins/troubleshooting#failed-to-load-hooks-from-and-hooks-that-dont-fire).
799
800<h4 id="environment-quoting-and-matching-mcp-tools">
801 Environnement, guillemets et correspondance des outils MCP
802</h4>
803
804L'environnement du hook, les guillemets de `${CLAUDE_PLUGIN_ROOT}`, et les matchers pour les outils MCP du plugin fonctionnent comme suit :
805
806* **Environnement** : chaque processus de hook reçoit `CLAUDE_PLUGIN_ROOT` et `CLAUDE_PLUGIN_DATA` dans son environnement, plus `CLAUDE_PLUGIN_OPTION_<KEY>` pour chaque valeur de [configuration utilisateur](#user-configuration), donc votre script peut les lire de là
807* **Guillemets** : quand `command` n'a pas `args`, il s'exécute via un shell, donc enveloppez le chemin `${CLAUDE_PLUGIN_ROOT}` entre guillemets doubles, comme l'exemple `hooks/hooks.json` sous [Hooks](#hooks) le fait, pour garder le chemin développé un mot shell. Quand vous passez `args` à la place, chaque élément est passé comme un argument sans shell et n'a besoin d'aucun guillemet. Consultez [forme exec et forme shell](/docs/fr/hooks#exec-form-and-shell-form)
808* **Correspondance des outils MCP du plugin** : un outil d'un [serveur MCP que ce plugin déclare](#mcp-servers) est nommé `mcp__plugin_<plugin>_<server>__<tool>`, donc écrivez ce nom complet dans le matcher. Un matcher sur le nom du serveur seul ne se déclenche jamais. Consultez [Correspondance des outils MCP](/docs/fr/hooks#match-mcp-tools)
809
810<h3 id="mcp-servers">
811 Serveurs MCP
812</h3>
813
814Un serveur MCP donne à Claude des outils d'un système externe. Déclarez-le dans `.mcp.json` à la racine du plugin, dans la même forme qu'un [`.mcp.json` de projet](/docs/fr/mcp#project-scope). Ce `.mcp.json` déclare un serveur nommé `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
827Vous pouvez aussi omettre le wrapper `mcpServers` et mettre `db` au niveau supérieur du fichier.
828
829Chargez le plugin et exécutez `/mcp` pour confirmer que le serveur apparaît comme `plugin:my-plugin:db`.
830
831`claude plugin validate` vérifie `.mcp.json` et signale une entrée de serveur que Claude Code supprimerait au moment du chargement comme une erreur. Nécessite Claude Code v2.1.281 ou ultérieur.
832
833Pour où une mauvaise entrée s'affiche au moment du chargement, consultez [Serveurs MCP qui ne démarrent pas](/docs/fr/plugins/troubleshooting#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start).
834
835La clé de manifeste `mcpServers` prend une carte de serveur en ligne, un chemin vers un fichier JSON, ou un tableau de ceux-ci. Quand un serveur de manifeste a le même nom qu'un dans `.mcp.json`, le serveur de manifeste le remplace.
836
837<h4 id="reach-users-on-claude-ai-and-cowork">
838 Atteindre les utilisateurs sur claude.ai et Cowork
839</h4>
840
841Un serveur stdio local, comme le serveur `db` sous [Serveurs MCP](#mcp-servers), s'exécute dans Claude Code et dans une session Cowork qui s'exécute sur votre machine dans l'application Claude Desktop, mais pas sur claude.ai. Pour atteindre les utilisateurs là aussi, référencez un serveur distant par son URL `https://`, que claude.ai et Cowork offrent à l'utilisateur comme connecteur.
842
843<h4 id="server-names-tool-names-and-reloads">
844 Noms de serveur, noms d'outils et rechargements
845</h4>
846
847Les noms du serveur, la substitution de variables, et le comportement de rechargement suivent ces règles :
848
849* **Nom du serveur** : `plugin:<plugin>:<server>`, donc le serveur `db` dans `my-plugin` est `plugin:my-plugin:db` dans `/mcp`. Utilisez la même forme pour nommer le serveur dans un hook [`mcp_tool`](/docs/fr/hooks#mcp-tool-hook-fields)
850* **Noms d'outils** : `mcp__plugin_<plugin>_<server>__<tool>`, donc un outil `query` sur ce serveur `db` est `mcp__plugin_my-plugin_db__query`. C'est le nom à utiliser dans les [règles de permission](/docs/fr/permissions) et les [matchers de hook](#hooks)
851* **Substitution** : `${CLAUDE_PLUGIN_ROOT}` et les autres [variables de chemin](#path-variables-and-persistent-data) sont substituées dans `command`, `args`, et `env`. Aucun guillemet n'est nécessaire dans `args`, car chaque élément est passé comme un argument
852* **Rechargement** : quand l'utilisateur exécute `/reload-plugins` et que [le rechargement s'applique](/docs/fr/plugins/cli-reference#reloads-that-change-mcp-tools), un serveur dont la configuration est inchangée garde sa connexion. Un serveur dont la configuration a changé se reconnecte, et un que vous avez supprimé se déconnecte
853
854<h4 id="include-a-packaged-mcpb-server">
855 Inclure un serveur MCPB emballé
856</h4>
857
858La clé `mcpServers` accepte aussi un serveur emballé comme un [fichier MCPB](https://github.com/modelcontextprotocol/mcpb), dont l'extension est `.mcpb` ou l'ancienne `.dxt`. Pointez la clé vers le fichier, comme un chemin à l'intérieur du plugin ou une URL `https://` :
859
860```json .claude-plugin/plugin.json theme={null}
861{
862 "name": "my-plugin",
863 "mcpServers": "./servers/db.mcpb"
864}
865```
866
867Le serveur prend son nom du `name` dans le manifeste du bundle.
868
869Pour les transports et l'authentification, consultez [MCP](/docs/fr/mcp#plugin-provided-mcp-servers).
870
871<h3 id="lsp-servers">
872 Serveurs LSP
873</h3>
874
875Un serveur LSP donne à Claude des diagnostics et une navigation de code pour une langue. Si un [plugin officiel de code intelligence](/docs/fr/plugins/code-intelligence) couvre déjà votre langue, installez celui-ci à la place d'en écrire un. Sinon, déclarez le serveur dans `.lsp.json` à la racine du plugin :
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
889Le fichier mappe chaque nom de serveur directement à sa configuration, sans objet wrapper autour de la carte. `command` est le nom du binaire, avec ses arguments dans `args`. `extensionToLanguage` a besoin d'au moins une extension, chacune commençant par `.`.
890
891`claude plugin validate` ne lit pas ce fichier. Quand une entrée est invalide, le fichier entier est ignoré au chargement et `Invalid LSP server config for ".lsp.json"` apparaît dans l'onglet **Errors** de `/plugin`.
892
893Votre plugin configure la connexion mais n'installe pas le binaire du serveur, et chaque extension de fichier obtient un serveur :
894
895* **Binaire manquant** : Claude Code démarre `command` par nom depuis le `PATH` de l'utilisateur. Quand le binaire n'est pas là, le serveur échoue à démarrer et `claude --debug` enregistre `LSP server <name> failed to start`
896* **Conflits d'extension** : quand deux serveurs activés revendiquent la même extension, le premier enregistré gère ces fichiers et l'autre n'est pas utilisé pour eux, que les serveurs proviennent d'un plugin ou de deux. L'onglet **Errors** de `/plugin` montre l'avertissement `LSP server "<name>" is not used for <ext> files`
897
898La clé de manifeste `lspServers` prend la même carte en ligne, un chemin vers un fichier JSON, ou un tableau de ceux-ci, et ses serveurs s'ajoutent à ceux dans `.lsp.json`. Quand un serveur de manifeste a le même nom qu'un dans `.lsp.json`, le serveur de manifeste le remplace.
899
900Pour `transport`, les délais d'attente, les redémarrages, et les autres champs, consultez [`lspServers`](/docs/fr/plugins/manifest-reference#lspservers).
901
902Envoyez la sortie du journal à stderr, pas stdout. Claude Code lit le stdout d'un serveur comme des messages de protocole seulement, et accepte les en-têtes de message jusqu'à 64 KiB et un corps de message jusqu'à 32 MiB.
903
904Claude Code déconnecte un serveur qui dépasse l'une ou l'autre limite ou écrit une sortie non-protocole à stdout, et compte la déconnexion comme un crash pour `restartOnCrash` et `maxRestarts`. Quand vous exécutez avec `--debug`, Claude Code écrit une erreur nommant la cause au journal de débogage.
905
906<h3 id="executables">
907 Exécutables
908</h3>
909
910Les fichiers dans `bin/` à la racine du plugin sont sur le `PATH` du shell de l'outil Bash tant que le plugin est activé, donc Claude peut les exécuter comme des commandes nues. Ajoutez un script exécutable :
911
912```bash bin/hello-plugin theme={null}
913#!/bin/bash
914echo "hello from my-plugin"
915```
916
917Rendez-le exécutable avec `chmod +x bin/hello-plugin` et chargez le plugin. Quand vous demandez à Claude d'exécuter `hello-plugin`, le résultat de l'outil Bash montre la sortie du script.
918
919Les répertoires `bin/` du plugin viennent après les entrées `PATH` de l'utilisateur, donc un plugin ne peut pas masquer `git`, `ls`, ou une autre commande système.
920
921claude.ai et Cowork n'installent pas un plugin qui a un répertoire `bin/` de niveau supérieur, y compris un que vous [distribuez via les paramètres d'organisation claude.ai](/docs/fr/plugins/host-marketplace#distribute-through-organization-settings).
922
923<h3 id="default-settings">
924 Paramètres par défaut
925</h3>
926
927Pour définir les paramètres par défaut qui s'appliquent tant que le plugin est activé, ajoutez un `settings.json` à la racine du plugin, ou mettez le même objet en ligne dans la clé de manifeste `settings`. Deux clés prennent effet, `agent` et `subagentStatusLine`, et toute autre clé est supprimée.
928
929Définissez `agent` pour exécuter l'un des propres agents du plugin comme le fil principal :
930
931```json settings.json theme={null}
932{
933 "agent": "security-reviewer"
934}
935```
936
937Chargez le plugin et démarrez une session. Claude répond alors dans la conversation principale avec l'invite système et le modèle de l'agent `security-reviewer`.
938
939Pour tout ce que la clé contrôle, consultez le [paramètre `agent`](/docs/fr/settings-reference#agent).
940
941Quand la même clé est définie à plus d'un endroit, ces règles décident quelle valeur s'applique :
942
943* **Fichier sur manifeste** : quand les deux existent et `settings.json` définit au moins une clé supportée, `settings.json` s'applique et le `settings` du manifeste est ignoré
944* **Paramètres utilisateur sur paramètres par défaut du plugin** : dans les sources de paramètres, les paramètres par défaut du plugin sont la couche la plus basse, donc un `agent` personnel de l'utilisateur dans `~/.claude/settings.json` remplace le vôtre
945* **Deux plugins définissent la même clé** : la valeur du plugin chargé en dernier s'applique, et `claude --debug` enregistre `overrides setting`
946
947Pour la forme `subagentStatusLine`, consultez [lignes d'état du sous-agent](/docs/fr/statusline#subagent-status-lines).
948
949<h3 id="themes-and-output-styles">
950 Thèmes et styles de sortie
951</h3>
952
953Un plugin peut inclure des thèmes de couleur et des styles de sortie. Les deux apparaissent dans les mêmes sélecteurs que ceux de l'utilisateur. Pour l'un ou l'autre, définir la clé de manifeste remplace le scan de dossier.
954
955| Composant | Enregistrer comme | Format | Apparaît dans | Clé de manifeste |
956| :-------------- | :------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------- | :-------------------- |
957| Thème | `themes/<slug>.json` | Le format de [fichier de thème personnalisé](/docs/fr/terminal-config#create-a-custom-theme) que les utilisateurs écrivent dans `~/.claude/themes/` | `/theme`, sous le `name` du fichier | `experimental.themes` |
958| Style de sortie | `output-styles/<name>.md` | Le format de [style de sortie personnalisé](/docs/fr/output-styles#create-a-custom-output-style), avec le frontmatter `name` et `description` | `/output-style`, comme `<plugin>:<name>` | `outputStyles` |
959
960Les thèmes du plugin sont en lecture seule, donc quand un utilisateur en édite un dans `/theme`, l'édition est enregistrée comme une copie dans son propre répertoire de thèmes.
961
962Ce thème recolore l'accent d'invite et le texte d'erreur sur le préréglage sombre :
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 Canaux
977</h3>
978
979Un [canal](/docs/fr/channels) permet à un système externe tel qu'une application de chat d'envoyer des messages dans une session. Dans un plugin, un canal est l'un des serveurs MCP plus une entrée `channels` qui se lie à lui et peut demander sa propre configuration. Ce manifeste lie un canal à un serveur `telegram` et demande un jeton de bot :
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` doit correspondre à une clé dans `mcpServers`. Le `userConfig` par canal prend la même forme que la clé [`userConfig`](#user-configuration) de niveau supérieur.
1008
1009Pour ce que le serveur doit implémenter et comment les utilisateurs activent un plugin de canal, consultez [Empaqueter comme un plugin](/docs/fr/channels-reference#package-as-a-plugin) dans la référence des canaux. Pour le tableau des champs, consultez [`channels`](/docs/fr/plugins/manifest-reference#channels).
1010
1011<h3 id="monitors">
1012 Moniteurs
1013</h3>
1014
1015Un moniteur est une commande shell qui s'exécute en arrière-plan pour toute la session. Ce qu'il imprime atteint Claude comme des notifications, donc Claude peut réagir à un journal ou à un changement d'état sans être demandé de le surveiller. Enregistrez les entrées dans `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
1027La commande s'exécute dans un shell, dans le répertoire de travail dans lequel la session a démarré.
1028
1029La commande d'un moniteur est limitée dans où elle démarre et ce qu'elle peut référencer :
1030
1031* **Sessions interactives seulement** : les moniteurs du plugin démarrent dans une session interactive et jamais en mode non-interactif avec le drapeau `-p`. Ils démarrent aussi seulement où l'[outil Monitor](/docs/fr/tools-reference#monitor-tool) est disponible
1032* **Pas de configuration utilisateur** : `command` obtient les [variables de chemin](#path-variables-and-persistent-data) et `${ENV_VAR}` de l'environnement, mais jamais `${user_config.*}`. Un moniteur qui en référence un ne démarre pas, et les processus de moniteur ne reçoivent pas non plus `CLAUDE_PLUGIN_OPTION_<KEY>`
1033* **Désactivation en cours de session** : si vous désactivez un plugin en cours de session, Claude Code n'arrête pas les moniteurs qui s'exécutent déjà. Ils s'arrêtent quand la session se termine
1034
1035La clé de manifeste `experimental.monitors` prend le même tableau en ligne ou un chemin vers un fichier JSON, et est lue à la place de `monitors/monitors.json`.
1036
1037Pour le déclencheur `when` et les autres champs, consultez [`monitors`](/docs/fr/plugins/manifest-reference#monitors).
1038
1039<h2 id="user-configuration">
1040 Demander à l'utilisateur des valeurs de configuration
1041</h2>
1042
1043Déclarez les valeurs dont votre plugin a besoin de l'utilisateur dans la clé de manifeste `userConfig`, pour que les utilisateurs ne modifient pas `settings.json` eux-mêmes. Chaque option apparaît dans une boîte de dialogue avec son `title` comme étiquette et sa `description` en dessous.
1044
1045Définissez `"sensitive": true` pour un jeton ou un mot de passe. La boîte de dialogue masque alors l'entrée, et la valeur est stockée dans un stockage sécurisé plutôt que dans `settings.json`.
1046
1047Ce manifeste demande un point de terminaison et un jeton :
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 Quand la boîte de dialogue de configuration apparaît
1070</h3>
1071
1072La boîte de dialogue n'apparaît que dans l'interface interactive `/plugin`. Elle s'ouvre pour toute option qui n'est pas encore définie quand l'utilisateur fait l'une des choses suivantes :
1073
1074* Installe le plugin dans `/plugin`
1075* Exécute `/plugin install <plugin>@<marketplace>` à l'intérieur d'une session
1076* Active le plugin à partir de l'onglet **Installed** dans `/plugin`
1077
1078Pour ouvrir la même boîte de dialogue à tout moment, l'utilisateur exécute `/plugin configure <plugin>@<marketplace>`.
1079
1080La commande shell `claude plugin install` ne demande jamais les valeurs `userConfig`. Pour définir les valeurs à partir du shell, passez chacune comme `--config KEY=VALUE`. Quand les options restent non définies, la commande imprime une ligne `userConfig options not yet set` qui nomme les deux façons de les définir. [La boîte de dialogue `userConfig` ne s'affiche jamais](/docs/fr/plugins/troubleshooting#the-userconfig-dialog-never-appears) cite la ligne.
1081
1082Pour les champs d'option, où chaque valeur est stockée, comment un composant référence une valeur enregistrée, et quels champs rejettent `${user_config.*}`, consultez [Configuration utilisateur](/docs/fr/plugins/manifest-reference#user-configuration).
1083
1084<h2 id="path-variables-and-persistent-data">
1085 Référencer les chemins du plugin et stocker les données
1086</h2>
1087
1088Vous ne savez pas où votre plugin sera installé, donc référencez ses fichiers et données via ces variables plutôt que des chemins fixes. Ils sont substitués dans le contenu des skills, commandes et agents, dans les commandes des hooks et moniteurs, et dans les configurations des serveurs MCP et LSP. Ils sont aussi exportés aux processus des hooks, MCP et LSP :
1089
1090* **`${CLAUDE_PLUGIN_ROOT}`** : le répertoire d'installation du plugin. Chaque version a son propre [répertoire de cache](/docs/fr/plugins/loading#find-plugins-on-disk), donc le chemin change quand le plugin se met à jour. N'écrivez pas d'état là
1091* **`${CLAUDE_PLUGIN_DATA}`** : un répertoire qui survit aux mises à jour, pour `node_modules`, les environnements virtuels, et les caches. Il se résout en `~/.claude/plugins/data/<id>/` et est créé quand d'abord référencé
1092* **`${CLAUDE_PROJECT_DIR}`** : la racine du projet, la même valeur que les hooks reçoivent
1093
1094Dans le chemin du répertoire de données, `<id>` est l'identifiant du plugin avec chaque caractère autre que les lettres, les chiffres, `_`, et `-` remplacé par `-`, donc `my-plugin@my-marketplace` devient `my-plugin-my-marketplace`.
1095
1096Sur Windows, les chemins substitués utilisent des barres obliques avant pour qu'un shell ne lise pas les barres obliques arrière comme des échappements.
1097
1098<h3 id="install-dependencies-into-the-data-directory">
1099 Installer les dépendances dans le répertoire de données
1100</h3>
1101
1102Pour un plugin installé depuis la marketplace, Claude Code installe automatiquement les [dépendances de package Node.js](/docs/fr/plugins/loading#node-js-package-dependencies) éligibles quand il met en cache le plugin, donc vous n'aurez peut-être pas besoin de les installer vous-même. Quand vous le faites, ce hook `SessionStart` installe `node_modules` dans `${CLAUDE_PLUGIN_DATA}` à la première exécution et à nouveau après une mise à jour qui change `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
1121Après la première session, `~/.claude/plugins/data/<id>/node_modules` existe. Un serveur MCP peut alors définir `NODE_PATH` à `${CLAUDE_PLUGIN_DATA}/node_modules` dans son `env`. Pour quels champs substituent quelle variable, consultez [Variables d'environnement](/docs/fr/plugins/manifest-reference#environment-variables).
1122
1123<h2 id="next-steps">
1124 Étapes suivantes
1125</h2>
1126
1127* [Référence du manifeste du plugin](/docs/fr/plugins/manifest-reference) : champs `plugin.json`, règles de chemin, et la disposition standard
1128* [Tester les plugins avec des evals](/docs/fr/plugin-evals) : vérifiez que les composants que vous avez ajoutés changent le comportement de Claude de la façon que vous avez l'intention
1129* [Publier et distribuer un plugin](/docs/fr/plugins/publish) : versionnez le plugin et mettez-le dans une marketplace
1130* [Dépanner les plugins](/docs/fr/plugins/troubleshooting) : quoi faire quand un composant ne charge pas ou qu'un hook ne se déclenche pas