The skill_linter ensures SKILL.md files are well-formatted and contain valid metadata. It is integrated with fx format-code and SHAC for automated validation and fixing of skill documentation.
To check a directory for errors without modifying files:
PYTHONPATH=third_party/pyyaml/src/lib python3 \ scripts/skill_linter/skill_linter.py /path/to/skill/dir
To automatically fix errors in-place:
PYTHONPATH=third_party/pyyaml/src/lib python3 \ scripts/skill_linter/skill_linter.py --fixit /path/to/skill/dir
To output fixed content to stdout without modifying the file:
PYTHONPATH=third_party/pyyaml/src/lib python3 \ scripts/skill_linter/skill_linter.py --suggest-fix /path/to/skill/dir
To output findings as structured JSON (for machine integration):
PYTHONPATH=third_party/pyyaml/src/lib python3 \ scripts/skill_linter/skill_linter.py --suggest-fix-in-json /path/to/skill/dir
Unit tests for the linter are written using the standard Python unittest framework and are integrated into the Fuchsia build system.
To run the tests using fx test:
fx test skill_linter_test
To run the tests directly with Python (useful for fast iteration):
python3 scripts/skill_linter/skill_linter_test.py
fx format-code: This is the primary way users interact with the linter. It runs shac fmt, which invokes the linter to automatically format and fix rule violations in the workspace.
CI/Presubmit: SHAC runs the linter in check-only mode on the build bots. It identifies metadata and formatting errors, providing suggestions in the code review UI.
Note: The skills.star integration is configured to scan for SKILL.md files within the .agents/skills/ and zircon/skills/ directories. This scope can be expanded to include other directories in the future as needed.
Metadata at the top of SKILL.md must be valid YAML and follow these specific field constraints:
name
description
description: >) for better readability.The Markdown content following the frontmatter is automatically formatted to ensure consistency across all skills:
Line Wrapping: Body text is wrapped to fit within an 80-character limit.
Smart Exclusions: The formatter detects and preserves the layout of elements that should not be wrapped:
```) is entirely excluded from formatting, including line wrapping and list item spacing adjustments, preserving it exactly as-is.# (ATX headers) are ignored.> are ignored.Whitespace Hygiene: Trailing whitespace is removed, and consecutive empty lines are collapsed into single breaks.
The linter supports several modes to accommodate different workflows:
Check-Only (Default)
stdout/stderr.1 if any violations are found, and 0 otherwise.In-Place Fix (--fixit)
SKILL.md files in the filesystem.Suggested Fix (--suggest-fix)
stdout.JSON Output (--suggest-fix-in-json)
filepath: Relative path to the file.message: A consolidated string of all findings (errors, warnings, and applied fixes).level: Severity of the finding (error for fatal/blocking issues, warning for fixable violations).replacements: (Optional) An array containing a single string representing the entire fixed file content.error level findings rather than script crashes.0 even if findings are reported. A non-zero exit code indicates a fatal script crash.When contributing to the skill_linter or its integrations, adhere to the following patterns:
error (blocking) or a warning (non-blocking). This logic is communicated via the JSON findings.--suggest-fix-in-json interface for all machine integrations (like SHAC). This avoids fragile exit code dependencies and allows passing rich metadata (like specific error messages per file).0 for success/processed and 1 for validation failure in human-readable modes.yaml.safe_load() for frontmatter parsing. Never use regex or manual string splitting to extract YAML values, as this is error-prone for complex keys or nested structures.textwrap.TextWrapper, while block-level elements (tables, code blocks) trigger immediate flushes to preserve their structure._pre_process to standardize list indentation and _post_process for final whitespace hygiene. This keeps the core wrapping logic focused on text flow.skill_linter.py must contain a docstring or comment explaining their purpose, arguments, and return values. This ensures the tool remains maintainable and that its logic is transparent to both human developers and AI agents.pyyaml, which is not in the standard Python library. The SHAC integration (skills.star) dynamically constructs the PYTHONPATH to include third_party/pyyaml/src/lib.logging module instead of print(). This allows the tool to direct diagnostics to stderr while keeping stdout clean for formatted content or JSON findings.skill_linter_test.py for all core logic. Any change to validation regex or formatting rules must be accompanied by a corresponding test case.SKILL.md and running the linter with the various modes described in the Execution Modes section.