.claude/skills/modern-python/SKILL.md
Modern Python tooling best practices using uv, ruff, ty, and pytest. Mandates the Trail of Bits Python coding standards for project setup, dependency management, linting, type checking, and testing. Based on patterns from trailofbits/cookiecutter-python.
npx skillsauth add oimiragieo/agent-studio modern-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.
This skill implements Trail of Bits' modern Python coding standards for the agent-studio framework. The core philosophy is: use Rust-based tools for faster feedback loops, especially when working with AI agents. Every tool in this stack (uv, ruff, ty) is written in Rust and provides sub-second execution times, enabling tight iteration cycles.
Source repository: https://github.com/trailofbits/skills
Template: https://github.com/trailofbits/cookiecutter-python
License: CC-BY-SA-4.0
pyproject.toml -- no separate config files (setup.cfg, .flake8, mypy.ini, black.toml) are permitted.uv add/uv remove for dependency management -- never use bare pip install in projects managed by uv.venv/, .venv/, or pip-generated requirements.txt -- commit uv.lock for reproducible builds.uv run to execute tools and scripts -- this ensures the correct virtual environment and dependency resolution.| Anti-Pattern | Why It Fails | Correct Approach |
| --------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Using pip install directly in a uv-managed project | Bypasses lockfile and dependency resolution; creates reproducibility drift | Use uv add <pkg> to add dependencies and uv sync to install |
| Maintaining .flake8, mypy.ini, or black.toml config files | Fragments configuration across multiple files; hard to maintain and audit | Consolidate all tool config into pyproject.toml under [tool.ruff] and [tool.ty] |
| Running python script.py instead of uv run python script.py | Uses system Python instead of project venv; dependency mismatches | Always use uv run to execute within the managed environment |
| Globally installing CLI tools with pip install --user | Pollutes global environment; version conflicts across projects | Use uv tool run <tool> or uvx <tool> for one-off tool execution |
| Ignoring ruff security rules (S select) | Misses bandit-equivalent security checks like hardcoded passwords and SQL injection | Enable select = ["S"] in [tool.ruff.lint] for security linting |
| Tool | Replaces | Purpose | Speed | | -------------- | ------------------------------------------------------- | ---------------------------- | -------------- | | uv | pip, Poetry, pipenv, pip-tools | Package & project management | 10-100x faster | | ruff | flake8, isort, black, pyflakes, pycodestyle, pydocstyle | Linting + formatting | 10-100x faster | | ty | mypy, pyright, pytype | Type checking | 5-10x faster | | pytest | unittest | Testing | -- | | hypothesis | (manual property tests) | Property-based testing | -- |
# Create new project with uv
uv init my-project
cd my-project
# Add dependency groups
uv add --group dev ruff ty
uv add --group test pytest pytest-cov hypothesis
uv add --group docs sphinx myst-parser
# Install all dependencies
uv sync --all-groups
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ruff", "ty"]
test = ["pytest", "pytest-cov", "hypothesis"]
docs = ["sphinx", "myst-parser"]
# === Ruff Configuration ===
[tool.ruff]
target-version = "py312"
line-length = 100
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # flake8-comprehensions
"SIM", # flake8-simplify
"S", # flake8-bandit (security)
"TCH", # flake8-type-checking
"RUF", # ruff-specific rules
]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"] # Allow assert in tests
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
# === Pytest Configuration ===
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
"--strict-markers",
"--strict-config",
"-ra",
]
[tool.coverage.run]
source = ["src"]
branch = true
[tool.coverage.report]
fail_under = 80
show_missing = true
exclude_lines = [
"if TYPE_CHECKING:",
"if __name__ == .__main__.:",
]
# Add a dependency
uv add requests
# Add a dev dependency
uv add --group dev ipdb
# Remove a dependency
uv remove requests
# Update all dependencies
uv lock --upgrade
# Update a specific dependency
uv lock --upgrade-package requests
# Run a script in the project environment
uv run python script.py
# Run a tool (without installing globally)
uv run --with httpie http GET https://api.example.com
# Check for lint errors
uv run ruff check .
# Auto-fix lint errors
uv run ruff check --fix .
# Format code
uv run ruff format .
# Check formatting (dry run)
uv run ruff format --check .
# Check specific rules
uv run ruff check --select S . # Security rules only
# Run type checker
uv run ty check
# Check specific file
uv run ty check src/main.py
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov
# Run specific test file
uv run pytest tests/test_auth.py
# Run with verbose output
uv run pytest -v
# Run and stop at first failure
uv run pytest -x
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Initialize project from existing requirements
uv init
uv add $(cat requirements.txt | grep -v '^#' | grep -v '^$')
# Remove old files
rm requirements.txt requirements-dev.txt
# uv can read pyproject.toml with Poetry sections
uv init
# Move Poetry dependencies to [project.dependencies]
# Move [tool.poetry.group.dev.dependencies] to [dependency-groups]
# Remove [tool.poetry] section
uv sync
# Remove old tools
uv remove flake8 black isort pyflakes pycodestyle
# Add ruff
uv add --group dev ruff
# Convert .flake8 config to ruff (manual)
# ruff supports most flake8 rules with same codes
# Remove old config files
rm .flake8 .isort.cfg pyproject.toml.bak
# Remove mypy
uv remove mypy
# Add ty
uv add --group dev ty
# ty uses the same type annotation syntax as mypy
# Most code requires no changes
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Install dependencies
run: uv sync --all-groups
- name: Lint
run: uv run ruff check .
- name: Format check
run: uv run ruff format --check .
- name: Type check
run: uv run ty check
- name: Test
run: uv run pytest --cov --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
file: coverage.xml
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: 'uv'
directory: '/'
schedule:
interval: 'weekly'
groups:
all:
patterns:
- '*'
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
from __future__ import annotations
from collections.abc import Sequence
from typing import TypeAlias
# Use modern syntax (Python 3.12+)
type Vector = list[float] # Type alias (PEP 695)
def process_items(items: Sequence[str], *, limit: int = 10) -> list[str]:
"""Process items with a limit."""
return [item.strip() for item in items[:limit]]
# Use | instead of Union
def maybe_int(value: str) -> int | None:
try:
return int(value)
except ValueError:
return None
my-project/
pyproject.toml # Single config file for all tools
uv.lock # Locked dependencies (commit this)
src/
my_project/
__init__.py
main.py
models.py
utils.py
tests/
__init__.py
test_main.py
test_models.py
conftest.py # Shared fixtures
.github/
workflows/
ci.yml
dependabot.yml
.pre-commit-config.yaml
uv add / uv remove / uv run. Never pip install.pyproject.toml. Delete .flake8, mypy.ini, black.toml.uv run or uv tool run instead of globally installing CLI tools.uv.lock for reproducible builds.ruff --select UP to auto-upgrade to modern syntax (match statements, | unions, etc.).S (bandit) rules in ruff to catch security issues.modern-python to set up or migrate Python projectspython-backend-expert for framework-specific patterns (Django, FastAPI)tdd skill for test-driven development workflowcomprehensive-unit-testing-with-pytest for test strategy| Skill | Relationship |
| ---------------------------------------- | ---------------------------------------------------- |
| python-backend-expert | Framework-specific patterns (Django, FastAPI, Flask) |
| comprehensive-unit-testing-with-pytest | Testing strategies and patterns |
| comprehensive-type-annotations | Type annotation best practices |
| prioritize-python-3-10-features | Modern Python language features |
| tdd | Test-driven development methodology |
| property-based-testing | Hypothesis-based testing patterns |
Before starting: Check if the project already has Python tooling configured. Identify which legacy tools need migration.
During setup: Write configuration incrementally, verifying each tool works before moving to the next. Run ruff check, ruff format --check, and uv run pytest at each step.
After completion: Record the toolchain versions and any migration issues to .claude/context/memory/learnings.md for future reference.
tools
Comprehensive biosignal processing toolkit for analyzing physiological data including ECG, EEG, EDA, RSP, PPG, EMG, and EOG signals. Use this skill when processing cardiovascular signals, brain activity, electrodermal responses, respiratory patterns, muscle activity, or eye movements. Applicable for heart rate variability analysis, event-related potentials, complexity measures, autonomic nervous system assessment, psychophysiology research, and multi-modal physiological signal integration.
tools
Comprehensive toolkit for creating, analyzing, and visualizing complex networks and graphs in Python. Use when working with network/graph data structures, analyzing relationships between entities, computing graph algorithms (shortest paths, centrality, clustering), detecting communities, generating synthetic networks, or visualizing network topologies. Applicable to social networks, biological networks, transportation systems, citation networks, and any domain involving pairwise relationships.
data-ai
Molecular featurization for ML (100+ featurizers). ECFP, MACCS, descriptors, pretrained models (ChemBERTa), convert SMILES to features, for QSAR and molecular ML.
development
Run Python code in the cloud with serverless containers, GPUs, and autoscaling. Use when deploying ML models, running batch processing jobs, scheduling compute-intensive tasks, or serving APIs that require GPU acceleration or dynamic scaling.