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# Agregar componentes a un plugin
6
7> Agrega skills, hooks, servidores MCP y todos los demás tipos de componentes a un plugin de Claude Code, con un ejemplo que valida cada uno.
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 de Claude Code se construye a partir de componentes, como skills, agentes, hooks y servidores MCP. Cada componente tiene una carpeta predeterminada en el plugin, una clave de manifiesto opcional en `.claude-plugin/plugin.json` que reemplaza o se suma a esa carpeta, y un nombre que ve el usuario. Para la tabla de campos completa de cada clave, consulte la [referencia de manifiesto](/docs/es/plugins/manifest-reference#fields).
406
407Utilice esta página para agregar un componente a un plugin que ya se carga.
408
409Después de agregar un componente, ejecute `/reload-plugins` en una sesión en ejecución o inicie una nueva para que Claude Code lo cargue. Para verificar el archivo del componente antes de cargarlo, ejecute [`claude plugin validate .`](/docs/es/plugins/cli-reference#plugin-validate) en su shell desde el directorio del plugin.
410
411<Note>
412 Estos casos se tratan en otras páginas:
413
414 * **Construir su primer plugin**: comience con [Crear un plugin](/docs/es/plugins/create)
415 * **Instalar el plugin de otra persona**: consulte [Instalar plugins](/docs/es/plugins/install)
416 * **Los usuarios de su plugin están en claude.ai o en Cowork**: se carga un conjunto diferente de componentes allí. Consulte [Plugins en claude.ai y en Cowork](https://claude.com/docs/plugins/overview)
417</Note>
418
419<h2 id="explore-the-plugin-directory">
420 Explorar el directorio del plugin
421</h2>
422
423El explorador muestra un plugin de ejemplo, `my-plugin`, que tiene uno de cada tipo de componente en su ubicación predeterminada:
424
425* Una skill de revisión y un comando `about`
426* Un subagente de revisión de seguridad
427* Un hook que formatea archivos después de que Claude los edita, y la carpeta `scripts/` que llama
428* Un monitor de registro
429* Un estilo de salida y un tema de color
430* Un flujo de trabajo de auditoría de rutas
431* Un ejecutable `hello-plugin`
432* Configuración predeterminada
433* Un servidor MCP local y un servidor de lenguaje Go
434
435Cada archivo es el ejemplo válido más pequeño de su formato, presente para mostrar la forma en lugar de ser útil: una skill o agente real lleva instrucciones completas y a menudo archivos de apoyo, y un hook o monitor real realiza trabajo real. Las secciones después del explorador utilizan los mismos archivos que sus ejemplos y enlazan a otros más completos. Seleccione un archivo o carpeta para leer para qué sirve, ver qué va en él y encontrar la sección que lo cubre.
436
437<PluginExplorer>
438 <Piece id="manifest">
439 El [manifiesto](/docs/es/plugins/manifest-reference) es el archivo `plugin.json` en el directorio `.claude-plugin/` de un plugin. Contiene los metadatos del plugin y los valores de `userConfig` que Claude Code solicita al usuario. Solo `name` es obligatorio. En este, `description` es el texto que los usuarios ven para el plugin en `/plugin`, y `version` mantiene a los usuarios en esa versión hasta que la cambie:
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 Una [skill](/docs/es/skills) es un archivo `SKILL.md`. Guarde cada skill en su propio directorio bajo `skills/`. Claude lee la `description` de cada skill, y cuando lo que el usuario pregunta coincide con ella, como pedirle a Claude que revise una solicitud de extracción aquí, Claude carga las instrucciones de la skill y las sigue. El usuario también puede ejecutarla directamente como `/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 Un comando es un único archivo Markdown que el usuario ejecuta por nombre. Los comandos son el formato anterior: una skill se ejecuta por nombre de la misma manera y también puede llevar archivos de apoyo en su propio directorio, así que escriba los nuevos como skills y mantenga `commands/` para los archivos que ya tiene. Este archivo se convierte en `/my-plugin:about` y toma el mismo frontmatter que una 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 [subagente](/docs/es/sub-agents) es un asistente separado, con sus propias instrucciones y su propia ventana de contexto, al que Claude puede delegar una tarea y obtener un resultado. Cada archivo Markdown bajo `agents/` define uno: el frontmatter lo nombra y dice cuándo usarlo, y el cuerpo es su indicación del sistema. Este se llama `my-plugin:security-reviewer`, y el usuario puede invocarlo con `@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/es/hooks-guide) ejecuta algo automáticamente en un punto del ciclo de vida de Claude Code, como después de cada edición de archivo: un comando de shell, una solicitud HTTP, una llamada a herramienta MCP, un indicador a un modelo o un subagente. Guarde los hooks del plugin en `hooks/hooks.json` en la raíz del plugin. Este ejecuta el script `scripts/format.sh` del plugin después de que Claude escribe o edita un archivo:
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 monitor es un comando de shell que Claude Code inicia en segundo plano cuando la sesión comienza y mantiene en ejecución hasta que termina, utilizando la [herramienta Monitor](/docs/es/tools-reference#monitor-tool). Lo que imprime llega a Claude como notificaciones. Un campo `when` puede iniciarlo la primera vez que se ejecuta una skill nombrada. Este rastrea un registro de errores:
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 puede incluir [estilos de salida](/docs/es/output-styles), que cambian cómo Claude formatea y expresa sus respuestas. Guarde cada estilo de salida como `output-styles/<name>.md`. Este aparece en `/output-style` como `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 puede incluir [temas de color](/docs/es/terminal-config#create-a-custom-theme) para la interfaz de Claude Code. Guarde cada tema como `themes/<slug>.json`. Este aparece en `/theme` como `Dracula`, marcado como 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 La carpeta `workflows/` contiene archivos [workflow](/docs/es/workflows) `.js`: un bloque `meta`, luego un cuerpo de script que orquesta varios subagentes. Este se ejecuta como `/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/` es cómo un plugin envía una herramienta de línea de comandos. Mientras el plugin está habilitado, Claude Code coloca esta carpeta en el `PATH` del shell en el que ejecuta comandos, para que Claude, o las instrucciones de una skill, puedan ejecutar la herramienta por nombre sin que el usuario instale nada. Con este [ejecutable](#executables) en su lugar, `hello-plugin` es un comando que Claude puede ejecutar:
576
577 ```bash theme={null}
578 #!/bin/bash
579 echo "hello from my-plugin"
580 ```
581 </Piece>
582
583 <Piece id="scripts">
584 El hook en `hooks/hooks.json` ejecuta un script, y esta carpeta es donde el ejemplo lo mantiene. El nombre `scripts/` es una convención, no algo que Claude Code busque: el hook apunta al archivo por su ruta, `${CLAUDE_PLUGIN_ROOT}/scripts/format.sh`. Un script de formateador podría verse así:
585
586 ```bash theme={null}
587 #!/bin/bash
588 npx prettier --write .
589 ```
590 </Piece>
591
592 <Piece id="settings">
593 Un `settings.json` en la raíz del plugin contiene [configuración](/docs/es/settings-reference) que se aplica mientras el plugin está habilitado, para que un plugin pueda cambiar cómo se comporta la sesión y no solo agregar componentes. Solo dos claves tienen efecto desde un plugin, [`agent`](/docs/es/settings-reference#agent) y [`subagentStatusLine`](/docs/es/settings-reference#subagentstatusline); todas las demás claves se descartan. Consulte [Configuración predeterminada](#default-settings).
594
595 Este establece `agent`, que ejecuta el hilo principal de la sesión como el agente `security-reviewer` del plugin, para que el indicador del sistema de ese agente, las restricciones de herramientas y el modelo se apliquen a toda la sesión:
596
597 ```json theme={null}
598 {
599 "agent": "security-reviewer"
600 }
601 ```
602 </Piece>
603
604 <Piece id="mcp">
605 Un [servidor MCP](/docs/es/mcp) proporciona a Claude herramientas de un sistema externo. Declárelo en `.mcp.json` en la raíz del plugin. Este inicia un servidor local desde un script dentro del plugin y aparece en `/mcp` como `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 servidor LSP proporciona a Claude [diagnósticos y navegación de código](/docs/es/plugins/code-intelligence) para un lenguaje. Declare el servidor en `.lsp.json` en la raíz del plugin. Este conecta el servidor de lenguaje Go para archivos `.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 Agregar cada tipo de componente
638</h2>
639
640Cada sección a continuación cubre un tipo de componente: dónde van sus archivos en el plugin, un ejemplo que valida, qué ve el usuario una vez que se carga el plugin, y la clave de manifiesto que cambia la ubicación predeterminada. Agregue los que su plugin necesite; ninguno es obligatorio.
641
642<h3 id="skills">
643 Skills
644</h3>
645
646Una [skill](/docs/es/skills) es un archivo `SKILL.md` que Claude puede cargar cuando su descripción coincide con la tarea. El usuario también puede ejecutarla como un comando. Guarde cada skill en su propio directorio bajo `skills/`:
647
648```text theme={null}
649my-plugin/
650├── .claude-plugin/
651│ └── plugin.json
652└── skills/
653 └── review/
654 └── SKILL.md
655```
656
657Dé al `SKILL.md` una `description` para que Claude sepa cuándo usarla:
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
667Después de cargar el plugin, `/my-plugin:review` ejecuta la skill. El nombre del comando y quién puede invocarlo siguen estas reglas:
668
669* **Nombre del comando**: `/<plugin>:<directory>`, así que `skills/review/SKILL.md` en `my-plugin` es `/my-plugin:review`. Si establece `name` en el frontmatter, reemplaza el último segmento y el prefijo del plugin permanece. Consulte [cómo una skill obtiene su nombre de comando](/docs/es/skills#how-a-skill-gets-its-command-name)
670* **Quién la invoca**: Claude, el usuario, o ambos, controlado por frontmatter. Consulte [Controlar quién invoca una skill](/docs/es/skills#control-who-invokes-a-skill)
671
672También puede colocar skills fuera del directorio predeterminado `skills/`:
673
674* **Directorios adicionales**: enumérelos en la clave de manifiesto `skills`. Se suman al escaneo predeterminado de `skills/` en lugar de reemplazarlo, a diferencia de `commands` y `agents`
675* **Una única skill en la raíz del plugin**: sin directorio `skills/` y sin clave de manifiesto `skills`, un `SKILL.md` en la raíz del plugin se carga como una skill. Establezca `name` en su frontmatter, porque de lo contrario una instalación de marketplace nombra la skill después de su [directorio de caché](/docs/es/plugins/loading#find-plugins-on-disk) en lugar de su plugin
676
677Para incluir instrucciones en un plugin, escríbalas como una skill. Claude Code no carga un `CLAUDE.md` en la raíz del plugin, y `claude plugin validate` advierte `CLAUDE.md at the plugin root is not loaded as project context`.
678
679Para campos de frontmatter y archivos de apoyo, consulte [Skills](/docs/es/skills).
680
681<h3 id="commands">
682 Comandos
683</h3>
684
685Un comando es un único archivo Markdown que el usuario ejecuta por nombre, como `/my-plugin:about`.
686
687<Note>
688 Los comandos son el formato anterior, y [skills](#skills) los reemplazan para trabajo nuevo. Una skill se ejecuta por nombre de la misma manera, y también puede llevar archivos de apoyo en su directorio. Mantenga `commands/` para archivos que está moviendo desde `.claude/commands/`.
689</Note>
690
691Guarde un comando en `commands/<file>.md` y se convierte en `/<plugin>:<file>`. Un subdirectorio agrega un segmento, así que `commands/db/migrate.md` es `/my-plugin:db:migrate`.
692
693Los archivos de comando toman el mismo frontmatter que las skills.
694
695<h4 id="define-commands-in-the-manifest">
696 Definir comandos en el manifiesto
697</h4>
698
699Solo necesita esto si desea mantener archivos de comando en algún lugar que no sea `commands/`, o para definir un comando corto dentro de `plugin.json` sin un archivo Markdown separado. Establezca la clave de manifiesto `commands`, y Claude Code la lee en lugar de escanear `commands/`. La clave toma una ruta, una matriz de rutas, u un objeto que asigna cada nombre de comando a un archivo `source` o contenido `content` en línea.
700
701Este manifiesto define `/my-plugin:about` en línea, sin archivo 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
715Cargue el plugin y ejecute `/my-plugin:about` en la sesión para confirmar que se cargó.
716
717Para la sintaxis completa de la clave, consulte [`commands`](/docs/es/plugins/manifest-reference#commands).
718
719<h3 id="agents">
720 Agentes
721</h3>
722
723Un [subagente](/docs/es/sub-agents) es un asistente separado, con sus propias instrucciones y ventana de contexto, al que Claude puede delegar una tarea. Cada archivo Markdown bajo `agents/` define uno:
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
735Este agente se llama `my-plugin:security-reviewer`, y el usuario puede [invocarlo explícitamente](/docs/es/sub-agents#invoke-subagents-explicitly) con `@agent-my-plugin:security-reviewer`. La forma del nombre es `<plugin>:<name>`, donde `<name>` viene del frontmatter, o del nombre del archivo cuando no hay ninguno.
736
737La clave de manifiesto `agents` reemplaza el escaneo de `agents/`.
738
739<h4 id="organize-agents-in-subfolders">
740 Organizar agentes en subcarpetas
741</h4>
742
743Puede colocar archivos de agente del plugin en subcarpetas de `agents/`. Claude Code [los carga recursivamente](/docs/es/sub-agents#choose-the-subagent-scope) y une el nombre del plugin, cada nombre de subcarpeta y el nombre del archivo con dos puntos para formar el nombre con alcance del agente. Por ejemplo, `agents/review/security.md` en un plugin llamado `my-plugin` se carga como `my-plugin:review:security`. Dos configuraciones cambian ese nombre:
744
745* Frontmatter `name`: reemplaza solo el nombre del archivo, así que `name: audit` en `agents/review/security.md` se carga como `my-plugin:review:audit`
746* Campo de manifiesto [`agents`](/docs/es/plugins/manifest-reference#fields): un archivo que enumera allí se carga sin nombres de subcarpeta, así que `"agents": "./custom/review/security.md"` se carga como `my-plugin:security`
747
748<h4 id="frontmatter-fields-in-plugin-agents">
749 Campos de frontmatter en agentes de plugin
750</h4>
751
752El frontmatter de un agente de plugin sigue estas reglas:
753
754* **Campos admitidos**: `name`, `description`, `model`, `effort`, `maxTurns`, `tools`, `disallowedTools`, `skills`, `memory`, `background`, `omitClaudeMd`, `isolation`, `color`, y la clave `cacheTtl` de `experimental`. El único valor válido de `isolation` es `"worktree"`. Consulte [campos de frontmatter admitidos](/docs/es/sub-agents#supported-frontmatter-fields) para ver qué hace cada uno
755* **Campos ignorados**: `permissionMode`, `hooks`, `mcpServers`, e `initialPrompt`. Un archivo de agente no puede agregar hooks o servidores MCP por su cuenta, así que agregue esos como plugin [hooks](#hooks) y [servidores MCP](#mcp-servers) en su lugar
756* **Frontmatter que no se analiza**: el agente aún se carga con cada campo ignorado. Se nombra después del archivo, y su descripción dice `Agent from my-plugin plugin`. Ejecute [`claude plugin validate`](/docs/es/plugins/cli-reference#plugin-validate) en su shell para encontrar estos archivos
757
758Para ver qué hace cada campo y las reglas de precedencia, consulte [Subagentes](/docs/es/sub-agents#supported-frontmatter-fields).
759
760<h3 id="hooks">
761 Hooks
762</h3>
763
764Un [hook](/docs/es/hooks-guide) ejecuta algo automáticamente en un punto del ciclo de vida de Claude Code, como después de cada edición de archivo: un comando de shell, una solicitud HTTP, una llamada a herramienta MCP, un indicador a un modelo o un subagente. Guarde los hooks del plugin en `hooks/hooks.json` en la raíz del plugin, bajo una clave `"hooks"` de nivel superior, en la misma forma que el objeto `hooks` en `settings.json`. Eso le permite copiar un hook de configuración existente sin cambios.
765
766Este hook ejecuta un script incluido después de cada `Write` o `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
786Guarde el script en `scripts/format.sh` y hágalo ejecutable.
787
788Cargue el plugin y pida a Claude que edite un archivo. Un hook `PostToolUse` que sale con 0 no muestra nada en la transcripción, así que confirme que se ejecutó con [registro de depuración](/docs/es/hooks#debug-hooks) o por lo que el script mismo cambia.
789
790Los hooks en `hooks/hooks.json` y en la clave de manifiesto `hooks` se cargan ambos. Para cada evento y su carga útil, consulte [Eventos de hook](/docs/es/hooks#hook-events).
791
792<h4 id="when-plugin-hooks-fire">
793 Cuándo se activan los hooks del plugin
794</h4>
795
796Los hooks de un plugin no esperan a que se use una de las skills o comandos del plugin. Claude Code los registra cuando una sesión carga el plugin, y se activan en sus eventos a partir de entonces. Para limitar cuándo se ejecuta un hook, reduzca su `matcher`.
797
798Si un hook nunca se activa, consulte [hooks que no se activan](/docs/es/plugins/troubleshooting#failed-to-load-hooks-from-and-hooks-that-dont-fire).
799
800<h4 id="environment-quoting-and-matching-mcp-tools">
801 Entorno, entrecomillado y coincidencia de herramientas MCP
802</h4>
803
804El entorno del hook, el entrecomillado de `${CLAUDE_PLUGIN_ROOT}` y los matchers para las herramientas MCP propias del plugin funcionan de la siguiente manera:
805
806* **Entorno**: cada proceso de hook recibe `CLAUDE_PLUGIN_ROOT` y `CLAUDE_PLUGIN_DATA` en su entorno, más `CLAUDE_PLUGIN_OPTION_<KEY>` para cada valor de [configuración del usuario](#user-configuration), para que su script pueda leerlos desde allí
807* **Entrecomillado**: cuando `command` no tiene `args`, se ejecuta a través de un shell, así que envuelva la ruta `${CLAUDE_PLUGIN_ROOT}` entre comillas dobles, como hace el ejemplo `hooks/hooks.json` bajo [Hooks](#hooks), para mantener la ruta expandida como una palabra de shell. Cuando pasa `args` en su lugar, cada elemento se pasa como un argumento sin shell y no necesita entrecomillado. Consulte [forma exec y forma shell](/docs/es/hooks#exec-form-and-shell-form)
808* **Coincidencia de las herramientas MCP propias del plugin**: una herramienta de un [servidor MCP que este plugin declara](#mcp-servers) se llama `mcp__plugin_<plugin>_<server>__<tool>`, así que escriba ese nombre completo en el matcher. Un matcher solo en el nombre del servidor nunca se activa. Consulte [Coincidir herramientas MCP](/docs/es/hooks#match-mcp-tools)
809
810<h3 id="mcp-servers">
811 Servidores MCP
812</h3>
813
814Un servidor MCP proporciona a Claude herramientas de un sistema externo. Declárelo en `.mcp.json` en la raíz del plugin, en la misma forma que un [`.mcp.json` de proyecto](/docs/es/mcp#project-scope). Este `.mcp.json` declara un servidor llamado `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
827También puede omitir el contenedor `mcpServers` y poner `db` en el nivel superior del archivo.
828
829Cargue el plugin y ejecute `/mcp` para confirmar que el servidor aparece como `plugin:my-plugin:db`.
830
831`claude plugin validate` verifica `.mcp.json` e informa una entrada de servidor que Claude Code descartaría en el tiempo de carga como un error. Requiere Claude Code v2.1.281 o posterior.
832
833Para ver dónde aparece una entrada incorrecta en el tiempo de carga, consulte [Servidores MCP que no se inician](/docs/es/plugins/troubleshooting#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start).
834
835La clave de manifiesto `mcpServers` toma un mapa de servidor en línea, una ruta a un archivo JSON, o una matriz de esos. Cuando un servidor de manifiesto tiene el mismo nombre que uno en `.mcp.json`, el servidor de manifiesto lo reemplaza.
836
837<h4 id="reach-users-on-claude-ai-and-cowork">
838 Alcanzar usuarios en claude.ai y Cowork
839</h4>
840
841Un servidor stdio local, como el servidor `db` bajo [Servidores MCP](#mcp-servers), se ejecuta en Claude Code y en una sesión de Cowork que se ejecuta en su máquina en la aplicación Claude Desktop, pero no en claude.ai. Para alcanzar a los usuarios allí también, haga referencia a un servidor remoto por su URL `https://`, que claude.ai y Cowork ofrecen al usuario como un conector.
842
843<h4 id="server-names-tool-names-and-reloads">
844 Nombres de servidor, nombres de herramientas y recargas
845</h4>
846
847Los nombres del servidor, la sustitución de variables y el comportamiento de recarga siguen estas reglas:
848
849* **Nombre del servidor**: `plugin:<plugin>:<server>`, así que el servidor `db` en `my-plugin` es `plugin:my-plugin:db` en `/mcp`. Use la misma forma para nombrar el servidor en un [hook `mcp_tool`](/docs/es/hooks#mcp-tool-hook-fields)
850* **Nombres de herramientas**: `mcp__plugin_<plugin>_<server>__<tool>`, así que una herramienta `query` en ese servidor `db` es `mcp__plugin_my-plugin_db__query`. Ese es el nombre a usar en [reglas de permisos](/docs/es/permissions) y [matchers de hook](#hooks)
851* **Sustitución**: `${CLAUDE_PLUGIN_ROOT}` y las otras [variables de ruta](#path-variables-and-persistent-data) se sustituyen en `command`, `args` y `env`. No se necesita entrecomillado en `args`, porque cada elemento se pasa como un argumento
852* **Recarga**: cuando el usuario ejecuta `/reload-plugins` y [la recarga se aplica](/docs/es/plugins/cli-reference#reloads-that-change-mcp-tools), un servidor cuya configuración no ha cambiado mantiene su conexión. Un servidor cuya configuración cambió se reconecta, y uno que eliminó se desconecta
853
854<h4 id="include-a-packaged-mcpb-server">
855 Incluir un servidor MCPB empaquetado
856</h4>
857
858La clave `mcpServers` también acepta un servidor empaquetado como un [archivo MCPB](https://github.com/modelcontextprotocol/mcpb), cuya extensión es `.mcpb` o la anterior `.dxt`. Apunte la clave al archivo, como una ruta dentro del plugin o una URL `https://`:
859
860```json .claude-plugin/plugin.json theme={null}
861{
862 "name": "my-plugin",
863 "mcpServers": "./servers/db.mcpb"
864}
865```
866
867El servidor toma su nombre del `name` en el manifiesto del paquete.
868
869Para transportes y autenticación, consulte [MCP](/docs/es/mcp#plugin-provided-mcp-servers).
870
871<h3 id="lsp-servers">
872 Servidores LSP
873</h3>
874
875Un servidor LSP proporciona a Claude diagnósticos y navegación de código para un lenguaje. Si un [plugin oficial de inteligencia de código](/docs/es/plugins/code-intelligence) ya cubre su lenguaje, instale ese en su lugar de escribir uno. De lo contrario, declare el servidor en `.lsp.json` en la raíz del 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
889El archivo asigna cada nombre de servidor directamente a su configuración, sin un objeto contenedor alrededor del mapa. `command` es el nombre del binario, con sus argumentos en `args`. `extensionToLanguage` necesita al menos una extensión, cada una comenzando con `.`.
890
891`claude plugin validate` no lee este archivo. Cuando cualquier entrada es inválida, todo el archivo se omite en la carga y `Invalid LSP server config for ".lsp.json"` aparece en la pestaña **Errors** de `/plugin`.
892
893Su plugin configura la conexión pero no instala el binario del servidor, y cada extensión de archivo obtiene un servidor:
894
895* **Binario faltante**: Claude Code inicia `command` por nombre desde el `PATH` del usuario. Cuando el binario no está allí, el servidor falla al iniciarse y `claude --debug` registra `LSP server <name> failed to start`
896* **Conflictos de extensión**: cuando dos servidores habilitados reclaman la misma extensión, el primero registrado maneja esos archivos y el otro no se usa para ellos, ya sea que los servidores provengan de un plugin o dos. La pestaña **Errors** de `/plugin` muestra la advertencia `LSP server "<name>" is not used for <ext> files`
897
898La clave de manifiesto `lspServers` toma el mismo mapa en línea, una ruta a un archivo JSON, o una matriz de esos, y sus servidores se suman a los de `.lsp.json`. Cuando un servidor de manifiesto tiene el mismo nombre que uno en `.lsp.json`, el servidor de manifiesto lo reemplaza.
899
900Para `transport`, tiempos de espera, reinicios y los otros campos, consulte [`lspServers`](/docs/es/plugins/manifest-reference#lspservers).
901
902Envíe la salida de registro a stderr, no a stdout. Claude Code lee el stdout de un servidor solo como mensajes de protocolo, y acepta encabezados de mensaje de hasta 64 KiB y un cuerpo de mensaje de hasta 32 MiB.
903
904Claude Code desconecta un servidor que excede cualquiera de los límites o escribe salida que no es de protocolo a stdout, y cuenta la desconexión como un bloqueo para `restartOnCrash` y `maxRestarts`. Cuando ejecuta con `--debug`, Claude Code escribe un error que nombra la causa en el registro de depuración.
905
906<h3 id="executables">
907 Ejecutables
908</h3>
909
910Los archivos en `bin/` en la raíz del plugin están en el `PATH` del shell de la herramienta Bash mientras el plugin está habilitado, para que Claude pueda ejecutarlos como comandos simples. Agregue un script ejecutable:
911
912```bash bin/hello-plugin theme={null}
913#!/bin/bash
914echo "hello from my-plugin"
915```
916
917Hágalo ejecutable con `chmod +x bin/hello-plugin` y cargue el plugin. Cuando pide a Claude que ejecute `hello-plugin`, el resultado de la herramienta Bash muestra la salida del script.
918
919Los directorios `bin/` del plugin vienen después de las entradas `PATH` propias del usuario, así que un plugin no puede sombrear `git`, `ls` u otro comando del sistema.
920
921claude.ai y Cowork no instalan un plugin que tenga un directorio `bin/` de nivel superior, incluido uno que [distribuya a través de la configuración de la organización de claude.ai](/docs/es/plugins/host-marketplace#distribute-through-organization-settings).
922
923<h3 id="default-settings">
924 Configuración predeterminada
925</h3>
926
927Para establecer valores predeterminados que se apliquen mientras el plugin está habilitado, agregue un `settings.json` en la raíz del plugin, o coloque el mismo objeto en línea en la clave de manifiesto `settings`. Dos claves tienen efecto, `agent` y `subagentStatusLine`, y todas las demás claves se descartan.
928
929Establezca `agent` para ejecutar uno de los agentes propios del plugin como el hilo principal:
930
931```json settings.json theme={null}
932{
933 "agent": "security-reviewer"
934}
935```
936
937Cargue el plugin e inicie una sesión. Claude entonces responde en la conversación principal con el indicador del sistema del agente `security-reviewer` y el modelo.
938
939Para todo lo que controla la clave, consulte la [configuración `agent`](/docs/es/settings-reference#agent).
940
941Cuando la misma clave se establece en más de un lugar, estas reglas deciden qué valor se aplica:
942
943* **Archivo sobre manifiesto**: cuando ambos existen y `settings.json` establece al menos una clave admitida, `settings.json` se aplica y el `settings` del manifiesto se ignora
944* **Configuración del usuario sobre valores predeterminados del plugin**: en todas las fuentes de configuración, los valores predeterminados del plugin son la capa más baja, así que un `agent` propio del usuario en `~/.claude/settings.json` anula el suyo
945* **Dos plugins establecen la misma clave**: el valor del plugin cargado último se aplica, y `claude --debug` registra `overrides setting`
946
947Para la forma `subagentStatusLine`, consulte [líneas de estado de subagente](/docs/es/statusline#subagent-status-lines).
948
949<h3 id="themes-and-output-styles">
950 Temas y estilos de salida
951</h3>
952
953Un plugin puede incluir temas de color y estilos de salida. Ambos aparecen en los mismos selectores que los del usuario. Para cualquiera de los dos, establecer la clave de manifiesto reemplaza el escaneo de carpeta.
954
955| Componente | Guardar como | Formato | Aparece en | Clave de manifiesto |
956| :--------------- | :------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------- | :-------------------- |
957| Tema | `themes/<slug>.json` | El formato de [archivo de tema personalizado](/docs/es/terminal-config#create-a-custom-theme) que los usuarios escriben en `~/.claude/themes/` | `/theme`, bajo el `name` del archivo | `experimental.themes` |
958| Estilo de salida | `output-styles/<name>.md` | El formato de [estilo de salida personalizado](/docs/es/output-styles#create-a-custom-output-style), con frontmatter `name` y `description` | `/output-style`, como `<plugin>:<name>` | `outputStyles` |
959
960Los temas del plugin son de solo lectura, así que cuando un usuario edita uno en `/theme`, la edición se guarda como una copia en su propio directorio de temas.
961
962Este tema recolora el acento del indicador y el texto de error en el preajuste oscuro:
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 Canales
977</h3>
978
979Un [canal](/docs/es/channels) permite que un sistema externo como una aplicación de chat envíe mensajes a una sesión. En un plugin, un canal es uno de los servidores MCP más una entrada `channels` que se vincula a él y puede solicitar su propia configuración. Este manifiesto vincula un canal a un servidor `telegram` y solicita un token 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` debe coincidir con una clave en `mcpServers`. El `userConfig` por canal toma la misma forma que la clave `userConfig` de [nivel superior](#user-configuration).
1008
1009Para lo que el servidor debe implementar y cómo los usuarios habilitan un plugin de canal, consulte [Empaquetar como un plugin](/docs/es/channels-reference#package-as-a-plugin) en la referencia de canales. Para la tabla de campos, consulte [`channels`](/docs/es/plugins/manifest-reference#channels).
1010
1011<h3 id="monitors">
1012 Monitores
1013</h3>
1014
1015Un monitor es un comando de shell que se ejecuta en segundo plano durante toda la sesión. Lo que imprime llega a Claude como notificaciones, para que Claude pueda reaccionar a un registro o un cambio de estado sin que se le pida que lo observe. Guarde las entradas en `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
1027El comando se ejecuta en un shell, en el directorio de trabajo en el que comenzó la sesión.
1028
1029El comando de un monitor está limitado en dónde comienza y qué puede referenciar:
1030
1031* **Solo sesiones interactivas**: los monitores del plugin comienzan en una sesión interactiva y nunca en modo no interactivo con la bandera `-p`. También comienzan solo donde la [herramienta Monitor](/docs/es/tools-reference#monitor-tool) está disponible
1032* **Sin configuración del usuario**: `command` obtiene las [variables de ruta](#path-variables-and-persistent-data) y `${ENV_VAR}` del entorno, pero nunca `${user_config.*}`. Un monitor que hace referencia a uno no comienza, y los procesos de monitor tampoco reciben `CLAUDE_PLUGIN_OPTION_<KEY>`
1033* **Deshabilitación a mitad de sesión**: si deshabilita un plugin a mitad de sesión, Claude Code no detiene los monitores que ya se están ejecutando. Se detienen cuando termina la sesión
1034
1035La clave de manifiesto `experimental.monitors` toma la misma matriz en línea o una ruta a un archivo JSON, y se lee en lugar de `monitors/monitors.json`.
1036
1037Para el disparador `when` y los otros campos, consulte [`monitors`](/docs/es/plugins/manifest-reference#monitors).
1038
1039<h2 id="user-configuration">
1040 Pedir al usuario valores de configuración
1041</h2>
1042
1043Declare los valores que su plugin necesita del usuario en la clave de manifiesto `userConfig`, para que los usuarios no editen `settings.json` ellos mismos. Cada opción aparece en un diálogo con su `title` como etiqueta y su `description` debajo.
1044
1045Establezca `"sensitive": true` para un token o contraseña. El diálogo entonces enmascara la entrada, y el valor se almacena en almacenamiento seguro en lugar de `settings.json`.
1046
1047Este manifiesto solicita un punto final y un token:
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 Cuándo aparece el diálogo de configuración
1070</h3>
1071
1072El diálogo aparece solo en la interfaz interactiva `/plugin`. Se abre para cualquier opción que aún no esté establecida cuando el usuario hace cualquiera de lo siguiente:
1073
1074* Instala el plugin en `/plugin`
1075* Ejecuta `/plugin install <plugin>@<marketplace>` dentro de una sesión
1076* Habilita el plugin desde la pestaña **Installed** en `/plugin`
1077
1078Para abrir el mismo diálogo en cualquier momento, el usuario ejecuta `/plugin configure <plugin>@<marketplace>`.
1079
1080El comando de shell `claude plugin install` nunca solicita valores de `userConfig`. Para establecer valores desde el shell, pase cada uno como `--config KEY=VALUE`. Cuando las opciones permanecen sin establecer, el comando imprime una línea `userConfig options not yet set` que nombra ambas formas de establecerlas. [El diálogo `userConfig` nunca aparece](/docs/es/plugins/troubleshooting#the-userconfig-dialog-never-appears) cita la línea.
1081
1082Para los campos de opción, dónde se almacena cada valor, cómo un componente hace referencia a un valor guardado, y qué campos rechazan `${user_config.*}`, consulte [Configuración del usuario](/docs/es/plugins/manifest-reference#user-configuration).
1083
1084<h2 id="path-variables-and-persistent-data">
1085 Hacer referencia a rutas de plugin y almacenar datos
1086</h2>
1087
1088No sabe dónde se instalará su plugin, así que haga referencia a sus archivos y datos a través de estas variables en lugar de rutas fijas. Se sustituyen en contenido de skill, comando y agente, en comandos de hook y monitor, y en configuraciones de servidor MCP y LSP. También se exportan a procesos de hook, MCP y LSP:
1089
1090* **`${CLAUDE_PLUGIN_ROOT}`**: el directorio de instalación del plugin. Cada versión tiene su propio [directorio de caché](/docs/es/plugins/loading#find-plugins-on-disk), así que la ruta cambia cuando el plugin se actualiza. No escriba estado allí
1091* **`${CLAUDE_PLUGIN_DATA}`**: un directorio que sobrevive a las actualizaciones, para `node_modules`, entornos virtuales y cachés. Se resuelve a `~/.claude/plugins/data/<id>/` y se crea cuando se hace referencia por primera vez
1092* **`${CLAUDE_PROJECT_DIR}`**: la raíz del proyecto, el mismo valor que los hooks reciben
1093
1094En la ruta del directorio de datos, `<id>` es el identificador del plugin con cada carácter que no sea letra, dígito, `_` y `-` reemplazado por `-`, así que `my-plugin@my-marketplace` se convierte en `my-plugin-my-marketplace`.
1095
1096En Windows, las rutas sustituidas usan barras diagonales para que un shell no lea las barras invertidas como escapes.
1097
1098<h3 id="install-dependencies-into-the-data-directory">
1099 Instalar dependencias en el directorio de datos
1100</h3>
1101
1102Para un plugin instalado desde marketplace, Claude Code instala automáticamente [dependencias de paquetes Node.js](/docs/es/plugins/loading#node-js-package-dependencies) elegibles cuando almacena en caché el plugin, así que es posible que no necesite instalarlas usted mismo. Cuando lo hace, este hook `SessionStart` instala `node_modules` en `${CLAUDE_PLUGIN_DATA}` en la primera ejecución y nuevamente después de que una actualización cambie `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
1121Después de la primera sesión, `~/.claude/plugins/data/<id>/node_modules` existe. Un servidor MCP puede entonces establecer `NODE_PATH` a `${CLAUDE_PLUGIN_DATA}/node_modules` en su `env`. Para qué campos sustituyen qué variable, consulte [Variables de entorno](/docs/es/plugins/manifest-reference#environment-variables).
1122
1123<h2 id="next-steps">
1124 Próximos pasos
1125</h2>
1126
1127* [Referencia de manifiesto de plugin](/docs/es/plugins/manifest-reference): campos `plugin.json`, reglas de ruta y el diseño estándar
1128* [Probar plugins con evals](/docs/es/plugin-evals): verifique que los componentes que agregó cambien el comportamiento de Claude de la manera que pretende
1129* [Publicar y distribuir un plugin](/docs/es/plugins/publish): versione el plugin y colóquelo en un marketplace
1130* [Solucionar problemas de plugins](/docs/es/plugins/troubleshooting): qué hacer cuando un componente no se carga o un hook no se activa