# Cookiecutter PyPackage: a uv, ruff and just scaffold for Python packages

> Cookiecutter PyPackage generates a Python package with uv, ruff, ty, pytest, Typer and GitHub Actions wired together. It is opinionated, and the opinion is the point.

**audreyfeldroy/cookiecutter-pypackage** — Cookiecutter template for a Python package.

- Repository: https://github.com/audreyfeldroy/cookiecutter-pypackage
- Stars: 4,602 · Forks: 1,789
- Language: Python
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/audreyfeldroy-cookiecutter-pypackage

## The problem Cookiecutter PyPackage solves

Starting a Python package is a sequence of small decisions that have to agree with each other. Which package manager creates the virtual environment. Which linter runs in CI. Which Python versions the test matrix covers. How the release reaches PyPI without a long-lived token sitting in repository secrets. Get one of those wrong and the mismatch shows up weeks later, usually as a failing workflow on the day you want to publish.

Cookiecutter PyPackage answers those questions once, in a template. The README describes the result as a "Cookiecutter template for a Python package with production-ready CI and automated PyPI publishing". The audience is a developer who is about to create a new Python library or CLI and would rather adopt a working set of defaults than assemble one.

The trade-off is stated in the README itself: "This template is opinionated." That sentence is doing real work. The generated project uses uv for environments, just as the task runner, ruff for both formatting and linting, ty for type checking, pytest for tests, Typer for the CLI entry point, and Zensical with mkdocstrings for documentation. None of those are placeholders you are expected to replace. If you already have a preferred stack that disagrees with this one, the template is the wrong starting point.

## What the generated tree actually wires together

The template repository keeps its own tooling in the same shape it hands to you. The root contains a justfile, a pyproject.toml, a cookiecutter.json, a hooks/ directory, a docs/ directory, a scripts/ directory, tests/, and the templated output directory named {{cookiecutter.package_name}}/. That last entry is the Jinja-rendered skeleton; everything else is the machinery that bakes and verifies it.

The justfile is where the workflow becomes concrete. `just fix` runs ruff format and ruff check with `--fix`. `just check` runs the same two commands in verification mode, then ty, then pytest. `just fix-and-check` chains them, and `qa` and `ci` are documented as compatibility aliases for those two recipes. `just testall` runs pytest three times, once each on Python 3.12, 3.13 and 3.14.

On the CI side, the README lists four GitHub Actions workflows. CI runs on pushes to main and on pull requests, doing lint, type check and tests across three Python versions. Publish triggers on a `v*` tag and builds with Sigstore attestation before uploading to PyPI through Trusted Publishers, which the README describes as "no tokens". Docs builds and deploys to GitHub Pages on pushes to main. Dependabot opens weekly pull requests for Python dependencies and for the SHA-pinned actions. The README also states that all actions are pinned by SHA, permissions are minimal, and no credentials are persisted.

That is a coherent design: the local gate and the CI gate run the same commands, so passing `just check` locally is meant to predict the CI result rather than approximate it.

## Install and generate your first package

The README's quickstart assumes uv is already installed and uses uvx to run the template without adding it to a project environment. The command is a single line, and the tool then prompts for your package name, GitHub username and a few other values.

```bash
uvx cookiecutter-pypackage
```

After the prompts finish, Cookiecutter writes the rendered project into a directory named after your package. The README points to a full list of prompts and to a tutorial that covers generating, verifying and releasing the package.

If you would rather not use uvx, the README gives an explicit alternative that installs Cookiecutter into a virtual environment and runs it against the GitHub repository.

```bash
uv venv
source .venv/bin/activate
uv pip install cookiecutter
cookiecutter --keep-project-on-failure gh:audreyfeldroy/cookiecutter-pypackage
```

The `--keep-project-on-failure` flag is worth noticing: if rendering fails partway through, the partially generated directory stays on disk instead of being cleaned up, which makes the failing template expression inspectable.

For automation, the README documents passing `key=value` arguments to prefill prompts, and `--no-input` to skip prompting entirely. The example given is a single prefilled value.

```bash
uvx cookiecutter-pypackage full_name="Your Name"
```

Inside the generated project, the justfile is the entry point. `just list` prints the available recipes, and the README's task runner row describes the intended loop: `just fix` applies safe fixes, `just check` verifies, `just fix-and-check` does both. Type checking has a watch mode through `just type-check-watch`.

## Where the template pushes back

The strongest constraint is the Python floor. The template's own pyproject.toml declares `requires-python = ">=3.12"`, and the classifiers list 3.12, 3.13 and 3.14. If you maintain a library that still supports 3.9 or 3.10, this is not a template you can adopt unchanged; you would be editing the generated metadata and the test matrix before writing any code.

The environment story is equally fixed. uv is not one option among several here, it is the assumed package manager, and the justfile recipes invoke `uv run --python=3.14` for the local quality gate. A team standardized on Poetry or pip-tools would spend its first hour undoing that.

The GitHub coupling is the third constraint. Publish relies on Trusted Publishers and Sigstore attestation, Docs deploys to GitHub Pages, and Dependabot is the update mechanism. The README does not document an equivalent path for GitLab CI, CircleCI or a self-hosted runner, so a project hosted anywhere other than GitHub loses the publish and docs workflows and keeps only the Python-side tooling.

Finally, the README's own troubleshooting section is the honest signal about where friction lives. It exists, which means generation and first release do not always go smoothly on the first attempt, and the prompts page is the reference for what each answer controls.

## Cookiecutter PyPackage compared with writing your own template

The README names two alternatives directly: browsing the fork network for variants, or creating your own Cookiecutter template from scratch. Those are genuinely different approaches, not restatements of the same thing.

A fork keeps the architecture and changes the choices. You inherit the hooks, the CI workflows, the release script and the justfile, then swap ruff for something else or drop ty. The cost is that you now maintain a divergent copy, and upstream changes have to be merged by hand.

Writing your own template inverts that. You start from an empty cookiecutter.json and decide every prompt, every hook and every generated file yourself. You get exactly the stack you want and none of the assumptions above. You also own the CI hardening, the publish workflow and the release script, which in this project are substantial enough to have their own documentation page.

A third path is to skip templating entirely and copy an existing repository. That works once. It stops working when the second package needs the same fixes the first one received, because there is no single place where the fix lives.

There is also a practical difference in how the template is consumed. Because cookiecutter-pypackage is published to PyPI, `uvx cookiecutter-pypackage` runs it without a clone. Cloning the repository and running `cookiecutter .` inside it, as the justfile's `bake` recipe does, is the maintainer's path for developing the template itself.

## Maintenance, licence and what a release costs

The repository is not archived, and the last push was on 2026-08-17. The most recent release listed is v0.5.0, tagged 2026-03-17 and titled "Cookiecutter PyPackage 0.5.0: Docs, coverage, and one-command releases"; v0.4.0 preceded it on 2026-02-16. So the project has shipped two minor releases in the months before the last push, and the release cadence is visible in the changelog directory rather than inferred.

Upgrade cost depends on how you consume it. If you generate a project and never look at the template again, upgrades cost nothing and you simply miss later improvements. If you track the template, you are re-rendering or diffing against a new version, and the prompts page is what tells you which answers changed meaning.

The maintainer's own release process is scripted. The justfile has a `release` recipe that runs `uv run scripts/release.py`, described in a comment as finalizing release notes, tagging, pushing and creating a GitHub release. That is the same one-command release named in the v0.5.0 title.

On licensing: the template is MIT, and pyproject.toml declares `license = { text = "MIT" }`. The README states the MIT License and links to a LICENSE file. What that means for the licence of code you generate is a question for your own legal review, not something the repository answers. Note also the README's closing section about WriterStead, which explains that the maintainer improves this template while building software for that product. That is disclosed in the README rather than hidden, but it is context worth knowing when you weigh how the template's priorities get set.

## Conclusion

Adopt Cookiecutter PyPackage when you want a Python package whose lint, type check, test and publish steps already agree with each other, and when you accept its tool choices rather than planning to swap them out. Skip it if you need a setup.py-based layout, a non-uv workflow, or a project that will not live on GitHub, since the CI and publish workflows assume GitHub Actions and Trusted Publishers. Before generating anything, read the prompts page to see which values are baked into the tree, and check that your target Python is 3.12 or newer, because the template's own project metadata declares requires-python >=3.12.

## FAQ

### What is Cookiecutter PyPackage used for?

It is a Cookiecutter template that generates a Python package with CI and automated PyPI publishing already configured. The README describes the output as production-ready, with uv, just, ruff, ty, pytest and Typer wired together.

### What is a cookiecutter template?

A cookiecutter template is a project skeleton that Cookiecutter renders by prompting for values and substituting them into files and directory names. In this repository the templated output lives in the directory named {{cookiecutter.package_name}}/, and the prompts are defined in cookiecutter.json.

### How does Python packaging work?

The generated project uses hatchling as its build backend, declared under [build-system] in pyproject.toml, and publishes to PyPI through a GitHub Actions workflow triggered by a v* tag. The README states that uploads go through Trusted Publishers with no tokens.

### What are Python packages and what are they used for?

In this project a package is the unit the template generates: a named source tree plus metadata in pyproject.toml, tests, documentation and CI workflows. The README frames the goal as a package with production-ready CI and automated PyPI publishing.

## Sources

- [audreyfeldroy/cookiecutter-pypackage on GitHub](https://github.com/audreyfeldroy/cookiecutter-pypackage)
- [Issues](https://github.com/audreyfeldroy/cookiecutter-pypackage/issues)
- [License: MIT](https://github.com/audreyfeldroy/cookiecutter-pypackage/blob/main/LICENSE)
- [README](https://github.com/audreyfeldroy/cookiecutter-pypackage/blob/main/README.md)
- [Releases](https://github.com/audreyfeldroy/cookiecutter-pypackage/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/audreyfeldroy-cookiecutter-pypackage
