shebangpython
Validate Python shebangs and PEP 723 inline script metadata. Use when checking if Python files have correct shebangs based on their dependency requirements, when fixing incorrect shebang patterns, or when adding PEP 723 script blocks to standalone scripts with external dependencies.
From python3-developmentnpx claudepluginhub jamie-bitflight/claude_skills --plugin python3-developmentThis skill uses the workspace's default tool permissions.
<file_paths>$ARGUMENTS</file_paths>
Python Shebang Validation
The model validates Python shebangs against dependency requirements and ensures correct PEP 723 inline script metadata.
Arguments
<file_paths/>
Instructions
If file paths provided above:
- Read each file using the Read tool
- Check for shebang presence and correctness
- Validate against the rules below
- Check execute bit status
- Fix any misalignments with this guidance
- Report findings for each file
If no arguments provided:
- Ask the user which files or directories need shebang validation
- Suggest searching for Python files that might need shebangs
- Offer to check if existing shebangs are correct
Shebang Selection Rules
Rule 1: Stdlib-only executable scripts
Pattern: #!/usr/bin/env python3
Conditions:
- File is executable
- Has no external dependencies
- Uses only Python standard library
Reasoning: No dependency installation required, standard Python interpreter sufficient.
Rule 2: Package executables
Pattern: #!/usr/bin/env python3
Conditions:
- File is part of installed package
- Has setup.py or pyproject.toml managing dependencies
Reasoning: Dependencies installed via package manager, not script metadata.
Rule 3: Standalone scripts with external dependencies
Pattern: #!/usr/bin/env -S uv --quiet run --active --script
Conditions:
- File is executable standalone script
- Requires external packages
Reasoning: PEP 723 inline metadata declares dependencies, uv installs them automatically.
Rule 4: Non-executable files
Pattern: No shebang line
Conditions:
- File is library module
- Imported by other code
- Not directly executable
Reasoning: Not intended for direct execution.
UV Shebang Command Structure
The shebang: #!/usr/bin/env -S uv --quiet run --active --script
Component Breakdown
| Component | Position | Purpose |
|---|---|---|
#!/usr/bin/env -S | Prefix | Shebang invoking env with -S flag for multiple arguments |
uv | Command | The uv binary on PATH |
--quiet | GLOBAL flag (before subcommand) | Suppresses progress output from uv |
run | Subcommand | Executes Python scripts with automatic environment management |
--active | run flag (after subcommand) | Prefer active virtual environment over isolated environment |
--script | run flag (after subcommand) | Indicates file contains PEP 723 inline script metadata |
Command Syntax Pattern
uv [GLOBAL_FLAGS] SUBCOMMAND [SUBCOMMAND_FLAGS] [ARGS]
Flag Ordering Rule
Global flags modify the uv binary behavior and MUST appear before the subcommand. Subcommand flags modify that specific subcommand's behavior and MUST appear after the subcommand.
Valid: uv --quiet run --active --script
Invalid: uv run --quiet --active --script (--quiet is global flag)
Invalid Variations
The model MUST reject these malformed shebangs:
#!/usr/bin/env -S uv run --quiet --active --script(--quiet in wrong position)#!/usr/bin/env -S uv --quiet run --script(missing --active)#!/usr/bin/env -S uv run --active --script(missing --quiet)#!/usr/bin/env -S uv --quiet --active run --script(--active in wrong position)
Execute Bit Requirement
All files with shebangs MUST have execute permission set.
chmod +x filename
Without execute bit, the shebang is ignored by the kernel.
Mandatory Verification Format
For each file, output in this exact order:
- Current shebang: [exact line from file or "none"]
- PEP 723 metadata dependencies: [exact list or "none"]
- External package count: [number with evidence]
- Import analysis:
- stdlib: [list]
- external: [list]
- Rule condition evaluation:
- Rule 1: [condition 1 MET/NOT MET] [condition 2 MET/NOT MET] [condition 3 MET/NOT MET]
- Rule 2: [condition 1 MET/NOT MET] [condition 2 MET/NOT MET]
- Rule 3: [condition 1 MET/NOT MET] [condition 2 MET/NOT MET]
- Rule 4: [condition 1 MET/NOT MET]
- Applicable rule: [number] because [one-sentence justification citing specific unmet/met conditions]
- Execute bit: [executable/not executable via test command]
- Verdict: CORRECT / INCORRECT [if incorrect, Edit the file to fix]
Transformation Examples
Example 1: Remove redundant PEP 723 from stdlib-only script
Before (invalid - no external dependencies):
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
from __future__ import annotations
import re
from pathlib import Path
After (corrected):
#!/usr/bin/env python3
from __future__ import annotations
import re
from pathlib import Path
Bundled Transitive Dependency Constraint
typer>=0.12.0 ships with rich and shellingham as bundled transitive dependencies. When typer appears in a PEP 723 dependencies block, the model MUST NOT add rich or shellingham as separate entries.
# WRONG — rich is transitively installed by typer
# dependencies = [
# "typer>=0.21.2",
# "rich>=13.0.0", # ← redundant, DO NOT ADD
# ]
# CORRECT — typer only; rich and shellingham arrive automatically
# dependencies = [
# "typer>=0.21.2",
# ]
This rule applies regardless of how much rich API surface the script uses (Console, Panel, Progress, Table, etc.). The import works because typer guarantees rich's presence.
SOURCE: "By default, typer comes with rich and shellingham." — https://typer.tiangolo.com/#installation (accessed 2026-02-22)
Example 2: Add PEP 723 to script with external dependencies
Before (invalid - missing PEP 723):
#!/usr/bin/env python
from __future__ import annotations
from pathlib import Path
from typing import Annotated
import typer
from rich.console import Console
from rich.panel import Panel
After (corrected):
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "typer>=0.21.2",
# ]
# ///
from __future__ import annotations
from pathlib import Path
from typing import Annotated
import typer
from rich.console import Console
from rich.panel import Panel