Skip to main content

preen

PyPI version Downloads CI Documentation License: MIT

Preen is the conformance-and-adoption CLI for the py-canon fleet standard. py-canon defines the standard — a copier template, reusable GitHub workflows, and shared Sphinx configuration. Preen is how repos enter the fleet and stay in it: it scaffolds new packages, retrofits existing ones, pulls template updates, checks conformance, and cuts tag-driven releases.

preen itself requires Python >=3.12, stricter than the >=3.11 floor of the fleet standard it enforces on other repos — the tool can hold itself to a higher bar than the standard it applies.

Install

uv tool install preen   # or: pipx install preen

Use with Claude Code

/plugin marketplace add gojiplus/preen
/plugin install preen@gojiplus

The bundled skill teaches Claude Code to reach for the preen CLI — scaffolding, adoption, checks, and releases — instead of reimplementing its logic.

Commands

Command What it does
preen new NAME Scaffold a new package from the py-canon copier template
preen adopt [PATH] Retrofit an existing repo: mine answers from the repo, copy in the managed files, rewrite [tool.*] in pyproject.toml
preen update [PATH] Pull the latest template changes into an adopted repo (copier update)
preen check [PATH] Run conformance checks (detection only); --strict for CI
preen fix [CHECK] Apply fixes for issues the checks found
preen release [X.Y.Z] Guided release: run checks, confirm, git tag vX.Y.Z, push — the tag triggers the release workflow

Adopting an existing repo

cd my-package
preen adopt
# review the ADOPTION REPORT, then:
uv lock && uv sync --all-groups
preen check

preen adopt mines the copier answers from the repo itself (name, description, and authors from pyproject.toml; org from the git remote), renders the template into a temp directory, and copies in only the managed files: the CI/docs/release workflow shims, .pre-commit-config.yaml and dependabot config (if absent), docs/conf.py (old one backed up), .copier-answers.yml, py.typed, plus LICENSE and CITATION.cff if missing. It rewrites the [tool.ruff] (preserving any repo-specific lint ignores already present, and setting target-version from the repo's own requires-python floor, falling back to py311), [tool.pyright], and [tool.pydoclint] sections to the standard with tomlkit (comments elsewhere survive) and deletes legacy [tool.black], [tool.isort], [tool.flake8], and [tool.mypy] sections.

Pass --release-migration to also convert the build backend to the fleet's current uv_build series. The minimum is the latest tested release and the upper bound prevents an unreviewed backend-series upgrade. An existing project.version is preserved; a legacy dynamic-version project takes its current version from its latest v* tag.

Checks

preen check runs: template (copier adoption + drift against the latest py-canon tag), workflows (the four canon workflows are callers of the reusable workflows, not stale copies), ruff, tests, citation, changelog (Keep a Changelog structure), deps (deptry), deptree (circular imports), depgroups (PEP 735 dependency-groups usage), dropped-args (a parameter a caller accepts but never forwards), audit (pip-audit over the locked dependencies), ci-matrix (canon shim, or a matrix covering the requires-python floor), structure, runtime-assets (schema-bearing data formats, pinned Hugging Face revisions), files (README and .gitignore exist), precommit (.pre-commit-config.yaml exists and parses), version (hardcoded version strings), license (PEP 639 license metadata), links, metadata (build backend, requires-python upper bound, PEP 561 py.typed), pydoclint, pyright, and codespell.

Issues carry an impact level: critical blocks release, important can be overridden with informed consent, info is advisory. preen release walks that ladder interactively before tagging. Most checks are detection-only; preen fix license migrates the deprecated { text = ... } license table form to an SPDX string where the mapping is unambiguous, drops redundant License :: classifiers, and adds a missing license-files entry.

Releasing

The fleet standard keeps one explicit version in pyproject.toml, set with uv version X.Y.Z; the matching vX.Y.Z tag identifies the release. preen release runs the checks, then refuses to proceed unless the version is committed in pyproject.toml, is PEP 440-valid, the tag doesn't already exist, and CHANGELOG.md has an entry for it (offering to rename [Unreleased] to the new version and commit that rename if the Unreleased section has content). It then asks for confirmation, tags vX.Y.Z, and pushes the tag; the repo's release workflow does the rest (build, PEP 740 attestations, PyPI trusted publishing, GitHub Release). Use --dry-run to see the plan without acting.

Configuration

Preen reads an optional [tool.preen] section in pyproject.toml:

[tool.preen]
src_layout = true       # expect src/ layout (default: true)
tests_at_root = true    # expect tests/ at the repo root (default: true)
skip_checks = ["links"] # checks to skip by default

Notes

  • pydoclint covers docstring-signature consistency for now; ruff ships equivalent DOC rules ([tool.ruff.lint] external = ["DOC"] reserves the codes), but they're still preview-only, so pydoclint stays until ruff stabilizes them.
  • codespell stays: ruff has no spelling-check rules.

License

MIT

Release files for preen 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for preen 0.5.0
File Size Uploaded
preen-0.5.0.tar.gz 89.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for preen 0.5.0
File Interpreter ABI Platform
preen-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 203.1 kB

Release files / preen-0.5.0.tar.gz

Download URL preen-0.5.0.tar.gz
Size 89.6 kB
Tags Source
SHA-256 checksum
How to use checksums
266315f80bd1db6ffc7195694fc41fe9e7fb5f788076d1739762235f30f78c3a
BLAKE2b-256 checksum
How to use checksums
2e10f72d622975c2b521bb711b7536880bcd5005d7a22d46eee953701d63268c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.

Transparency log

Release files / preen-0.5.0-py3-none-any.whl

Download URL preen-0.5.0-py3-none-any.whl
Size 113.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dd0c5c2a396139b751f4231377eb10ab64b1232b431ba6deb1f66329a638c242
BLAKE2b-256 checksum
How to use checksums
8c641a519c8417ad54abfaacc961996ea619c44bf05fad6423b614c09b23c6d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

This release

0.5.0 This release

2 release files

0.4.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page