Content checks validate the quality and completeness of the SKILL.md body content, including token budgets, examples, script references, and path validation.
Check List
This dimension includes 11 checks (all quality suggestions, none spec-required).
| Check ID | Severity | What It Validates |
|---|
content.body-not-empty | WARNING | Body has meaningful content |
content.line-budget | WARNING | Body is under 500 lines |
content.token-budget | WARNING | Body is under 5000 tokens |
content.metadata-token-budget | INFO | Metadata under 150 tokens |
content.has-examples | INFO | Content contains code examples |
content.description-actionable | INFO | Description has activation phrasing |
content.reference-depth | WARNING | References max 1 level deep |
content.scripts-referenced | WARNING | Scripts mentioned in body |
content.script-paths-exist | WARNING | Script paths exist on disk |
content.asset-paths-exist | WARNING | Asset paths exist on disk |
content.compatibility-prereqs | INFO | Command runners documented |
content.body-not-empty
Severity: WARNING
Validates that SKILL.md body has meaningful content (quality suggestion; spec allows empty body).
What It Checks
- Body is not empty after trimming whitespace
- Body has at least 50 characters of content
Implementation
def run(self, skill: Skill) -> CheckResult:
body = skill.body.strip()
if not body:
return self._fail(
"SKILL.md body is empty",
location=self._skill_md_location(skill),
)
if len(body) < 50:
return self._fail(
f"SKILL.md body is too short ({len(body)} characters)",
details={"length": len(body), "minimum": 50},
location=self._skill_md_location(skill),
)
return self._pass(
f"SKILL.md body has content ({len(body)} characters)",
location=self._skill_md_location(skill),
)
content.line-budget
Severity: WARNING
Validates that body content stays under 500 lines for readability.
Constants
Implementation
def run(self, skill: Skill) -> CheckResult:
lines = skill.body.split("\n")
line_count = len(lines)
if line_count > MAX_LINE_COUNT:
return self._fail(
f"Body exceeds {MAX_LINE_COUNT} lines (got {line_count})",
details={"line_count": line_count, "max_lines": MAX_LINE_COUNT},
location=self._skill_md_location(skill),
)
return self._pass(
f"Body within line budget ({line_count}/{MAX_LINE_COUNT})",
location=self._skill_md_location(skill),
)
content.token-budget
Severity: WARNING
Validates that body instructions stay under the spec-recommended 5,000 token budget.
Constants
Implementation
Uses estimate_tokens() from skill_lab.core.tokens for token estimation.
from skill_lab.core.tokens import estimate_tokens
def run(self, skill: Skill) -> CheckResult:
tokens = estimate_tokens(skill.body)
if tokens > MAX_BODY_TOKENS:
return self._fail(
f"Body exceeds {MAX_BODY_TOKENS} token budget ({tokens} estimated)",
details={"estimated_tokens": tokens, "max_tokens": MAX_BODY_TOKENS},
location=self._skill_md_location(skill),
)
return self._pass(
f"Body within token budget ({tokens}/{MAX_BODY_TOKENS})",
location=self._skill_md_location(skill),
)
Token estimation uses a simple heuristic (characters / 4). Actual token counts may vary by model.
content.metadata-token-budget
Severity: INFO
Validates that metadata (name + description) fits the ~100-token discovery budget for efficient skill matching.
Constants
MAX_METADATA_TOKENS = 150
Implementation
def run(self, skill: Skill) -> CheckResult:
if skill.metadata is None:
return self._pass(
"No metadata to check",
location=self._skill_md_location(skill),
)
combined = f"{skill.metadata.name} {skill.metadata.description}"
tokens = estimate_tokens(combined)
if tokens > MAX_METADATA_TOKENS:
return self._fail(
f"Metadata exceeds {MAX_METADATA_TOKENS} token budget ({tokens} estimated)",
details={"estimated_tokens": tokens, "max_tokens": MAX_METADATA_TOKENS},
location=self._skill_md_location(skill),
)
return self._pass(
f"Metadata within token budget ({tokens}/{MAX_METADATA_TOKENS})",
location=self._skill_md_location(skill),
)
Keeping metadata concise improves skill discovery performance when agents scan multiple skills.
content.has-examples
Severity: INFO
Validates that content contains code examples to help agents understand usage.
Detection Patterns
CODE_EXAMPLE_PATTERNS = [
r"```", # Fenced code blocks
r"^\s{4,}\S", # Indented code blocks (4+ spaces)
r"<example>", # Example tags
]
Implementation
def run(self, skill: Skill) -> CheckResult:
body = skill.body
for pattern in CODE_EXAMPLE_PATTERNS:
if re.search(pattern, body, re.MULTILINE):
return self._pass(
"Content contains code examples",
location=self._skill_md_location(skill),
)
return self._fail(
"Content does not contain code examples",
details={"suggestion": "Add code examples using fenced code blocks (```)"},
location=self._skill_md_location(skill),
)
Example
# ✅ Has examples (fenced code)
```python
import requests
response = requests.get("https://api.example.com")
```
# ✅ Has examples (indented)
import requests
response = requests.get("https://api.example.com")
# ✅ Has examples (example tags)
<example>
usage example here
</example>
content.description-actionable
Severity: INFO
Validates that description includes activation phrasing to help agents match tasks to skills.
Activation Phrases
_ACTIVATION_PHRASES = (
"use when",
"use for",
"use this",
"trigger",
"activate",
"invoke",
"run when",
"run this",
"helps with",
"designed for",
"intended for",
"works with",
)
Implementation
def run(self, skill: Skill) -> CheckResult:
if skill.metadata is None or not skill.metadata.description.strip():
return self._pass(
"No description to check (other checks catch this)",
location=self._skill_md_location(skill),
)
desc_lower = skill.metadata.description.lower()
for phrase in _ACTIVATION_PHRASES:
if phrase in desc_lower:
return self._pass(
f"Description contains activation phrase: '{phrase}'",
location=self._skill_md_location(skill),
)
return self._fail(
"Description lacks activation phrasing for agent matching",
details={
"suggestion": "Add 'Use when...' or 'Designed for...' phrasing "
"to help agents match tasks to this skill",
},
location=self._skill_md_location(skill),
)
Example
# ❌ Not actionable
---
description: A helper for API calls
---
# ✅ Actionable
---
description: Use when making authenticated REST API calls with retries
---
content.reference-depth
Severity: WARNING
Validates that references are not too deeply nested (max 1 level).
Constants
Implementation
def run(self, skill: Skill) -> CheckResult:
references_path = skill.path / "references"
if not references_path.exists() or not references_path.is_dir():
return self._pass(
"No references folder to check",
)
deep_paths: list[str] = []
def check_depth(path: Path, current_depth: int) -> None:
if current_depth > MAX_REFERENCE_DEPTH:
deep_paths.append(str(path.relative_to(skill.path)))
return
if path.is_dir():
for item in path.iterdir():
if item.is_dir():
check_depth(item, current_depth + 1)
check_depth(references_path, 0)
if deep_paths:
return self._fail(
f"References nested too deeply (max {MAX_REFERENCE_DEPTH} level)",
details={"deep_paths": deep_paths},
location=str(references_path),
)
return self._pass(
f"References within depth limit ({MAX_REFERENCE_DEPTH} level max)",
location=str(references_path),
)
Example
# ✅ Valid structure (1 level deep)
my-skill/
references/
api/
reference.md
guide.md
# ❌ Too deep (2 levels)
my-skill/
references/
api/
v1/
reference.md # Too deep!
content.scripts-referenced
Severity: WARNING
Validates that scripts in scripts/ are mentioned in the SKILL.md body.
Implementation
def run(self, skill: Skill) -> CheckResult:
scripts_path = skill.path / "scripts"
if not scripts_path.exists() or not scripts_path.is_dir():
return self._pass("No scripts folder present (optional)")
script_files = [
item.name
for item in scripts_path.iterdir()
if item.is_file() and item.suffix.lower() in VALID_SCRIPT_EXTENSIONS
]
if not script_files:
return self._pass(
"No script files in scripts/",
location=str(scripts_path),
)
body = skill.body
mentioned = [f for f in script_files if f in body]
if mentioned:
return self._pass(
f"Script(s) mentioned in body: {', '.join(mentioned)}",
location=self._skill_md_location(skill),
)
return self._fail(
f"Scripts exist but none mentioned in body: {', '.join(sorted(script_files))}",
details={
"script_files": sorted(script_files),
"suggestion": "List available scripts in your SKILL.md so the agent knows they exist",
},
location=self._skill_md_location(skill),
)
If you include scripts but don’t mention them in the body, agents won’t know they exist.
content.script-paths-exist
Severity: WARNING
Validates that script paths referenced in body (e.g., scripts/setup.py) exist on disk.
Detection Pattern
_SCRIPT_EXT_PATTERN = "|".join(ext.lstrip(".") for ext in sorted(VALID_SCRIPT_EXTENSIONS))
_SCRIPT_PATH_RE = re.compile(rf"(?<![/\w-])scripts/[\w.-]+\.(?:{_SCRIPT_EXT_PATTERN})\b")
Matches patterns like:
scripts/setup.py
scripts/build.sh
scripts/helper.js
Implementation
def run(self, skill: Skill) -> CheckResult:
refs = _SCRIPT_PATH_RE.findall(skill.body)
if not refs:
return self._pass(
"No script path references in body",
location=self._skill_md_location(skill),
)
# Deduplicate while preserving order
seen: set[str] = set()
unique_refs: list[str] = []
for ref in refs:
if ref not in seen:
seen.add(ref)
unique_refs.append(ref)
missing = [ref for ref in unique_refs if not (skill.path / ref).exists()]
if missing:
return self._fail(
f"Script path(s) not found on disk: {', '.join(missing)}",
details={"missing_paths": missing, "all_references": unique_refs},
location=self._skill_md_location(skill),
)
return self._pass(
f"All referenced script paths exist ({len(unique_refs)} verified)",
location=self._skill_md_location(skill),
)
content.asset-paths-exist
Severity: WARNING
Validates that asset paths referenced in body (e.g., assets/logo.png) exist on disk.
Detection Pattern
_ASSET_PATH_RE = re.compile(r"(?<![/\w-])assets/[\w.-]+\.\w+\b")
Matches patterns like:
assets/logo.png
assets/diagram.svg
assets/template.json
Implementation
def run(self, skill: Skill) -> CheckResult:
refs = _ASSET_PATH_RE.findall(skill.body)
if not refs:
return self._pass(
"No asset path references in body",
location=self._skill_md_location(skill),
)
# Deduplicate while preserving order
seen: set[str] = set()
unique_refs: list[str] = []
for ref in refs:
if ref not in seen:
seen.add(ref)
unique_refs.append(ref)
missing = [ref for ref in unique_refs if not (skill.path / ref).exists()]
if missing:
return self._fail(
f"Asset path(s) not found on disk: {', '.join(missing)}",
details={"missing_paths": missing, "all_references": unique_refs},
location=self._skill_md_location(skill),
)
return self._pass(
f"All referenced asset paths exist ({len(unique_refs)} verified)",
location=self._skill_md_location(skill),
)
content.compatibility-prereqs
Severity: INFO
Validates that command runners referenced in body are documented in the compatibility field.
Command Runner Mapping
_RUNNER_TO_RUNTIME: dict[str, str] = {
"npx": "Node.js",
"uvx": "uv",
"bunx": "Bun",
"deno run": "Deno",
"go run": "Go",
"pipx run": "pipx",
}
Implementation
def run(self, skill: Skill) -> CheckResult:
matches = _RUNNER_RE.findall(skill.body)
if not matches:
return self._pass(
"No command runners referenced in body",
location=self._skill_md_location(skill),
)
# Normalize matches to canonical form
runners_found: dict[str, str] = {}
for match in matches:
canonical = match.lower()
if canonical not in runners_found:
runners_found[canonical] = _RUNNER_TO_RUNTIME.get(
canonical, _RUNNER_TO_RUNTIME.get(match, match)
)
# Get compatibility field
compat = ""
if skill.metadata and skill.metadata.raw.get("compatibility"):
compat_val = skill.metadata.raw["compatibility"]
if isinstance(compat_val, str):
compat = compat_val.lower()
missing: dict[str, str] = {}
for runner, runtime in runners_found.items():
if runtime.lower() not in compat:
missing[runner] = runtime
if missing:
pairs = [f"{r} (needs {rt})" for r, rt in missing.items()]
return self._fail(
f"Command runners missing from compatibility: {', '.join(pairs)}",
details={
"missing_runners": missing,
"suggestion": "Add runtime prerequisites to the compatibility frontmatter field",
},
location=self._skill_md_location(skill),
)
return self._pass(
"All command runners documented in compatibility field",
location=self._skill_md_location(skill),
)
Example
# ❌ Missing compatibility info
---
name: api-helper
description: Use when making API calls
---
Run `npx fetch-api` to test the endpoint.
# ✅ Documented in compatibility
---
name: api-helper
description: Use when making API calls
compatibility: Requires Node.js
---
Run `npx fetch-api` to test the endpoint.
File Location
Content checks are implemented in: src/skill_lab/checks/static/content.py