simple-modern-uv Python Project Template

repository·main·Indexed 43 days ago

https://github.com/jlevy/simple-modern-uv

A minimal, modern Python project template supporting Python 3.11–3.14, built on the uv ecosystem. It integrates ruff for linting and formatting, BasedPyright for type checking, Pytest for testing, and GitHub Actions for CI/CD and PyPI publishing. The template includes supply chain hardening via a 14-day dependency cooldown policy and supports flexible adoption paths through Copier or coding agent skill bundles.

Tokens
17.7K
Snippets
40
Records
79
Agent score
55%

What's inside simple-modern-uv

  1. Overview of tools included in the simple-modern-uv template

    main

    The template provides a modern Python stack centered around uv. Key tools included are:

    • uv: Project setup, dependency management, and a simple Makefile for dev workflows.
    • ruff: Modern linting and fast, Black-compatible formatting.
    • GitHub Actions: CI and automated publishing workflows.
    • uv-dynamic-versioning: Simplifies releases by using GitHub tags/releases to manage package versions.
    • PyPI Publishing: Automated workflows for packaging and publishing using uv and GitHub Actions.
    • BasedPyright: Advanced type checking.
    • Pytest: Testing framework, often used with pytest-sugar for improved output.
    • codespell: Spell checking for project files.

    Generated projects also include AGENTS.md (following the agents.md standard) and CLAUDE.md to ensure they are immediately ready for use with AI coding agents.

  2. What this template does not include

    main

    This template is designed to be minimal and focuses on essentials. It does not include:

    • Docker configuration
    • Private or enterprise package repository setup (though you can add this via uv's alternative indexes)
    • Website or documentation building (e.g., mkdocs)
    • Conda dependency management
    • Non-GitHub/GitHub Actions CI/CD workflows
    • Project management boilerplate (issue templates, contributing guidelines, etc.)
  3. Understand the Release Sequence for the Template

    main

    The simple-modern-uv template uses a two-repo release process to ensure stability. The Template repo (jlevy/simple-modern-uv) is where dependency and tool updates originate. The Downstream project(s) (e.g., jlevy/simple-modern-uv-template) act as the final release gate by verifying updates via copier update across a full Python version matrix.

    A standard release follows these five stages:

    1. Finish the candidate PR: Resolve blockers, freeze dependency evidence, and ensure all template-repo CI jobs pass.
    2. Merge and identify the candidate: Merge into main and record the exact merge commit as TEMPLATE_COMMIT.
    3. Pass the downstream gate: Update the downstream project from TEMPLATE_COMMIT, verify locally, and merge the validation PR (ensuring the full Python matrix passes).
    4. Publish the template release: Create a GitHub Release targeting TEMPLATE_COMMIT. Use the GitHub action to create the version tag; do not push a bare tag manually.
    5. Record the public tag downstream: Update the downstream project from the new tag and merge the updated .copier-answers.yml.
  4. Reconcile customizations when running `copier update`

    main

    When updating an existing project with copier update, new template questions may be introduced. If you have manually edited files that correspond to these new questions, copier update --defaults might overwrite your changes with default values.

    To prevent this, pass explicit --data flags for any area where your project deviates from a fresh template render:

    • Custom License: Pass the matching package_license (or Proprietary for custom licenses).
    • Private Projects: Pass publish_to_pypi=false if you have removed publishing workflows or added the Private :: Do Not Upload classifier.
  5. Adopt simple-modern-uv features selectively or fully

    main

    The template supports three distinct adoption paths depending on your needs:

    1. Selective adoption: Adds specific named capabilities (like linting or CI) without changing your existing project structure or claiming Copier ownership.
    2. Core toolchain adoption: Adds uv, reproducible locking, linting, typing, tests, and CI while attempting to preserve your existing packaging or layout.
    3. Full template-managed adoption: Uses the complete rendered structure and .copier-answers.yml, enabling future copier update runs to pull in template improvements automatically.

    Before making changes, the agent will audit your repository and report what it intends to adopt unchanged, adapt to local constraints, preserve, or defer. Decisions regarding Python versions, package layout, build backends, versioning, licensing, and publishing remain explicit user decisions.

  6. Implement supply chain hardening

    main

    To protect against malicious dependency updates, this template follows these hardening practices:

    1. Dependency Cooldown: Do not install or upgrade to a release less than 14 days old. This template configures a relative cooldown in uv.toml, CI, and the Makefile using "14 days".
    2. Vet Dependencies: Only add dependencies you can verify upstream.
    3. Pin and Lock: Always commit your uv.lock file. Pin GitHub Actions to full commit SHAs rather than tags to ensure immutability.
  7. Use uv sync --locked for CI and deployment

    main

    In the v0.5.0 version and later, the recommended way to synchronize dependencies in CI and publishing workflows is using uv sync --locked instead of uv sync --frozen.

    • --locked: Installs from the committed uv.lock but fails if the project metadata (e.g., pyproject.toml) would make the lockfile stale. This provides a validation gate to ensure the lockfile is always up-to-date with the project definition.
    • --frozen: Installs from the lockfile but skips the validation check, allowing the sync to proceed even if the lockfile is technically stale relative to the metadata.
    uv sync --locked
  8. Understand the Agent Skill structure for simple-modern-uv

    main

    The project provides a portable "Agent Skill" located at skills/simple-modern-uv/. This skill is designed to be used by AI coding agents to automate project creation, modernization, and updates.

    Skill Components

    • SKILL.md: The main entry point and orientation map. It defines adoption levels (selective, core, full), routing for different workflows, and the shared contract for safety and verification.
    • references/: A directory containing detailed, one-level deep procedures for specific tasks:
      • start-new-project.md: For fresh project initialization.
      • adopt-selectively.md: For adding specific feature bundles to an existing project without full template management.
      • adopt-existing.md: For migrating an existing project to the template.
      • update-templated-project.md: For running copier update to pull in template changes.
      • customize.md: Guidance on customizing licenses, privacy settings, and app vs. library configurations.
      • faq.md: Troubleshooting guide for common migration issues (e.g., layout moves, Python version conflicts, type-checker errors).
  9. Recommended Python Type Checker for simple-modern-uv

    main

    The simple-modern-uv template uses BasedPyright as its default type checker. This choice is based on its high conformance to the official Python typing specification and its maturity.

    Alternatives

    • ty: A fast, promising alternative from Astral. It is currently in beta and may have lower coverage compared to BasedPyright. It is noted in the project README as a fast option for users who prioritize speed over maximum conformance.
    • Pyrefly: A high-conformance option from Meta, though its ecosystem maturity is a factor to consider.
  10. How to evolve Copier template questions

    main

    When adding or changing questions in copier.yml, follow this policy to ensure existing projects can update without manual intervention:

    1. Behavior-preserving defaults: New questions must have a default value that reproduces exactly what the template generated before the question existed. This ensures copier update --defaults remains a no-op for existing users.
    2. Valid answer files: Never require manual edits to .copier-answers.yml. Use --defaults --skip-answered to fill new keys.
    3. Reconciliation: Hand customizations should be handled by the agent skill (using --data) rather than relying on defaults.
    4. CI Validation: The update-path job must render the previous release and the new candidate to assert convergence.
    5. Release Notes: Explicitly name new keys and their defaults in the release notes.
  11. Maintain Supply Chain Hygiene

    main

    To harden the project against supply chain attacks, follow these practices:

    • Cooling-off Period: Prefer the latest version that is at least 14 days old and has had subsequent patch releases without being yanked. The project's pyproject.toml, CI, and Makefile enforce this 14-day window.
    • Verification: For every change, verify the canonical repository and maintainer, inspect release notes, record registry hashes/attestations, and confirm the release is not yanked.
    • Lockfile Inspection: Inspect the entire rendered lockfile diff. A clean direct-package query is insufficient; you must vet transitive package changes.
    • Dependency Selection: Only upgrade dependencies you can personally vet (active maintenance, reputable source, clear changelog). Avoid adding new dependencies if first-party code suffices.
  12. Debug stale lockfile resolution (14-day cooling-off window)

    main

    The project uses a 14-day supply-chain cooling-off window via uv.toml. This means releases newer than 14 days are deliberately ignored to ensure stability.

    If you need to debug resolution differences or bypass this, do not remove the setting from the file. Instead, use the project's standard commands (which use UV_CONFIG_FILE) or make an explicit, documented override for your specific invocation.