skill-linter
Lint a SKILL.md against the canonical structural template and report findings (missing sections, wrong ordering, non-canonical headings, infinite-loop risks, polyglot skills) for skill-creator to fix. Use this skill whenever the user asks to lint a skill, whenever a skill has just been created or edited with skill-creator, or whenever the user mentions skill structure, skill template, or skill consistency.
- License 许可
- MIT
- 最近更新
- 2026-11-08
- Stars
- ★ 0
- Forks
- 1
01 前言 Front Matter
- name
- skill-linter
- description
- Lint a SKILL.md against the canonical structural template and report findings (missing sections, wrong ordering, non-canonical headings, infinite-loop risks, polyglot skills) for skill-creator to fix. Use this skill whenever the user asks to lint a skill, whenever a skill has just been created or edited with skill-creator, or whenever the user mentions skill structure, skill template, or skill consistency.
02 资源文件 5
- 参考文档references/rules.md14.4 KB
- 参考文档references/template.md3.2 KB
- 脚本scripts/lint.py45.6 KB
- 参考文档tests/fixtures/unreadable/README.md77 B
- 脚本tests/test_lint.py18.3 KB
03 SKILL.md 正文
Skill Linter
A companion linter to skill-creator that enforces a canonical SKILL.md body structure and flags suspicious loops and polyglot skills.
Overview
Skill-linter inspects the body of a SKILL.md after a skill has been created or edited and reports structural findings against a fixed, opinionated template. It checks heading names, section ordering, the presence of a one-line pitch, the shape of the Overview, the use of ### Step N: sub-headings inside Workflow, and two semantic-but-syntactically-detectable risks: loops without a clear exit condition, and skills that appear to cover multiple unrelated workflows (polyglot skills).
This skill exists because skill-creator deliberately produces skills generatively, optimizing for the user's intent rather than a uniform shape. That flexibility is good, but a portfolio of skills written across different sessions and model versions tends to drift in section names, ordering, verbosity, and structure. A small, focused linter that runs after creation closes that gap without conflicting with skill-creator: skill-linter only reports findings and proposes the shape of a fix, never the content. Skill-creator decides how to apply the fix.
Success looks like this: after skill-creator finishes producing or editing a skill, skill-linter is invoked, produces a JSON report of findings (errors, warnings, info), and hands that report to skill-creator with a clear instruction to fix errors, decide on warnings, and revalidate omitted optional sections. The result is a skill whose SKILL.md follows the canonical template exactly — same heading names, same ordering, same minimum content shape — while preserving the substantive instructions skill-creator wrote.
When to use this skill
Use skill-linter whenever:
- A skill has just been created or edited (especially via skill-creator) and you want to enforce the canonical SKILL.md structure before shipping.
- The user asks to "lint", "validate the structure of", "check the template of", or "audit" a skill.
- You suspect a skill might be polyglot — i.e., trying to do many different things — and want a syntactic signal to confirm.
- You want to catch loops in a Workflow that lack an explicit exit condition.
- You are reviewing a portfolio of skills and want a consistent structural baseline.
Skill-linter is intentionally narrow: it only inspects the SKILL.md body. It is complementary to (not a replacement for) skill-creator/scripts/quick_validate.py, which already enforces frontmatter validity, naming rules, and length limits.
When NOT to use this skill
- Do not use skill-linter to judge the substance of a skill's instructions. It is a syntactic linter, not a semantic reviewer.
- Do not use it as a gating step for skills that are intentionally exploratory drafts the user has not yet asked to finalize.
- Do not use it to validate the YAML frontmatter — that is
quick_validate.py's job. - Do not use it to evaluate skill performance — that is the eval/benchmark loop in skill-creator.
Constraints
- Read-only and explicitly invoked: Skill-linter never edits the skill it lints, never watches files, never hooks into editors, and never auto-triggers on save. It only runs when explicitly invoked, and only ever produces a JSON report and a hand-off message; skill-creator decides and applies fixes.
- Syntactic, not semantic: All suggestions describe the shape of a fix, not the content. The linter never proposes what a section should say, what a polyglot skill should be split into, or what a loop's exit condition should be.
- Body-only scope: Inspects only the body of
SKILL.md. Frontmatter validation is delegated toskill-creator/scripts/quick_validate.py; performance evaluation is delegated to skill-creator's eval/benchmark loop. - Zero false positives: Trust in the linter requires zero false positives. When a check is ambiguous, pass. Better to miss a real issue than to flag a non-issue. Each new rule must ship with at least one negative fixture proving it does NOT fire on compliant skills.
Inputs
To lint a skill, gather:
skill_path(required): Absolute path to the skill directory containingSKILL.md.output_path(optional): Where to write the report file. Defaults to no file — output is printed to stdout only. Pass an explicit path (e.g.,/tmp/skill-lint-<name>.json) only when you need a persistent artifact. Never write into the skill's own directory — it may be version-controlled and owned by someone else.hand_off_to_skill_creator(optional, defaulttrue): Whether to format the findings as a hand-off prompt for skill-creator after producing the JSON report.strict(optional, defaultfalse): Whether to run in strict mode. Strict mode adds rule R017 (non-canonical-section) which flags ANY##heading not in the canonical set — useful for new skills where applying the template is cheap. Leave off for legacy skills where retrofit cost is high.
If the user provides only a skill name and no path, search common locations (~/.agents/skills/<name>/, ./<name>/, ./skills/<name>/) and confirm with the user before proceeding.
Output
Skill-linter produces two artifacts:
- A JSON (or markdown) report printed to stdout. Optionally also written to
output_pathwhen--outputis explicitly provided — never to the skill's own directory.
{
"skill_path": "path/to/skill",
"skill_name": "skill-name",
"passed": false,
"summary": {"errors": 2, "warnings": 1, "info": 1},
"findings": [
{
"rule": "missing-section",
"severity": "error",
"location": "SKILL.md body",
"found": null,
"expected": "## Overview",
"suggestion": "Add a `## Overview` section with 3-5 paragraphs (what / why / how success looks)."
}
]
}
passed is true only when there are zero errors. Warnings and info findings do not block.
- A hand-off message for skill-creator (if
hand_off_to_skill_creatoris true), using this exact wording:
The skill-linter found the following structural issues in the SKILL.md you just produced.
For each
error→ fix the structural violation while preserving all existing content and intent. For eachwarning→ fix or briefly justify keeping as-is. For eachinfo→ revalidate whether the omitted optional section is appropriate.Do not change the skill's substantive behavior — only its structure and clarity. Suggestions describe the shape of the fix, not the content; you decide the content.
Suggestions in findings are always syntactic: they describe the shape of the fix (e.g., "split into narrower skills", "add a ## Overview section with 3 paragraphs"), never the content of the fix (e.g., they never say what the new skills should be or what the Overview paragraphs should contain). Skill-creator owns those decisions.
Workflow
Step 1: Locate and read the SKILL.md
Resolve skill_path to an absolute path. Read <skill_path>/SKILL.md in full. Parse the frontmatter (YAML) to extract name and description. Separate the body (everything after the closing ---).
If the file does not exist or the frontmatter cannot be parsed, stop with a single error finding (rule: "skill-md-unreadable") — there is nothing to lint without a body.
Step 2: Run the structural rules
Run the rules defined in references/rules.md. The full catalog is documented there; the rule engine in scripts/lint.py implements them. Each rule produces zero or more findings with rule, severity, location, optional found and expected, and a suggestion describing the shape of the fix.
The structural rules check, in this order:
- The H1 title exists and matches the kebab
namefrom frontmatter when title-cased. - A single-line pitch exists directly under the H1.
- All required sections (
## Overview,## When to use this skill,## Workflow) are present. - Headings use canonical names exactly (no synonyms like
## Process,## Steps,## How it works). - Sections appear in the locked order: H1 → pitch → Overview → When to use → (optional Inputs) → (optional Output) → Workflow.
## Overviewcontains 3 to 5 plain paragraphs and no sub-headings.## Workflowcontains### Step N:sub-headings, numbered sequentially starting at 1.- Empty workflow steps are flagged (single empty step → warning; ≥2 empty steps → error).
Step 3: Run the loop-termination rule
Inside ## Workflow, scan each step body for loop-language signals: repeat, loop, until, iterate, keep going, while, go back to step, return to step.
For each signal, look in the same step for a clear exit condition: phrases like until the user says…, until <state>, when <condition>, once <condition>, if <state>, stop. If no clear exit condition is found, emit a warning (rule: "loop-without-exit-condition").
Iteration caps are not required — a clear exit condition suffices. If both are missing or the exit is suspiciously vague, raise the warning.
Step 4: Run the polyglot-detection rule
Look for syntactic signals that the skill covers multiple unrelated workflows:
- The one-line pitch joins two distinct activity verbs with
" and ". ## Overviewlists multiple distinct primary use cases joined byalso,in addition,or alternatively, oras well as.## Workflowcontains top-level branches like "if the user wants X, follow these steps; if they want Y, follow these completely different steps".- The frontmatter
descriptionlists ≥3 distinct domains/verbs joined by commas orand.
If any signal fires, emit a single warning (rule: "polyglot-skill") with a syntactic suggestion: "This skill appears polyglot. Consider splitting it into narrower skills, each with a single primary workflow. Skill-creator should decide how to split."
Do not propose what the new skills should be — that is skill-creator's call.
Step 5: Emit info findings for omitted optional sections
If ## Inputs or ## Output is absent, emit a single info-severity finding per missing optional section, with the suggestion: "Optional section ## Inputs is omitted. If the skill takes user-provided inputs, consider adding it; otherwise leave omitted."
Info findings never block — they exist so skill-creator can revalidate the necessity of each optional section.
Step 6: Aggregate, write the report, and hand off
Aggregate all findings into the JSON shape shown in ## Output. Compute summary.errors, summary.warnings, summary.info. Set passed = (summary.errors == 0).
Write the report to output_path. If hand_off_to_skill_creator is true, also print the hand-off message verbatim, followed by the report path.
Do not edit the skill yourself. Skill-linter only reports; skill-creator fixes.
Reference files
references/template.md— The canonical SKILL.md body template (locked v0.1). Read this when you need to remind yourself of the exact required structure, ordering, and naming.references/rules.md— The full rule catalog with rule IDs, severities, detection logic, and suggestion text. Read this when you need to understand exactly what a rule checks or why it fired.scripts/lint.py— Executable Python implementation of all rules. Run it withpython scripts/lint.py <skill_path> [--output <path>] [--no-handoff] [--strict] [--format json|md]to produce a JSON or grouped-markdown report. Output goes to stdout by default;--outputis opt-in and should never point inside the reviewed skill's directory.
04 同仓库更多 Skills
programming
Before writing, changing, or fixing any code in any language, read this guide of design principles (deep modules, functional core and imperative shell, explicit dependencies, modular monolith). It applies under any workflow skill, including test-first ones, and does not define a test loop.
writing-studio
Write or review professional, human-facing prose so the result is clear, well-structured, correctly shaped for its document type, and free of AI-sounding filler. Use this skill WHENEVER you are about to write something a person will read (a proposal, email, chat or Slack message, document or wiki page, blog post, announcement, status update, RFC or design doc, release notes, exec brief, incident report, peer performance feedback, RACI or roles-and-responsibilities matrix, program or project poster, PR/FAQ or working-backwards doc) OR when asked to review, improve, polish, critique, proofread, tighten, sharpen, or shorten any existing text. Prefer it over ad-hoc style fixes, especially for multi-paragraph or long-form writing. Do NOT use it for code, code comments, commit messages, machine-readable data (JSON/YAML/CSV), or trivial one-line replies.
workflow-step-numbering
Fixture with non-sequential step numbering to verify R011 fires.
workflow-no-steps
Fixture whose Workflow has no Step sub-headings to verify R010 fires.
valid-skill
A fully compliant fixture skill used to verify skill-linter passes a clean SKILL.md without findings.
section-out-of-order
Fixture with Workflow before When to use to verify R007 fires.