tools/skill-validator.md
An LLM-readable validation prompt for skills following the Agent Skills open standard.
Before running inference-based validation, run the deterministic validator:
node tools/validate-skills.js --json path/to/skill-dir
This checks 14 rules deterministically: SKILL-01, SKILL-02, SKILL-03, SKILL-04, SKILL-05, SKILL-06, SKILL-07, WF-01, WF-02, PATH-02, STEP-01, STEP-06, STEP-07, SEQ-02.
Review its JSON output. For any rule that produced zero findings in the first pass, skip it during inference-based validation below — it has already been verified. If a rule produced any findings, the inference validator should still review that rule (some rules like SKILL-04 and SKILL-06 have sub-checks that benefit from judgment). Focus your inference effort on the remaining rules that require judgment (PATH-01, PATH-03, PATH-04, PATH-05, WF-03, STEP-02, STEP-03, STEP-04, STEP-05, SEQ-01, REF-01, REF-02, REF-03).
If no findings are generated (from either pass), the skill passes validation.
SKILL.md and all supporting files.planning_artifacts, implementation_artifacts, communication_language).spec_file, date, status).SKILL.md (exact case).SKILL.md as the skill entrypoint.name in FrontmatterSKILL.mdname field.--- delimited frontmatter block and check for name:.name: <skill-name> to the frontmatter.description in FrontmatterSKILL.mddescription field.--- delimited frontmatter block and check for description:.description: '<what it does and when to use it>' to the frontmatter.name FormatSKILL.mdname value must start with bmad-, use only lowercase letters, numbers, and single hyphens between segments.^bmad-[a-z0-9]+(-[a-z0-9]+)*$.bmad-my-skill).name Must Match Directory NameSKILL.mdname value in SKILL.md frontmatter must exactly match the skill directory name. The directory name is the canonical identifier used by installers, manifests, and skill: references throughout the project.name: frontmatter value against the basename of the skill directory (i.e., the immediate parent directory of SKILL.md).name: value to match the directory name, or rename the directory to match — prefer changing name: unless other references depend on the current value.description QualitySKILL.mddescription must state both what the skill does AND when to use it. Max 1024 characters.SKILL.md--- frontmatter delimiter and check it is non-empty after trimming whitespace.---.name in Frontmatter.md files except SKILL.mdname field belongs only in SKILL.md. No other markdown file in the skill directory may have name: in its frontmatter.name: key.name: line from the file's frontmatter.bmad-agent-tech-writer — has sub-skill files with intentional name fields (to be revisited).description in Frontmatter.md files except SKILL.mddescription field belongs only in SKILL.md. No other markdown file in the skill directory may have description: in its frontmatter.description: key.description: line from the file's frontmatter.bmad-agent-tech-writer — has sub-skill files with intentional description fields (to be revisited).Severity: HIGH
Applies to: workflow.md frontmatter
Rule: Every variable defined in workflow.md frontmatter must be either:
{project-root} or a config-derived variable like {planning_artifacts})It must NOT be a path to a file within the skill directory (see PATH-04), nor a path into another skill's directory (see PATH-05).
Detection: For each frontmatter variable, check if its value resolves to a file inside the skill (e.g., starts with ./, {installed_path}, or is a bare relative path to a sibling file). If so, it is an intra-skill path variable. Also check if the value is a path into another skill's directory — if so, it violates PATH-05 and is not a legitimate external path.
Fix: Remove the variable. Use a hardcoded relative path inline where the file is referenced.
./ prefix for siblings or children, ../ for parent traversal. Bare relative filenames in markdown links (e.g., [text](sibling.md)) are also acceptable../, ../, or bare filename). Always resolve the path from the originating file's directory — a reference to ./steps/step-01.md from a file already inside steps/ would resolve to steps/steps/step-01.md, which is wrong../steps/step-01-init.md (from workflow.md at skill root to a step)./template.md (from workflow.md to a sibling)../template.md (from steps/step-01.md to a skill-root file)workflow.md (bare relative filename for sibling)./step-02-plan.md (from steps/step-01.md to a sibling step)./steps/step-02-plan.md (from a file already inside steps/ — resolves to steps/steps/){installed_path}/template.md{project-root}/.claude/skills/my-skill/template.md/Users/someone/.claude/skills/my-skill/steps/step-01.md~/.claude/skills/my-skill/file.mdinstalled_path Variableinstalled_path variable is an anti-pattern from the pre-skill workflow era. It must not be defined in any frontmatter, and {installed_path} must not appear anywhere in any file.installed_path:{installed_path} anywhere in contentinstalled_path (e.g., `installed_path` = `.`)installed_path definitions. Replace every {installed_path}/path with ./path (relative from the file that contains the reference). If the reference is in a step file and points to a skill-root file, use ../path instead.{project-root} or Config Variables{project-root}/... or a config-derived variable path (e.g., {planning_artifacts}/..., {implementation_artifacts}/...).{project-root} or a known config variable. Flag absolute paths, home-relative paths (~/), or bare paths that resolve outside the skill.{project-root}/... or the appropriate config variable.skill:skill-name syntax, which invokes the skill as a unit. Reaching into another skill to cherry-pick an internal file (e.g., a template, a step, or even its workflow.md) breaks encapsulation and creates fragile coupling that breaks when the target skill is moved or reorganized.SKILL.md). Patterns to flag:
{project-root}/_bmad/.../other-skill/anything.md{project-root}/_bmad/.../other-skill/steps/...{project-root}/_bmad/.../other-skill/templates/...core/workflows/skill-name/ when the skill has since moved to core/skills/skill-name/)skill:skill-name.core/data/, bmm/data/, or a config-referenced path) — not reached into from across skill boundaries.`template` = `./template.md` under a ### Paths section)../, ../, {installed_path}, or is a bare filename of a file that exists in the skill. Exclude variables whose values are prefixed with a config variable like {planning_artifacts}, {implementation_artifacts}, {project-root}, or other config-derived paths — these are external references and are legitimate.{variable_name} usage with the direct relative path.steps/ directorystep-NN-description.md where NN is a zero-padded two-digit number. An optional single-letter variant suffix is allowed for branching steps (e.g., step-01b-continue.md).^step-\d{2}[a-z]?-[a-z0-9-]+\.md$## YOUR TASK, ## STEP GOAL, ## INSTRUCTIONS, ## INITIALIZATION, ## EXECUTION, # Step N:, or a frontmatter goal: field.# Step N: Title as a top-level heading that names the step's purpose) or frontmatter.## NEXT section or inline reference to a next step file. Remember to resolve the reference from the originating file's directory (PATH-01 applies here too).## NEXT section with the relative path to the next step.[C] Continue, [A] Approve, [S] Split) must explicitly HALT and wait for user response before proceeding.## NEXT sections, navigation/dispatch sections that list valid resumption targets, and conditional routing branches.name or descriptionname: or description: in their YAML frontmatter. These are metadata noise — the step's purpose is conveyed by its goal section and filename.name: or description: keys.name: and description: from step file frontmatter.step-*.md in the steps/ directory.{variable_name} reference in any file (body text, frontmatter values, inline instructions) must resolve to a defined source. Valid sources are:
workflow.md (workflow-level variables are available to all steps)project-root, planning_artifacts, implementation_artifacts, communication_language)date, status, project_name, user-provided input variables){...} tokens in the file. For each, check whether it is defined in the file's own frontmatter, in workflow.md frontmatter, or is a recognized config/runtime variable. Flag any token that cannot be traced to a source. Use the config variable list from the project's config.yaml as the reference for recognized config variables. Runtime variables are those explicitly described as user-provided or set during execution in the workflow instructions.{{variable}} — these are template placeholders intended to survive into generated output (e.g., {{project_name}} in a template file). Do not flag these.{planning_artifacts}/*.md is plausible, {planning_artifacts}/../../etc/passwd is not).Invoke the \skill-name` skill`. Phrases like "Read fully and follow", "Execute", "Run", "Load", "Open", or "Follow" are invalid — they imply file-level operations on a document, not skill invocation. A skill is a unit that is invoked, not a file that is read.Invoke the \skill-name` skill. Remove any "read fully and follow" or similar file-oriented phrasing. Do NOT add a skill:` prefix to the name — use natural language.When reporting findings, use this format:
# Skill Validation Report: {skill-name}
**Directory:** {path}
**Date:** {date}
**Files scanned:** {count}
## Summary
| Severity | Count |
| -------- | ----- |
| CRITICAL | N |
| HIGH | N |
| MEDIUM | N |
| LOW | N |
## Findings
### {RULE-ID} — {Rule Title}
- **Severity:** {severity}
- **File:** `{relative-path-within-skill}`
- **Line:** {line number or range, if identifiable}
- **Detail:** {what was found}
- **Fix:** {specific fix for this instance}
---
(repeat for each finding, grouped by rule ID)
## Passed Rules
(list rule IDs that produced no findings)
If zero findings: report "All {N} rules passed. No findings." and list all passed rule IDs.
Quick-reference for the Agent Skills open standard. For the full standard, see: Agent Skills specification
SKILL.md as the required entrypoint--- markers provides metadata; markdown body provides instructionsbranch-a/deep/next.md, ./deeper/final.md resolves to branch-a/deep/deeper/final.mdbranch-a/deep/next.md, ./branch-b/alt/leaf.md incorrectly resolves to branch-a/deep/branch-b/alt/leaf.mdname: lowercase letters, numbers, hyphens only; max 64 chars; no "anthropic" or "claude"description: required, max 1024 chars; should state what the skill does AND when to use itname + description loaded at startup into system promptdescription drives auto-discovery — use keywords users would naturally say