claudecode-linter 2.1.148 → 2.1.150-patch.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.claudecode-lint.defaults.yaml +21 -2
  2. package/README.md +90 -3
  3. package/contracts/agent-frontmatter.schema.json +142 -2
  4. package/contracts/command-frontmatter.schema.json +128 -2
  5. package/contracts/hooks.schema.json +275 -0
  6. package/contracts/lsp.schema.json +2 -2
  7. package/contracts/mcp.schema.json +326 -0
  8. package/contracts/monitors.schema.json +3 -3
  9. package/contracts/plugin.schema.json +672 -22
  10. package/contracts/schemastore/keybindings.schema.json +179 -0
  11. package/contracts/schemastore/manifest.json +25 -0
  12. package/contracts/schemastore/marketplace.schema.json +2067 -0
  13. package/contracts/schemastore/plugin-manifest.schema.json +1834 -0
  14. package/contracts/schemastore/settings.schema.json +3062 -0
  15. package/contracts/settings.schema.json +333 -4
  16. package/contracts/skill-frontmatter.schema.json +198 -2
  17. package/dist/config.js +13 -8
  18. package/dist/contracts.js +20 -1
  19. package/dist/discovery.js +23 -0
  20. package/dist/formatters/human.js +3 -2
  21. package/dist/index.js +80 -12
  22. package/dist/linters/agent-md.js +44 -7
  23. package/dist/linters/command-md.js +37 -1
  24. package/dist/linters/hooks-json.js +24 -0
  25. package/dist/linters/keybindings-json.js +53 -0
  26. package/dist/linters/marketplace-json.js +55 -0
  27. package/dist/linters/mcp-json.js +24 -0
  28. package/dist/linters/settings-json.js +42 -15
  29. package/dist/linters/skill-md.js +48 -1
  30. package/dist/plugin-schema.js +96 -39
  31. package/dist/utils/asset-path.js +56 -0
  32. package/dist/utils/effort.js +29 -0
  33. package/dist/utils/frontmatter-keys.js +32 -3
  34. package/dist/utils/frontmatter.js +1 -1
  35. package/dist/utils/safe-write.js +36 -0
  36. package/dist/utils/terminal.js +18 -0
  37. package/package.json +6 -2
@@ -1,6 +1,6 @@
1
1
  {
2
- "extractedFromClaudeCodeVersion": "2.1.138",
3
- "extractedAt": "2026-05-11T08:02:42.909Z",
2
+ "extractedFromClaudeCodeVersion": "2.1.150",
3
+ "extractedAt": "2026-05-23T18:30:08.356Z",
4
4
  "schema": {
5
5
  "$schema": "https://json-schema.org/draft/2020-12/schema",
6
6
  "title": "Claude Code plugin.json",
@@ -15,6 +15,10 @@
15
15
  "minLength": 1,
16
16
  "description": "Unique identifier for the plugin, used for namespacing (prefer kebab-case)"
17
17
  },
18
+ "displayName": {
19
+ "type": "string",
20
+ "description": "Human-readable name shown in UI (e.g., \"GitHub Utils\"). Falls back to `name` when omitted. Unlike `name`, may contain spaces and any casing; not used for namespacing or lookup."
21
+ },
18
22
  "version": {
19
23
  "type": "string",
20
24
  "description": "Semantic version (e.g., 1.2.3) following semver.org specification"
@@ -101,6 +105,264 @@
101
105
  "description": "Path to file with additional hooks (in addition to those in hooks/hooks.json, if it exists), relative to the plugin root"
102
106
  },
103
107
  {
108
+ "type": "object",
109
+ "additionalProperties": {
110
+ "type": "array",
111
+ "items": {
112
+ "type": "object",
113
+ "properties": {
114
+ "matcher": {
115
+ "type": "string",
116
+ "description": "String pattern to match (e.g. tool names like \"Write\")"
117
+ },
118
+ "hooks": {
119
+ "type": "array",
120
+ "items": {
121
+ "oneOf": [
122
+ {
123
+ "type": "object",
124
+ "properties": {
125
+ "type": {
126
+ "const": "command",
127
+ "description": "Shell command hook type"
128
+ },
129
+ "command": {
130
+ "type": "string",
131
+ "description": "Shell command to execute"
132
+ },
133
+ "args": {
134
+ "type": "array",
135
+ "items": {
136
+ "type": "string"
137
+ },
138
+ "description": "Argument list for exec form. When present, `command` is resolved as \"+\"an executable and spawned directly with these arguments \\u2014 no shell. \"+\"Path placeholders like ${CLAUDE_PLUGIN_ROOT} are substituted per-element as plain strings, so paths with quotes, $, or backticks never reach a shell parser. When absent, `command` runs through a shell (bash on POSIX, PowerShell on Windows without Git Bash)."
139
+ },
140
+ "if": {
141
+ "type": "string",
142
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
143
+ },
144
+ "shell": {
145
+ "enum": [
146
+ "bash",
147
+ "powershell"
148
+ ],
149
+ "description": "Shell interpreter. 'bash' uses your $SHELL (bash/zsh/sh); 'powershell' uses pwsh. Defaults to bash (powershell on Windows without Git Bash)."
150
+ },
151
+ "timeout": {
152
+ "type": "number",
153
+ "description": "Timeout in seconds for this specific command"
154
+ },
155
+ "statusMessage": {
156
+ "type": "string",
157
+ "description": "Custom status message to display in spinner while hook runs"
158
+ },
159
+ "once": {
160
+ "type": "boolean",
161
+ "description": "If true, hook runs once and is removed after execution"
162
+ },
163
+ "async": {
164
+ "type": "boolean",
165
+ "description": "If true, hook runs in background without blocking"
166
+ },
167
+ "asyncRewake": {
168
+ "type": "boolean",
169
+ "description": "If true, hook runs in background and wakes the model on exit code 2 (blocking error). Implies async."
170
+ },
171
+ "rewakeMessage": {
172
+ "type": "string",
173
+ "minLength": 1,
174
+ "description": "@internal Custom prefix for the system-reminder shown to the model when an asyncRewake hook exits with code 2. The hook output is appended after this prefix."
175
+ },
176
+ "rewakeSummary": {
177
+ "type": "string",
178
+ "minLength": 1,
179
+ "description": "@internal One-line summary shown to the user in the terminal when an asyncRewake hook exits with code 2. Defaults to \"Stop hook feedback\"."
180
+ }
181
+ },
182
+ "required": [
183
+ "type",
184
+ "command"
185
+ ]
186
+ },
187
+ {
188
+ "type": "object",
189
+ "properties": {
190
+ "type": {
191
+ "const": "prompt",
192
+ "description": "LLM prompt hook type"
193
+ },
194
+ "prompt": {
195
+ "type": "string",
196
+ "description": "Prompt to evaluate with LLM. Use $ARGUMENTS placeholder for hook input JSON."
197
+ },
198
+ "if": {
199
+ "type": "string",
200
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
201
+ },
202
+ "timeout": {
203
+ "type": "number",
204
+ "description": "Timeout in seconds for this specific prompt evaluation"
205
+ },
206
+ "model": {
207
+ "type": "string",
208
+ "description": "Model to use for this prompt hook (e.g., \"claude-sonnet-4-6\"). If not specified, uses the default small fast model."
209
+ },
210
+ "continueOnBlock": {
211
+ "type": "boolean",
212
+ "description": "`Sets the continue value for the decision:\"block\" produced when ok is false. Default false (turn ends). Whether continue:true lets the turn proceed depends on the event's decision:\"block\" semantics. On PostToolUse, the reason is fed back to Claude and the turn continues.`"
213
+ },
214
+ "statusMessage": {
215
+ "type": "string",
216
+ "description": "Custom status message to display in spinner while hook runs"
217
+ },
218
+ "once": {
219
+ "type": "boolean",
220
+ "description": "If true, hook runs once and is removed after execution"
221
+ }
222
+ },
223
+ "required": [
224
+ "type",
225
+ "prompt"
226
+ ]
227
+ },
228
+ {
229
+ "type": "object",
230
+ "properties": {
231
+ "type": {
232
+ "const": "agent",
233
+ "description": "Agentic verifier hook type"
234
+ },
235
+ "prompt": {
236
+ "type": "string",
237
+ "description": "Prompt describing what to verify (e.g. \"Verify that unit tests ran and passed.\"). Use $ARGUMENTS placeholder for hook input JSON."
238
+ },
239
+ "if": {
240
+ "type": "string",
241
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
242
+ },
243
+ "timeout": {
244
+ "type": "number",
245
+ "description": "Timeout in seconds for agent execution (default 60)"
246
+ },
247
+ "model": {
248
+ "type": "string",
249
+ "description": "Model to use for this agent hook (e.g., \"claude-sonnet-4-6\"). If not specified, uses Haiku."
250
+ },
251
+ "statusMessage": {
252
+ "type": "string",
253
+ "description": "Custom status message to display in spinner while hook runs"
254
+ },
255
+ "once": {
256
+ "type": "boolean",
257
+ "description": "If true, hook runs once and is removed after execution"
258
+ }
259
+ },
260
+ "required": [
261
+ "type",
262
+ "prompt"
263
+ ]
264
+ },
265
+ {
266
+ "type": "object",
267
+ "properties": {
268
+ "type": {
269
+ "const": "http",
270
+ "description": "HTTP hook type"
271
+ },
272
+ "url": {
273
+ "type": "string",
274
+ "format": "uri",
275
+ "description": "URL to POST the hook input JSON to"
276
+ },
277
+ "if": {
278
+ "type": "string",
279
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
280
+ },
281
+ "timeout": {
282
+ "type": "number",
283
+ "description": "Timeout in seconds for this specific request"
284
+ },
285
+ "headers": {
286
+ "type": "object",
287
+ "additionalProperties": {
288
+ "type": "string"
289
+ },
290
+ "description": "Additional headers to include in the request. Values may reference environment variables using $VAR_NAME or ${VAR_NAME} syntax (e.g., \"Authorization\": \"Bearer $MY_TOKEN\"). Only variables listed in allowedEnvVars will be interpolated."
291
+ },
292
+ "allowedEnvVars": {
293
+ "type": "array",
294
+ "items": {
295
+ "type": "string"
296
+ },
297
+ "description": "Explicit list of environment variable names that may be interpolated in header values. Only variables listed here will be resolved; all other $VAR references are left as empty strings. Required for env var interpolation to work."
298
+ },
299
+ "statusMessage": {
300
+ "type": "string",
301
+ "description": "Custom status message to display in spinner while hook runs"
302
+ },
303
+ "once": {
304
+ "type": "boolean",
305
+ "description": "If true, hook runs once and is removed after execution"
306
+ }
307
+ },
308
+ "required": [
309
+ "type",
310
+ "url"
311
+ ]
312
+ },
313
+ {
314
+ "type": "object",
315
+ "properties": {
316
+ "type": {
317
+ "const": "mcp_tool",
318
+ "description": "MCP tool hook type"
319
+ },
320
+ "server": {
321
+ "type": "string",
322
+ "description": "Name of an already-configured MCP server to invoke"
323
+ },
324
+ "tool": {
325
+ "type": "string",
326
+ "description": "Name of the tool on that server to call"
327
+ },
328
+ "input": {
329
+ "type": "object",
330
+ "additionalProperties": {},
331
+ "description": "Arguments passed to the MCP tool. String values support ${path} interpolation from the hook input JSON (e.g. \"${tool_input.file_path}\")."
332
+ },
333
+ "if": {
334
+ "type": "string",
335
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
336
+ },
337
+ "timeout": {
338
+ "type": "number",
339
+ "description": "Timeout in seconds for this specific tool call"
340
+ },
341
+ "statusMessage": {
342
+ "type": "string",
343
+ "description": "Custom status message to display in spinner while hook runs"
344
+ },
345
+ "once": {
346
+ "type": "boolean",
347
+ "description": "If true, hook runs once and is removed after execution"
348
+ }
349
+ },
350
+ "required": [
351
+ "type",
352
+ "server",
353
+ "tool"
354
+ ]
355
+ }
356
+ ]
357
+ },
358
+ "description": "List of hooks to execute when the matcher matches"
359
+ }
360
+ },
361
+ "required": [
362
+ "hooks"
363
+ ]
364
+ }
365
+ },
104
366
  "description": "Additional hooks (in addition to those in hooks/hooks.json, if it exists)"
105
367
  },
106
368
  {
@@ -112,6 +374,264 @@
112
374
  "description": "Path to file with additional hooks (in addition to those in hooks/hooks.json, if it exists), relative to the plugin root"
113
375
  },
114
376
  {
377
+ "type": "object",
378
+ "additionalProperties": {
379
+ "type": "array",
380
+ "items": {
381
+ "type": "object",
382
+ "properties": {
383
+ "matcher": {
384
+ "type": "string",
385
+ "description": "String pattern to match (e.g. tool names like \"Write\")"
386
+ },
387
+ "hooks": {
388
+ "type": "array",
389
+ "items": {
390
+ "oneOf": [
391
+ {
392
+ "type": "object",
393
+ "properties": {
394
+ "type": {
395
+ "const": "command",
396
+ "description": "Shell command hook type"
397
+ },
398
+ "command": {
399
+ "type": "string",
400
+ "description": "Shell command to execute"
401
+ },
402
+ "args": {
403
+ "type": "array",
404
+ "items": {
405
+ "type": "string"
406
+ },
407
+ "description": "Argument list for exec form. When present, `command` is resolved as \"+\"an executable and spawned directly with these arguments \\u2014 no shell. \"+\"Path placeholders like ${CLAUDE_PLUGIN_ROOT} are substituted per-element as plain strings, so paths with quotes, $, or backticks never reach a shell parser. When absent, `command` runs through a shell (bash on POSIX, PowerShell on Windows without Git Bash)."
408
+ },
409
+ "if": {
410
+ "type": "string",
411
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
412
+ },
413
+ "shell": {
414
+ "enum": [
415
+ "bash",
416
+ "powershell"
417
+ ],
418
+ "description": "Shell interpreter. 'bash' uses your $SHELL (bash/zsh/sh); 'powershell' uses pwsh. Defaults to bash (powershell on Windows without Git Bash)."
419
+ },
420
+ "timeout": {
421
+ "type": "number",
422
+ "description": "Timeout in seconds for this specific command"
423
+ },
424
+ "statusMessage": {
425
+ "type": "string",
426
+ "description": "Custom status message to display in spinner while hook runs"
427
+ },
428
+ "once": {
429
+ "type": "boolean",
430
+ "description": "If true, hook runs once and is removed after execution"
431
+ },
432
+ "async": {
433
+ "type": "boolean",
434
+ "description": "If true, hook runs in background without blocking"
435
+ },
436
+ "asyncRewake": {
437
+ "type": "boolean",
438
+ "description": "If true, hook runs in background and wakes the model on exit code 2 (blocking error). Implies async."
439
+ },
440
+ "rewakeMessage": {
441
+ "type": "string",
442
+ "minLength": 1,
443
+ "description": "@internal Custom prefix for the system-reminder shown to the model when an asyncRewake hook exits with code 2. The hook output is appended after this prefix."
444
+ },
445
+ "rewakeSummary": {
446
+ "type": "string",
447
+ "minLength": 1,
448
+ "description": "@internal One-line summary shown to the user in the terminal when an asyncRewake hook exits with code 2. Defaults to \"Stop hook feedback\"."
449
+ }
450
+ },
451
+ "required": [
452
+ "type",
453
+ "command"
454
+ ]
455
+ },
456
+ {
457
+ "type": "object",
458
+ "properties": {
459
+ "type": {
460
+ "const": "prompt",
461
+ "description": "LLM prompt hook type"
462
+ },
463
+ "prompt": {
464
+ "type": "string",
465
+ "description": "Prompt to evaluate with LLM. Use $ARGUMENTS placeholder for hook input JSON."
466
+ },
467
+ "if": {
468
+ "type": "string",
469
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
470
+ },
471
+ "timeout": {
472
+ "type": "number",
473
+ "description": "Timeout in seconds for this specific prompt evaluation"
474
+ },
475
+ "model": {
476
+ "type": "string",
477
+ "description": "Model to use for this prompt hook (e.g., \"claude-sonnet-4-6\"). If not specified, uses the default small fast model."
478
+ },
479
+ "continueOnBlock": {
480
+ "type": "boolean",
481
+ "description": "`Sets the continue value for the decision:\"block\" produced when ok is false. Default false (turn ends). Whether continue:true lets the turn proceed depends on the event's decision:\"block\" semantics. On PostToolUse, the reason is fed back to Claude and the turn continues.`"
482
+ },
483
+ "statusMessage": {
484
+ "type": "string",
485
+ "description": "Custom status message to display in spinner while hook runs"
486
+ },
487
+ "once": {
488
+ "type": "boolean",
489
+ "description": "If true, hook runs once and is removed after execution"
490
+ }
491
+ },
492
+ "required": [
493
+ "type",
494
+ "prompt"
495
+ ]
496
+ },
497
+ {
498
+ "type": "object",
499
+ "properties": {
500
+ "type": {
501
+ "const": "agent",
502
+ "description": "Agentic verifier hook type"
503
+ },
504
+ "prompt": {
505
+ "type": "string",
506
+ "description": "Prompt describing what to verify (e.g. \"Verify that unit tests ran and passed.\"). Use $ARGUMENTS placeholder for hook input JSON."
507
+ },
508
+ "if": {
509
+ "type": "string",
510
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
511
+ },
512
+ "timeout": {
513
+ "type": "number",
514
+ "description": "Timeout in seconds for agent execution (default 60)"
515
+ },
516
+ "model": {
517
+ "type": "string",
518
+ "description": "Model to use for this agent hook (e.g., \"claude-sonnet-4-6\"). If not specified, uses Haiku."
519
+ },
520
+ "statusMessage": {
521
+ "type": "string",
522
+ "description": "Custom status message to display in spinner while hook runs"
523
+ },
524
+ "once": {
525
+ "type": "boolean",
526
+ "description": "If true, hook runs once and is removed after execution"
527
+ }
528
+ },
529
+ "required": [
530
+ "type",
531
+ "prompt"
532
+ ]
533
+ },
534
+ {
535
+ "type": "object",
536
+ "properties": {
537
+ "type": {
538
+ "const": "http",
539
+ "description": "HTTP hook type"
540
+ },
541
+ "url": {
542
+ "type": "string",
543
+ "format": "uri",
544
+ "description": "URL to POST the hook input JSON to"
545
+ },
546
+ "if": {
547
+ "type": "string",
548
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
549
+ },
550
+ "timeout": {
551
+ "type": "number",
552
+ "description": "Timeout in seconds for this specific request"
553
+ },
554
+ "headers": {
555
+ "type": "object",
556
+ "additionalProperties": {
557
+ "type": "string"
558
+ },
559
+ "description": "Additional headers to include in the request. Values may reference environment variables using $VAR_NAME or ${VAR_NAME} syntax (e.g., \"Authorization\": \"Bearer $MY_TOKEN\"). Only variables listed in allowedEnvVars will be interpolated."
560
+ },
561
+ "allowedEnvVars": {
562
+ "type": "array",
563
+ "items": {
564
+ "type": "string"
565
+ },
566
+ "description": "Explicit list of environment variable names that may be interpolated in header values. Only variables listed here will be resolved; all other $VAR references are left as empty strings. Required for env var interpolation to work."
567
+ },
568
+ "statusMessage": {
569
+ "type": "string",
570
+ "description": "Custom status message to display in spinner while hook runs"
571
+ },
572
+ "once": {
573
+ "type": "boolean",
574
+ "description": "If true, hook runs once and is removed after execution"
575
+ }
576
+ },
577
+ "required": [
578
+ "type",
579
+ "url"
580
+ ]
581
+ },
582
+ {
583
+ "type": "object",
584
+ "properties": {
585
+ "type": {
586
+ "const": "mcp_tool",
587
+ "description": "MCP tool hook type"
588
+ },
589
+ "server": {
590
+ "type": "string",
591
+ "description": "Name of an already-configured MCP server to invoke"
592
+ },
593
+ "tool": {
594
+ "type": "string",
595
+ "description": "Name of the tool on that server to call"
596
+ },
597
+ "input": {
598
+ "type": "object",
599
+ "additionalProperties": {},
600
+ "description": "Arguments passed to the MCP tool. String values support ${path} interpolation from the hook input JSON (e.g. \"${tool_input.file_path}\")."
601
+ },
602
+ "if": {
603
+ "type": "string",
604
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
605
+ },
606
+ "timeout": {
607
+ "type": "number",
608
+ "description": "Timeout in seconds for this specific tool call"
609
+ },
610
+ "statusMessage": {
611
+ "type": "string",
612
+ "description": "Custom status message to display in spinner while hook runs"
613
+ },
614
+ "once": {
615
+ "type": "boolean",
616
+ "description": "If true, hook runs once and is removed after execution"
617
+ }
618
+ },
619
+ "required": [
620
+ "type",
621
+ "server",
622
+ "tool"
623
+ ]
624
+ }
625
+ ]
626
+ },
627
+ "description": "List of hooks to execute when the matcher matches"
628
+ }
629
+ },
630
+ "required": [
631
+ "hooks"
632
+ ]
633
+ }
634
+ },
115
635
  "description": "Additional hooks (in addition to those in hooks/hooks.json, if it exists)"
116
636
  }
117
637
  ]
@@ -130,7 +650,7 @@
130
650
  "type": "string"
131
651
  }
132
652
  ],
133
- "description": "Path to additional command file or skill directory (in addition to those in the commands/ directory, if it exists), relative to the plugin root"
653
+ "description": "Path to a command file or skill directory, relative to the plugin root. When set, the commands/ directory is not auto-loaded list its files here if you want both."
134
654
  },
135
655
  {
136
656
  "type": "array",
@@ -143,9 +663,9 @@
143
663
  "type": "string"
144
664
  }
145
665
  ],
146
- "description": "Path to additional command file or skill directory (in addition to those in the commands/ directory, if it exists), relative to the plugin root"
666
+ "description": "Path to a command file or skill directory, relative to the plugin root. When set, the commands/ directory is not auto-loaded list its files here if you want both."
147
667
  },
148
- "description": "List of paths to additional command files or skill directories"
668
+ "description": "List of command file or skill directory paths. When set, the commands/ directory is not auto-loaded."
149
669
  },
150
670
  {
151
671
  "type": "object",
@@ -196,15 +716,15 @@
196
716
  "anyOf": [
197
717
  {
198
718
  "type": "string",
199
- "description": "Path to additional agent file (in addition to those in the agents/ directory, if it exists), relative to the plugin root"
719
+ "description": "Path to an agent file, relative to the plugin root. When set, the agents/ directory is not auto-loaded list its files here if you want both."
200
720
  },
201
721
  {
202
722
  "type": "array",
203
723
  "items": {
204
724
  "type": "string",
205
- "description": "Path to additional agent file (in addition to those in the agents/ directory, if it exists), relative to the plugin root"
725
+ "description": "Path to an agent file, relative to the plugin root. When set, the agents/ directory is not auto-loaded list its files here if you want both."
206
726
  },
207
- "description": "List of paths to additional agent files"
727
+ "description": "List of agent file paths. When set, the agents/ directory is not auto-loaded."
208
728
  }
209
729
  ]
210
730
  },
@@ -212,15 +732,15 @@
212
732
  "anyOf": [
213
733
  {
214
734
  "type": "string",
215
- "description": "Path to additional skill directory (in addition to those in the skills/ directory, if it exists), relative to the plugin root"
735
+ "description": "Path to a skill directory, relative to the plugin root. Loaded in addition to the skills/ directory."
216
736
  },
217
737
  {
218
738
  "type": "array",
219
739
  "items": {
220
740
  "type": "string",
221
- "description": "Path to additional skill directory (in addition to those in the skills/ directory, if it exists), relative to the plugin root"
741
+ "description": "Path to a skill directory, relative to the plugin root. Loaded in addition to the skills/ directory."
222
742
  },
223
- "description": "List of paths to additional skill directories"
743
+ "description": "List of skill directory paths, loaded in addition to the skills/ directory."
224
744
  }
225
745
  ]
226
746
  },
@@ -228,15 +748,15 @@
228
748
  "anyOf": [
229
749
  {
230
750
  "type": "string",
231
- "description": "Path to additional output styles directory or file (in addition to those in the output-styles/ directory, if it exists), relative to the plugin root"
751
+ "description": "Path to an output-styles directory or file, relative to the plugin root. When set, the output-styles/ directory is not auto-loaded list its files here if you want both."
232
752
  },
233
753
  {
234
754
  "type": "array",
235
755
  "items": {
236
756
  "type": "string",
237
- "description": "Path to additional output styles directory or file (in addition to those in the output-styles/ directory, if it exists), relative to the plugin root"
757
+ "description": "Path to an output-styles directory or file, relative to the plugin root. When set, the output-styles/ directory is not auto-loaded list its files here if you want both."
238
758
  },
239
- "description": "List of paths to additional output styles directories or files"
759
+ "description": "List of output-style directory or file paths. When set, the output-styles/ directory is not auto-loaded."
240
760
  }
241
761
  ]
242
762
  },
@@ -244,15 +764,31 @@
244
764
  "anyOf": [
245
765
  {
246
766
  "type": "string",
247
- "description": "Path to additional themes directory or file (in addition to those in the themes/ directory, if it exists), relative to the plugin root"
767
+ "description": "Path to a themes directory or file, relative to the plugin root. When set, the themes/ directory is not auto-loaded list its files here if you want both."
248
768
  },
249
769
  {
250
770
  "type": "array",
251
771
  "items": {
252
772
  "type": "string",
253
- "description": "Path to additional themes directory or file (in addition to those in the themes/ directory, if it exists), relative to the plugin root"
773
+ "description": "Path to a themes directory or file, relative to the plugin root. When set, the themes/ directory is not auto-loaded list its files here if you want both."
254
774
  },
255
- "description": "List of paths to additional themes directories or files"
775
+ "description": "List of theme directory or file paths. When set, the themes/ directory is not auto-loaded."
776
+ }
777
+ ]
778
+ },
779
+ "workflows": {
780
+ "anyOf": [
781
+ {
782
+ "type": "string",
783
+ "description": "Path to a workflows directory or .js file, relative to the plugin root. When set, the workflows/ directory is not auto-loaded — list its files here if you want both."
784
+ },
785
+ {
786
+ "type": "array",
787
+ "items": {
788
+ "type": "string",
789
+ "description": "Path to a workflows directory or .js file, relative to the plugin root. When set, the workflows/ directory is not auto-loaded — list its files here if you want both."
790
+ },
791
+ "description": "List of workflow directory or .js file paths. When set, the workflows/ directory is not auto-loaded."
256
792
  }
257
793
  ]
258
794
  },
@@ -398,8 +934,14 @@
398
934
  "type": "string"
399
935
  }
400
936
  },
937
+ "timeout": {
938
+ "type": "number"
939
+ },
401
940
  "alwaysLoad": {
402
941
  "type": "boolean"
942
+ },
943
+ "role": {
944
+ "const": "comms"
403
945
  }
404
946
  },
405
947
  "required": [
@@ -446,8 +988,14 @@
446
988
  }
447
989
  }
448
990
  },
991
+ "timeout": {
992
+ "type": "number"
993
+ },
449
994
  "alwaysLoad": {
450
995
  "type": "boolean"
996
+ },
997
+ "role": {
998
+ "const": "comms"
451
999
  }
452
1000
  },
453
1001
  "required": [
@@ -470,8 +1018,14 @@
470
1018
  "ideRunningInWindows": {
471
1019
  "type": "boolean"
472
1020
  },
1021
+ "timeout": {
1022
+ "type": "number"
1023
+ },
473
1024
  "alwaysLoad": {
474
1025
  "type": "boolean"
1026
+ },
1027
+ "role": {
1028
+ "const": "comms"
475
1029
  }
476
1030
  },
477
1031
  "required": [
@@ -498,8 +1052,14 @@
498
1052
  "ideRunningInWindows": {
499
1053
  "type": "boolean"
500
1054
  },
1055
+ "timeout": {
1056
+ "type": "number"
1057
+ },
501
1058
  "alwaysLoad": {
502
1059
  "type": "boolean"
1060
+ },
1061
+ "role": {
1062
+ "const": "comms"
503
1063
  }
504
1064
  },
505
1065
  "required": [
@@ -551,8 +1111,14 @@
551
1111
  }
552
1112
  }
553
1113
  },
1114
+ "timeout": {
1115
+ "type": "number"
1116
+ },
554
1117
  "alwaysLoad": {
555
1118
  "type": "boolean"
1119
+ },
1120
+ "role": {
1121
+ "const": "comms"
556
1122
  }
557
1123
  },
558
1124
  "required": [
@@ -578,8 +1144,14 @@
578
1144
  "headersHelper": {
579
1145
  "type": "string"
580
1146
  },
1147
+ "timeout": {
1148
+ "type": "number"
1149
+ },
581
1150
  "alwaysLoad": {
582
1151
  "type": "boolean"
1152
+ },
1153
+ "role": {
1154
+ "const": "comms"
583
1155
  }
584
1156
  },
585
1157
  "required": [
@@ -596,6 +1168,9 @@
596
1168
  "name": {
597
1169
  "type": "string"
598
1170
  },
1171
+ "timeout": {
1172
+ "type": "number"
1173
+ },
599
1174
  "alwaysLoad": {
600
1175
  "type": "boolean"
601
1176
  }
@@ -617,6 +1192,9 @@
617
1192
  "id": {
618
1193
  "type": "string"
619
1194
  },
1195
+ "timeout": {
1196
+ "type": "number"
1197
+ },
620
1198
  "alwaysLoad": {
621
1199
  "type": "boolean"
622
1200
  },
@@ -690,8 +1268,14 @@
690
1268
  "type": "string"
691
1269
  }
692
1270
  },
1271
+ "timeout": {
1272
+ "type": "number"
1273
+ },
693
1274
  "alwaysLoad": {
694
1275
  "type": "boolean"
1276
+ },
1277
+ "role": {
1278
+ "const": "comms"
695
1279
  }
696
1280
  },
697
1281
  "required": [
@@ -738,8 +1322,14 @@
738
1322
  }
739
1323
  }
740
1324
  },
1325
+ "timeout": {
1326
+ "type": "number"
1327
+ },
741
1328
  "alwaysLoad": {
742
1329
  "type": "boolean"
1330
+ },
1331
+ "role": {
1332
+ "const": "comms"
743
1333
  }
744
1334
  },
745
1335
  "required": [
@@ -762,8 +1352,14 @@
762
1352
  "ideRunningInWindows": {
763
1353
  "type": "boolean"
764
1354
  },
1355
+ "timeout": {
1356
+ "type": "number"
1357
+ },
765
1358
  "alwaysLoad": {
766
1359
  "type": "boolean"
1360
+ },
1361
+ "role": {
1362
+ "const": "comms"
767
1363
  }
768
1364
  },
769
1365
  "required": [
@@ -790,8 +1386,14 @@
790
1386
  "ideRunningInWindows": {
791
1387
  "type": "boolean"
792
1388
  },
1389
+ "timeout": {
1390
+ "type": "number"
1391
+ },
793
1392
  "alwaysLoad": {
794
1393
  "type": "boolean"
1394
+ },
1395
+ "role": {
1396
+ "const": "comms"
795
1397
  }
796
1398
  },
797
1399
  "required": [
@@ -843,8 +1445,14 @@
843
1445
  }
844
1446
  }
845
1447
  },
1448
+ "timeout": {
1449
+ "type": "number"
1450
+ },
846
1451
  "alwaysLoad": {
847
1452
  "type": "boolean"
1453
+ },
1454
+ "role": {
1455
+ "const": "comms"
848
1456
  }
849
1457
  },
850
1458
  "required": [
@@ -870,8 +1478,14 @@
870
1478
  "headersHelper": {
871
1479
  "type": "string"
872
1480
  },
1481
+ "timeout": {
1482
+ "type": "number"
1483
+ },
873
1484
  "alwaysLoad": {
874
1485
  "type": "boolean"
1486
+ },
1487
+ "role": {
1488
+ "const": "comms"
875
1489
  }
876
1490
  },
877
1491
  "required": [
@@ -888,6 +1502,9 @@
888
1502
  "name": {
889
1503
  "type": "string"
890
1504
  },
1505
+ "timeout": {
1506
+ "type": "number"
1507
+ },
891
1508
  "alwaysLoad": {
892
1509
  "type": "boolean"
893
1510
  }
@@ -909,6 +1526,9 @@
909
1526
  "id": {
910
1527
  "type": "string"
911
1528
  },
1529
+ "timeout": {
1530
+ "type": "number"
1531
+ },
912
1532
  "alwaysLoad": {
913
1533
  "type": "boolean"
914
1534
  },
@@ -1130,7 +1750,7 @@
1130
1750
  "command": {
1131
1751
  "type": "string",
1132
1752
  "minLength": 1,
1133
- "description": "Shell command to run as a persistent background monitor. Each stdout line is delivered to the model as a <task_notification> event; the process runs for the session lifetime. ${CLAUDE_PLUGIN_ROOT}, ${CLAUDE_PLUGIN_DATA}, ${user_config.*}, and ${ENV_VAR} are substituted. Runs in the session cwd \\u2014 prefix with `cd \"${CLAUDE_PLUGIN_ROOT}\" && ` if the script needs its own directory."
1753
+ "description": "Shell command to run as a persistent background monitor. Each stdout line is delivered to the model as a <task_notification> event; the process runs for the session lifetime. ${CLAUDE_PLUGIN_ROOT}, ${CLAUDE_PLUGIN_DATA}, ${CLAUDE_PROJECT_DIR}, ${user_config.*}, and ${ENV_VAR} are substituted. Runs in the session cwd \\u2014 prefix with `cd \"${CLAUDE_PLUGIN_ROOT}\" && ` if the script needs its own directory."
1134
1754
  },
1135
1755
  "description": {
1136
1756
  "type": "string",
@@ -1246,15 +1866,15 @@
1246
1866
  "anyOf": [
1247
1867
  {
1248
1868
  "type": "string",
1249
- "description": "Path to additional themes directory or file (in addition to those in the themes/ directory, if it exists), relative to the plugin root"
1869
+ "description": "Path to a themes directory or file, relative to the plugin root. When set, the themes/ directory is not auto-loaded list its files here if you want both."
1250
1870
  },
1251
1871
  {
1252
1872
  "type": "array",
1253
1873
  "items": {
1254
1874
  "type": "string",
1255
- "description": "Path to additional themes directory or file (in addition to those in the themes/ directory, if it exists), relative to the plugin root"
1875
+ "description": "Path to a themes directory or file, relative to the plugin root. When set, the themes/ directory is not auto-loaded list its files here if you want both."
1256
1876
  },
1257
- "description": "List of paths to additional themes directories or files"
1877
+ "description": "List of theme directory or file paths. When set, the themes/ directory is not auto-loaded."
1258
1878
  }
1259
1879
  ]
1260
1880
  },
@@ -1277,7 +1897,7 @@
1277
1897
  "command": {
1278
1898
  "type": "string",
1279
1899
  "minLength": 1,
1280
- "description": "Shell command to run as a persistent background monitor. Each stdout line is delivered to the model as a <task_notification> event; the process runs for the session lifetime. ${CLAUDE_PLUGIN_ROOT}, ${CLAUDE_PLUGIN_DATA}, ${user_config.*}, and ${ENV_VAR} are substituted. Runs in the session cwd \\u2014 prefix with `cd \"${CLAUDE_PLUGIN_ROOT}\" && ` if the script needs its own directory."
1900
+ "description": "Shell command to run as a persistent background monitor. Each stdout line is delivered to the model as a <task_notification> event; the process runs for the session lifetime. ${CLAUDE_PLUGIN_ROOT}, ${CLAUDE_PLUGIN_DATA}, ${CLAUDE_PROJECT_DIR}, ${user_config.*}, and ${ENV_VAR} are substituted. Runs in the session cwd \\u2014 prefix with `cd \"${CLAUDE_PLUGIN_ROOT}\" && ` if the script needs its own directory."
1281
1901
  },
1282
1902
  "description": {
1283
1903
  "type": "string",
@@ -1307,6 +1927,36 @@
1307
1927
  }
1308
1928
  ],
1309
1929
  "description": "Background watch scripts the host arms as persistent Monitor tasks (unsandboxed, same trust tier as hooks) so plugins need not instruct the model to arm them. When omitted, monitors/monitors.json at the plugin root is loaded if present."
1930
+ },
1931
+ "outputStyles": {
1932
+ "anyOf": [
1933
+ {
1934
+ "type": "string",
1935
+ "description": "Path to an output-styles directory or file, relative to the plugin root. When set, the output-styles/ directory is not auto-loaded — list its files here if you want both."
1936
+ },
1937
+ {
1938
+ "type": "array",
1939
+ "items": {
1940
+ "type": "string",
1941
+ "description": "Path to an output-styles directory or file, relative to the plugin root. When set, the output-styles/ directory is not auto-loaded — list its files here if you want both."
1942
+ },
1943
+ "description": "List of output-style directory or file paths. When set, the output-styles/ directory is not auto-loaded."
1944
+ }
1945
+ ]
1946
+ },
1947
+ "evals": {
1948
+ "anyOf": [
1949
+ {
1950
+ "type": "string"
1951
+ },
1952
+ {
1953
+ "type": "array",
1954
+ "items": {
1955
+ "type": "string"
1956
+ }
1957
+ }
1958
+ ],
1959
+ "description": "Path(s) to evaluation query files for `claude plugin eval`. Defaults to `evals/`."
1310
1960
  }
1311
1961
  },
1312
1962
  "description": "Components whose manifest shape may change without a deprecation cycle. Move a key out of here once it is promoted to stable."