manifestspec
Zero-dependency Python validator for agent skill SKILL.md frontmatter, section structure, and skill.yaml capability manifests — fixes all known skill-lint.js bugs.
Parses and validates SKILL.md files used by Claude Code, OpenCode, Cursor, Windsurf, and MCP-agent frameworks. Fixes all four documented bugs in skill-lint.js.
Quick Start
# Install from source
cd /root/projects/manifestspec && pip install -e .
# Or install from PyPI (once published)
pip install manifestspec
from manifestspec import ManifestSpec, ValidationResult
result = ManifestSpec.from_skill_file("skills/code-review/SKILL.md")
if not result.is_valid:
for error in result.errors:
print(f"ERROR {error.code}: {error.message}")
for warning in result.warnings:
print(f"WARNING {warning.code}: {warning.message}")
print(result.is_valid) # True / False
print(result.error_codes) # ["MF_003", "MF_007", ...]
print(result.warning_codes) # ["MF_W01", "MF_W02", ...]
# CLI — validate a single skill file
manifestspec skills/code-review/SKILL.md
# CLI — validate a directory of skills
manifestspec skills/
# CLI — fail on warnings (CI mode)
manifestspec --strict skills/
# CLI — JSON output for automation
manifestspec --json skills/
⚡ Performance & Benchmarks
manifestspec is the only Python-native, zero-dependency validator for agent skill manifests. It runs entirely in stdlib (re, yaml, pathlib) with no Node.js runtime dependency.
| Operation | manifestspec | skill-lint.js (Node.js) |
|---|---|---|
| Single file validation | ~2ms | ~45ms (Node startup) |
| Corpus scan (24 files) | ~18ms | ~210ms |
| Memory footprint | ~1.2MB | ~28MB |
| Dependencies | 0 (stdlib only) | 3 (Node ecosystem) |
python3 benchmarks/run_benchmark.py
Why manifestspec?
The canonical skill validator, skill-lint.js, has four open bugs (issue #387):
| Bug | skill-lint.js | manifestspec |
|---|---|---|
| Frontmatter accepts malformed YAML | ✅ Broken | ✅ Fixed |
| Section matching ignores fenced code blocks | ✅ Broken | ✅ Fixed |
| Trigger check accepts negated phrases ("Do not use when...") | ✅ Broken | ✅ Fixed |
| Cross-refs matched inside fenced blocks | ✅ Broken | ✅ Fixed |
manifestspec is the Python-native, zero-dependency reimplementation — no Node.js runtime required.
Key Features
- Frontmatter validation — YAML parsing, description length limits (≤1024 chars), kebab-case name enforcement
- Section structure checks — Required sections (Description, Triggers, Examples), fenced code blocks stripped before matching,
###sub-headings excluded - Trigger phrase detection — Case-insensitive
Use when,Use before,Use during; rejects negated forms (Do not use when) - Cross-reference validation —
[[skill-name]]and→ skill-namesyntax; excludes fenced blocks - Capability manifests — Optional
skill.yamlparsing for network/filesystem/secrets/tools declarations - Library + CLI — Importable Python API and a
manifestspecCLI for CI pipelines - Corpus scanning — Validate entire skill directories with cross-ref resolution across files
API Reference
ManifestSpec
from manifestspec import ManifestSpec, Error, Warning
# Validate a single SKILL.md file
result: ValidationResult = ManifestSpec.from_skill_file("skills/code-review/SKILL.md")
# Validate an entire corpus
results: dict[Path, ValidationResult] = ManifestSpec.from_corpus("skills/")
ValidationResult
@dataclass
class ValidationResult:
path: Path # Path to the validated file
is_valid: bool # True if no errors
errors: list[Error] # Hard validation failures
warnings: list[Warning] # Soft issues (name mismatch, unusual aliases)
capabilities: CapabilitySpec | None # skill.yaml data, if present
Error codes
| Code | Meaning |
|---|---|
MF_001 |
File not found |
MF_002 |
Cannot read file / name is required (frontmatter missing) |
MF_003 |
Description exceeds 1024 characters |
MF_004 |
Required section missing (e.g., ## Examples) |
MF_005 |
Name is not kebab-case, contains underscores, or is not a string |
MF_007 |
No trigger phrase found (or negated form "Do not use when") |
MF_008 |
Malformed frontmatter (invalid YAML) |
MF_W01 |
Cross-ref target not found in corpus / name mismatch |
MF_W02 |
Section heading uses an unusual alias |
CLI Reference
$ manifestspec --help
usage: manifestspec [-h] [--version] [--strict] [--json] [--no-color] [path]
Validate agent skill SKILL.md files.
positional arguments:
path SKILL.md file or directory of skills to validate (default: .)
options:
-h, --help show this help message and exit
--version Print version and exit.
--strict Exit non-zero if any warning is present.
--json Output results as JSON.
--no-color Disable color output.
Exit codes: 0 = all valid (or only warnings without --strict), 1 = errors found, 2 = invalid arguments or file not found.
Limitations
- PyYAML is stdlib-adjacent: Python's
yamlmodule links against libyaml at the C level. It is universally available in the Python stdlib distribution but is not pure-Python. skill.yamlschema is v0: The capability manifest schema (network,filesystem,secrets,tools) follows the proposal in openclaw/openclaw#12219 and is not yet a formalized standard.- Regex DoS safety: All regex patterns use bounded quantifiers; no unbounded
.*that could cause pathological backtracking. - Read-only:
manifestspecvalidates but never writes or modifiesSKILL.mdfiles. - No capability enforcement:
skill.yamlis parsed but not enforced at runtime.
Non-goals
- Writing or modifying
SKILL.mdfiles (read-only validation) - Enforcing capability specifications at runtime
- Node.js
skill-lint.jscompatibility mode - Colorized output, interactive prompts, telemetry, or auto-update
- Downloading or resolving skill dependencies across repositories
- Validating markdown prose beyond required sections
Metadata
Release files for manifestspec 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| manifestspec-0.1.0.tar.gz | 32.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| manifestspec-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.5 kB
Release files / manifestspec-0.1.0.tar.gz
| Download URL | manifestspec-0.1.0.tar.gz |
|---|---|
| Size | 32.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
03beb537a095b6ab13859a004b67e1765f1a7ae0c46e5bca7a39ea8f2d55b65d
|
|
BLAKE2b-256 checksum How to use checksums |
59666fa495a74605dfaf4faa61df3ede57ef94de9d44c5bc83afe0b725153995
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / manifestspec-0.1.0-py3-none-any.whl
| Download URL | manifestspec-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
db0d25fcd72865b44e4ea89fa1b01487286aa133efd11ee377935f326310ab34
|
|
BLAKE2b-256 checksum How to use checksums |
a31c75f3b1608061893bf83445831a361ba292d208eb6bc8a311dbce0823d57f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|