plugins/uv-strict-python/skills/uv-strict-python/SKILL.md
Configures Python projects to the Python Tooling SSOT Standard (uv, Ruff, BasedPyright strict, pytest+coverage, pip-audit). Use when creating projects, writing standalone scripts, configuring pyproject.toml, migrating from pip/Poetry/mypy/black/flake8, or auditing a project for conformance to the standard.
npx skillsauth add l3digital-net/claude-code-plugins uv-strict-pythonInstall 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.
Operational guide for the Python Tooling SSOT Standard: one small, strict, boring toolchain that behaves identically in CLI, VS Code, and CI. The standard prefers a few non-overlapping authorities over many competing tools, because contradictory feedback is expensive for coding agents.
This plugin operationalizes the Python Tooling standard — toolchain, layout, and the verification gate. Code shape and agent-behavior rules (error handling, side-effect boundaries, trust boundaries, prohibited behaviors) live in the companion Python Coding standard, summarized in coding-standard.md. A green gate on badly shaped code is not done — read both.
Sync pin: mirrors
project-standardspython-tooling (contract v1.0, README at commit79daeae, 2026-06-12) and the python-coding draft v0.4 (commita14ac7d). The standards repo is canonical; if it has moved past these commits, prefer it and re-sync this plugin.
pyproject.tomlrequires-python, add scanners, or keep mypy if an ADR records why.Verification gate — the non-mutating proof the repo is clean. Code is not complete until this passes (or the response says exactly what failed and why):
uv run ruff format --check .
uv run ruff check .
uv run basedpyright
uv run coverage run -m pytest
uv run coverage report
uv run pip-audit
Fix pass — allowed to modify source; run it first when changing code:
uv run ruff format .
uv run ruff check . --fix
| Avoid | Use Instead |
| --- | --- |
| mypy / pyright / ty | basedpyright strict — one semantic/type authority |
| select = ["ALL"] (auto-enables new rules on every Ruff bump) | A curated Ruff select set (stable, boring) |
| [tool.pytest] in templates | [tool.pytest.ini_options] (recognized back to pytest 6.0; avoids silent inert config) |
| --cov flags in pytest addopts | coverage run -m pytest + coverage report (branch coverage) |
| pre-commit / prek | The gate runs in CI + VS Code tasks + scripts/check.py — no overlapping hook runner |
| uv pip install | uv add / uv sync |
| Editing pyproject.toml to add deps by hand | uv add <pkg> / uv remove <pkg> |
| hatchling build backend | uv_build |
| Poetry / Pipenv / PDM | uv |
| requirements.txt | PEP 723 for single-file scripts, pyproject.toml for projects |
| [project.optional-dependencies] for dev tools | [dependency-groups] (PEP 735) |
| Manual venv activation (source .venv/bin/activate) | uv run <cmd> |
| Pylance / Python Environments as a second authority | BasedPyright (type) + Ruff (format/lint), nothing overlapping |
Key principles:
uv owns dependency resolution, the lockfile, the virtualenv, and command execution — always uv add/uv remove, never hand-edit deps or activate venvs.extend-exclude / [tool.basedpyright].include.[dependency-groups] for dev/test deps, not [project.optional-dependencies].What are you doing?
│
├─ Single-file script with dependencies?
│ └─ Use PEP 723 inline metadata (./references/pep723-scripts.md — plugin
│ extension; the standard governs script *projects*, not single files)
│
├─ New importable project or package?
│ └─ Full setup with src/ layout (see Full Setup below)
│
├─ Small automation/script project (lives in Git)?
│ └─ Still uv + pyproject + ruff + basic typing (Quick Start below)
│
└─ Migrating an existing project?
└─ See Migration Guide below
| Tool | Purpose | Replaces | | --- | --- | --- | | uv | Package/dependency management, venv, command execution | pip, virtualenv, pip-tools, pipx, pyenv | | ruff | Linting AND formatting AND import sorting | flake8, black, isort, pyupgrade | | basedpyright | Strict type checking (CLI + language server) | mypy, pyright, ty | | pytest | Testing | unittest | | coverage.py | Branch coverage enforcement | — | | pip-audit | Dependency vulnerability scanning | — |
Security baseline is pip-audit (run in CI) plus Dependabot for update PRs. Extra scanners (Bandit, shellcheck, actionlint, zizmor, detect-secrets) are threat-model-driven additions, not part of the baseline — add them when a project handles auth, secrets, public network services, subprocess execution, or uploaded files, and document the addition. See security-setup.md.
For small multi-file or automation projects that still live in Git:
# Create project with uv (src/ layout)
uv init --package myproject
cd myproject
# Runtime dependencies
uv add requests rich
# Standard dev toolchain (flat dev group)
uv add --dev basedpyright "coverage[toml]" pip-audit pytest pytest-cov ruff
# Run code and tools through uv (never activate the venv)
uv run python -m myproject
uv run ruff check .
uv run basedpyright
uv run coverage run -m pytest && uv run coverage report
Prefer the adopt CLI when the standards repo is reachable — it materializes the scaffolds (.python-version, check.yml, scripts/check.py, AGENTS.md/CLAUDE.md, .editorconfig, .vscode/extensions.json) and prints the pyproject.toml sections to copy:
uvx --from 'git+https://github.com/L3DigitalNet/project-standards@v3' \
project-standards adopt python-tooling
The steps below produce the same result manually.
uv init --package myproject
cd myproject
Target layout (importable code under src/, tooling/scripts outside it):
myproject/
├── pyproject.toml
├── uv.lock
├── .python-version
├── .editorconfig
├── README.md
├── AGENTS.md # full instructions or pointer to the canonical source
├── CLAUDE.md # Claude-specific notes or pointer
├── .github/workflows/check.yml
├── .vscode/ # extensions.json, settings.json, tasks.json
├── src/
│ └── myproject/
│ ├── __init__.py
│ └── py.typed # for packages exposing typed interfaces
├── tests/
│ ├── unit/
│ └── integration/
└── scripts/
└── check.py
src/ governs the importable product only. Repo tooling (scripts/check.py, automation under scripts/) MAY live outside src/; it is still linted and formatted and SHOULD carry basic typing, but is not held to the strict-src/ bar.
See pyproject.md for the complete baseline. The canonical starting point:
[project]
name = "myproject"
version = "0.1.0"
description = "Short project description."
readme = "README.md"
requires-python = ">=3.14"
dependencies = []
[dependency-groups]
# pytest floor backs minversion; ruff floor matches the adopt-CLI bundle
dev = ["basedpyright", "coverage[toml]", "pip-audit", "pytest>=9.0", "pytest-cov", "ruff>=0.9.0"]
[build-system]
requires = ["uv_build>=0.11,<0.12"]
build-backend = "uv_build"
[tool.ruff]
target-version = "py314"
line-length = 100
src = ["src", "tests"]
extend-exclude = [".claude", ".agents", ".codex", ".continue"]
[tool.ruff.lint]
select = ["E", "F", "I", "B", "UP", "SIM", "C4", "PIE", "PTH", "RET", "RUF"]
ignore = ["E501"] # formatter owns line wrapping
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
docstring-code-format = true
[tool.basedpyright]
include = ["src", "tests"]
typeCheckingMode = "strict"
pythonVersion = "3.14"
pythonPlatform = "All"
failOnWarnings = true
[tool.pytest.ini_options]
minversion = "9.0"
testpaths = ["tests"]
addopts = ["-ra", "--strict-markers", "--strict-config"]
[tool.coverage.run]
branch = true
source = ["src"]
[tool.coverage.report]
show_missing = true
skip_covered = true
fail_under = 85
uv sync --all-groups
The standard runs the gate three ways — all the same uv run commands — so CLI, editor, and CI never diverge:
scripts/check.py — a small Python wrapper that runs the gate in order (see §18 of the standard)..vscode/tasks.json — tasks check, fix, test, typecheck, audit..github/workflows/check.yml — the same sequence in CI on uv sync --locked --all-groups.uv run python -m scripts.check # if using the wrapper
See pyproject.md for VS Code and CI specifics.
Copy scaffolds from templates/ instead of transcribing fenced blocks — transcription is where typos and drift creep in:
| Template | Destination | Source |
| --- | --- | --- |
| check.py | scripts/check.py | adopt-CLI bundle (byte-identical) |
| check.yml | .github/workflows/check.yml | adopt-CLI bundle (byte-identical) |
| python-version | .python-version | adopt-CLI bundle (byte-identical) |
| pyproject.python-tooling.toml | merge into pyproject.toml | adopt-CLI bundle (byte-identical) |
| editorconfig | .editorconfig | shared superset (byte-identical) |
| vscode-extensions.json | .vscode/extensions.json | shared superset (byte-identical) |
| vscode-settings.json | .vscode/settings.json | standard §13 |
| vscode-tasks.json | .vscode/tasks.json | standard §13 |
| adr-python-tooling-exception.md | docs/decisions/adr-NNNN-python-tooling-exception.md | standard §20 skeleton |
The byte-identical templates are enforced against the standards repo by this plugin's tests/check-standard-sync.sh.
AGENTS.md and CLAUDE.md are part of the repo contract, not optional docs — a fresh CLI or VS Code agent must discover the gate, fix pass, and the dependency/typing/testing/security rules before editing. Copy a template:
AGENTS.mdA pointer file is valid only when the resolved source preserves this standard and is discoverable from a fresh session; if it can't be resolved, the agent must stop and report rather than guess.
When a user requests migration from legacy tooling (stage it; do not weaken the final standard):
Standalone scripts: convert to PEP 723 inline metadata (see pep723-scripts.md).
Projects:
uv init --bare
uv add requests rich # add each package via uv, not by editing pyproject.toml
# Or import from requirements.txt (review each package first)
grep -v '^#' requirements.txt | grep -v '^-' | grep -v '^\s*$' | while read -r pkg; do
uv add "$pkg" || echo "Failed to add: $pkg"
done
uv sync
Then delete requirements*.txt and any venv/, and commit uv.lock.
uv init --bareuv add each dependency from install_requires; uv add --dev for dev deps[project]setup.py, setup.cfg, MANIFEST.inuv remove flake8 black isort.flake8, [tool.black], [tool.isort]uv add --dev ruff, add the curated config (see ruff-config.md)uv run ruff check . --fix then uv run ruff format .uv remove mypy pyright ty (whichever is present)mypy.ini, pyrightconfig.json, [tool.mypy]/[tool.pyright]/[tool.ty]uv add --dev basedpyright[tool.basedpyright] with typeCheckingMode = "strict"uv run basedpyright — for messy codebases, adopt strictness in stages (BasedPyright baselines) rather than weakening the final bar.| Command | Description |
| --- | --- |
| uv init --package | Create a distributable src/ package |
| uv add <pkg> | Add runtime dependency |
| uv add --dev <pkg> | Add dev dependency |
| uv remove <pkg> | Remove dependency |
| uv sync --all-groups | Install everything |
| uv sync --locked --all-groups | CI install (fails if lockfile stale) |
| uv run <cmd> | Run a command in the project env |
| uv run --with <pkg> <cmd> | Run with a one-off dependency |
| uv tool install <pkg> | Install a global ad-hoc CLI (ruff, basedpyright, pip-audit) |
--withuv run --with httpx python script.py # project deps + httpx, not added to the project
uv add: package is a real project dependency (lands in pyproject.toml/uv.lock).--with: one-off usage or a script outside a project context.See uv-commands.md for the complete reference.
src/ layout for importable coderequires-python = ">=3.14", .python-version = 3.14select set (not ALL)typeCheckingMode = "strict"[tool.pytest.ini_options] with --strict-markers --strict-configfail_under = 85, via coverage run -m pytestpip-audit in CI[dependency-groups] for dev tools, uv.lock committed (apps)pyproject.toml, VS Code, and CI baselinedevelopment
Use when you're stuck or missing current information mid-task - the same command/API/approach failed twice, an error looks like a changed or deprecated API, or you need the current version of something, a fact from after your training cutoff, or to verify something you cannot confirm from the code in context. Starts with a cheap inline lookup and only escalates to a full research sweep if that fails. Do not use for routine pre-emptive checks before ordinary library work - for deliberate research, use /qdev:research.
documentation
Update the llm-wiki knowledge base (remote LXC CT 103, /srv/workspaces/llm-wiki, over SSH) with implementation-level details from the current session by dispatching the up-docs-propagate-wiki sub-agent. This skill should be used when the user runs /up-docs:wiki.
documentation
Update repository documentation (README.md, docs/, CLAUDE.md) based on session changes by dispatching the up-docs-propagate-repo sub-agent. This skill should be used when the user runs /up-docs:repo.
documentation
Update Notion pages with strategic and organizational context from the current session by dispatching the up-docs-propagate-notion sub-agent. This skill should be used when the user runs /up-docs:notion.