Skip to content
Development
Skill

/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.

From plugin
tenequm-skills
3630 skills
Install
$ npx -y skills add tenequm/skills --skill python-dev --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/python-dev

Context preview

The summary Claude sees to decide when to auto-load this skill.

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.

SKILL.md

python-dev.SKILL.md
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.0"
  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 r
Read more
Ships withtenequm-skills

Claude 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.

Get the whole plugin
Stats
36
Stars
1
Forks
Active
Maintenance
Python
Language
MIT
License
2d ago
Last commit
10mo ago
Created

Repo: tenequm/skills

Other skills on tenequm-skills.