Skip to content

fix(skills): give every skill description real 'Use when:' trigger phrasing - #2181

Merged
kyle-sexton merged 2 commits into
mainfrom
work/2174-auto
Aug 10, 2026
Merged

fix(skills): give every skill description real 'Use when:' trigger phrasing#2181
kyle-sexton merged 2 commits into
mainfrom
work/2174-auto

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Closes #2174

Summary

A skill description is the text Claude matches against to decide whether to load the skill, so
a description shaped like a summary of what the skill is makes the skill under-fire. The
skill-quality gate reported this on verification:measure:

WARN: description has no 'Use when:' trigger phrasing — a description is a trigger spec, not a summary

This fixes measure and sweeps the rest of the corpus, which the issue explicitly asks for. All
196 skills were checked
— not a base-ref diff. 29 carried a check-12 warning; 25 are fixed here and
4 are deliberately left as-is with the reasoning below.

Fix

Check 12 in plugins/skill-quality/scripts/check-skill.sh has two branches, and the sweep found both
in the wild:

Warning Found Fixed Left
description has no 'Use when:' trigger phrasing 22 18 4
'Use when:' triggers are not single-quoted 7 7 0

No Use when: phrasing (22). Most already had good routing phrases, but behind a lowercase
use for the gate does not recognize (planning:*, testing:*, toolchain:check,
review:fanout, implementation:implement, verification:confirm, verification:measure). A few
named only a topic or a state and no phrase a user types (context7:lookup, toolchain:lint).

Unquoted triggers (7). The gate's trigger-drop protection tracks only 'single-quoted' text, so
phrases written with escaped double quotes (debugging:debug, docs-hygiene:compress,
kindle-dedrm:manage) or as a bare comma list (repo-hygiene:clean) had no regression cover at
all
— a later rewrite could have dropped any of them silently. Those are quoting changes; the
wording is unchanged.

Across the 25, 108 typed trigger phrases were added and zero existing phrases were dropped — the
gate's keyword-preservation check sees a superset, not a rewrite. This matters most on measure,
whose base-ref trigger set includes 'cannot quantify': that is prose, not a trigger, but the
extractor tracks any single-quoted span, so the natural "clean this up" rewrite would have dropped it
and failed check 3. It is preserved verbatim.

Deliberately left as-is (4)

All four are disable-model-invocation: true and carried no pre-existing quoted phrase. A skill
that cannot be model-invoked is never matched against its description, so triggers would buy no
auto-invocation there — and inventing user-typed phrases for them would invite exactly the misfire
this issue is about.

The review round below sharpened this: dmi-true alone is not sufficient grounds, because a phrase
that lives only on a dmi-true skill is unreachable (that is the kindle-dedrm finding). So for
each of the four, the additional question is whether some phrase a user would type is left with no
model-invocable home. It isn't:

  • discipline:wait-what — its description is the instruction ("Type /discipline:wait-what the
    moment you notice you are skimming; only you know when you stopped following"). Self-observation
    is the trigger; by construction the model cannot detect it.
  • firecrawl:update, playbooks:update — maintainer-only drift checks whose descriptions say "Not
    for consumers — consumers update via /plugin marketplace update". There is no user phrase that
    should route here, so nothing is stranded. Their model-invocable siblings (firecrawl:firecrawl,
    playbooks:boris) are both fixed in this PR and carry the consumer-facing phrases.
  • github:setupSKILL.md states "User-invoked only", the plugin README lists it as
    "user-invoked only", and the only references to it are documentation. It is a deliberate slash
    command, not an orphan and not a routing target.

Where a disable-model-invocation: true skill already had quoted phrases (planning:questionnaire),
the connector is normalized to Use when: and nothing is invented — it is the only dmi-true skill
among the 25 changed here.

One deliberate cross-skill duplicate

kindle-dedrm:manage carries a byte-identical copy of 'set up Kindle DRM removal', a trigger on
its sibling kindle-dedrm:setup. It was invisible while double-quoted, and quoting it for tracking
makes two siblings claim the same typed phrase. It is kept anyway: setup is
disable-model-invocation: true, so its description is never matched against user text, and
manage — model-invocable, with an action router that delegates to /kindle-dedrm:setup — is the
only skill that can receive the phrase by model invocation. Dropping the duplicate would leave the
phrase reachable only by an explicit slash command. A collision check over the whole corpus confirms
this is the only overlap: the other 107 added phrases collide with nothing.

Versioning

13 plugins touched, each with a patch bump and a matching ## [x.y.z] CHANGELOG entry:
context7 0.5.1, debugging 0.6.1, docs-hygiene 0.10.1, firecrawl 0.5.1, implementation
0.13.1, kindle-dedrm 0.7.1, planning 0.30.1, playbooks 0.8.2, repo-hygiene 0.9.1, review
0.18.1, testing 0.5.2, toolchain 0.12.1, verification 0.5.2.

Verification

How the sweep covered all 196 skills: the gate ships no --all mode — check-changed-skills.sh maps
a base-ref diff to skill dirs — so check 12 was reimplemented against the checker's own
plugins/skill-quality/scripts/skill-frontmatter.sh semantics (extract / field / strip_quotes /
extract_triggers, including the intra-word-apostrophe normalization) and run over every
plugins/*/skills/*/SKILL.md. Two fidelity controls:

  • Spot-checked against the real check-skill.sh on one skill from each warning class
    (verification:measure, docs-hygiene:compress) — same classification both times.
  • The only place the reimplementation could diverge from the awk is block-scalar / trailing-comment
    handling. No SKILL.md in the corpus uses a block-scalar description: or when_to_use:
    (grep -c '^description: *[|>]' over all 196 = 0), so both take the plain-scalar path.
  • The authoritative confirmation is CI: check-changed-skills.sh origin/main runs the real
    checker over exactly the 25 changed skills.

Gates run locally on the committed tree, base-ref form:

Gate Result
scripts/check-changelog-parity.sh --check-bump origin/main pass
scripts/check-changelog-parity.sh --check pass
scripts/check-skill-portability.sh origin/main pass — no unexcused coupling tokens in 25 skill files
scripts/check-contract-slice-prune.sh --check-diff origin/main pass
markdownlint-cli2 over all 38 changed .md pass — 0 errors
Trigger preservation + listing cap, all 25 pass — 0 dropped, max listing 951/1536
Cross-skill trigger collision, whole corpus pass — 0 collisions
Line endings all changed files i/lf w/lf

scripts/check-changed-skills.sh origin/main — the gate that reported the original warning — runs
green in CI as skill-quality-gate over all 25 changed skills. It was also run to completion locally
on measure alone, before the sweep was layered on: PASS — 0 errors, 0 warning(s),
all 4 base-ref trigger phrase(s) preserved.

Post-change sweep: 192 of 196 skills clean, the remaining 4 being the documented exemptions.

Related

@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7b9376a488

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/kindle-dedrm/skills/manage/SKILL.md Outdated
@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 4m 29s —— View job


Review complete

  • Gather context (diff via gh pr diff 2181, CLAUDE.md/AGENTS.md, real check-skill.sh check-12 logic)
  • Understand the request (code review of PR fix(skills): give every skill description real 'Use when:' trigger phrasing #2181)
  • Review changed skill descriptions for correctness / trigger-phrasing quality
  • Check versioning/CHANGELOG consistency
  • Check the Codex bot's kindle-dedrm:manage finding
  • Post inline comments for findings
  • Final summary

Findings (posted inline)

  1. plugins/kindle-dedrm/skills/manage/SKILL.md:2 (medium) — corroborates the Codex bot's comment above, independently verified by reading skills/setup/SKILL.md: setup has disable-model-invocation: true and still carries 'set up Kindle DRM removal' as its own trigger, but a non-model-invocable skill's description is never auto-matched. manage (model-invocable) carried the same phrase before this PR and delegated to setup; removing it here to resolve the byte-identical duplicate leaves no model-invocable skill that fires on that phrase anymore. Net effect: a real regression in auto-routing coverage, not just de-duplication.
  2. plugins/planning/skills/questionnaire/SKILL.md:2 (low) — the PR body states this disable-model-invocation: true skill was only connector-normalized "without inventing any" new phrases, but the diff adds two new ones ('write questions for the client', 'I don't know, someone else does'). Harmless functionally (the skill can't be auto-matched), but it contradicts the stated rationale used to justify leaving the other four non-model-invocable skills untouched.

What I independently checked (not just author-claimed)

  • Read plugins/skill-quality/scripts/check-skill.sh's actual check 12 (lines 522–530): it does a case-insensitive grep -qi 'use when' over description + when_to_use, then requires skill_frontmatter::extract_triggers (single-quoted spans) to be non-empty. Every changed SKILL.md in this PR now satisfies both branches, so the fix is mechanically correct against the real checker logic, not just the PR author's reimplementation.
  • Spot-checked several plugins' new trigger lists against their own CHANGELOG entries by reading the actual diff (debugging, docs-hygiene, kindle-dedrm, testing, verification) — phrase counts and wording match what each CHANGELOG claims.
  • Confirmed all 13 touched plugin.json version bumps have a matching ## [x.y.z] CHANGELOG entry at HEAD.
  • Confirmed every changed SKILL.md diff is a single-line description edit (plus the two version-line plugin.json diffs) — no unrelated frontmatter drift.

Not independently verified (author-claimed only)

  • The "192/196 skills clean" full-corpus sweep, the "0 collisions" cross-skill trigger check, and the "0 dropped / max listing 951/1536" trigger-preservation numbers — these require re-running tooling I didn't execute in this session (sandboxed Bash here needed interactive approval for anything beyond simple git/gh/grep calls, so I could not run check-changed-skills.sh or the author's reimplementation myself). Treat those as author-claimed until CI confirms them.

No other correctness, security-lane, or maintainability issues found in the changed files — this is a low-risk, mechanical description/changelog/version-bump sweep and the two items above are the only substantive findings.

Branch: work/2174-auto

@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 49s —— View job


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Review changed files for security issues (injection, secrets, access control, GH Actions patterns)
  • Post findings

Scope reviewed: the full PR diff (git diff between the PR's base commit 9d9fe48 and head 887be02, matching the stated 51 files / +203/-38) — 13 plugin.json version bumps, 13 CHANGELOG.md entries, and 25 SKILL.md frontmatter description edits.

Findings: none.

Every change in this PR is confined to YAML frontmatter description:/quoting edits in SKILL.md files, semver bumps in plugin.json, and prose additions to CHANGELOG.md. There is:

  • No executable code, script, or hook logic touched (no .sh, .py, .ps1, or command-surface files in the diff).
  • No GitHub Actions workflow file touched, so no trigger/permission/pull_request_target concerns apply.
  • No .mcp.json, allowed-tools, argument-hint shell wiring, or other contract surface capable of expanding execution/tool access — only description strings changed.
  • No tokens, credentials, secrets, or URLs introduced.
  • No content resembling embedded prompt-injection payloads (checked the added text for instruction-hijacking phrasing, suspicious links, encoded blobs — none present); the new Use when: '...' trigger phrases are plain natural-language routing text of the same shape as the phrases they sit beside.

On the Codex bot comment (kindle-dedrm manage): that's a routing/functionality observation (whether the "set up Kindle DRM removal" phrase should stay reachable via a model-invocable skill), not a security defect — no privilege, trust-boundary, or data-exposure change results either way, since setup's actual mutations (firewall, ICACLS, Calibre plugins) are unchanged code, only which skill's description a user's phrasing matches. Leaving it to the PR author/Codex thread rather than re-reporting here per the security-only scope of this review.

Comment thread plugins/kindle-dedrm/skills/manage/SKILL.md Outdated
Comment thread plugins/planning/skills/questionnaire/SKILL.md Outdated
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 2 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

kyle-sexton and others added 2 commits August 10, 2026 19:21
`plugins/verification/skills/measure/SKILL.md`'s frontmatter `description`
opened with what the skill IS and buried its routing phrases behind a
lowercase `use for`. A description is the text Claude matches against to
decide whether to LOAD a skill, so a summary-shaped one makes the skill
under-fire: the skill-quality gate reported "description has no 'Use when:'
trigger phrasing — a description is a trigger spec, not a summary".

Move the phrases behind `Use when:` in the marketplace's house shape and add
six more a user would actually type. Every single-quoted phrase the previous
description carried is kept verbatim — including `'cannot quantify'`, which
is prose the trigger extractor also tracks — so the gate's keyword-
preservation check sees a superset rather than a rewrite.

Refs #2174

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdBsorqGjCU4Mg5nrmgz4m
…sing

A skill `description` is the text Claude matches against to decide whether to
LOAD the skill, so a summary-shaped description makes the skill under-fire.
The skill-quality gate has two checks for this, and a corpus-wide sweep found
28 skills tripping one of them beyond `verification:measure`:

  * 20 more carried no `Use when:` phrasing at all — most had good routing
    phrases sitting behind a lowercase `use for`, which the gate does not
    recognize; a few named only topics or states, never a phrase a user types.
  * 7 had `Use when:` but no SINGLE-quoted phrases. The gate's trigger-drop
    protection tracks only `'single-quoted'` text, so phrases written with
    escaped double quotes (debugging, docs-hygiene, kindle-dedrm) or as a bare
    comma list (repo-hygiene) had no regression cover at all — a later rewrite
    could silently drop any of them.

Fix 25 of the 28, across context7, debugging, docs-hygiene, firecrawl,
implementation, kindle-dedrm, planning, playbooks, repo-hygiene, review,
testing, toolchain and verification. Every phrase already present is preserved
verbatim, so the gate's keyword-preservation check sees a superset rather than
a rewrite; each list also gains phrases a user would actually type rather than
a paraphrase of the skill's purpose.

Four are deliberately left as-is, all `disable-model-invocation: true` with no
pre-existing quoted phrase: discipline:wait-what, firecrawl:update,
github:setup, playbooks:update. A skill that cannot be model-invoked is never
matched against its description, so triggers would buy no auto-invocation
there — and two of them are maintainer-only drift checks that say "Not for
consumers", where user-typed triggers would invite exactly the misfire this
issue is about. Where a dmi:true skill already had quoted phrases
(planning:questionnaire), the connector is normalized without inventing any.

Closes #2174

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdBsorqGjCU4Mg5nrmgz4m
@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 1s —— View job


Review complete

  • Gather context (gh pr diff 2181, CLAUDE.md/AGENTS.md, prior review comments)
  • Determine what changed since the prior Claude reviews (this run was triggered by a new push)
  • Review changed skill descriptions for correctness / trigger-phrasing quality
  • Check versioning/CHANGELOG consistency
  • Check whether the two previously-flagged findings (kindle-dedrm:manage, planning:questionnaire) were addressed
  • Post inline comments for any new findings
  • Final summary

What changed since the last review round

The diff at the current head (b807761) differs from what the earlier Claude/Codex reviews saw (887be02). Both previously-flagged issues are resolved in the code as it stands now:

  • kindle-dedrm:manage: the earlier concern (Codex + prior Claude review) was that dropping 'set up Kindle DRM removal' from manage to de-duplicate against setup would leave no model-invocable skill able to catch that phrase, since setup has disable-model-invocation: true. The current diff no longer drops it — it's a pure double-quote→single-quote normalization, and manage still carries all eight original phrases, 'set up Kindle DRM removal' included. Confirmed by reading the diff directly.
  • planning:questionnaire: the earlier concern was that two new phrases were invented for a disable-model-invocation: true skill, contradicting the PR's own stated rationale. The current diff is connector-only (Use forUse when:), no new phrases added — consistent with what the PR body claims for this skill.

New findings (this round)

  1. PR body narrative no longer matches the shipped kindle-dedrm diff. The "One routing ambiguity resolved" section states the 'set up Kindle DRM removal' phrase was removed from manage ("the phrase now routes straight there [to setup]... manage keeps the seven covering its own actions") — but the actual diff and kindle-dedrm CHANGELOG entry keep all eight phrases in manage, with a different, opposite rationale (kept deliberately because setup is non-model-invocable). The code's current behavior is correct and is in fact what the earlier reviews asked for — but the PR description text is now stale/inaccurate and should be updated before merge so it doesn't misdescribe what the diff does.
    kindle-dedrm/CHANGELOG.md#L278-L283 vs. the PR body's "routing ambiguity resolved" section.

  2. Versioning table has one wrong number. The PR body's version table lists review 0.18.1, but the actual diff bumps plugins/review/.claude-plugin/plugin.json from 0.18.10.18.2 (plugin.json#L4), matching the ## [0.18.2] CHANGELOG entry. Minor, but worth a one-word fix in the PR body. All other 12 plugin versions in the table check out against the diff.

  3. Possible fresh-docs mandate applicability. CLAUDE.md's fresh-docs mandate explicitly scopes in "a skill's frontmatter" as a contract-surface change requiring a same-session WebFetch citation from docs/OFFICIAL-DOCS.md's indexed pages before the change. This PR edits the description: frontmatter field on 25 SKILL.md files — a literal match for that example. The PR's verification section documents extensive re-derivation against this repo's own check-skill.sh/skill-frontmatter.sh logic, but I don't see a citation of current official Anthropic documentation on how description drives skill auto-invocation. This may be a defensible no-op if the team considers the underlying mechanism already-settled prior art rather than a new claim being asserted here — flagging so a maintainer can make that call, not blocking on it.

Not independently verified (author-claimed only)

Per lane instructions, these are not restated as confirmed: the "192/196 skills clean" full-corpus sweep, the "0 collisions" cross-skill trigger check, the "109 phrases added / 0 dropped" count, and the CI gate results table. I did verify by direct diff inspection that no existing single-quoted trigger phrase was removed anywhere in the 25 changed SKILL.md files, and that all 13 plugin.json version bumps (except the one noted above) match their CHANGELOG headers.

No correctness, security, or maintainability issues found beyond the three items above — this remains a low-risk, mechanical frontmatter/changelog/version-bump sweep.

Branch: work/2174-auto

@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 1s —— View job


Security review — no issues found

  • Gather context (git diff origin/main...HEAD, matching PR-reported 51 files / +208/-38)
  • Review changed files for security issues (injection, secrets, access control, GH Actions patterns)
  • Post findings

Scope reviewed: the full PR diff at HEAD b807761 (git diff origin/main...HEAD) — 13 plugin.json semver bumps, 13 CHANGELOG.md prose additions, and 25 SKILL.md YAML-frontmatter description: edits.

Findings: none.

Every hunk in this diff is confined to:

  • description: string edits inside SKILL.md YAML frontmatter (adding/quoting Use when: trigger phrases) — no other frontmatter fields (allowed-tools, argument-hint, disable-model-invocation, shell, etc.) are touched anywhere in the diff.
  • version bumps in plugin.json.
  • New ## [x.y.z] prose sections in CHANGELOG.md.

None of that constitutes an injection surface, a permission/trust-boundary change, or a place secrets/tokens could leak:

  • No executable code, script, hook, or MCP config changed (no .sh, .py, .ps1, .mcp.json, or command-surface files in the diff).
  • No GitHub Actions workflow touched — no trigger, permissions:, or run:/github context changes to worry about.
  • No new URLs, credentials, or tokens introduced in any of the added text.
  • The added description: text is plain natural-language trigger phrasing of the same shape as the phrases it sits beside — checked for instruction-hijacking/prompt-injection phrasing, none present. These strings are matched against user input to decide whether to load a skill; they aren't interpolated into shell commands, templates, or eval'd anywhere, so there's no injection path even in principle.
  • Supply-chain / unpinned-action / dangerous-trigger-pattern concerns are out of scope here per this lane's instructions (zizmor's advisory lane covers those statically) — moot anyway since no workflow or dependency file changed.

On the two functional threads already raised on this PR (Codex's and my own prior code-review comment, re: kindle-dedrm:manage's 'set up Kindle DRM removal' trigger possibly losing model-invocable routing coverage, and the planning:questionnaire rationale inconsistency): both are routing/behavior-correctness observations, not security defects — no privilege, trust-boundary, or data-exposure change results from either outcome, since the underlying setup skill's actual mutations (firewall, ICACLS, Calibre plugins) are unchanged code. Not re-reported here as this review is security-scoped.
· Branch: work/2174-auto

@kyle-sexton
kyle-sexton merged commit 67307ca into main Aug 10, 2026
35 of 37 checks passed
@kyle-sexton
kyle-sexton deleted the work/2174-auto branch August 10, 2026 23:33
kyle-sexton added a commit that referenced this pull request Aug 11, 2026
…eferred gate calls (#2186)

No linked issue

## Summary

Three deferred judgment calls, all made here.

**The uncited doc pages were never dispositioned, and the set is larger
than recorded.** PR #2177
worked from an index of 112 core `/docs/en/` pages with ~33 uncited.
Re-derived today, the index
lists **135** core pages and this repo cites **78**, leaving **57**
unevaluated. #2177 also
demonstrated the miss rate of dismissing by eye: it took six pages that
had been written off as
irrelevant and found every one load-bearing enough to warrant a verdict.
So all 57 get a recorded
disposition here rather than a second eyeball pass.

The finding that mattered is in the **cross-platform contract**. It
reads one axis — the operating
system — and names `feature-availability` as its canonical input. That
page carries two axes,
model provider and subscription plan, and scopes itself to what runs
locally: "The Claude Code CLI
and everything that runs locally work on every provider." The **host
surface** a consumer runs in
was therefore never read at all, by either the contract or its input. It
has to be, because a host
can withhold the plugin system itself rather than one capability, and
where no plugin loads there is
no portable path for one to owe.

**`check-skill.sh` check 5** and **check 12's 4-skill warning floor**
were both left open as "a
separate call". Both are decided, at their own sites, with the reasoning
recorded so neither is
re-litigated from a false premise.

## Fix

### 1. Uncited-page disposition (57 pages)

One stated relevance test, applied to all 57 so the dismissals are
auditable rather than tacit:

> **Relevant** if the page describes a surface a plugin author can
**declare, invoke, or must
> accommodate.** Otherwise **not relevant.**

**Split: 1 adopt / 0 defer / 3 decline / 4 relevant-as-evidence / 49 not
relevant.**

Verdicts land in `docs/PLUGIN-PHILOSOPHY.md` under Native-first →
**Recorded gate runs**, in the

[upstream-drift](https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/upstream-drift/README.md)
four-part shape (claim, basis, as-of date, recheck trigger), following
#2177's form.

| Page | Disposition |
|---|---|
| `platforms` | **Relevant → ADOPT, as a citation.** The canonical
host-surface index; the axis `feature-availability` does not carry.
Lands doctrine. |
| `github-enterprise-server` | **Relevant → DECLINE.** A real
plugin-distribution surface ("Plugin marketplaces \| ✅ Supported") —
declines on need, not subject: nothing here documents a GHES-hosted
mirror or fork. |
| `ultrareview` | **Relevant → DECLINE.** Fails gate 1: every run is
human-confirmed and metered, so no skill can reach it. |
| `chrome` | **Relevant → DECLINE.** Ships as the built-in
`claude-in-chrome` skill; nothing to declare. Recorded because it only
*looked* cited — see the dead-link note below. |
| `desktop`, `vs-code`, `mobile`, `desktop-wsl` | **Relevant → read in
full as the evidence base for the `platforms` row**; no separate
verdict, because they are one finding seen from four pages rather than
four surfaces. Quoted verbatim in that row. |
| `jetbrains` | Not relevant — false friend: "plugin" there is the
JetBrains IDE plugin, a different sense. Ranked 2nd by `plugin`-keyword
density and is the one page where that signal is pure noise. |
| `desktop-quickstart`, `desktop-linux`, `desktop-ios-simulator`,
`web-quickstart`, `troubleshoot-install` | Not relevant — install and
first-run recipes; nothing declarable. |
| `slack`, `claude-tag` | Not relevant on their own — delegation front
ends indexed by `platforms`, which is the adopted citation; `slack` is
additionally being retired for Team/Enterprise. |
| `devcontainer` | Not relevant — container recipe; its only
`marketplace` hit is a VS Code extension link. |
| `gitlab-ci-cd`, `github-actions-cloud-providers` | Not relevant — CI
recipes and provider IAM routing; zero plugin or skill surface
(`gitlab-ci-cd`: 0 keyword hits). |
| `amazon-bedrock`, `google-vertex-ai`, `microsoft-foundry`,
`claude-platform-on-aws` | Not relevant — provider auth/IAM config; the
plugin-facing consequence is the availability matrix, already adopted as
`feature-availability`. |
| `gateways`, `llm-gateway`, `llm-gateway-connect`,
`llm-gateway-protocol`, `llm-gateway-rollout` | Not relevant — org
request-routing plane between the client and a provider; no plugin
declares or observes it. |
| `claude-apps-gateway`, `claude-apps-gateway-config`,
`claude-apps-gateway-deploy`, `claude-apps-gateway-on-aws`,
`claude-apps-gateway-on-gcp`, `claude-apps-gateway-spend-limits` | Not
relevant — deploying and operating Anthropic's gateway product;
`gateway.yaml`, Kubernetes, spend caps. |
| `self-hosted-environments`, `self-hosted-environments-quickstart`,
`self-hosted-environments-configuration`,
`self-hosted-environments-deploy`, `self-hosted-environments-identity`,
`self-hosted-environments-reference`, `self-hosted-environments-testing`
| Not relevant — standing up and operating cloud-session runners on org
infrastructure. |
| `admin-setup`, `authentication`, `legal-and-compliance`,
`third-party-integrations` | Not relevant — enterprise deployment,
identity, and policy plane; no surface a plugin declares or observes. |
| `analytics` | Not relevant — but **fetched, not assumed**, because
per-skill or per-plugin cost attribution would have bound instruction
economy. It has none: attribution is PR-level only. (The
per-skill/per-plugin usage breakdown is a consumer-side `/usage` dialog,
not an authoring input.) |
| `network-config` | Not relevant, and the third clause of the test is
why rather than the family label: proxy, custom CA, and mTLS are
**transport configured on the client**, so a skill making a network call
either succeeds or sees an ordinary failure — there is nothing to
declare or degrade. Its two plugin-adjacent lines are egress allowlist
entries a network admin sets, not a plugin (`downloads.claude.ai` for
"Plugin executable downloads"; `storage.googleapis.com` for "plugin
metadata shown in `/plugin`"). |
| `corporate-launcher` | Not relevant, checked against the page rather
than dismissed as admin tooling: `CLAUDE_CODE_PROCESS_WRAPPER` wraps
"every process Claude Code launches **from its own binary** — the
background service, every session it hosts in agent view, and Claude
Code's relaunches after an update". A plugin's
`${CLAUDE_PLUGIN_ROOT}/bin/` invocation is a Bash-tool subprocess, not a
Claude Code self-spawn, so the `bin/` stance is unaffected and owes no
change. |
| `champion-kit`, `communications-kit` | Not relevant —
internal-advocacy and rollout-comms collateral. |
| `accessibility`, `keybindings`, `terminal-config`, `voice-dictation`,
`fullscreen`, `fast-mode` | Not relevant — consumer client settings; no
plugin declares or must accommodate them. |
| `prompt-library` | Not relevant — copy-paste prompts for users, not an
authoring surface. |

**Doctrine added — one paragraph, plus four table rows.** The
cross-platform contract gains the host
axis, citing `platforms` and restating none of its facts. The three
verbatim host facts (Desktop-in-WSL
sessions lack "connectors and plugins"; `/plugin` "[doesn't] work from
the app" on mobile; Desktop's
Cowork tab sources plugins "not from the CLI's `~/.claude` directory")
live in the gate-run row, where
they carry a recheck trigger — not in the contract, which states only
the rule they establish.

**A dead citation, deliberately not fixed.** Every doc URL this repo
cites was checked live — all 81
slugs plus the 4 subpath citations (`agent-sdk/overview`,
`agent-sdk/agent-loop`, `agent-sdk/plugins`,
`whats-new/2026-w32`). **84 of 85 return 200.** One does not:
`code.claude.com/docs/en/browser` now 404s (`chrome` is the live page).
Its sole occurrence
is `plugins/playbooks/skills/boris/vendor/SKILL.md:938` — a **verbatim
upstream baseline kept for
drift detection**, which the plugin README says to treat as untrusted
and which `/playbooks:update`
owns. Hand-editing it would corrupt the vendor SHA it exists to compare.
Recorded in the `chrome` row
with that path as its recheck trigger instead.

### 2. `check-skill.sh` check 5 — KEEP the extractor as-is (decided,
recorded at the site)

Two premises are usually offered for narrowing to markdown-link targets.
Both are false, and the
comment now says so, because the premise is what keeps the question
alive:

1. **"It matches bare paths in prose."** It does not, and never did.
Both generators are delimited —
backtick-wrapped, or a `](…)` link target — and both are scoped to the
`INTERNAL_DIRS` allowlist.
Naked prose cannot match. (#2179's own summary and CHANGELOG entry
describe it as extracting
"prose and inline-code refs"; the in-script wording is corrected here to
match what the greps do.)
2. **"The backtick branch is redundant."** Measured over the 196-skill
corpus rather than argued:

   | Measure | Count |
   |---|---|
   | Backtick-form refs, all SKILL.md | 282 |
   | Link-form refs, all SKILL.md | 475 |
| **Unique backtick-form refs with no link form anywhere in the same
file** | **122** |
   | …spread across | **39 skills** |
   | …of those 122, resolving to a real file today | **122 (100%)** |

Narrowing would drop 122 real, currently-resolving supporting-file
references across 39 skills.
The link branch being the larger share is not the question; the overlap
is, and 122 refs sit
   outside it.

The false-positive risk that motivated the proposal is real but
**latent, not observed** — zero on
the current corpus. It is handled by message wording (every failure
carries `hand-verify the line
before fixing, may be an illustrative example`) rather than by deleting
coverage of 39 skills.
Reopen only if a false positive is actually observed.

### 3. Check 12's 4-skill warning floor — INTENTIONAL, no dmi carve-out
(all 4 confirmed)

#2181's reasoning holds, and upstream states the premise more strongly
than #2181 did. The skills
doc's frontmatter-behavior table gives, for `disable-model-invocation:
true`:
**"Description not in context, full skill loads when you invoke"** — so
trigger phrasing on such a
skill cannot route anything, at all. `user-invocable` defaults to `true`
(confirmed on the same page,
not assumed), so `github:setup` omitting it is slash-command-only,
exactly its declared contract.

The load-bearing half of #2181's argument is the *stranded-phrase* test,
which is an empirical claim
about the current tree, so each was re-checked against the tree rather
than against #2181's prose:

| Skill | Verdict | Confirmed against the tree |
|---|---|---|
| `discipline:wait-what` | **Right to leave** | Its description *is* the
instruction; the trigger is noticing you have stopped following. No
sibling needed — by construction the model cannot detect it. |
| `firecrawl:update` | **Right to leave** | Maintainer-only. Sibling
`firecrawl:firecrawl` **verified** to carry the consumer phrases
(`'scrape this page'`, `'crawl this site'`, `'WebFetch is blocked'`, …).
Nothing stranded. |
| `playbooks:update` | **Right to leave** | Maintainer-only. Sibling
`playbooks:boris` **verified** to carry `'how does Boris use Claude
Code'`, `'Claude Code workflow tips'`, `'optimize my CLAUDE.md'`, …
Nothing stranded. |
| `github:setup` | **Right to leave** — the weakest of the four as
originally argued, and it holds | #2181 argued from intent
("user-invoked only"). Checked instead for a stranded phrase:
model-invocable siblings `github:advise` and `github:audit` carry the
plugin's consumer-facing routing, including `'help me set up Y'`.
`setup` covers plugin *prerequisites* (gh auth, writing
`.claude/github/`), which is a deliberate slash command, not a routing
target. |

**No carve-out is added**, and that is the recorded call. Exempting
dmi-true from check 12 would
suppress a warning that is doing no harm while hiding the `kindle-dedrm`
failure mode #2181 itself
surfaced — a phrase reachable only from a skill the model can never
match. The floor stays; the
exemptions stay documented at the check-12 site.

## Verification

**Method.** Every page was fetched with `curl -sL …/<slug>.md` — the raw
markdown, not WebFetch.
That removes the summarizer and the truncation window from the loop
entirely, so the METHOD RULE
holds trivially: every upstream sentence quoted in this PR and in the
doctrine is verbatim from a
complete page, and a genuine "the page never states X" is a checkable
claim rather than a routine
false negative. Byte counts confirm no truncation (e.g. `desktop.md`
96,288 bytes, `vs-code.md`
49,764). No page was asked to confirm a sentence from this repo.

**The uncited set was re-derived, not inherited.** The grep was also
re-run with **no `--include`
filters** to be sure no citation lives in a file type the filter misses
— identical result, 81
slugs, so 57 uncited is the real number.

**Every cited URL was checked live**: 84 of 85 (81 slugs + 4 subpath
citations) return 200; the
single 404 is the vendored `browser` link described above.

**The gate-1 check that decided the headline adopt** was run against the
page rather than assumed:
`feature-availability`'s section headings are *Availability by model
provider*, *Availability by
subscription plan*, and *Model availability* — no host-surface axis —
and its only feature table
header row is `| Feature | Pro | Max | Team | Enterprise |`. Had it
carried a host axis, `platforms`
would have been a redundant second index and this would be a decline
instead.

Gates run the CI way, against the **committed** tree, base-ref form:

| Gate | Result |
|---|---|
| `bash scripts/check-contract-slice-prune.sh --check-diff origin/main`
| pass — leaves no path under `docs/topics/` |
| `bash scripts/check-changelog-parity.sh --check-bump origin/main` |
pass |
| `bash scripts/check-changed-skills.sh origin/main` | pass — no changed
skills |
| `bash scripts/check-skill-portability.sh origin/main` | pass — no
skill files in scope |
| `bash scripts/check-shell-portability.sh origin/main` | pass — no
unexcused GNU-only constructs |
| `npx --yes markdownlint-cli2` over all 3 changed `.md` | **0 errors**
|
| `shellcheck` + `shfmt -i 2 -d` on `check-skill.sh` | clean |
| `bash -n check-skill.sh` | clean |
| Line endings | all 5 changed files `i/lf w/lf` |

Because the change to `check-skill.sh` is comments only,
`check-changed-skills.sh` exercises
nothing — so the script was run directly to prove it still parses and
behaves:

- `check-skill.sh measure` → `PASS — 0 errors, 0 warning(s)`, `all 10
base-ref trigger phrase(s) preserved`.
- `check-skill.sh wait-what` → `PASS — 0 errors, 2 warning(s)`, one of
which is verbatim
`description has no 'Use when:' trigger phrasing` — confirming the
documented floor still fires as
  described rather than being silently suppressed.
- `check-skill.test.sh` runs to completion in CI (`plugin-gate`);
locally on Windows/Git Bash it is
impractically slow, per the coverage note #2179 recorded. Nothing here
is behavioral.

`plugins/skill-quality` → **0.15.2** with a matching `## [0.15.2]`
entry. The `docs/` changes are
docs-only and owe no plugin bump; the `upstream-drift` **Adopters**
registry already carries a row
for the gate-run table (added in #2177), and these rows join that table
rather than create a new
adopter, so that convention needs no version change.

`docs/OFFICIAL-DOCS.md` gains the four newly load-bearing pages, per the
rule its own warning states
and the precedent #2177's review set: a needed page that is not listed
must be added.

No `docs/topics/<slug>/` directory was created — the durable outcome is
doctrine text, as the
Contract-tier prune rule requires.

## Review rounds

Three threads, all real, all answered and resolved. Each found a defect
in the *basis* of a row
rather than in its verdict, which is the failure mode a decision record
most needs caught: a verdict
outlives the reasoning nobody re-reads.

- **The GHES row's premise was overstated and its trigger fired on
arrival** (`chatgpt-codex-connector`).
It claimed "every plugin README ships the github.com shorthand".
Re-derived from the tree: 54 of 65
carry the literal string, 9 carry no install block, `dometrain` points
at another github.com
marketplace, and `plugins/github/README.md` — deliberately
marketplace-agnostic — uses the
`<marketplace-owner>/<marketplace-repo>` placeholder. All are still
`owner/repo` shorthand, so the
trigger now names the form that actually signals a non-github.com host,
a **full git URL**, of
which the tree has none. The verdict stays Decline, but the review
surfaced a real finding that had
been waved through and is now recorded in the row: a consumer
redistributing the `github` plugin
from a GHES-hosted marketplace would follow that README and have the
shorthand silently resolve to
  github.com instead of their own instance.
- **"Platform" was doing two jobs** (`chatgpt-codex-connector`). The
existing `feature-availability`
row and `docs/OFFICIAL-DOCS.md` both described that page as covering
"platform, provider, and plan",
while this change rests on the host axis being absent from it. Both
senses of the word in one table
would let a future audit read the host axis as already covered and
retire the new row as redundant.
The page's own sense is the **provider** platform — its axis headings
are *Availability by model
provider* and *Availability by subscription plan* — and both sites now
say so explicitly.
- **The `platforms` row claimed four evidence pages and quoted three**
(`claude`). Correctly
diagnosed as a missing fact rather than an overstated page: `vs-code`
does carry a host-axis fact,
and the most directly plugin-relevant of the four — its CLI-vs-extension
table gives
`Commands and skills` as `All` for the CLI against `Subset (type / to
see available)` for the
extension, so a skill this fleet ships may not be reachable there. It is
now quoted in the row.

All gates and `markdownlint-cli2` re-run clean over the changed files
after these edits. CI is green,
including `plugin-gate` — which runs `check-skill.test.sh`, the only
executable proof that the
check-5 comment insertions changed no behavior.

## Related

- #2177 — established the Recorded-gate-runs table and its four-part row
form; this run extends it
  and corrects its page census (112 → 135 core pages, ~33 → 57 uncited)
- #2179 — deferred the check-5 extractor question as "a separate call";
decided here
- #2181 — swept 196 skills for `Use when:` phrasing and left 4 with
stated reasoning; all 4 re-reviewed
  and confirmed here
- #2169 — the gate doc-currency audit these findings trace back to

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

verification:measure description has no 'Use when:' trigger phrasing

1 participant