{"id":26163498,"url":"https://github.com/jlevy/simple-modern-uv","last_synced_at":"2026-01-16T12:26:20.587Z","repository":{"id":281731655,"uuid":"946062586","full_name":"jlevy/simple-modern-uv","owner":"jlevy","description":"A minimal, modern Python project template using uv. An instantiated version of this template here","archived":false,"fork":false,"pushed_at":"2026-01-14T19:57:01.000Z","size":97,"stargazers_count":250,"open_issues_count":2,"forks_count":18,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-01-14T21:35:44.008Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/jlevy/simple-modern-uv-template","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jlevy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-10T14:52:05.000Z","updated_at":"2026-01-14T19:57:05.000Z","dependencies_parsed_at":"2025-06-05T21:24:03.685Z","dependency_job_id":"c108ffcb-02e0-4094-b3d0-02f78785b597","html_url":"https://github.com/jlevy/simple-modern-uv","commit_stats":null,"previous_names":["jlevy/simple-modern-uv"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/jlevy/simple-modern-uv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fsimple-modern-uv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fsimple-modern-uv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fsimple-modern-uv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fsimple-modern-uv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jlevy","download_url":"https://codeload.github.com/jlevy/simple-modern-uv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fsimple-modern-uv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478642,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-11T14:27:22.579Z","updated_at":"2026-01-16T12:26:20.582Z","avatar_url":"https://github.com/jlevy.png","language":"Jinja","funding_links":[],"categories":["Jinja"],"sub_categories":[],"readme":"[![As usual, XKCD has a comic for this](https://imgs.xkcd.com/comics/python_environment.png)](https://xkcd.com/1987/)\n\n(As usual, XKCD has a comic for this.\nAppropriately enough, the comic is out of date.)\n\n# simple-modern-uv\n\n[![image](https://img.shields.io/pypi/pyversions/uvtemplate.svg)](https://pypi.python.org/pypi/uvtemplate)\n[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)\n[![Copier](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-border.json)](https://github.com/copier-org/copier)\n[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/ojoshe)](https://x.com/ojoshe)\n\n## What is This?\n\n**simple-modern-uv** is a minimal, modern **Python project template** for new projects\n(Python 3.11–3.14) based on [**uv**](https://docs.astral.sh/uv/). This template aims to\nbe a good base for serious work but also simple so it’s an easy option for any small\nproject, like an open source library or tool.\n\n## In a Hurry?\n\nYou can try out this template right from your terminal.\nTry running:\n\n```shell\nuvx uvtemplate\n```\n\nThe [uvtemplate](https://git.new/uvtemplate) tool now walks you through using this\ntemplate.\n\nFor more installation options, scroll down to\n[How to Use This Template](#how-to-use-this-template).\n\n## Why a New Python Project Template?\n\n\u003e **The Story So Far**\n\u003e \n\u003e In the beginning, there was a hack called\n\u003e [`setup.py`](https://github.com/pypa/setuptools) for packaging (1990s–2000s) and it\n\u003e was not good.\n\u003e \n\u003e Then there arose [`virtualenv`](https://github.com/pypa/virtualenv),\n\u003e [`pip`](https://github.com/pypa/pip), and `requirements.txt` for isolated environments\n\u003e (2008–2011). Yet confusion still reigned.\n\u003e \n\u003e Meanwhile, [`conda`](https://github.com/conda/conda),\n\u003e [`pyenv`](https://github.com/pyenv/pyenv), [`brew`](https://github.com/Homebrew/brew),\n\u003e and [`PyInstaller`](https://github.com/pyinstaller/pyinstaller) vied to rule the\n\u003e system installations (2010s).\n\u003e \n\u003e Years of dissatisfaction led to the spread of a new religion,\n\u003e [`pyproject.toml`](https://github.com/pypa/pyproject.toml).\n\u003e Adherents of [`poetry`](https://github.com/python-poetry/poetry),\n\u003e [`pipenv`](https://github.com/pypa/pipenv), and [`pipx`](https://github.com/pypa/pipx)\n\u003e promised peace and prosperity (2020s) yet somehow, life felt mostly the same.\n\u003e \n\u003e Then AI robots began to invade.\n\u003e Rebel forces [`uv`](https://github.com/astral-sh/uv) and\n\u003e [`pixi`](https://github.com/prefix-dev/pixi) aligned with Rust gathered strength …\n\nApologies for the digression.\nThe point is that unfortunately, the accidents of history make it quite confusing to\nlearn best practices for setting up Python projects and dependencies.\nBut it shouldn’t have to be this difficult, especially since uv has now significantly\nsimplified Python dev tooling.\n\nIf you haven’t switched to uv, I can say I too was a little hesitant.\nIt’s often possible to switch dev tooling prematurely because a the new tool is shiny\nand exciting. But the advantages of uv have become too numerous to ignore.\n[This article](https://www.bitecode.dev/p/a-year-of-uv-pros-cons-and-should) (Feb 2025)\nhas a good overview.\n\nThis is the template I now use myself as I have been migrating from Poetry to uv for\nseveral projects. It’s new but it’s working well.\n\n## But I Don’t Like Templates\n\nA lot of more senior engineers have justified hesitancy about templates.\nTemplates can be a real problem if they add mindless, unexamined complexity.\nBut if done carefully, I think they are better than official docs (they show real-world\ncode you can adapt, instead of leaving you to figure out each tool choice and setting)\nor blog posts (that are typically not maintained or updated).\n\nI think a good project template should be **3 Ms: minimalist, modern, and maintained**.\nI looked at [other templates](#alternatives) but wanted one that was modern and “done\nright” but *absolutely as simple as possible*. Few existing templates seem to be both\nsimple and use the newest generation of tools and best practices.\n\nThe template is short enough to read and understand in about 10 minutes.\nIt’s **only ~300 lines of code** so you can just look at it, use it, and change what you\nwant without fuss.\n\nBecause this template is minimal, you can always start with it and then pull in other\ntools and features if you want them.\n(In fact, even if you don’t like this template, you might want to use it as inspiration\nfor your *own* Copier template, to take advantage of the Copier update workflow\ndiscussed next.)\n\n## Why Use Copier?\n\nOne other benefit of this template is it uses\n[**copier**](https://github.com/copier-org/copier).\n\nUnlike with many previous project template tools, Copier allows you\n[pull future changes](#updating-your-project-template) to a template back into your\ninstantiated copy any time.\n\nYou can start a project now, then if this template improves or is updated with other\ntools, you can pull those improvements back into your project, much like a git merge.\nYou could even fork this repo yourself, then build your own forked template, and\nmaintain it yourself.\n\nIf you’re not familiar with Copier, take a moment to understand the\n[update feature](#updating-your-project-template).\nThen the options below will make sense.\nI put a few more thoughts on why a workflow like this is underrated is in\n[a Twitter thread](https://x.com/ojoshe/status/1896696860297019733).\n\n## What Tools are In This Template?\n\nsimple-modern-uv uses uses the tools I’ve come to think are best for new projects:\n\n- [**uv**](https://github.com/astral-sh/uv) for project setup and dependencies.\n  There is also a simple makefile for dev workflows, but it simply is a convenience for\n  running uv commands.\n\n- [**ruff**](https://github.com/charliermarsh/ruff) for modern linting and formatting.\n  Previously, [black](https://github.com/psf/black) was the definitive formatting tool,\n  but ruff now handles linting and fast, black-compatible formatting.\n\n- [**GitHub Actions**](https://github.com/actions/setup-python) for CI and publishing\n  workflows.\n\n- [**Dynamic versioning**](https://github.com/ninoseki/uv-dynamic-versioning/) so\n  release and package publication is as simple as creating a tag/release on GitHub (no\n  machinery needed to manually bump versions and commit files every release).\n\n- Workflows for **packaging and publishing to PyPI** with uv.\n  This has always been more confusing than it should be.\n  The\n  [official docs](https://packaging.python.org/en/latest/tutorials/packaging-projects/)\n  about packaging are several pages long, and then even\n  [toy tutorials](https://realpython.com/pypi-publish-python-package/) about publishing\n  are even longer. This template makes all of that basically automatic with uv, GitHub\n  Actions, and dynamic versioning.\n\n- Type checking with [**BasedPyright**](https://github.com/detachhead/basedpyright).\n  (See below for more on this.)\n\n- [**Pytest**](https://github.com/pytest-dev/pytest) for tests (with the excellent\n  plugin [**pytest-sugar**](https://github.com/Teemu/pytest-sugar) for faster errors and\n  nicer output).\n\n- [**codespell**](https://github.com/codespell-project/codespell) for drop-in spell\n  checking.\n\n## Starter Docs\n\nThe template includes a few **starter docs** for you, collaborators, and users:\n\n- [README.md](https://github.com/jlevy/simple-modern-uv/blob/main/template/README.md.jinja)\n  is a placeholder for your project readme.\n\n- [installation.md](https://github.com/jlevy/simple-modern-uv/blob/main/template/docs/installation.md)\n  has brief reminders on the modern ways to install uv and Python.\n\n- [development.md](https://github.com/jlevy/simple-modern-uv/blob/main/template/docs/development.md.jinja)\n  covers basic developer workflows.\n\n- [publishing.md](https://github.com/jlevy/simple-modern-uv/blob/main/template/docs/publishing.md)\n  covers how to publish your project to PyPI.\n\nIf you haven’t done it before, publishing a package to PyPI can be a bit confusing,\nespecially because the\n[official Python docs](https://packaging.python.org/en/latest/guides/section-build-and-publish/)\ncover older and more complex workflows.\nBe sure to check `publishing.md` for a modern and simple way that uses uv and GitHub\nactions.\n\nYou can edit or delete these, but typically it’s sufficient to just edit the README.md.\nIt helps to have the others in separate files so they get updated whenever you update\nthe template.\n\n## Agent Rules\n\nPreviously, this template included a few agent rules for use with Claude Code, Codex,\nCursor, etc. But agent rules are changing so fast I have since removed them from this\ntemplate and instead suggest adding your own or copying my recent rules from the\n[Speculate](https://github.com/jlevy/speculate) repo.\n\n## What’s the Best Python Type Checker?\n\nThe choice of what tool to use for type checking deserves some explanation.\nThis seems to be a confusing area.\n\nLike many, I’d previously been using [Mypy](https://github.com/python/mypy), the OG type\nchecker for Python. Mypy has since been enhanced with\n[BasedMypy](https://github.com/KotlinIsland/basedmypy).\n\nThe other popular alternative is Microsoft’s\n[Pyright](https://github.com/microsoft/pyright).\nAnd it has a newer extension and fork called\n[BasedPyright](https://github.com/DetachHead/basedpyright).\n\nAll of these work in build systems.\nBut this is a choice not just of build tooling—it is far preferable to have your type\nchecker warnings align with your IDE warnings.\nWith the rises of AI-powered IDEs like Cursor and Windsurf that are VSCode extensions,\nit seems like type checking support as a VSCode-compatible extension is essential.\n\nHowever, Microsoft’s popular\n[Mypy VSCode extension](https://marketplace.visualstudio.com/items?itemName=ms-python.mypy-type-checker)\nis licensed only for use in VSCode (not other IDEs) and\n[sometimes](https://forum.cursor.com/t/pylance-server-fails-to-initialize-due-to-licensing-restriction/48548)\n[refuses](https://forum.cursor.com/t/does-pylance-just-not-work-with-cursor-how-to-get-imports-in-quick-fix-menu/5747)\nto work in Cursor. [Cursor’s docs](https://docs.cursor.com/guides/languages/python)\nsuggest Mypy but don’t suggest a VSCode extension.\n\nAfter some experimentation, I found\n[BasedPyright](https://github.com/detachhead/basedpyright) to be a credible improvement\non [Pyright](https://github.com/microsoft/pyright).\nBasedPyright is well maintained, is faster than Mypy, and has a good\n[VSCode extension](https://marketplace.visualstudio.com/items?itemName=detachhead.basedpyright)\nthat works with Cursor and other VSCode forks.\nSo I have now switched this template to use BasedPyright.\n(But please drop a note in the Discussion tab if you have better suggestions.)\n\n## What Does This Template Not Include?\n\nThe template doesn’t have lots of options or try to use every bell and whistle.\nIt just adds the above essentials.\n\nThis template **does not** handle:\n\n- Using Docker\n\n- Private or enterprise package repositories (but you can add this—see\n  [uv’s docs on alternative indexes](https://docs.astral.sh/uv/guides/integration/alternative-indexes/))\n\n- Building websites or docs, e.g. with [mkdocs](https://github.com/mkdocs/mkdocs)\n\n- Using [Conda](https://github.com/conda/conda) for dependencies (but note many deep\n  learning libraries like PyTorch now support pip so this isn’t as necessary as often as\n  it used to be)\n\n- Using a code repo or build system that isn’t GitHub and GitHub Actions\n\n- Boilerplate docs or project management of any kind, like issue templates, contributing\n  guidelines, code of conduct, etc.\n\nDocker and private repo use can be added by you manually to the project after you get\nstarted. Similarly, you can change CI/CD workflows if you are not using GitHub or GitHub\nActions or PyPI.\n\nAlso see [below](#alternatives) for other templates you can look at or use as\nreferences.\n\n## How to Use This Template\n\nBy default this template uses MIT license.\nIf you want a different license or are not publishing your project as open source,\nupdate `license` in pyproject.yaml and the LICENSE file.\nIf desired, you may delete the `.github/workflows/publish.yml` file if you are not\npublishing to PyPI.\n\nThe template can be used in three ways.\nOption 1 is the quickest option with full flexibility.\nOption 2 is the normal way to use a Copier template by hand.\nOption 3 is handy if you prefer a GitHub template.\n\n### Option 1: Run `uvx uvtemplate`\n\nI’ve now created a little tool, [uvtemplate](https://www.github.com/jlevy/uvtemplate)\nthat copies this template for you and walks you through everything:\n\n```shell\nuvx uvtemplate\n```\n\nIt’s the same as running `copier` and a few `git` commands yourself, with a little more\nguidance and less typing.\n\n### Option 2: Use `copier` and `git` Yourself\n\nThis template uses [Copier](https://github.com/copier-org/copier), which seems like the\nbest tool nowadays for project templates.\nUsing Copier is the recommended approach since it then lets you instantiate the template\nvariables and makes future updates possible.\nBut it requires a few more commands.\n\nTo create a new project repo with `copier`:\n\n```shell\n# Install Copier:\nuv tool install copier\n\n# Change dirs to the place you want the new GitHub repo to be.\ncd ~/projects/github   # Wherever you do your project work.\n\n# Clone this template. This does everything!\n# It will fetch from this GitHub repo and create a new directory\n# with whatever name you put below:\ncopier copy gh:jlevy/simple-modern-uv YOURNEWREPO\n# Then follow the instructions.\n```\n\nYou can enter names for the project, description, etc., or just press enter and later\nlook for `changeme` in the code.\n\nOnce you have the template set up, you will need to check the code into Git for uv to\nwork.\n[Create a new GitHub repo](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository)\nand add your initial code:\n\n```shell\ncd PROJECT\ngit init\n# Make license or other initial adjustments if needed.\ngit add .\ngit commit -m \"Initial commit from simple-modern-uv.\"\n# Create repo on GitHub.\ngit remote add origin git@github.com:OWNER/PROJECT.git  # or https://github.com/...\ngit branch -M main\ngit push -u origin main\n```\n\n### Option 3: Use the GitHub Template\n\nIf you prefer you can click the **use this template** on\n[**this repository**](https://github.com/jlevy/simple-modern-uv-template), which is the\ncurrent output of this template.\n\nGo there and hit the “Use this template” button.\nOnce you have the code, search for **`changeme`** for all field names like project name,\nauthor, etc. You want to do this to the `.copier-answers.yml` file as well.\nYou will also want to check the license/copyright.\n\n## Getting Started on Your Project\n\nEverything to get started is linked from the project **README.md**. It links to the\n**installation.md**, **development.md**, and **publishing.md**\n[starter docs](#starter-docs).\n\n## Updating Your Project Template\n\nIf you use Option 1 or Option 2 or if you pick Option 3 and correctly fill in your\n`.copier-answers.yml` file, you have the option to update your project with any future\nupdates to this template at any time.\n\nIf this file is updated with your project name etc., then you can\n[update your project](https://copier.readthedocs.io/en/latest/updating/) to reflect any\nchanges to this template by running `copier update`.\n\n## Alternatives\n\nThere are a couple other good uv templates, especially\n[**cookiecutter-uv**](https://github.com/fpgmaas/cookiecutter-uv) and\n[**copier-uv**](https://github.com/pawamoy/copier-uv) you may wish to consider.\n\nThis template takes a somewhat different philosophy.\nI found existing templates to have machinery or files you often don’t need.\nAnd it’s hard to maintain a complex template repo.\nThis is intended instead to be a very simple template.\nYou can always add to it if you want.\n\nThere is also [**uv-migrator**](https://github.com/stvnksslr/uv-migrator) to help you\nmigrate projects to uv.\n\nPreviously, [Poetry](https://python-poetry.org/docs/basic-usage/) was probably the best\nmodern tool for managing dependencies.\nIt is not as new as uv and arguably more mature (it just hit version 2.0). In fact, this\ntemplate is based on my earlier Poetry template,\n[simple-modern-poetry](https://github.com/jlevy/simple-modern-poetry).\n\nAnother great resource to check is\n[**python-blueprint**](https://github.com/johnthagen/python-blueprint), which is a more\nestablished template with an excellent overview of other standard Python project best\npractices. It uses [Poetry](https://python-poetry.org/docs/basic-usage/),\n[nox](https://github.com/wntrblm/nox),\n[Material for Mkdocs](https://github.com/squidfunk/mkdocs-material), and Docker.\n\nFor [Conda](https://github.com/conda/conda) dependencies, also consider the newer\n[**pixi**](https://github.com/prefix-dev/pixi/) package manager.\n\n## Maintaining This Template\n\nIf you’re contributing to this template or forking it for your own use, here’s the\nworkflow for keeping dependencies up to date:\n\n### Testing and Updating Dependencies\n\n1. **Instantiate the template to a test directory:**\n\n   ```shell\n   mkdir -p /tmp/template-test\n   cd /tmp/template-test\n   copier copy --defaults /path/to/simple-modern-uv test-project\n   cd test-project\n   git init \u0026\u0026 git add . \u0026\u0026 git commit -m \"Initial commit\"\n   ```\n\n2. **Install and test:**\n\n   ```shell\n   uv sync --all-extras\n   uv run pytest\n   uv run python devtools/lint.py\n   ```\n\n3. **Check for newer versions:**\n\n   ```shell\n   # See what versions were actually installed\n   cat uv.lock | grep -E \"^name = |^version = \"\n   ```\n\n4. **Compare to template minimums and backfill updates:**\n\n   Compare the installed versions in `uv.lock` against the minimum versions specified in\n   `template/pyproject.toml.jinja`. Update the template’s minimum versions to match the\n   latest stable releases that pass all tests.\n\n5. **Check for uv updates:**\n\n   ```shell\n   # Check your local version\n   uv --version\n   \n   # Check latest release\n   curl -s https://api.github.com/repos/astral-sh/uv/releases/latest | grep tag_name\n   ```\n\n   Update the uv version in `template/.github/workflows/ci.yml` and\n   `template/.github/workflows/publish.yml` if needed.\n\n### Current Versions to Track\n\n- **Python dev dependencies** in `template/pyproject.toml.jinja`:\n\n  - pytest, pytest-sugar, ruff, codespell, rich, basedpyright, funlog\n\n- **uv version** in GitHub Actions workflows\n\n- **Python version support** (currently 3.11–3.14)\n\n## Contributing\n\nI’m new to uv, so please help me improve this!\nPlease use the Discussions thread with any feedback or suggestions.\nPRs welcome on [this repository](https://github.com/jlevy/simple-modern-uv) (not on the\nGitHub template repo, which mirrors this one).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlevy%2Fsimple-modern-uv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjlevy%2Fsimple-modern-uv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlevy%2Fsimple-modern-uv/lists"}