Skip to content

nacharbeit rubric ​

The fixed rule set nacharbeit grades a Claude Code plugin against: every skill, agent, command, workflow prompt and reference file, plus its hooks, scripts, report viewers, manifest, README, CHANGELOG and the repo-level developer docs that wire it in. This file is an input to the review, never an output of it. Its SHA-256 rides in the workflow args as rubricHash; every finding cites one rule_id from the tables below, and a rerun with an edited rubric cannot hit the resume cache.

Contents ​

Two rule kinds, in six families:

  • Mechanical (M-* H-* S-* A-* P-* D-*) — checked by scripts/nacharbeit_lint.py with regex, a YAML parser, a JSON parser and Python's ast. No model in the loop. Model finders are told these ids are out of scope.
  • Judgement (Q-* HQ-* SQ-* AQ-* PQ-* DQ-*) — checked by the sonnet finders, refuted by sonnet verifiers, synthesized by opus. A judgement finding must quote ≥20 verbatim characters from the file.

Sources and precedence ​

Where sources disagree, official Anthropic documentation wins:

  1. Claude Code skills
  2. Claude Code subagents
  3. Claude Code hooks
  4. Claude Code plugins reference
  5. Agent Skills best practices

Third-party rules fill gaps only: the installed plugin-dev and skill-creator plugins (Anthropic-authored but not normative), obra/superpowers writing-skills, and the werkstoff workshop's own docs/plugin-authoring/references/craft-standards.md, report-viewer-standard.md and docs/orchestration/references/hazards.md. The seven contradictions between those sources are settled in the last section.

Severity ​

severitymeaning
blockerthe component will not load, will never trigger, or violates a hard cap the runtime enforces
majorthe component triggers or runs wrong in a way a user would notice
minormeasurably worse than the recommendation; fix is local
nitstyle; only worth fixing when touching the file anyway

Fix tier ​

Every finding names the cheapest model that can apply its fix without judgement it lacks: haiku (trim, delete, add TOC, path fix), sonnet (rewrite a description, add a negative trigger, restructure steps, add an output example), opus (merge or rescope components, redesign step order), human (changes a plugin's contract or pipeline order).

M — mechanical rules (nacharbeit_lint.py) ​

Frontmatter and description ​

idruleapplies toseveritysource
M-FM-PARSEFrontmatter starts at line 1 with ---, parses as YAML, is a mapping with a non-empty description (and name for agents).skill, agent, commandblockercode.claude.com/skills "YAML frontmatter must start at line 1"; sub-agents "A file without name or description is skipped"
M-DESC-LENdescription ≤ 1024 characters.skill, agentmajorplatform best-practices "Maximum 1,024 characters"
M-DESC-XMLdescription contains no XML-style tags such as <example>.skill, agentmajorplatform best-practices "Cannot contain XML tags"
M-DESC-POINTERdescription does not refer the reader to the file's own body ("see the agent body", "details in the body below", "see the … section").skill, agentminorF8 decision below; sub-agents "the description is what the router reads"
M-DESC-PERSONdescription is third person: no "I can", "I will", "You can use this", "you should".skill, agentminorplatform best-practices "Always write in third person"
M-DESC-VAGUEdescription is not a generic capability claim ("Helps with…", "Processes data", "Does stuff").skill, agent, commandmajorplatform best-practices "Avoid vague descriptions"
M-DESC-WHENONLYSkill description does not open with the when-only template This skill should be used when/after/… — it must lead with what the skill does.skillminorF1 decision below; code.claude.com/skills "Put the key use case first"
M-NAME-FORMATname ≤ 64 chars, lowercase letters, digits, hyphens only, no anthropic/claude, equal to the skill directory or agent file stem.skill, agentmajorplatform best-practices frontmatter note

Body, references, and wiring ​

idruleapplies toseveritysource
M-BODY-LINESSKILL.md body (after frontmatter) < 500 lines.skillminorcode.claude.com/skills "Keep SKILL.md under 500 lines"
M-REF-TOCA reference file > 100 lines has a table of contents (a Contents/Table of contents heading or a link list) within its first 40 lines.referenceminorplatform best-practices "reference files longer than 100 lines, include a table of contents"
M-REF-DEPTHA reference file does not link to another reference file (references stay one level deep from SKILL.md).referenceminorplatform best-practices "Keep references one level deep"
M-REF-UNWIREDEvery file under a skill's references/ is linked or named from that skill's SKILL.md.skillminorcode.claude.com/skills "Reference supporting files from SKILL.md so Claude knows what each file contains and when to load it"
M-LINK-BROKENEvery relative markdown link or backticked relative path under the plugin resolves to an existing file.allmajorcraft-standards "wiring references"; plugin-validator
M-DUP-CONTENTNo two prompt-bearing files anywhere under plugins/ are byte-identical (a fact lives in one place). A group whose every copy is a .rrt.toml artifact_targets path is exempt: that is one source distributed and hash-locked, the fix this rule asks for. One hand-made copy in the group voids the exemption.allminorcraft-standards "no duplication"; plugin-dev skill-development
M-SKILL-VOICESKILL.md body avoids second-person address ("You should", "You need to", "You can"); it uses imperative or infinitive form.skillnitplugin-dev skill-development "imperative/infinitive form"

Agents ​

idruleapplies toseveritysource
M-AGENT-VOICEAgent body does not speak in first person ("I will", "I am going to").agentnitplugin-dev agent-development; sub-agents "Be explicit about behavior"
M-AGENT-MODELAgent model, if present, is one of inherit, sonnet, opus, haiku, fable, or a full model id.agentmajorsub-agents model field
M-AGENT-TOOLS-SHAPEAgent tools, if present, is a comma-separated string of known tool names (not a YAML list, not *).agentminorsub-agents tools allowlist syntax; CLAUDE.md gotcha on tool-declaration formats
M-AGENT-TOOLS-VERBSAn agent whose body instructs it to edit, write, create, or modify files declares Edit or Write; an agent whose body says it is read-only does not declare them.agentmajorsub-agents "Read-only subagents: use tools: Read, Grep, Glob"
M-VERSION-FIELDFrontmatter carries no version: key (not a documented field; nothing maintains it).skill, agentnitF4 decision below; craft-standards

Commands, paths, and secrets ​

idruleapplies toseveritysource
M-CMD-ARGHINTA command body that uses $ARGUMENTS, $1…$9 declares argument-hint.commandminorplugin-dev command-development
M-CMD-DESC-LENCommand description ≤ 150 chars (it renders in /help).commandnitplugin-dev command-development "≤~60 chars" relaxed
M-TIME-SENSITIVEBody contains no dated instructions ("before <month year>", "as of <year>", "until Q3 <year>").allminorplatform best-practices "Avoid time-sensitive information"
M-WIN-PATHSNo backslash file paths.allnitplatform best-practices "Avoid Windows-style paths"
M-BASH-WILDCARDallowed-tools never grants Bash(*), Bash, or * unscoped.skill, commandminorplugin-dev command-development "scope Bash"
M-SECRETSNo credential-shaped literals (sk-…, ghp_…, AKIA…, password: "…").allblockerplugin-validator

Q — judgement rules (finders and verifiers) ​

Angles map to the user's review axes: meaning, contract, clarity, step-logic, procedure, cannibalization, other.

Meaning and contract ​

idangleruleseveritysource
Q-MEANING-PROMISEmeaningThe body delivers what the description promises, and promises nothing the body does not do.majorplatform best-practices "description … the rest of SKILL.md provides the implementation details"
Q-MEANING-CONTRACTcontractA component that produces an artifact states its output contract (where it writes, what shape) in one place the reader can find.majorcraft-standards; output-shape-findings
Q-MEANING-ASSUMEDmeaningNo hidden precondition: every input the body relies on (a file, a prior skill's artifact, a setting) is named as required, with what happens when it is absent.majorCLAUDE.md "never infer a missing gating value"
Q-FIXTURE-AGREESmeaningA claim in shipped prose (SKILL.md, agent, reference page) that names a committed fixture or example-data path, about that fixture's state, contents or shape, matches the fixture. Judgement, not mechanical: deciding whether a sentence and a JSON record disagree needs reading both; scoped to prose that names a committed path so the finder has an anchor.majorissue #85

Clarity ​

idangleruleseveritysource
Q-CLARITY-CONCISEclarityNo paragraph explains what Claude already knows; every paragraph justifies its recurring token cost.minorplatform best-practices "Concise is key"; code.claude.com/skills "every line is a recurring token cost"
Q-CLARITY-TERMSclarityOne term per concept throughout the file (not finding/issue/violation for the same thing).minorplatform best-practices "Use consistent terminology"
Q-CLARITY-OPTIONSclarityOne default plus a named escape hatch, not a menu of approaches.minorplatform best-practices "Avoid offering too many options"
Q-CLARITY-EXAMPLEclarityWhere output format matters, at least one concrete, complete example exists; placeholder-only templates do not count when the content is non-obvious.minorplatform best-practices "Examples pattern"; output-shape-findings
Q-CLARITY-AMBIGclarityNo sentence a careful reader could execute two different ways (undefined pronoun referents, "it", "this", "the file" with several candidates).majorcode.claude.com/sub-agents "Be explicit about behavior"

Step logic ​

idangleruleseveritysource
Q-STEPS-NUMBEREDstep-logicMulti-step work is numbered, in execution order, ideally with a copyable checklist.minorplatform best-practices "Use workflows for complex tasks"
Q-STEPS-INPUTSstep-logicEvery step consumes only artifacts an earlier step or a named input produced; no forward reference.majorplatform best-practices workflow pattern
Q-STEPS-GATEstep-logicA step that can fail names its gate and where to return ("Only proceed when…"; "If X fails, return to step N").majorplatform best-practices "Implement feedback loops"
Q-STEPS-TERMINATIONstep-logicEvery loop or retry names its stop condition and its escalation path.majorzeugnis agentic-reliability categories; superpowers writing-skills
Q-STEPS-PREDICATEstep-logicBranches key off an observable predicate, not an unconditional rule plus exemption clauses ("unless it matters").minorsuperpowers writing-skills "observable conditional"

Procedure ​

idangleruleseveritysource
Q-PROC-WHATWHENprocedureDescription states both what the component does and when to use it, with key terms a router would match; not overfit to a literal query list.majorplatform best-practices "Writing effective descriptions"
Q-PROC-FREEDOMprocedureSpecificity matches fragility: exact commands for fragile sequences, prose direction for open-ended judgement.minorplatform best-practices "Set appropriate degrees of freedom"
Q-PROC-TOOLS-ROLEprocedureAgent tool grant is the minimum its stated role needs; model (if set) matches task difficulty (haiku read-only research, sonnet balanced, opus complex reasoning).majorsub-agents "Model selection" and "Tool access"
Q-PROC-OUTPUT-SHOWNprocedureA component producing a structured artifact shows one fenced instance of the shape, including the empty branch, rather than naming fields in prose.minoroutput-shape-findings §4; platform best-practices "Template pattern"
Q-PROC-DISCLOSUREprocedureContent sits at the right level: always-loaded description is short; body is the standing instruction; bulky reference goes to references/ and is pointed at with when-to-read guidance.minorcode.claude.com/skills "Add supporting files"; platform best-practices "Progressive disclosure"
Q-PROC-CLAUDEMD-DUPprocedureAn agent body does not restate repository CLAUDE.md rules that load automatically.nitsub-agents "Don't duplicate CLAUDE.md"
Q-PROC-DESC-DUPprocedureA description does not restate what the file's own body already carries. The mirror of Q-PROC-CLAUDEMD-DUP, and the expensive direction: the description is loaded into every session, the body only on dispatch. Judgement only — see F8 for why no mechanical predicate decides it.minorF8 decision below
Q-PROC-FORK-TASKprocedureA skill with context: fork contains an actionable task, not only guidelines.majorcode.claude.com/skills "Avoid forked skills without task instructions"

Cannibalization ​

idangleruleseveritysource
Q-CANN-NEGATIVEcannibalizationWhere a sibling component covers an adjacent job, the description says when not to use this one and names the sibling.majorplugin-dev agent-development "Do not invoke when…"
Q-CANN-OVERLAPcannibalizationTwo components do not claim the same job for the same trigger unless one names the other as an intended handoff. Judged from the routing simulation, not from prose alone.majorplatform best-practices "Claude uses it to choose the right Skill from potentially 100+"
Q-CANN-INTERNALcannibalizationWithin one plugin, skills have distinct triggers a router can separate.majorplugin-dev component-patterns "distinct, non-overlapping roles"
Q-ROUTE-MISScannibalizationA documented example prompt (one carrying a > Triggers line in the prompt index) routes, by majority of the routing simulation, to the component it names. Produced in code from the simulation, never by a finder, and only when the router proxy clears 0.8 accuracy on known answers; below it the rule is recorded as skipped, not emitted.majordocs/prompt-index.md known answers; the misroute the simulation always computed and discarded
Q-CANN-CAPTUREcannibalizationNaming a sibling as a handoff excuses an overlap only while each side still wins its own documented prompts. A pair judged intended-handoff or leave where one side's known-answer prompts route to the other is a capture. Produced in code, measured runs only.majorcupertino: cupertino-council fired 2/2 on cupertino-backwards's documented prompts while the handoff wording excused the overlap

Other ​

idangleruleseveritysource
Q-OTHER-RIGIDITYotherGuidance form matches failure type: prohibitions and red-flag tables for rule-skipping, positive recipes for wrong-shaped output. Capitalisation density alone is never a finding.nitF7 decision below; superpowers writing-skills
Q-OTHER-STATEFULotherAny stateful field (status marker, version, amendments log) has something that keeps it current, or is removed.minorcraft-standards "structure implies a maintainer"
Q-OTHER-NARRATIVEotherA skill or reference is a reusable instruction, not a narrative of one past session.minorsuperpowers writing-skills
Q-OTHER-INJECTIONotherThe prompt contains no instruction-shaped text aimed at a reader model that the author did not intend (report, do not act).majorcanonize.js UNTRUSTED discipline
Q-OTHER-SCRIPT-INTENTotherEvery bundled script reference says whether to run it or read it, and names its required packages.minorplatform best-practices "Make execution intent clear"

H — hooks ​

Applies to hooks/hooks.json (kind hooks) and every script it declares (kind hookscript). The contract is Claude Code's PreToolUse protocol as plugins/takt/hooks/takt_guard.py states it: deny = exit 2 + reason on stderr + stdout JSON {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "…"}}; omitting hookEventName, or using systemMessage instead of permissionDecisionReason, makes the runtime silently ignore the deny.

Mechanical ​

idruleapplies toseveritysource
H-JSON-PARSEhooks.json parses; hooks maps an event name to a list of {matcher, hooks[]}; ≥1 event is registered.hooksblockerhooks docs (hooks.json shape); tools/surface-index/build_surface_index.py raises on the same
H-TYPE-COMMANDEvery handler is type: "command".hooksmajorhazards.md; verify-hooks-deny.py ("declares type=prompt — not enforcement")
H-CMD-PLUGIN-ROOTEach command locates its script through ${CLAUDE_PLUGIN_ROOT} and hard-codes no absolute path.hooksmajorplugins-reference (${CLAUDE_PLUGIN_ROOT})
H-SCRIPT-EXISTSThe script a command names exists under the plugin.hooksblockerverify-hooks-deny.py failure mode missing
H-TIMEOUTEach command handler sets an integer timeout.hooksminorhooks docs timeout
H-MATCHER-KNOWNmatcher is |-joined documented tool names (or empty / *).hooksminorhooks docs (a matcher that matches nothing is a hook that never runs)
H-MATCHER-MULTIEDITA matcher naming Edit or Write also names MultiEdit.hooksnithazards.md ("andon's matcher does not list MultiEdit")
H-INERT-STATEDhooks.json's description states when the hook is inert.hooksnithazards.md cards ("Inert unless")
H-DENY-SHAPEA script that emits permissionDecision also emits hookEventName; a script using systemMessage without permissionDecisionReason fails; a script that never emits a decision fails. A Stop/SubagentStop hook's decision is {"decision": "block", "reason": …} and counts as one.hookscriptmajorhooks docs (PreToolUse decision control; Stop decision control); CLAUDE.md silent-defect row
H-EXIT-2The deny path exits 2 (sys.exit(2), return 2 through sys.exit(main()), or a DENY/BLOCK constant equal to 2).hookscriptmajorhooks docs ("exit code 2 = blocking error")
H-ESCAPE-HATCHThe script reads a <NAME>_DISABLE_GUARD env var and names it again in a deny reason.hookscriptminorhazards.md ("escape hatch named in the hook's own deny message")
H-FAIL-CLOSEDThe last broad except handler calls deny(…) (or block(…) in a Stop hook), not allow()/exit(0) (AST proxy; documented).hookscriptminorhazards.md "All fail closed"; takt docstring
H-MULTI-PATHAn edit-gating script reads edits[].file_path and file_paths besides file_path.hookscriptminortakt_guard.py::edit_targets; test/plugins/verify-takt-payload-shapes.py
H-TEST-EXISTStest_<stem>.py exists beside the hook script (or anywhere under the plugin).hookscriptminorCLAUDE.md "verify the instrument"; lehre/andon/befund convention

Judgement ​

idangleruleseveritysource
HQ-LOCK-SCOPEcontractA guard that arbitrates edits gates on a per-dispatch lock naming the files it may touch, never on repo-level state (the payload carries no field saying whose edit it is).majorhazards.md "Why a hook cannot tell whose edit it is"
HQ-EMPTY-SET-DENYstep-logicWhen a gated tool's target set cannot be determined, the script denies.majortakt docstring
HQ-DENY-NOT-RECIPEotherThe denial text does not tell the caller how to forge the state that would satisfy the gate.majorlehre Gate 0 comment; takt ESCAPE_HATCH wording
HQ-INERT-MATCHESmeaningThe inert condition stated in hooks.json and the README is the marker the script actually tests.majorhazards.md cards
HQ-README-HOOKprocedureThe README documents the matcher, the inert condition, the escape hatch and how to test the hook.minorplugins/takt/README.md "## Hooks", "## Testing"

S — scripts ​

Applies to scripts/**/*.{py,sh,js} and hooks/*.py (kinds script and hookscript), skipping fixtures/ and testdata/ for these mechanical script-style rules only — that skip is not a skip of Q-FIXTURE-AGREES, which reads a fixture's own contents on purpose and applies wherever shipped prose names a committed fixture path, fixtures/ and testdata/ included. S-JS-SYNTAX, S-WF-SHAPE, S-WF-MODEL and S-WF-RELAY also cover workflows/*.js.

Mechanical ​

idruleapplies toseveritysource
S-PY-COMPILEast.parse succeeds.script (.py)blockerCLAUDE.md verification list
S-JS-SYNTAXnode --check passes; when node is absent the rule is listed under skipped, never silently passed.script (.js), workflowblockerscripts/ci/check-js-syntax.sh
S-WF-SHAPEA workflow script has a top-level return. The runtime evaluates the body, so one wrapped in export default defines a function nothing calls and dispatches nothing. Detected by parsing a copy as an ES module, where node's Illegal return statement refusal is the positive signal; when node is absent the rule is listed under skipped.workflowblockerscripts/ci/check-js-syntax.sh; the workflow-authoring contract
S-WF-MODELA literal model passed to agent() is a valid per-call model: haiku, sonnet, opus, fable, or a full id matching ^claude-[a-z0-9.-]+$. An omitted or caller-supplied model inherits by design (#118) and is never a finding: no options argument, options without a model key, options in a variable or built with Object.assign, a spread with no model key (...modelFor('worker')), model: undefined/null/void 0 and any dynamic value (model: args.model) all pass, leaving a dynamic value's validity to a runtime guard. An unknown literal ('gpt-5'), the literal 'inherit' (documented only for agent frontmatter; omit model to inherit), a spread after a stated model key, and agent aliased or passed as a value all fail. Strings, comments, template text and regex literals are masked first, so agent( in a prompt is not a call. Per-role tiering is a recommendation, not a gate.workflowmajorscripts/ci/check_workflow_models.py (vendored); docs/orchestration/references/delegation.md "Which model for which workstream"; issues #87, #118
S-WF-RELAYA workflow that dispatches carries the canonical relayed-request briefing (RELAY_TEXT) verbatim, so a user's "merge it" reaching a subagent is noted and left to the orchestrating session. A paraphrase fails. Presence per file, not per prompt.workflowminorsame checker; delegation.md "Writing the dispatch prompt"; issue #90
S-SHEBANGAn entry-point script starts with #!/usr/bin/env python3 (or bash).scriptnitrepo convention
S-DOCSTRING-USAGEAn entry-point .py has a module docstring stating its usage, or an argparse --help; test files are exempt.scriptminorplatform best-practices "Make execution intent clear"
S-ARGPARSEAn entry-point script reading sys.argv imports argparse.script (.py)minorsame; --help must exist
S-SILENT-REGEXWhere a regex is used, no \b!==, \b===, [^.]{0,N≥50}, or (in shell) [^\n].script, workflowmajorCLAUDE.md silent-defect table; test/plugins/lint-oracles.sh
S-EXCEPT-SWALLOWNo bare or Exception handler whose body is only pass.script (.py)majorCLAUDE.md "looks correct and silently does nothing"
S-SHELL-TRUENo subprocess call with shell=True (AST).script (.py)minorplugin-validator
S-REFERENCEDEvery non-test script is named by a skill, agent, command, README, hooks.json or an importing sibling script.scriptminorbest-practices "reference supporting files"; audit_reachability.py class unreferenced

Judgement ​

idangleruleseveritysource
SQ-INTENTprocedureThe docstring states purpose, inputs and outputs; the caller says whether to run or read it.minorscript-side twin of Q-OTHER-SCRIPT-INTENT
SQ-FAIL-LOUDstep-logicA missing or unreadable input exits non-zero and says so; it never reports "nothing found".majorCLAUDE.md "a guard predicated on its own input existing is not a guard"
SQ-STALE-OUTPUTcontractA failed run cannot leave a previous output looking fresh (atomic write, or a FAILED marker).majorCLAUDE.md "a failed run leaves the previous output in place"
SQ-SELF-ASSERTotherA checker ships a calibration that can make it go red.majorCLAUDE.md "verify the instrument"

A — assets and viewers ​

Applies to assets/*-viewer.html (kind viewer), its screenshot, and the README citation. The six rules the CI checker already decides delegate to scripts/check_viewer_conformance.py's check() (vendored from scripts/ci/); nothing in it is reimplemented. The standard is docs/plugin-authoring/references/report-viewer-standard.md.

Mechanical ​

idruleapplies toseveritysource
A-R1-VERDICTA static element with class="verdict" states the finding in words.viewermajorstandard R1 → checker code R1
A-R4-LEGENDA static legend or note element, visible without interaction.viewermajorstandard R4 → R4
A-S1-HEIGHTNo hard-coded 61px header height.viewerminorstandard S1 → S1
A-S2-HEADCSP default-src 'none', the canonical tokens marker, <title> = <plugin> — <noun>, a static <h1> equal to it and not overwritten.viewermajorstandard S2 → S2
A-C1-SCREENSHOT<viewer>-screenshot.jpg exists, 1600 px wide, and parses.viewerminorstandard C1 → C1
A-C2-DEMO-DATAThe README cites committed demo data under scripts/fixtures/ or scripts/testdata/.viewerminorstandard C2 → C2
A-S3-INNERHTMLNo innerHTML=/outerHTML=/insertAdjacentHTML( fed anything but a constant literal.viewermajorstandard S3 (second barrier)
A-S4-FAIL-VISIBLEThe script contains a visible-failure branch that tells the reader to re-run or regenerate (documented proxy).viewerminorstandard S4
A-NO-CDNNo <script src= / <link href= to the network.viewermajorstandard S2 CSP rationale; tools/d3-subset
A-TOKENS-PRESENTA plugin with a viewer ships assets/tokens.css.viewerminorstandard "What is mechanically checked"
A-BUILDER-EXISTSA scripts/*.py names the viewer or injects the __DESIGN_TOKENS__ marker.viewerminorstandard (builder + template pairing)
A-REPORT-KITThe template carries <!--__REPORT_KIT__--> and the plugin vendors assets/report-kit.css, assets/report-kit.js and scripts/report_kit.py. Half a migration is a finding.viewermajorstandard R6–R8 (content tier); tools/report-kit/
A-C4-ALTThe README's screenshot alt text is ≥10 characters and not the plugin name.readmenitstandard C4
A-VIEWER-REQUIREDThe plugin ships at least one assets/*-viewer.html. Keyed on the manifest, because every other A-* rule grades a viewer that exists and so can never report one that does not.manifestmajorCLAUDE.md "Every plugin ships an HTML report viewer"

Judgement ​

idangleruleseveritysource
AQ-R2-ONCEclarityNo number is printed twice.minorstandard R2
AQ-R3-ACTIONABLEclarityAn actionable number does not look inert.minorstandard R3
AQ-R5-HEIGHTprocedureHeight derives from content, not a fixed viewport.minorstandard R5
AQ-C3-SHOWS-FAILUREmeaningThe demo data shows the failure the plugin exists for.majorstandard C3

P — manifest, README, CHANGELOG ​

Applies to .claude-plugin/plugin.json (kind manifest), README.md (kind readme), CHANGELOG.md (kind changelog) and the plugin's skills/ and references/ layout. P-MARKETPLACE-MEMBER runs only with --marketplace and is fix-tier human: the marketplace entry lives outside the plugin.

Mechanical ​

idruleapplies toseveritysource
P-MANIFEST-PARSEplugin.json exists and parses to an object with non-empty name, version, description.manifestblockerplugins-reference; claude plugin validate --strict
P-MANIFEST-NAME-DIRname equals the plugin directory name.manifestmajorplugins-reference
P-MANIFEST-SEMVERversion is x.y.z.manifestmajorrrt package_json version target
P-AUTHOR-PRESENTauthor.name is non-empty and not a placeholder.manifestmajortest/plugins/lint-plugin-authors.py
P-MARKETPLACE-MEMBERThe marketplace entry exists; author.name and description equal the manifest's; source points at ./plugins/<name>.manifestmajorlint-plugin-authors; .rrt.toml field_targets
P-MANIFEST-KEYWORDSkeywords is a non-empty list.manifestnittakt convention
P-MANIFEST-LICENSElicense is present.manifestnittakt convention
P-DESC-BUDGETAgent and skill description totals across every linted plugin stay under nacharbeit_lint.DESC_BUDGET (agent 32000 chars, skill 56000). Reported once, on the largest contributor's manifest; skipped when only a subset of the marketplace is linted.manifestmajorF8 decision below; platform cap of 15k tokens for the agent listing
P-README-H1README.md exists and its first heading is # <name>.readmeminorlehre/takt
P-README-THESISA bold one-line thesis sits directly under the H1.readmenitlehre/takt
P-README-WHY-NOT## Why this exists and ## What it is not are present.readmeminorlehre
P-README-PURPOSE-BLOCKAbove the first ##: a **The name.** paragraph and a - **Use when** / - **Not when** pair whose not-when line names a sibling plugin in backticks; then a ## Use case with **Situation.**, **Call.**, **Writes.**, **Next.** and a fenced output excerpt.readmeminorissue #144
P-README-INSTALLAn ## Install section carries /plugin install <name>@… or a --plugin-dir line.readmeminorlehre/takt
P-README-PROMPTS-BLOCK(with --readme-markers) the rrt example-prompts-intro marker pair is present.readmeminor.rrt.toml shared_blocks; rrt docs inject --check
P-README-PROMPT-TRIPLEUnder ## Example Prompts, every ##### label is followed by a ````prompt fence, and ≥1 exists (mirrors build_prompt_index.py's scan).readmeminortools/prompt-index/build_prompt_index.py
P-README-VERIFYA ## Verifying … or ## Testing section exists.readmenitlehre/takt
P-README-ESCAPE-HATCHA plugin with a hook names its _DISABLE_GUARD variable in the README.readmeminorhazards.md
P-README-SCREENSHOTA plugin with a viewer embeds its screenshot in the README.readmeminorstandard C2
P-CHANGELOG-UNRELEASEDCHANGELOG.md exists with a ## [Unreleased] section.changelogminor.rrt.toml changelog_file
P-SKILL-DIR-HAS-FILEEvery skills/*/ directory contains SKILL.md.manifestmajorcode.claude.com/skills (a directory without one is silently ignored)
P-REF-REACHABLEEvery plugin-level references/*.md is named by a skill, agent, command or the README.manifestminorplugin-level twin of M-REF-UNWIRED

Judgement ​

idangleruleseveritysource
PQ-THESISmeaningThe README thesis and the manifest description promise the same job.majorplugin-level Q-MEANING-PROMISE
PQ-NOT-SECTIONcannibalization"What it is not" names the sibling plugins with adjacent jobs.majorlehre README; routing.md
PQ-WRITE-SURFACEcontractThe description states the write surface: read-only, a scoped output dir, or the named Edit exceptions.majorevery werkstoff marketplace entry
PQ-PROMPTS-ROUTEcannibalizationThe example prompts route to this plugin's own skills (cross-checked with the routing simulation).majordocs/prompt-index.md known answers
PQ-NARRATIVEotherThe README is a reference, not a log of one session.minorsuperpowers writing-skills

D — repo-level developer docs ​

Applies only with --docs-root (kind docs, one unit per plugin). These are the places a docs-bearing repo like werkstoff has to wire a plugin into; each has drifted at least once (lehre shipped without a root-README bullet or a hazards card).

Mechanical ​

idruleapplies toseveritysource
D-DOCS-STUBdocs/plugins/<name>.md exists and @includes the plugin README.docsmajortest/docs/docs_ux_audit.py
D-SIDEBAR-ENTRYdocs/.vitepress/config.mjs links /plugins/<name>.docsmajorlehre commit e3d4f53
D-SIDEBAR-REFSEvery docs/plugins/references/*.md stub that includes one of the plugin's references is linked from the sidebar.docsminorlehre's ruleset-schema stub
D-GRID-ENTRYPluginGrid.vue carries a card for the plugin.docsminorthe component's own "hand-kept" comment
D-COUNT-PROSEThe "N plugins" count in headings, taglines and the CLAUDE.md Layout line equals the plugins on disk (reported once).docsminordocs/index.md, docs/plugins/index.md, CLAUDE.md
D-ROOT-READMEThe root README links plugins/<name>/README.md and names the plugin.docsminorroot README ## Plugins
D-CLAUDE-MD-LAYOUTCLAUDE.md's ## Layout list names the plugin.docsminorCLAUDE.md
D-ORCH-TABLESdocs/orchestration/README.md mentions the plugin (so its skills are classified as orchestrators or leaves).docsminororchestration README
D-HAZARDS-CARDA plugin with a hook has a card in docs/orchestration/references/hazards.md.docsminorhazards.md
D-CATALOG-VALIDEvery docs/catalog/** beat naming <name>:<id> resolves to a skill, agent or command of the plugin.docsmajortools/catalog-validator/validate_catalog.py
D-GENERATED-FRESHdocs/prompt-index.md has the plugin's section and surface.json carries its current version.docsmajorthe two generators; docs.yml diff gate

Judgement ​

idangleruleseveritysource
DQ-DOCS-MATCHmeaningDocs-site prose about the plugin matches what its skills and hooks do.majorplugin-level Q-MEANING-PROMISE
DQ-ROUTING-STATEDcannibalizationrouting.md names which sibling pipeline owns an overlapping task.minorrouting.md "Two honest overlaps"

Settled contradictions (F1–F7) ​

#disagreementdecision
F1description = what + when (official, plugin-dev) vs when-only (superpowers) vs intent categories, no literal list (skill-creator)What + when, third person, key terms included. When-only boilerplate is M-DESC-WHENONLY (minor). Summarising the workflow in the description is not penalised. Overfit literal query lists are a Q-PROC-WHATWHEN minor.
F2agent <example> transcript blocks required (validator) vs deprecated (docs)Neither required nor forbidden in the body. In the description field they are M-DESC-XML (official: no XML tags) and usually also M-DESC-LEN.
F3five different body-length ceilings< 500 lines (official). Word-count targets are advisory and produce no finding.
F4version: in frontmatterNot a documented field. M-VERSION-FIELD, nit.
F5hook docs contradict themselves on prompt-hook events and hooks.json shapeIn scope, as H-* / HQ-*. An enforcement hook is type: "command" (a prompt hook asks a model to decide, which is the model-mediated path a hook exists to replace — hazards.md); H-TYPE-COMMAND reports a prompt hook. The hooks.json shape graded is the one every command hook in the wild uses: hooks.<event>[].{matcher, hooks[].{type, command, timeout}}.
F6.claude/commands/ is "legacy"Reported once, as a cross-plugin nit against passung's command set, not per file.
F7ALL-CAPS / rigid structure is a yellow flag vs bulletproofing toolkitForm follows failure type (Q-OTHER-RIGIDITY). Density of MUST/NEVER is never a finding on its own.
F8description-restates-body: mechanical rule or judgement?Judgement (Q-PROC-DESC-DUP), not mechanical — measured, not assumed. Word-overlap between a description sentence and the body was calibrated on a labelled corpus of 203 sentences (112 known-duplicated, removed 2026-09-20; 91 known-good, retained). The measure is INVERTED: duplicated sentences scored a median 0.43 overlap, retained ones 0.67, because a trigger sentence names other components' vocabulary while "what this agent does" reuses the body's own words. No threshold separates them — at every cut, false positives outnumber true ones (0.70: 13/112 caught, 35/91 wrongly flagged). What IS exact is the pointer sentence (M-DESC-POINTER, 56/62 before the 2026-09-20 trim, 0/62 after) and the aggregate cost (P-DESC-BUDGET). Do not replace F8 with a similarity threshold without re-running that calibration.

Known mis-flags the finders must avoid ​

  • "This skill should be used when…" is third person. The defect is when-only (M-DESC-WHENONLY), not voice.
  • Workflow .js files contain ${…} template interpolations inside agent() prompt strings. These are not undefined placeholders.
  • MUST/NEVER density is not a finding (F7).
  • A fenced example that is a template is only a finding when the content of the format is non-obvious (Q-CLARITY-EXAMPLE).
  • Handoffs a description names explicitly ("hands off to andon-verify") are intended overlaps, not Q-CANN-OVERLAP — unless the simulation shows a capture (Q-CANN-CAPTURE). Human-tier is right about the fix (the handoff wording is correct); it must not suppress the finding (one side no longer wins its own prompts).