/init-python-project — Scaffold a modern Python project
This skill sets up a new Python project that follows current best practices.
uv is the default and recommended project/venv manager, but the skill can
fall back to pip + venv, pipenv, a manual .venv, or skip environment setup
entirely if the user prefers. It is opinionated about quality defaults (ruff +
mypy + pre-commit + pytest) and confirms optional pieces (Docker, CI,
coverage, placeholder structure) before acting.
Be conversational and decisive: state the sensible defaults, confirm them, ask
only the questions that genuinely change the output, then build.
Steps
1. Choose the project/venv manager
Run command -v uv (or uv --version).
- If uv is present, use it — it's the recommended path. Continue.
- If uv is missing, ask the user how they want to proceed. Offer:
- Install uv for them (recommended). Install via the official installer
(
curl -LsSf https://astral.sh/uv/install.sh | sh, or brew install uv
if Homebrew is available and they prefer it), then re-check with
uv --version.
- They install uv themselves — point them at
https://docs.astral.sh/uv/getting-started/installation/ and let them run
it in this session with the
! prefix; wait, re-check, continue.
- Use an alternative manager —
pip + venv (stdlib), pipenv, or a
manually created .venv. Confirm which.
- Skip environment setup — just scaffold files/config and let the user
wire up an environment later.
Record the chosen manager; the steps below are written for uv and include
equivalents for the alternatives (see Manager equivalents at the end). When
a manager is skipped, still create all config files and note clearly which
setup commands the user must run themselves.
2. Clarify what the project is for
Ask the user, conversationally:
- What is the project? (its purpose / what it does) — shapes the package
name, structure, and dependencies.
- What name should the project/package use (default: derive a sensible
kebab/snake name from the description).
- Where should it be created? Run
pwd and suggest a default path —
a new subdirectory named after the project inside the current working
directory (e.g. <cwd>/<name>). Present it clearly and let the user change
it to any path they prefer.
- Is it a library, a CLI, or an application/service? Affects layout
(e.g.
--package/src layout for libraries, an entry point for CLIs/apps)
and whether Docker makes sense.
3. Choose the Python version
Ask which Python version to target (default: the latest stable the user
has, or the newest if installing fresh). Then:
- With uv: pin it with
uv python pin <version> (creating .python-version),
and if that version isn't installed, offer uv python install <version>.
- With other managers: confirm the interpreter (
python3 --version) and write
a .python-version and a requires-python in pyproject.toml to match.
4. State the defaults, then confirm the optional pieces
Tell the user plainly what you'll set up by default (let them opt out):
- Ruff as the linter and formatter.
- mypy for static type checking.
- pre-commit running ruff (lint + format), mypy, and a set of standard
hygiene hooks automatically before every commit.
- A
tests/ folder with pytest added to the dev environment.
Then ask the questions that DO change the output (use AskUserQuestion):
- Docker?
Dockerfile, docker-compose.yml, both, or neither?
(Default: neither.)
- CI workflow? A GitHub Actions workflow running lint + type-check + tests
on push/PR. (Default: yes for libraries/apps that'll live on GitHub; ask.)
- Test coverage? Add
pytest-cov with a coverage config. (Default: yes.)
- Placeholder structure & files? Starter scaffolding (package module(s), a
sample entry point, a sample test, README) or just the bare project? Tailor
placeholders to the project type from step 2.
- Git? Confirm initializing a git repo (default: yes) — you'll add an
appropriate Python
.gitignore.
5. Safety check before initializing
Before creating anything, verify the target path is safe:
- Run
test -e <path> / ls -la <path>. If it exists and is non-empty,
stop and confirm with the user (pick a different path, or explicitly proceed
into the existing directory). Never silently overwrite or clobber an
existing project.
6. Initialize the project
With uv, pick the form that matches the project type:
- Application/CLI:
uv init <name> (add --package for an installable CLI
with an entry point).
- Library:
uv init --lib <name> (src layout, installable package).
Then work inside the project dir (use absolute paths in subsequent commands to
avoid permission prompts) and confirm pyproject.toml, the package module,
and the lockfile workflow exist. For alternative managers, create the dir,
pyproject.toml, and package layout yourself and set up the environment with
the chosen tool (see Manager equivalents).
7. Add tooling to the environment
Add dev dependencies: ruff, mypy, pytest, pre-commit (plus pytest-cov
if coverage was chosen).
- uv:
uv add --dev ruff mypy pytest pre-commit (and uv add --dev pytest-cov if coverage was chosen)
- Verify with
uv run ruff --version, uv run mypy --version,
- For pip/pipenv, install the same packages as dev dependencies (see Manager
equivalents).
8. Configure ruff
Add a [tool.ruff] section to pyproject.toml with modern defaults: target
the pinned Python version, a reasonable line length, and a useful lint rule
selection (e.g. E, F, I imports, UP pyupgrade, B bugbear). Configure
both linting and formatting. Keep it readable and lightly commented.
9. Configure mypy
Add a [tool.mypy] section with sensible-but-not-punishing strictness for a
fresh project (e.g. python_version matching the pin, warn_unused_configs,
warn_redundant_casts, warn_unused_ignores, disallow_untyped_defs, and
ignore_missing_imports = true to start). Note the user can tighten toward
strict = true later.
10. Configure pre-commit
Create .pre-commit-config.yaml with pinned hook revisions:
ruff-pre-commit: the ruff hook (lint, with --fix) and ruff-format.
mirrors-mypy: the mypy hook.
pre-commit-hooks: standard hygiene hooks (trailing-whitespace,
end-of-file-fixer, check-yaml, check-added-large-files,
check-merge-conflict).
After the git repo exists (step 15), run pre-commit install (via the chosen
manager, e.g. uv run pre-commit install) so hooks fire on every commit, and
consider pre-commit autoupdate to freshen pinned revs. If git isn't being
set up, note that pre-commit install requires a git repo.
11. Tests folder
Ensure a tests/ directory exists (with __init__.py or relying on pytest
rootdir conventions) and, if placeholders were chosen, a minimal passing
tests/test_smoke.py. Add [tool.pytest.ini_options] (e.g.
testpaths = ["tests"]). If coverage was chosen, add a [tool.coverage.run]
section (e.g. source = ["<package>"]) and document --cov usage.
12. Docker (only if requested)
- Dockerfile: modern, multi-stage-friendly, using the official
uv base
image (or installing the chosen manager) with uv sync --frozen / uv run.
Slim Python base, non-root user.
- docker-compose.yml: define the app service (and an obvious companion
like a database only if the user mentions needing one). Keep it minimal.
- Add a
.dockerignore.
13. CI workflow (only if requested)
Create .github/workflows/ci.yml that, on push and pull_request: checks out
the repo, sets up the chosen manager (e.g. astral-sh/setup-uv), installs
deps, then runs ruff check, ruff format --check, mypy, and pytest
(with coverage if enabled). Pin action versions.
14. Placeholder structure (only if requested)
Create starter files appropriate to the project type:
- A package module with a
main() / sample function and, for CLIs/apps, a
runnable entry point wired in pyproject.toml ([project.scripts]).
- A
README.md with a short description and the run/test/lint/type-check
commands.
- The sample test from step 11.
Keep placeholders minimal and obviously-replaceable.
15. Git + .gitignore
- If the user wants git (default yes):
git init, create a Python
.gitignore (cover .venv/, __pycache__/, *.pyc, .pytest_cache/,
.ruff_cache/, .mypy_cache/, coverage files (.coverage, htmlcov/),
build/dist artifacts, .env, and editor/OS cruft; add Docker ignores only
if Docker was set up).
- Then run
pre-commit install (via the chosen manager).
- Make an initial commit only if the user wants one (ask) — otherwise leave
the working tree staged/clean for them to review.
16. Validate the scaffold
Before handing off, prove the setup is green by running (via the chosen
manager; skip cleanly if env setup was skipped):
uv run ruff check . and uv run ruff format --check .
uv run mypy .
uv run pytest
Report the results. If anything fails, fix the scaffold (not by loosening
config blindly) until it passes, or clearly flag what the user needs to
resolve.
17. Confirm and hand off
Summarize what was created (paths, key files, defaults applied, optional
pieces included/skipped, and the chosen manager) and give the everyday
commands (uv form shown; translate for the chosen manager):
- Run the app:
uv run <entrypoint> (or uv run python -m <package>)
- Run tests:
uv run pytest
- Lint/format:
uv run ruff check . / uv run ruff format .
- Type-check:
uv run mypy .
- Hooks run automatically on
git commit.
Manager equivalents
The steps default to uv. For the alternatives, map commands as follows:
- pip + venv (stdlib):
- Create env:
python3 -m venv .venv then activate it.
- Init: create the project dir,
pyproject.toml, and package layout by hand.
- Add dev deps:
pip install ruff mypy pytest pre-commit pytest-cov and
record them under [dependency-groups] / an optional dev extra (or a
requirements-dev.txt).
- Run tools directly once the venv is active (
ruff check ., mypy .,
pytest), i.e. drop the uv run prefix.
- pipenv:
- Env + deps:
pipenv install --dev ruff mypy pytest pre-commit pytest-cov.
- Run tools via
pipenv run <cmd> instead of uv run <cmd>.
- manual
.venv: same as pip + venv, but the user manages activation; be
explicit about the activation step in the hand-off.
- skip: create every config file and the layout, but run no install/venv
commands — list the exact commands the user should run later to finish.
Principles
- uv is the default project manager — use
uv init, uv add, uv run,
uv sync. Only fall back to pip/pipenv/manual when uv is unavailable and the
user chooses an alternative.
- Install uv only with consent — if it's missing, ask first; install it for
the user if they say yes, otherwise offer the alternatives above.
- Quality is on by default — ruff, mypy, pytest, and pre-commit are baked
in; Docker, CI, coverage, placeholders, and the initial commit are the
branch points to ask about.
- Never clobber — check the target path before initializing.
- Always validate — finish by running lint, types, and tests so the user
receives a known-green scaffold.
- Prefer modern, minimal, well-commented config over kitchen-sink setups the
user has to delete.
- Use absolute paths in shell commands once inside the new project dir.
1---2name: init-python-project3description: Scaffold a new Python project that follows modern best practices, using uv by default to initialize and manage the project (with pip/venv, pipenv, or manual fallbacks if uv isn't available). Sets up ruff (lint + format), mypy type checking, pre-commit, a tests/ folder with pytest, and optionally Docker, a CI workflow, coverage, placeholder structure, and a git repo with .gitignore. Use when the user wants to start/create/bootstrap a new Python project, says "set up a Python project", "init a python repo", "new python project with best practices", or similar.4---56# /init-python-project — Scaffold a modern Python project78This skill sets up a new Python project that follows current best practices.9**uv is the default and recommended project/venv manager**, but the skill can10fall back to pip + venv, pipenv, a manual `.venv`, or skip environment setup11entirely if the user prefers. It is opinionated about quality defaults (ruff +12mypy + pre-commit + pytest) and confirms optional pieces (Docker, CI,13coverage, placeholder structure) before acting.1415Be conversational and decisive: state the sensible defaults, confirm them, ask16only the questions that genuinely change the output, then build.1718## Steps1920### 1. Choose the project/venv manager21Run `command -v uv` (or `uv --version`).2223- **If uv is present**, use it — it's the recommended path. Continue.24- **If uv is missing**, ask the user how they want to proceed. Offer:25 1. **Install uv for them** (recommended). Install via the official installer26 (`curl -LsSf https://astral.sh/uv/install.sh | sh`, or `brew install uv`27 if Homebrew is available and they prefer it), then re-check with28 `uv --version`.29 2. **They install uv themselves** — point them at30 https://docs.astral.sh/uv/getting-started/installation/ and let them run31 it in this session with the `!` prefix; wait, re-check, continue.32 3. **Use an alternative manager** — `pip` + `venv` (stdlib), `pipenv`, or a33 **manually created `.venv`**. Confirm which.34 4. **Skip environment setup** — just scaffold files/config and let the user35 wire up an environment later.3637**Record the chosen manager**; the steps below are written for uv and include38equivalents for the alternatives (see *Manager equivalents* at the end). When39a manager is skipped, still create all config files and note clearly which40setup commands the user must run themselves.4142### 2. Clarify what the project is for43Ask the user, conversationally:44- **What is the project?** (its purpose / what it does) — shapes the package45 name, structure, and dependencies.46- **What name** should the project/package use (default: derive a sensible47 kebab/snake name from the description).48- **Where** should it be created? Run `pwd` and **suggest a default path** —49 a new subdirectory named after the project inside the current working50 directory (e.g. `<cwd>/<name>`). Present it clearly and let the user change51 it to any path they prefer.52- **Is it a library, a CLI, or an application/service?** Affects layout53 (e.g. `--package`/src layout for libraries, an entry point for CLIs/apps)54 and whether Docker makes sense.5556### 3. Choose the Python version57**Ask which Python version to target** (default: the latest stable the user58has, or the newest if installing fresh). Then:59- With uv: pin it with `uv python pin <version>` (creating `.python-version`),60 and if that version isn't installed, offer `uv python install <version>`.61- With other managers: confirm the interpreter (`python3 --version`) and write62 a `.python-version` and a `requires-python` in `pyproject.toml` to match.6364### 4. State the defaults, then confirm the optional pieces65Tell the user plainly what you'll set up **by default** (let them opt out):66- **Ruff** as the linter **and** formatter.67- **mypy** for static type checking.68- **pre-commit** running ruff (lint + format), mypy, and a set of standard69 hygiene hooks automatically before every commit.70- A **`tests/`** folder with **pytest** added to the dev environment.7172Then ask the questions that DO change the output (use AskUserQuestion):73- **Docker?** `Dockerfile`, `docker-compose.yml`, both, or neither?74 (Default: neither.)75- **CI workflow?** A GitHub Actions workflow running lint + type-check + tests76 on push/PR. (Default: yes for libraries/apps that'll live on GitHub; ask.)77- **Test coverage?** Add `pytest-cov` with a coverage config. (Default: yes.)78- **Placeholder structure & files?** Starter scaffolding (package module(s), a79 sample entry point, a sample test, README) or just the bare project? Tailor80 placeholders to the project type from step 2.81- **Git?** Confirm initializing a git repo (default: yes) — you'll add an82 appropriate Python `.gitignore`.8384### 5. Safety check before initializing85Before creating anything, verify the target path is safe:86- Run `test -e <path>` / `ls -la <path>`. If it **exists and is non-empty**,87 stop and confirm with the user (pick a different path, or explicitly proceed88 into the existing directory). Never silently overwrite or clobber an89 existing project.9091### 6. Initialize the project92With uv, pick the form that matches the project type:93- Application/CLI: `uv init <name>` (add `--package` for an installable CLI94 with an entry point).95- Library: `uv init --lib <name>` (src layout, installable package).9697Then work inside the project dir (use absolute paths in subsequent commands to98avoid permission prompts) and confirm `pyproject.toml`, the package module,99and the lockfile workflow exist. For alternative managers, create the dir,100`pyproject.toml`, and package layout yourself and set up the environment with101the chosen tool (see *Manager equivalents*).102103### 7. Add tooling to the environment104Add dev dependencies: **ruff, mypy, pytest, pre-commit** (plus **pytest-cov**105if coverage was chosen).106- uv: `uv add --dev ruff mypy pytest pre-commit` (and `uv add --dev pytest-cov` if coverage was chosen)107- Verify with `uv run ruff --version`, `uv run mypy --version`,108- For pip/pipenv, install the same packages as dev dependencies (see *Manager109 equivalents*).110111### 8. Configure ruff112Add a `[tool.ruff]` section to `pyproject.toml` with modern defaults: target113the pinned Python version, a reasonable line length, and a useful lint rule114selection (e.g. `E`, `F`, `I` imports, `UP` pyupgrade, `B` bugbear). Configure115both linting and formatting. Keep it readable and lightly commented.116117### 9. Configure mypy118Add a `[tool.mypy]` section with sensible-but-not-punishing strictness for a119fresh project (e.g. `python_version` matching the pin, `warn_unused_configs`,120`warn_redundant_casts`, `warn_unused_ignores`, `disallow_untyped_defs`, and121`ignore_missing_imports = true` to start). Note the user can tighten toward122`strict = true` later.123124### 10. Configure pre-commit125Create `.pre-commit-config.yaml` with **pinned hook revisions**:126- `ruff-pre-commit`: the `ruff` hook (lint, with `--fix`) and `ruff-format`.127- `mirrors-mypy`: the `mypy` hook.128- `pre-commit-hooks`: standard hygiene hooks (`trailing-whitespace`,129 `end-of-file-fixer`, `check-yaml`, `check-added-large-files`,130 `check-merge-conflict`).131After the git repo exists (step 15), run `pre-commit install` (via the chosen132manager, e.g. `uv run pre-commit install`) so hooks fire on every commit, and133consider `pre-commit autoupdate` to freshen pinned revs. If git isn't being134set up, note that `pre-commit install` requires a git repo.135136### 11. Tests folder137Ensure a `tests/` directory exists (with `__init__.py` or relying on pytest138rootdir conventions) and, if placeholders were chosen, a minimal passing139`tests/test_smoke.py`. Add `[tool.pytest.ini_options]` (e.g.140`testpaths = ["tests"]`). If coverage was chosen, add a `[tool.coverage.run]`141section (e.g. `source = ["<package>"]`) and document `--cov` usage.142143### 12. Docker (only if requested)144- **Dockerfile**: modern, multi-stage-friendly, using the official `uv` base145 image (or installing the chosen manager) with `uv sync --frozen` / `uv run`.146 Slim Python base, non-root user.147- **docker-compose.yml**: define the app service (and an obvious companion148 like a database only if the user mentions needing one). Keep it minimal.149- Add a `.dockerignore`.150151### 13. CI workflow (only if requested)152Create `.github/workflows/ci.yml` that, on push and pull_request: checks out153the repo, sets up the chosen manager (e.g. `astral-sh/setup-uv`), installs154deps, then runs `ruff check`, `ruff format --check`, `mypy`, and `pytest`155(with coverage if enabled). Pin action versions.156157### 14. Placeholder structure (only if requested)158Create starter files appropriate to the project type:159- A package module with a `main()` / sample function and, for CLIs/apps, a160 runnable entry point wired in `pyproject.toml` (`[project.scripts]`).161- A `README.md` with a short description and the run/test/lint/type-check162 commands.163- The sample test from step 11.164Keep placeholders minimal and obviously-replaceable.165166### 15. Git + .gitignore167- If the user wants git (default yes): `git init`, create a Python168 `.gitignore` (cover `.venv/`, `__pycache__/`, `*.pyc`, `.pytest_cache/`,169 `.ruff_cache/`, `.mypy_cache/`, coverage files (`.coverage`, `htmlcov/`),170 build/dist artifacts, `.env`, and editor/OS cruft; add Docker ignores only171 if Docker was set up).172- Then run `pre-commit install` (via the chosen manager).173- Make an initial commit only if the user wants one (ask) — otherwise leave174 the working tree staged/clean for them to review.175176### 16. Validate the scaffold177Before handing off, **prove the setup is green** by running (via the chosen178manager; skip cleanly if env setup was skipped):179- `uv run ruff check .` and `uv run ruff format --check .`180- `uv run mypy .`181- `uv run pytest`182Report the results. If anything fails, fix the scaffold (not by loosening183config blindly) until it passes, or clearly flag what the user needs to184resolve.185186### 17. Confirm and hand off187Summarize what was created (paths, key files, defaults applied, optional188pieces included/skipped, and the chosen manager) and give the everyday189commands (uv form shown; translate for the chosen manager):190- Run the app: `uv run <entrypoint>` (or `uv run python -m <package>`)191- Run tests: `uv run pytest`192- Lint/format: `uv run ruff check .` / `uv run ruff format .`193- Type-check: `uv run mypy .`194- Hooks run automatically on `git commit`.195196## Manager equivalents197The steps default to uv. For the alternatives, map commands as follows:198199- **pip + venv (stdlib):**200 - Create env: `python3 -m venv .venv` then activate it.201 - Init: create the project dir, `pyproject.toml`, and package layout by hand.202 - Add dev deps: `pip install ruff mypy pytest pre-commit pytest-cov` and203 record them under `[dependency-groups]` / an optional `dev` extra (or a204 `requirements-dev.txt`).205 - Run tools directly once the venv is active (`ruff check .`, `mypy .`,206 `pytest`), i.e. drop the `uv run` prefix.207- **pipenv:**208 - Env + deps: `pipenv install --dev ruff mypy pytest pre-commit pytest-cov`.209 - Run tools via `pipenv run <cmd>` instead of `uv run <cmd>`.210- **manual `.venv`:** same as pip + venv, but the user manages activation; be211 explicit about the activation step in the hand-off.212- **skip:** create every config file and the layout, but run no install/venv213 commands — list the exact commands the user should run later to finish.214215## Principles216- **uv is the default project manager** — use `uv init`, `uv add`, `uv run`,217 `uv sync`. Only fall back to pip/pipenv/manual when uv is unavailable and the218 user chooses an alternative.219- **Install uv only with consent** — if it's missing, ask first; install it for220 the user if they say yes, otherwise offer the alternatives above.221- **Quality is on by default** — ruff, mypy, pytest, and pre-commit are baked222 in; Docker, CI, coverage, placeholders, and the initial commit are the223 branch points to ask about.224- **Never clobber** — check the target path before initializing.225- **Always validate** — finish by running lint, types, and tests so the user226 receives a known-green scaffold.227- Prefer modern, minimal, well-commented config over kitchen-sink setups the228 user has to delete.229- Use absolute paths in shell commands once inside the new project dir.