When building scripts for a skill, follow these standards to ensure portability and zero-friction execution. Skills must work across macOS, Linux, and Windows (native, Git Bash, and WSL).
Always favor Python for script logic. Bash is not portable — it fails or behaves inconsistently on Windows (Git Bash is MSYS2-based, not a full Linux shell; WSL bash can conflict with Git Bash on PATH; PowerShell is a different language entirely). Python with uv run works identically on all platforms.
Safe bash commands — these work reliably across all environments and are fine to use directly:
git, gh — version control and GitHub CLIuv run — Python script execution with automatic dependency handlingnpm, npx, pnpm — Node.js ecosystemmkdir -p — directory creationEverything else should be Python — piping, jq, grep, sed, awk, find, diff, wc, and any non-trivial logic. Even sed -i behaves differently on macOS vs Linux. If it's more than a single safe command, write a Python script.
Always prefer Python's standard library over external dependencies. The stdlib is pre-installed everywhere, requires no uv run, and has zero supply-chain risk. Common stdlib modules that cover most script needs:
json — JSON parsing and outputpathlib — cross-platform path handlingre — pattern matchingargparse — CLI interfacecollections — counters, defaultdictsdifflib — text comparisonast — Python source analysiscsv, xml.etree — data formatsOnly pull in external dependencies when the stdlib genuinely cannot do the job (e.g., tiktoken for accurate token counting, pyyaml for YAML parsing, jsonschema for schema validation). External dependencies must be confirmed with the user during the build process — they add install-time cost, supply-chain surface, and require uv to be available.
Every Python script MUST include a PEP 723 metadata block. For scripts with external dependencies, use the uv run shebang:
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.10"
# dependencies = ["pyyaml>=6.0", "jsonschema>=4.0"]
# ///
For scripts using only the standard library, use a plain Python shebang but still include the metadata block:
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# ///
Key rules:
requires-pythonrequirements.txt, pip install, or expect global package installsuv run scripts/foo.py, not direct shebang executionHow a built skill's SKILL.md should reference its scripts (bare path from the skill root, per the path conventions):
uv run scripts/foo.py {args} — consistent invocation regardless of whether the script has external dependenciesuv run reads the PEP 723 metadata, silently caches dependencies in an isolated environment, and runs the script — no user prompt, no global install. Like npx for Python.
Skills may run in environments where Python or uv is unavailable (e.g., claude.ai web). Scripts should be the fast, reliable path — but the skill must still deliver its outcome when execution is not possible.
Pattern: When a script cannot execute, the LLM performs the equivalent work directly. The script's --help documents what it checks, making this fallback natural. Design scripts so their logic is understandable from their help output and the skill's context.
In SKILL.md, frame script steps as outcomes, not just commands:
scripts/scan-paths.py --help for details)"uv run scripts/scan-paths.py" with no context about what it does--help via argparse (single source of truth for the script's API)-o flag for output file (default to stdout)--verbose flag for debuggingscripts/tests/