.agents/skills/python-scripts/SKILL.md
Enforces code quality, modularity, and test coverage for Python scripts in the Skill System Foundry repository. Triggers when creating, editing, reviewing, refactoring, or debugging any Python file under scripts/ or scripts/lib/, writing or updating tests under tests/, adding new validation logic, modifying shared library modules, creating new entry points, or working with the configuration.yaml validation rules. Also triggers when asked to improve test coverage, enforce type hints, fix error handling, extract shared logic, or ensure stdlib-only compliance. Use this skill for any Python work in the repository, even if the user does not explicitly mention code quality.
npx skillsauth add milanhorvatovic/skill-system-foundry python-scriptsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Enforces code quality, modularity, test coverage, and best practices for all Python scripts in the Skill System Foundry repository.
The repository's Python codebase follows strict conventions: stdlib-only imports, thin entry points with shared logic in scripts/lib/, type hints on all signatures, and comprehensive test coverage. This skill codifies those conventions.
skill-system-foundry/
├── scripts/ ← entry points (thin wrappers)
│ ├── __init__.py
│ ├── validate_skill.py ← validates a single skill
│ ├── audit_skill_system.py ← audits entire skill system
│ ├── scaffold.py ← scaffolds new components
│ ├── bundle.py ← bundles for distribution
│ └── lib/ ← shared logic (single responsibility per module)
│ ├── __init__.py
│ ├── constants.py ← centralized constants loaded from configuration.yaml
│ ├── configuration.yaml ← validation rules (limits, patterns, reserved words)
│ ├── validation.py ← shared name/field validation
│ ├── references.py ← reference scanning and graph traversal
│ ├── frontmatter.py ← YAML frontmatter parsing
│ ├── reporting.py ← structured output formatting
│ ├── discovery.py ← skill directory discovery
│ ├── manifest.py ← manifest parsing and validation
│ ├── bundling.py ← bundle packaging logic
│ ├── codex_config.py ← Codex agents/openai.yaml validation
│ └── yaml_parser.py ← subset YAML parser (stdlib-only)
tests/
├── helpers.py ← shared test utilities
├── test_validation.py ← tests for lib/validation.py
├── test_validate_skill.py ← tests for validate_skill.py
├── test_references.py ← tests for lib/references.py
├── ... ← one test file per module
scripts/*.py) — argument parsing, output formatting, sys.exit(). Thin wrappers that delegate to library codescripts/lib/*.py) — domain logic, validation, data transformation. No print() or sys.exit() except in dedicated output helpers (reporting.py)scripts/lib/constants.py) — structural constants in Python, validation rules loaded from configuration.yamltests/) — one test file per module, comprehensive coveragePrefer the simplest solution that works. Avoid abstractions, indirection, or patterns that add complexity without clear benefit. If a function can be understood in one reading, it is the right size.
Each piece of logic has a single authoritative location. If the same validation, pattern, or transformation appears in more than one place, extract to scripts/lib/. But do not over-extract — three similar lines are better than a premature abstraction.
Each module in scripts/lib/ has a single, clear responsibility. Do not let modules grow into catch-all utilities. When a module handles unrelated concerns, split it.
Validate inputs at entry point boundaries before doing any work. If arguments are missing, names are invalid, or required files do not exist, report the error immediately.
No third-party imports. These scripts ship with the skill and must run without pip install. The only external dev dependency is coverage (in requirements-dev.txt), used exclusively for test coverage measurement.
Do not use features introduced in Python 3.13 or later. Specifically avoid:
type parameter defaults (type Alias[T = int])warnings.deprecated decoratorPythonFinalizationErrorLimits, patterns, and reserved words live in scripts/lib/configuration.yaml. Change rules in the YAML, not by hardcoding values in Python. constants.py loads and exposes them.
Type hints on all function signatures. Use builtin generic types:
# Correct
def validate_name(name: str, dir_name: str) -> tuple[list[str], list[str]]:
# Wrong — do not use typing.Optional or typing.List
def validate_name(name: Optional[str], dir_name: str) -> Tuple[List[str], List[str]]:
Use X | None instead of Optional[X]. Fall back to typing only for advanced types (TypedDict, Literal, TypeAlias).
PEP 257 docstrings on all public functions and modules.
Entry point module docstrings double as the usage message printed when the script runs without arguments (via print(__doc__)).
"""
Validate a single skill directory against the Agent Skills specification.
Usage:
python scripts/validate_skill.py <skill-path>
python scripts/validate_skill.py skills/project-mgmt --verbose
"""
Always specify encoding="utf-8" on open() calls:
# Correct
with open(path, "r", encoding="utf-8") as f:
# Wrong — platform-dependent behavior
with open(path, "r") as f:
Required for all entry points:
if __name__ == "__main__":
main()
Validation functions return (errors, passes) tuples — never raise exceptions for validation failures. Collect all issues and return them so callers can report everything at once.
def validate_description(description: str) -> tuple[list[str], list[str]]:
"""Validate the description field."""
errors: list[str] = []
passes: list[str] = []
if not description:
errors.append(f"{LEVEL_FAIL}: [spec] 'description' field is empty")
return errors, passes
if len(description) > MAX_DESCRIPTION_CHARS:
errors.append(
f"{LEVEL_FAIL}: [spec] 'description' exceeds "
f"{MAX_DESCRIPTION_CHARS} characters ({len(description)} chars)"
)
else:
passes.append(f"description: {len(description)} chars (max {MAX_DESCRIPTION_CHARS})")
return errors, passes
Key patterns:
LEVEL_FAIL, LEVEL_WARN, LEVEL_INFO) from lib/constants.py — never hardcode strings[spec] for specification rules, [platform: X] for platform restrictions, [foundry] for conventionsException — use specific exception typesLEVEL_FAIL)All entry points support --json for machine-readable output. Use to_json_output() from lib/reporting.py, which auto-injects a version key for forward-compatible schema evolution.
Two error shapes exist:
"error" (string) — early-exit path, single fatal condition (missing arguments, invalid path)"errors" (object) — full validation results with "failures", "warnings", "info" listsOverride parser.error() to emit JSON on argparse failures when --json is present:
def _json_aware_error(message: str) -> None:
if _json_mode:
print(to_json_output({"tool": "my_tool", "success": False, "error": message}))
sys.exit(1)
parser.print_usage(sys.stderr)
print(f"{parser.prog}: error: {message}", file=sys.stderr)
sys.exit(1)
parser.error = _json_aware_error
Use os.path throughout. Do not mix os.path and pathlib within the same codebase.
# Correct — consistent os.path usage
skill_dir = os.path.dirname(skill_md_path)
ref_path = os.path.normpath(os.path.join(skill_dir, normalized_ref))
# Wrong — mixing paradigms
skill_dir = Path(skill_md_path).parent
ref_path = os.path.normpath(os.path.join(str(skill_dir), normalized_ref))
One test file per source module. Test files mirror the source structure:
| Source | Test |
|---|---|
| scripts/validate_skill.py | tests/test_validate_skill.py |
| scripts/lib/validation.py | tests/test_validation.py |
| scripts/lib/references.py | tests/test_references.py |
| scripts/lib/bundling.py | tests/test_bundle.py |
Use unittest.TestCase with descriptive class and method names. Group related tests into classes by feature or rule being tested. Use section separators for visual clarity:
# ===================================================================
# Empty Name
# ===================================================================
class ValidateNameEmptyTests(unittest.TestCase):
"""Tests for validate_name when the name is empty."""
def test_empty_string_returns_fail(self) -> None:
"""An empty name produces a single FAIL error and no passes."""
errors, passes = validate_name("", "some-dir")
self.assertEqual(len(errors), 1)
self.assertIn(LEVEL_FAIL, errors[0])
self.assertIn("empty", errors[0])
self.assertEqual(passes, [])
Shared test utilities live in tests/helpers.py:
def write_skill_md(
skill_dir: str,
*,
name: str = "demo-skill",
description: str = DEFAULT_DESCRIPTION,
body: str = "# Demo Skill\n",
) -> None:
Use keyword-only arguments for optional parameters. Create temporary directories with tempfile.mkdtemp() and clean up in tearDown or addCleanup.
The repository targets 70% branch coverage (configured in .coveragerc). Coverage source is skill-system-foundry/scripts with branch measurement enabled.
Run tests with coverage:
python -m coverage run -m unittest discover -s tests -t .
python -m coverage report
Excluded from coverage:
if __name__ == "__main__" blockspragma: no cover markersraise NotImplementedErrorMethod names describe the scenario and expected outcome:
def test_name_at_max_length_passes(self) -> None:
def test_name_one_over_max_length_returns_fail(self) -> None:
def test_empty_string_short_circuits(self) -> None:
def test_short_name_returns_info(self) -> None:
scripts/lib/<module>.py with a module docstring and type-hinted functionslib/constants.py — add new constants to configuration.yaml if they are validation rulestests/test_<module>.py with comprehensive test coveragescripts/scripts/<name>.py with a module docstring that doubles as usage textargparsescripts/lib/ modules--json flag for machine-readable output (use to_json_output from lib/reporting.py)--verbose flag for detailed outputparser.error() for JSON-compatible error reportingif __name__ == "__main__" guardtests/test_<name>.pypip install)scripts/lib/open() without encoding="utf-8"except or swallowed exception without actionable output"FAIL") instead of LEVEL_FAILconfiguration.yamlprint() or sys.exit() in library code outside output helpersif __name__ == "__main__" guardos.path and pathlibtools
Greets a recipient through one of two registered tones — formal or casual — by dispatching to a dedicated capability. Activates when the conversation asks for a tone-specific welcome or a switch between formal and casual greetings; use when comparing the two styles. Demonstrates the router pattern in the Skill System Foundry — a thin SKILL.md entry point routing to capability files, with allowed-tools declared in frontmatter so capability shell fences pass validation.
testing
Greets a single recipient with a friendly welcome message rendered in a formal or casual tone. Activates when the conversation asks to say hello or welcome someone; use when a minimal standalone skill is needed. Demonstrates the smallest valid standalone skill in the Skill System Foundry — required name and description frontmatter plus an optional metadata block — and how its layout passes validation.
testing
Designs and evolves AI-agnostic skill systems. Triggers on skill/capability creation, role definition, or router migration; use when auditing consistency or improving token efficiency.
development
Governs the configuration.yaml file that serves as the single source of truth for all validation rules in the Skill System Foundry. Triggers when adding, modifying, or reviewing validation rules, limits, patterns, or reserved words. Also triggers when working with constants.py, yaml_parser.py, or any code that reads from configuration.yaml. Use this skill when asked to add a new validation check, change a limit or threshold, update reserved word lists, add SPDX license identifiers, modify regex patterns, or troubleshoot why a validation rule is not working as expected. Activates on mentions of configuration, validation rules, constants, thresholds, or pattern definitions.