
Triggering Reliability
- 52 installs
- 50 repo stars
- Updated June 18, 2026
- josiahsiegel/claude-plugin-marketplace
Helps with ai & agent building tasks.
About
triggering-reliability is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- triggering-reliability
- AI & Agent Building
- AI-coding skill
Triggering Reliability by the numbers
- 52 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #7,086 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill triggering-reliabilityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 52 |
|---|---|
| repo stars | ★ 50 |
| Last updated | June 18, 2026 |
| Repository | josiahsiegel/claude-plugin-marketplace ↗ |
What it does
Helps with ai & agent building tasks.
Files
Common mistakes that break triggering
This skill is the reference catalog of everything that makes Claude Code agents and skills fail to trigger. Every mistake below has been observed in real plugins. Treat this as a checklist before shipping any plugin, and as the first place to look when an existing plugin installed fine but nothing happens.
Quick triage: symptoms to likely cause
| Symptom | Most-likely cause |
|---|---|
| Skill directory exists but never loads | Missing YAML frontmatter (file starts with # not ---) |
| Agent file exists but cannot be invoked by name | Deprecated agent: true flag with no name: field |
| Agent rarely triggers despite obvious queries | Missing <example> blocks or abstract-capability description |
| Skill triggers inconsistently | Description describes WHAT it does, not WHEN to use it |
| Multiple skills fight over the same query | Trigger-phrase overlap between descriptions |
| Agent description matches generic unrelated queries | Windows/docs boilerplate inside YAML description: poisons routing |
| Agent uses wrong model | model: field missing or hard-coded instead of inherit |
Nine canonical anti-patterns (summary)
Full symptom / root cause / fix narrative for each lives in references/anti-patterns-catalog.md. Quick table:
| # | Anti-pattern | Severity | One-line fix |
|---|---|---|---|
| 1 | Zero-frontmatter skill — no --- | P0 | Add canonical YAML frontmatter (name:, description:) |
| 2 | Deprecated agent: true flag | P0 | Replace with name: <kebab> |
| 3 | Abstract "Use this agent for X" description | P1 | Rewrite with PROACTIVELY activate for: (1)... (N)... and Provides: |
| 4 | Description describes WHAT, not WHEN | P1 | Flip to user-intent triggers; lead with PROACTIVELY activate for: |
| 5 | Fat agent (>2,500 words) missing <example> blocks | P1 | Add 3-5 example blocks; lean orchestrators exempt |
| 6 | Windows/docs boilerplate inside YAML description: | P0 | Move boilerplate to a named body section |
| 7 | Missing or hard-coded model: field | P2 | Set model: inherit |
| 8 | Trigger-phrase overlap across skills | P1 | Assign exclusive ownership; add disambiguation in skill activation table |
| 9 | Description over 1024 chars or 15+ diluted triggers | P1 | Trim to 400-1000 chars; front-load triggers; split skill if needed |
The "lean orchestrator with no examples" shape is not anti-pattern 5 — see the tier table in agent-development and the audit caveat in agent-development/references/validation-and-audits.md before re-adding examples during an audit.
Description length caps (from anti-pattern 9)
- 400-1000 characters — recommended target.
- 1024 characters — Claude Code API spec hard ceiling. Never exceed.
- 1536 characters — current listing cap (combined description + when_to_use, v2.1.105+).
- ~1% of context window — aggregate budget across all installed skills.
Front-load triggers — the front of the description survives any truncation.
Audit process for an existing plugin
Run the audit sweeps from the repo root, in priority order (P0 → P2). Every row of output is a triggering bug. Fix earlier items first — they have larger blast radius.
The full bash and PowerShell sweep scripts (7 audit probes plus the positive-signal validation greps) live in references/audit-greps.md. The quick one-liners are also reproduced under One-line greps for the canonical checks at the bottom of this file.
Per-mistake fix priority
1. P0 - zero-frontmatter skills and agent: true agents (invisible/broken). 2. P0 - Windows/docs boilerplate inside YAML (actively poisons routing). 3. P1 - missing <example> blocks on fat agents (body > 2,500 words) that back multiple skills. Lean orchestrators under the 2,500-word threshold are exempt by design. 4. P1 - descriptions missing PROACTIVELY activate for: / Provides: enumeration. 5. P2 - metadata hygiene (model: inherit, color:, tools: tightening). 6. P2 - trigger-phrase overlap audit and disambiguation.
Fix in priority order - do not spend time on P2 while P0 bugs exist.
Severity tiers and description length limits
When reporting findings, use P0 / P1 / P2 tiers (plugin-breaking / routing-unreliable / polish). Description length is governed by three caps: 1024-char API spec hard ceiling, 1536-char listing cap that Claude sees during routing, and a ~1% context-window aggregate budget across all installed skills.
Full tier table with concrete examples for each severity, the description-length cap table with values and meanings, and the authoring targets: see references/severity-and-limits.md.
Pre-commit size and DRY gates (mandatory)
Two gates run before any content addition to a SKILL.md or reference file:
1. Size gate — wc -w (or PowerShell Measure-Object -Word) the target file. If it is in the 2,800-3,000 word band, extract a reference-style section to references/ BEFORE adding. Over 3,000 words = already broken, extract down to under 2,000 before doing anything else. 2. DRY gate — grep -rn (or Select-String) the first distinctive line of the candidate block across skills/, agents/, commands/, README.md. Even one hit elsewhere means the block must be extracted to skills/_shared/ (cross-skill) or references/ (single-skill) instead of pasted.
Full decision tables, exact commands for bash and PowerShell, and the combined workflow: see references/size-and-dry-gates.md.
Canonical pre-publish checklist
The full 26-item checklist (plugin.json shape, agent and skill frontmatter, description content, DRY-gate grep, code-sample sanity, size ceilings, NOTICES.md, marketplace.json registration) lives in references/pre-publish-checklist.md. Run every item before shipping.
Code-sample sanity pass
Two defects routinely slip into fenced code blocks and silently break readers:
1. Smart punctuation (curly quotes, em/en dashes, Unicode ellipsis) inside fenced code blocks breaks copy-paste — grep stops matching, JSON fails to parse, shell quoting falls apart. Authors typing in editors with autocorrect on, or pasting from word processors, introduce these without noticing. 2. Missing language tags on fenced code blocks (opening with bare ``` ` `` instead of `` `bash `` / `` `powershell `` / `` `yaml ```) disable syntax highlighting and, worse, hide the platform assumption. A bash-only snippet that renders as plain text looks identical to a PowerShell snippet — a Windows reader will copy it and watch it fail with no signal as to why.
Code-sample sanity checklist — run before every ship. Each unchecked item is a finding to fix manually.
- [ ] No smart-punctuation codepoints (U+2026, U+201C/D, U+2018/9, U+2013/4) inside any fenced code block. Replace with the ASCII equivalent:
...,",',-. - [ ] Every fenced code block opens with a language tag (e.g. ```
`bash``,```powershell``,```yaml``,```json``,```python``,```markdown``). Bare`````` openings are a defect. - [ ] Every executable snippet is either dual-form (shows both POSIX and PowerShell variants) or explicitly platform-tagged with a one-line prose marker such as
On bash/macOS/Linux:orOn PowerShell (Windows):immediately before the fence, and the fence language tag matches.
This repo's primary shell is PowerShell on Windows, so a bash-only snippet without a platform tag is a defect.
Sweeps and full character tables: see references/code-sample-sanity.md for the bash and PowerShell sweep scripts (smart-punctuation probe and fence-language-tag probe), the canonical smart-quote → ASCII fix table, and the list of recognised language tags.
Validator as canonical quality gate
The single source of truth for what counts as a "real" triggering defect in this marketplace is scripts/validate_plugins.py. Manual greps below help locate findings; the validator is what decides whether they ship.
python scripts/validate_plugins.py # whole marketplace
python scripts/validate_plugins.py --plugin my-plugin # one plugin
python scripts/validate_plugins.py --strict # warnings fail the buildKey validator rules with bearing on this skill:
| Validator check | Severity | Maps to |
|---|---|---|
Skill missing frontmatter | error | Anti-pattern 1 |
Deprecated agent: true | error | Anti-pattern 2 |
Skill missing PROACTIVELY / Provides | warning | Anti-patterns 3-4 |
Agent missing PROACTIVELY / Provides | warning | Anti-patterns 3-4 |
Agent missing examples | warning | Anti-pattern 5 — fires only when agent body > 2,500 words |
Agent missing model: inherit | error | Anti-pattern 7 |
| Description / SKILL.md length checks | error/warning | Anti-pattern 9 + size ceiling |
The complete validator rule index (agent, skill, and plugin level) plus known validator gaps lives in agent-development/references/validation-and-audits.md. Keep that table and the validator code in lockstep.
Audit caveat: check intent before recommending fixes
When auditing an existing plugin, an apparent defect is not automatically a real defect — it may be the deliberate output of a prior refactor. The canonical example: example blocks stripped from lean orchestrators during a fat-to-lean refactor. A follow-up audit that recommends re-adding them would undo the refactor.
Before listing any agent or skill finding in an audit report, run the three-question intent check:
1. Word count tier — Does the current size of the agent/skill make the apparent defect a defect, or is it exempt by design? 2. Git log — Was the absent content recently removed on purpose? Look for refactor commits. 3. Validator output — Does scripts/validate_plugins.py flag it? If not, do not invent stricter rules in the audit than the validator enforces.
Only when all three return "real defect" does it belong in the remediation list. Full rationale, the broader list of "stripped on purpose" patterns to watch for, and the authoring-vs-auditing contrast: agent-development/references/validation-and-audits.md.
One-line greps for the canonical checks
Run these from a plugin directory. Any output is a finding.
On bash/macOS/Linux:
grep -L "^---" skills/*/SKILL.md # zero-frontmatter skills (P0)
grep -l "^agent: true" agents/*.md # deprecated agents (P0)
grep -L "<example>" agents/*.md # agents with no <example> blocks - cross-check body word count before flagging (lean orchestrators under 2,500 words are exempt; see agent-development tier table)
grep -L "PROACTIVELY activate for:" skills/*/SKILL.md # skills missing trigger enumeration (P1)
grep -L "Provides:" skills/*/SKILL.md # skills missing capability list (P1)
grep -L "^model: inherit" agents/*.md # agents not inheriting model (P2)
grep -l "MANDATORY: Always Use Backslashes" agents/*.md skills/*/SKILL.md # Windows boilerplate in YAML (P0)On PowerShell (Windows), references/audit-greps.md carries the equivalent sweeps (probes 1-7) plus the positive-signal validation queries.
Triggering-Reliability Anti-Patterns Catalog
Nine canonical anti-patterns that cause agents and skills to never trigger. SKILL.md keeps a summary table; this reference has the full symptom / root cause / fix narrative for each.
Anti-pattern 1: Missing YAML frontmatter (zero-frontmatter skill)
Symptom
skills/my-skill/SKILL.md starts with # My Skill or plain prose. No --- line. The skill silently fails to appear in discovery.
Root cause
Skill discovery parses YAML frontmatter for name: and description:. With no frontmatter, the skill has no identity, no description, and no way to match user queries.
Fix
Prepend canonical frontmatter with a proper description:
---
name: my-skill
description: One-sentence summary. PROACTIVELY activate for: (1) trigger, (2) trigger, ..., (N) trigger. Provides: capability list.
---
# My Skill
(rest of body)How to find these
for f in plugins/*/skills/*/SKILL.md; do
head -1 "$f" | grep -q "^---" || echo "BROKEN: $f"
doneAnti-pattern 2: Deprecated agent: true flag
Symptom
plugins/my-plugin/agents/my-expert.md has agent: true as a frontmatter field but no name: field. The agent is not routable by name.
Root cause
agent: true is a legacy flag from an older plugin format. Modern agent routing requires name: as a kebab-case identifier. Without it, the agent cannot be invoked deliberately and can be missed by auto-discovery.
Fix
Replace agent: true with name: <kebab-name> derived from the filename.
How to find these
grep -rn "^agent: true" plugins/*/agents/*.md
# Expected output: zero matchesAnti-pattern 3: Abstract "Use this agent for X" description
Symptom
Description reads like a capability statement:
description: Use this agent for help with Azure.Root cause
Claude routes to agents based on trigger-phrase matching against the description. A description that describes the agent in the third person, without enumerating concrete triggers and query shapes, provides almost no routing signal.
Fix
Rewrite the description with the PROACTIVELY activate for: (1)... (N)... enumeration and a Provides: ... capability list, AND add 4-6 <example> blocks.
Anti-pattern 4: Description describes WHAT, not WHEN
Symptom
description: This skill contains a comprehensive reference for Terraform AzureRM provider usage.Root cause
Claude routes based on matching user intent. "Contains a reference" tells Claude nothing about when the user would need this. The description must be phrased as trigger conditions from the user's point of view.
Fix
Flip the perspective. Lead with PROACTIVELY activate for: and enumerate named triggers as the user would phrase them.
Anti-pattern 5: Missing example blocks on a fat agent
Symptom
Agent description: is a single paragraph with no <example> blocks, AND the agent body is more than 2,500 words.
Root cause
<example> blocks give Claude concrete query shapes to match against. On a substantial agent body where the description alone cannot disambiguate routing, the absence forces loose prose matching, which is far less reliable.
Fix
Add 3-5 <example> blocks. Each block must include Context, user quote, assistant response (1-2 sentences), and commentary with trigger keywords. Use description: | (YAML block scalar) so the <example> blocks parse correctly.
Skill coverage rule (applies only when examples are present): every skill the agent delegates to must have at least one <example> that would route to it. If a fat agent has 9 skills and only 4 <example> blocks, 5 skills will trigger unreliably. This rule does NOT compel adding examples to a lean orchestrator that has none by design.
Not an anti-pattern: lean orchestrator with no examples
A lean orchestrator (agent body under 2,500 words) deliberately omits <example> blocks and relies on the PROACTIVELY activate for: enumeration in the description plus the skill activation table in the body to drive routing. This is the correct shape for most modern Claude Code agents — do not "fix" it. See the tier table in agent-development SKILL.md ("Example-block requirement by agent body size") and the audit caveat in agent-development/references/validation-and-audits.md.
Anti-pattern 6: Windows / docs boilerplate inside YAML description
Symptom
description: |
Complete Docker expertise. Use backslashes on Windows for file paths. Never create documentation files unless requested...Root cause
Cross-cutting boilerplate that appears in many agent/skill descriptions poisons routing. The boilerplate contains generic phrases that match many unrelated queries, so the agent over-triggers on irrelevant requests.
Fix
Move the boilerplate to a dedicated body section under a named heading. The YAML description: stays purely routing-focused.
Anti-pattern 7: Missing or hard-coded model field
Symptom
# Either missing entirely, or:
model: sonnetRoot cause
The marketplace convention is model: inherit so the agent adopts the parent session's model. Hard-coding a model breaks the user's model preference and can silently downgrade capability on long-context sessions.
Fix
Set model: inherit. Only deviate when the agent has a documented capability requirement.
Anti-pattern 8: Trigger-phrase overlap across skills
Symptom
Two skills in the same plugin both claim the same keyword in their descriptions. Users' queries route inconsistently between them.
Root cause
Claude has no tiebreaker when two skills match the same query with similar strength.
Fix
Assign exclusive ownership of each ambiguous keyword. The other skill should use a more specific phrase. Add a disambiguation hint in the agent's skill-activation table.
Anti-pattern 9: Description too long / too many triggers
Symptom
Description is over 1024 characters, or pushes past 1000 with diluted trigger phrases competing with each other.
Root cause
Three distinct caps apply to descriptions (see references/severity-and-limits.md). Crossing the 1024-char API spec ceiling means the skill may be rejected by authoring tools or have its tail truncated. Even below the ceiling, descriptions over ~1000 chars typically indicate the skill is doing too much.
Fix
- Target 400-1000 characters per skill or agent description.
- Hard ceiling: 1024 characters (Claude Code API spec).
- Front-load trigger keywords — the front of the description always survives any truncation.
- If you genuinely have 15+ triggers, split the skill into two focused skills.
- Collapse near-duplicate triggers into a single item.
Triggering-reliability audit greps — extended reference
Full multi-line audit and validation sweeps referenced from SKILL.md under Audit process for an existing plugin and Validation: what good looks like. Run from the repo root, in priority order — earlier items have larger blast radius. Every row of output is a triggering bug.
Audit sweep (P0 → P2)
On bash/macOS/Linux:
# 1. Find skills with no frontmatter (BROKEN, P0)
for f in plugins/*/skills/*/SKILL.md; do
head -1 "$f" | grep -q "^---" || echo "NO FRONTMATTER: $f"
done
# 2. Find agents still using deprecated agent: true (P0)
grep -rn "^agent: true" plugins/*/agents/*.md
# 3. Find agents missing example blocks (P1)
for f in plugins/*/agents/*.md; do
grep -q "<example>" "$f" || echo "NO EXAMPLES: $f"
done
# 4. Find skills missing PROACTIVELY activate for: (P1)
for f in plugins/*/skills/*/SKILL.md; do
head -20 "$f" | grep -q "PROACTIVELY activate for:" || echo "NO ENUMERATION: $f"
done
# 5. Find skills missing Provides: (P1)
for f in plugins/*/skills/*/SKILL.md; do
head -20 "$f" | grep -q "Provides:" || echo "NO PROVIDES: $f"
done
# 6. Find agents missing model: inherit (P2)
for f in plugins/*/agents/*.md; do
head -20 "$f" | grep -q "^model: inherit" || echo "NO MODEL INHERIT: $f"
done
# 7. Find Windows boilerplate inside YAML descriptions (P0)
grep -rn "MANDATORY: Always Use Backslashes" plugins/*/agents/*.md plugins/*/skills/*/SKILL.mdOn PowerShell (Windows):
# 1. Skills with no frontmatter
Get-ChildItem -Recurse -Path plugins -Filter SKILL.md | ForEach-Object {
$first = (Get-Content -LiteralPath $_.FullName -TotalCount 1)
if ($first -notmatch '^---') { "NO FRONTMATTER: $($_.FullName)" }
}
# 2. Deprecated agent: true
Get-ChildItem -Recurse -Path plugins -Filter *.md `
| Where-Object { $_.FullName -match '\\agents\\' } `
| Select-String -Pattern '^agent: true'
# 3. Agents missing <example>
Get-ChildItem -Recurse -Path plugins -Filter *.md `
| Where-Object { $_.FullName -match '\\agents\\' } `
| ForEach-Object {
if (-not (Select-String -Path $_.FullName -Pattern '<example>' -Quiet)) {
"NO EXAMPLES: $($_.FullName)"
}
}
# 4. Skills missing PROACTIVELY activate for:
Get-ChildItem -Recurse -Path plugins -Filter SKILL.md | ForEach-Object {
$head = Get-Content -LiteralPath $_.FullName -TotalCount 20
if (-not ($head -match 'PROACTIVELY activate for:')) {
"NO ENUMERATION: $($_.FullName)"
}
}
# 5. Skills missing Provides:
Get-ChildItem -Recurse -Path plugins -Filter SKILL.md | ForEach-Object {
$head = Get-Content -LiteralPath $_.FullName -TotalCount 20
if (-not ($head -match 'Provides:')) {
"NO PROVIDES: $($_.FullName)"
}
}
# 6. Agents missing model: inherit
Get-ChildItem -Recurse -Path plugins -Filter *.md `
| Where-Object { $_.FullName -match '\\agents\\' } `
| ForEach-Object {
$head = Get-Content -LiteralPath $_.FullName -TotalCount 20
if (-not ($head -match '^model: inherit')) {
"NO MODEL INHERIT: $($_.FullName)"
}
}
# 7. Windows boilerplate inside YAML descriptions
Get-ChildItem -Recurse -Path plugins -Include *.md `
| Where-Object { $_.FullName -match '\\(agents|skills)\\' } `
| Select-String -Pattern 'MANDATORY: Always Use Backslashes'Validation: positive signal
After fixes, all seven sweeps above should produce zero output (or, for items 4 and 5, the count should trend dramatically toward zero as skills are rewritten).
For a positive signal, confirm:
On bash/macOS/Linux:
# Count agents with example blocks (should equal total agent count)
grep -l "<example>" plugins/*/agents/*.md | wc -l
# Count skills with PROACTIVELY enumeration
grep -l "PROACTIVELY activate for:" plugins/*/skills/*/SKILL.md | wc -lOn PowerShell (Windows):
# Count agents with example blocks
(Get-ChildItem -Recurse -Path plugins -Filter *.md `
| Where-Object { $_.FullName -match '\\agents\\' } `
| Select-String -Pattern '<example>' -List).Count
# Count skills with PROACTIVELY enumeration
(Get-ChildItem -Recurse -Path plugins -Filter SKILL.md `
| Select-String -Pattern 'PROACTIVELY activate for:' -List).Count<!-- validator:allow-smart-punct --> <!-- This reference legitimately catalogs the smart-punctuation codepoints the validator flags. -->
Code-sample sanity pass — extended reference
This file holds the full sweeps and tables that SKILL.md summarises under the Code-sample sanity pass section. Run these before every ship. Any output is a finding to fix manually.
The sanity pass has two probes:
1. Smart-punctuation probe — fenced code blocks must contain only ASCII (curly quotes, em/en dashes, and Unicode ellipsis break grep, JSON, and shell quoting). 2. Fence-language-tag probe — every fenced code block must declare a language tag (e.g. ``` `bash ``, `` `powershell ``, `` `yaml ```). Untagged fences disable syntax highlighting and obscure platform assumptions — a fence written for bash that renders as plain text looks identical to one written for PowerShell.
Shell-portability rule for executable snippets
Any executable snippet inside a fenced code block in a SKILL.md or reference file MUST either:
- be dual-form — show both a POSIX (bash/sh) variant AND a PowerShell variant, OR
- be explicitly platform-tagged — open with a one-line prose marker such as
On bash/macOS/Linux:orOn PowerShell (Windows):immediately before the fence, AND use the matching language tag on the fence (````bash``vs```powershell```).
This repo's primary shell is PowerShell on Windows, so a bash-only snippet without a platform tag is a defect: a reader on Windows will copy it and watch it fail with no signal as to why.
Smart-punctuation sweep — bash
# Pull every fenced code block and grep it for smart punctuation.
# awk extracts content between ``` fences; grep -nP flags suspicious chars.
for f in $(find . -name '*.md' -not -path './node_modules/*'); do
awk '/^```/{flag=!flag; next} flag' "$f" \
| grep -nP '[\x{2026}\x{201C}\x{201D}\x{2018}\x{2019}\x{2013}\x{2014}]' \
&& echo " ^ in $f"
doneSmart-punctuation sweep — PowerShell
# PowerShell equivalent of the bash sweep above.
# Walks every .md file, tracks whether the current line is inside a fenced block,
# and flags lines that contain smart-punctuation codepoints.
$pattern = '[…“”‘’–—]'
Get-ChildItem -Recurse -Filter '*.md' -Exclude 'node_modules' | ForEach-Object {
$file = $_.FullName
$inFence = $false
$lineNo = 0
Get-Content -LiteralPath $file | ForEach-Object {
$lineNo++
if ($_ -match '^```') { $inFence = -not $inFence; return }
if ($inFence -and ($_ -match $pattern)) {
"${file}:${lineNo}: $_"
}
}
}Fence-language-tag probe — bash
# Flag fenced code blocks that open with ``` and no language tag.
# Matches lines that are exactly three backticks (optionally followed by whitespace) and nothing else.
grep -rnE '^```[[:space:]]*$' --include='*.md' . \
| awk -F: '{
# Toggle: every untagged fence is a candidate. Authors should review each hit.
print $0
}'Note: the grep above flags BOTH opening and closing fences. Closing fences are legitimate. To narrow to opening fences only, pair fences in order — odd-indexed hits (1st, 3rd, 5th, ...) within a file are openings:
for f in $(find . -name '*.md' -not -path './node_modules/*'); do
awk '
/^```[[:space:]]*$/ {
count++
if (count % 2 == 1) { print FILENAME ":" NR ": untagged opening fence" }
next
}
/^```[a-zA-Z]/ { count++; next }
' "$f"
doneFence-language-tag probe — PowerShell
# Flag opening fences that have no language tag.
Get-ChildItem -Recurse -Filter '*.md' -Exclude 'node_modules' | ForEach-Object {
$file = $_.FullName
$count = 0
$lineNo = 0
Get-Content -LiteralPath $file | ForEach-Object {
$lineNo++
if ($_ -match '^```[a-zA-Z]') { $count++; return }
if ($_ -match '^```\s*$') {
$count++
if ($count % 2 -eq 1) { "${file}:${lineNo}: untagged opening fence" }
}
}
}Characters to watch for
Each row is the canonical Unicode codepoint; the ASCII fix follows the arrow:
| Smart | Codepoint | ASCII fix |
|---|---|---|
… (ellipsis) | U+2026 | ... |
" (left double quote) | U+201C | " |
" (right double quote) | U+201D | " |
' (left single quote) | U+2018 | ' |
' (right single quote) | U+2019 | ' |
– (en dash) | U+2013 | - |
— (em dash) | U+2014 | - (or rephrase) |
Smart punctuation in prose outside code blocks is fine and often correct. The sweep is scoped to fenced code only because that is where it breaks downstream tooling.
Recognised language tags
Use a real language identifier on every fence. Common tags:
| Tag | Use for |
|---|---|
bash, sh | POSIX shell snippets |
powershell, pwsh | PowerShell snippets |
python | Python code |
json | JSON config or payloads |
yaml | YAML (including frontmatter examples) |
markdown, md | Markdown samples (including SKILL.md templates) |
text | Generic plain text where no language applies (last resort) |
When the content genuinely has no language (e.g. a diagram-ish tree), text is acceptable but rarely correct — most "no language" fences are actually shell, YAML, or markdown and should be tagged accordingly.
Canonical Pre-Publish Checklist
Every item below must be true before publishing any plugin in this marketplace.
- [ ]
plugin.jsonexists at.claude-plugin/plugin.jsonand is valid JSON - [ ]
nameis kebab-case - [ ]
authoris an object{ "name": "..." }— not a string - [ ]
versionis a string"1.0.0"— not a number - [ ]
keywordsis an array — not a string - [ ] No
agents/skills/slashCommandsfields inplugin.json(auto-discovered) - [ ] Every agent file starts with
---(YAML frontmatter present) - [ ] Every agent has a
name:field (not the deprecatedagent: trueflag) - [ ] Every agent has
model: inherit - [ ] Every agent has
<example>blocks if its body exceeds 2,500 words (3-5 preferred). Lean orchestrators under 2,500 words are exempt — seeagent-developmentSKILL.md "Example-block requirement by agent body size". - [ ] Every agent has a
color:field - [ ] Every agent has
tools:(minimal set) or omits the field for full tool access - [ ] Every
SKILL.mdstarts with---(NOT# Title) - [ ] Every skill
description:containsPROACTIVELY activate for:enumeration - [ ] Every skill
description:containsProvides:capability list - [ ] Every skill
description:is under 1024 characters (target 400-1000) - [ ] No Windows / docs / cross-cutting boilerplate inside any YAML
description:field - [ ] No verbatim duplicate blocks across skills — the mandatory DRY-gate grep (see
references/size-and-dry-gates.md) has been run for every newly added block and any 2nd-copy hit was extracted toskills/_shared/orreferences/before commit - [ ] No smart-punctuation inside fenced code blocks — see "Code-sample sanity pass" section below
- [ ] Every fenced code block has a language tag — see "Code-sample sanity pass" section below
- [ ] Every executable snippet is dual-form (POSIX + PowerShell) or explicitly platform-tagged — see "Code-sample sanity pass" section below
- [ ] Every SKILL.md is under the 3,000-word ceiling, and any skill within 200 words of the ceiling has had its largest reference-style sections extracted to
references/(seereferences/size-and-dry-gates.md) - [ ] If the plugin ships any vendored, derived, or licensed third-party content,
NOTICES.mdexists at the plugin root, has no duplicate H2 sections for the same upstream, preserves required license text, and is cross-referenced fromREADME.mdandplugin.jsonwhere applicable (seeplugin-masterskill,references/publishing-guide.mdpublishing checklist) - [ ] If a
marketplace.jsonexists at repo root, the plugin is registered there with matchingdescriptionandkeywords
Severity tiers and description length limits
This reference holds two tables that are consulted during validation reporting but not during day-to-day authoring. They live here to keep the parent SKILL.md under its word-count ceiling.
Severity table for validation reports
Use these tiers when reporting validation findings on a plugin:
| Tier | Meaning | Examples |
|---|---|---|
| P0 - critical, must fix before ship | Plugin will not load or component will not appear in discovery | plugin.json missing or invalid JSON; required field missing; wrong field type (author as string, version as number, keywords as string); skill with no YAML frontmatter; agent using deprecated agent: true; Windows/docs boilerplate inside YAML description (actively poisons routing) |
| P1 - major, should fix before ship | Plugin loads but triggers unreliably | Agent missing <example> blocks when body > 2,500 words (lean orchestrators under that threshold are exempt — see agent-development SKILL.md tier table); skill description missing PROACTIVELY activate for: / Provides: enumeration; description describes WHAT instead of WHEN; skill or agent description over 1024 characters (per Claude Code API spec hard ceiling — see length-limits table below) |
| P2 - polish | Cosmetic or efficiency improvements | Missing model: inherit, color:, or tools: (defaults apply); description over the 400-700 char target (still well under the 1024 hard ceiling); trigger-phrase overlap between sibling skills; SKILL.md body over 3,000 words |
Description length limits (Claude Code, current as of 2026)
Three caps apply to every skill/agent description:
| Cap | Value | What it means |
|---|---|---|
| API spec hard ceiling | 1024 chars | Hard ceiling per description field. Authoring tools reject anything over this. |
| Listing-cap for matching | 1536 chars | Combined description + when_to_use Claude sees when routing. Raised from 250 in v2.1.105. |
| Aggregate budget | ~1% of context window | Total across ALL installed skills. Over-budget (v2.1.129+) drops least-recently-used skills' descriptions rather than truncating. |
Authoring targets: target 400-1000 chars; hard ceiling 1024; front-load trigger keywords so the front survives any truncation; if you genuinely need 15+ triggers, split the skill rather than bloating the description.
Size and DRY gates for SKILL.md authoring
This reference holds the two mandatory pre-commit checks that gate every content addition to a SKILL.md or reference file. Both gates live here (rather than in SKILL.md) to keep the parent skill under its word-count ceiling.
Precondition: size check before adding content to an existing skill
Before adding ANY new paragraph, table, or section to an existing SKILL.md, run a word-count check. The 3,000-word ceiling is a hard limit, not an aspiration — a SKILL.md that lands at 3,050 words is broken, not "close enough."
On bash/macOS/Linux:
wc -w plugins/<plugin>/skills/<skill>/SKILL.mdOn PowerShell (Windows):
(Get-Content plugins/<plugin>/skills/<skill>/SKILL.md | Measure-Object -Word).WordsDecision rule:
| Current word count | Action before adding content |
|---|---|
| < 2,500 words | Safe to add. Proceed. |
| 2,500-2,799 words | Add cautiously. After the addition, re-count; if over 2,800, start planning the extraction. |
| 2,800-3,000 words (within 200 of the ceiling) | Extraction to `references/` is mandatory BEFORE adding. Identify the largest reference-style section (detailed table, exhaustive checklist, full sweep script) and move it to references/<topic>.md, leaving a one-line pointer in SKILL.md. Then add the new content. |
| > 3,000 words | The skill is already broken. Do not add anything — extract until SKILL.md is back under 2,000 words. |
This precondition prevents the common failure mode where each individual addition looks small but the skill silently crosses the ceiling.
Mandatory DRY-gate before any content add
Cross-cutting paragraphs, tables, and checklists that get pasted into multiple files are the #1 source of plugin bloat. Before adding any block longer than ~3 lines to a SKILL.md or reference file, run this grep from the plugin root:
# Replace FIRST_DISTINCTIVE_LINE with the first distinctive line of the candidate block.
grep -rn "FIRST_DISTINCTIVE_LINE" skills/ agents/ commands/ README.mdOn PowerShell (Windows):
Get-ChildItem -Recurse -Path skills,agents,commands,README.md -Include *.md -ErrorAction SilentlyContinue `
| Select-String -Pattern 'FIRST_DISTINCTIVE_LINE'Decision rule (from skill-development skill, "two or more verbatim copies = extract" gate):
| grep finds the block in | Action |
|---|---|
| 0 other files | Safe to add. Proceed. |
| 1 other file (this will be the 2nd copy) | STOP. Extract to skills/_shared/<topic>.md (cross-skill) or skills/<this-skill>/references/<topic>.md (single-skill). Replace both call sites with a one-line pointer. |
| 2+ other files | Treat as a P1 bug. Extract immediately, then audit for further occurrences. |
This gate is mandatory, not advisory. Skipping it is the mechanism that lets identical canonical text drift into two or three files.
Combined workflow
For any content add to an existing SKILL.md or reference:
1. Run the size check. If the file is in the 2,800-3,000 band, extract before adding. 2. Run the DRY-gate grep on the first distinctive line of the candidate block. If it shows up in even one other file, extract instead of pasting. 3. Only after both gates clear, add the content. 4. After the add, re-run the size check. If the file crossed 3,000 words, extract the largest reference-style section to bring it back under the ceiling before commit.