/python-dev
Opinionated Python development setup with uv, ty, ruff, pytest, lefthook, and just. Use when creating a new Python project, writing or fixing pyproject.toml, or configuring linting, formatting, type checking, testing, git hooks, or CI.
Claude Code
$ npx -y skills add tenequm/skills --skill python-dev --agent claude-code
Codex
$ npx skills add tenequm/skills --skill python-dev -a codex -y
Cursor
$ npx skills add tenequm/skills --skill python-dev -a cursor -y
Gemini CLI
$ npx skills add tenequm/skills --skill python-dev -a gemini-cli -y
GitHub Copilot
$ npx skills add tenequm/skills --skill python-dev -a github-copilot -y
OpenCode
$ npx skills add tenequm/skills --skill python-dev -a opencode -y
Windsurf
$ npx skills add tenequm/skills --skill python-dev -a windsurf -y
SKILL.md
python-dev.SKILL.mdname: python-dev
description: Opinionated Python development setup with uv, ty, ruff, pytest, lefthook, and just. Use when creating a new Python project, writing or fixing pyproject.toml, or configuring linting, formatting, type checking, testing, git hooks, or CI.
metadata:
version: "0.3.1"
categories: "development"
topics: "python, uv, ruff, pytest, lefthook"
upstream: "uv@0.12.11, ty@0.0.79, ruff@0.16.6, pytest@9.1.1, pytest-asyncio@1.4.0, lefthook@2.1.12"
openclaw:
homepage: https://github.com/tenequm/skills/tree/main/skills/python-dev
emoji: "🐍"Python Development Setup
Opinionated, production-ready Python development stack. No choices to make - just use this.
When to Use
- Starting a new Python project
- Modernizing an existing project (migrating from pip/poetry/mypy/black/flake8)
- Setting up linting, formatting, type checking, or testing
- Creating a Justfile for project commands
- Configuring pyproject.toml as the single source of truth
The Stack
| Tool | Role | Replaces | |------|------|----------| | [uv](https://docs.astral.sh/uv/) 0.12+ | Package manager, Python versions, runner | pip, poetry, pyenv, virtualenv | | [ty](https://docs.astral.sh/ty/) (beta) | Type checker (Astral, Rust) | mypy, pyright | | [ruff](https://docs.astral.sh/ruff/) | Linter + formatter | flake8, black, isort, pyupgrade | | [pytest](https://docs.pytest.org/) | Testing | unittest | | [just](https://just.systems/) | Command runner | make | | [lefthook](https://lefthook.dev/) 2.1+ | Git hooks (single binary, parallel) | pre-commit |
> **Note on ty**: ty is in beta (0.0.x) - no stable API, and inference can change between any > two versions, so pin it. Pydantic is no longer a fair complaint: ty has shipped a dedicated > library-support track for it since 0.0.57 (constructors, `model_config`, `BaseSettings`, > `RootModel`, strict vs lax). Django and SQLAlchemy still have no such support and remain the > likely source of false positives. Before swapping the whole checker, reach for > `[tool.ty.analysis] replace-imports-with-any = ["sqlalchemy.**"]`, which silences one bad > dependency instead of all of them. If you do need rock-solid checking today, swap `ty` for > `pyright` and keep the rest of the stack unchanged.
Quick Start: New Project
# 1. Create project with src layout (uv 0.12+ packages by default; --package is redundant)
uv init my-project
cd my-project
# 2. Pin Python version
uv python pin 3.13
# 3. Add dev dependencies
uv add --dev ruff ty pytest pytest-asyncio lefthook
# 4. Create Justfile and lefthook.yml (see templates below)
# 5. Configure pyproject.toml (see template below)
# 6. Install git hooks
uv run lefthook install
# 7. Run checks
just check
pyproject.toml Template
This is the single config file. Copy this and adjust `[project]` fields.
[project]
name = "my-project"
version = "0.1.0"
description = "Project description"
readme = "README.md"
requires-python = ">=3.13"
license = {text = "MIT"}
dependencies = []
[project.scripts]
my-project = "my_project:main" # CLI: `uv run my-project` -> main() in src/my_project/__init__.py
[dependency-groups]
dev = [
"ruff>=0.16.6", # 0.16 changed the default rule set - see the lint note below
"ty>=0.0.79", # beta: pin tight, inference changes between minors
"pytest>=9.1.1", # 9.1 fixed addopts strictness being ignored
"pytest-asyncio>=1.4.0", # 1.4 added the loop-factories hook
"lefthook>=2.1.12",
]
# uv 0.12+ generates `uv_build` here instead. Keep that unless you need a hatchling
# plugin - this block is a deliberate override, not what `uv init` gives you.
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/my_project"]
# =============================================================================
# RUFF - Loose, helpful rules only
# =============================================================================
[tool.ruff]
target-version = "py313"
line-length = 100
[tool.ruff.lint]
# Ruff 0.16 enables 413 rules by default (up from 59). Do NOT write a `select`
# list here unless you mean to shrink that - `select = ["E","F","I","UP"]` now
# makes ruff weaker than no config at all. Narrow with `extend-select`/`ignore`.
ignore = [
"E501", # line too long - formatter handles it
"UP007", # X | Y unions - Optional[X] is more readable
]
exclude = [".git", ".venv", "__pycache__", "build", "dist"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "lf"
# Ruff 0.16 formats Python blocks inside Markdown by default. Drop this line
# only if you want README code fences reformatted too.
exclude = ["*.md"]
# =============================================================================
# TY - Type Checker
# =============================================================================
[tool.ty.environment]
python-version = "3.13"
[tool.ty.src]
include = ["src"]
# =============================================================================
# PYTEST
# =============================================================================
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
asyncio_mode = "auto"
# pytest 9.0 silently ignored --strict-markers/--strict-config passed via
# addopts. Use the ini keys, which work on 9.0 and 9.1 alike. `strict = true`
# is the shorthand and also covers strict_xfail + strict_parametrization_ids.
strict = true
addopts = ["-ra"]`asyncio_default_fixture_loop_scope` is intentionally unset above; pytest-asyncio warns about that on every run. Set it to `"function"` to silence the warning and lock the behavior in.
Justfile Template
# Check types, lint, and formatting (non-mutating; mirrors CI)
check:
uv run ty check
uv run ruff check
uv run ruff format --check
# Run tests
test *ARGS:
uv rRead more
name: python-dev
description: Opinionated Python development setup with uv, ty, ruff, pytest, lefthook, and just. Use when creating a new Python project, writing or fixing pyproject.toml, or configuring linting, formatting, type checking, testing, git hooks, or CI.
metadata:
version: "0.3.1"
categories: "development"
topics: "python, uv, ruff, pytest, lefthook"
upstream: "uv@0.12.11, ty@0.0.79, ruff@0.16.6, pytest@9.1.1, pytest-asyncio@1.4.0, lefthook@2.1.12"
openclaw:
homepage: https://github.com/tenequm/skills/tree/main/skills/python-dev
emoji: "🐍"Python Development Setup
Opinionated, production-ready Python development stack. No choices to make - just use this.
When to Use
- Starting a new Python project
- Modernizing an existing project (migrating from pip/poetry/mypy/black/flake8)
- Setting up linting, formatting, type checking, or testing
- Creating a Justfile for project commands
- Configuring pyproject.toml as the single source of truth
The Stack
| Tool | Role | Replaces | |------|------|----------| | [uv](https://docs.astral.sh/uv/) 0.12+ | Package manager, Python versions, runner | pip, poetry, pyenv, virtualenv | | [ty](https://docs.astral.sh/ty/) (beta) | Type checker (Astral, Rust) | mypy, pyright | | [ruff](https://docs.astral.sh/ruff/) | Linter + formatter | flake8, black, isort, pyupgrade | | [pytest](https://docs.pytest.org/) | Testing | unittest | | [just](https://just.systems/) | Command runner | make | | [lefthook](https://lefthook.dev/) 2.1+ | Git hooks (single binary, parallel) | pre-commit |
> **Note on ty**: ty is in beta (0.0.x) - no stable API, and inference can change between any > two versions, so pin it. Pydantic is no longer a fair complaint: ty has shipped a dedicated > library-support track for it since 0.0.57 (constructors, `model_config`, `BaseSettings`, > `RootModel`, strict vs lax). Django and SQLAlchemy still have no such support and remain the > likely source of false positives. Before swapping the whole checker, reach for > `[tool.ty.analysis] replace-imports-with-any = ["sqlalchemy.**"]`, which silences one bad > dependency instead of all of them. If you do need rock-solid checking today, swap `ty` for > `pyright` and keep the rest of the stack unchanged.
Quick Start: New Project
# 1. Create project with src layout (uv 0.12+ packages by default; --package is redundant) uv init my-project cd my-project # 2. Pin Python version uv python pin 3.13 # 3. Add dev dependencies uv add --dev ruff ty pytest pytest-asyncio lefthook # 4. Create Justfile and lefthook.yml (see templates below) # 5. Configure pyproject.toml (see template below) # 6. Install git hooks uv run lefthook install # 7. Run checks just check
pyproject.toml Template
This is the single config file. Copy this and adjust `[project]` fields.
[project]
name = "my-project"
version = "0.1.0"
description = "Project description"
readme = "README.md"
requires-python = ">=3.13"
license = {text = "MIT"}
dependencies = []
[project.scripts]
my-project = "my_project:main" # CLI: `uv run my-project` -> main() in src/my_project/__init__.py
[dependency-groups]
dev = [
"ruff>=0.16.6", # 0.16 changed the default rule set - see the lint note below
"ty>=0.0.79", # beta: pin tight, inference changes between minors
"pytest>=9.1.1", # 9.1 fixed addopts strictness being ignored
"pytest-asyncio>=1.4.0", # 1.4 added the loop-factories hook
"lefthook>=2.1.12",
]
# uv 0.12+ generates `uv_build` here instead. Keep that unless you need a hatchling
# plugin - this block is a deliberate override, not what `uv init` gives you.
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/my_project"]
# =============================================================================
# RUFF - Loose, helpful rules only
# =============================================================================
[tool.ruff]
target-version = "py313"
line-length = 100
[tool.ruff.lint]
# Ruff 0.16 enables 413 rules by default (up from 59). Do NOT write a `select`
# list here unless you mean to shrink that - `select = ["E","F","I","UP"]` now
# makes ruff weaker than no config at all. Narrow with `extend-select`/`ignore`.
ignore = [
"E501", # line too long - formatter handles it
"UP007", # X | Y unions - Optional[X] is more readable
]
exclude = [".git", ".venv", "__pycache__", "build", "dist"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "lf"
# Ruff 0.16 formats Python blocks inside Markdown by default. Drop this line
# only if you want README code fences reformatted too.
exclude = ["*.md"]
# =============================================================================
# TY - Type Checker
# =============================================================================
[tool.ty.environment]
python-version = "3.13"
[tool.ty.src]
include = ["src"]
# =============================================================================
# PYTEST
# =============================================================================
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
asyncio_mode = "auto"
# pytest 9.0 silently ignored --strict-markers/--strict-config passed via
# addopts. Use the ini keys, which work on 9.0 and 9.1 alike. `strict = true`
# is the shorthand and also covers strict_xfail + strict_parametrization_ids.
strict = true
addopts = ["-ra"]`asyncio_default_fixture_loop_scope` is intentionally unset above; pytest-asyncio warns about that on every run. Set it to `"function"` to silence the warning and lock the behavior in.
Justfile Template
# Check types, lint, and formatting (non-mutating; mirrors CI)
check:
uv run ty check
uv run ruff check
uv run ruff format --check
# Run tests
test *ARGS:
uv rClaude Code skills for founders, developers, and web3 builders. This repository publishes reusable skill folders under skills//, ships stable bundle downloads through GitHub Releases, and publishes changed skills to ClawHub.
Other skills on skills.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about python-dev.
- Which coding agents can use python-dev?
- python-dev installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

