Skip to main content

coldframe

Project scaffolding and quality gates that run the same way on a laptop and on a build agent.

pip install "coldframe[gates]"

coldframe new my-service    # scaffold a project
cd my-service
pip install -e ".[dev]"
coldframe check             # run every gate
coldframe fix               # apply what can be applied automatically

The problem it solves

A quality pipeline usually starts like this:

- script: ruff format --check --output-format=json src || true

Two things are wrong with that line, and they compound.

ruff format does not accept --output-format; the flag belongs to ruff check. Ruff exits 2 with a usage error having read no files. Then || true converts that exit code into success. The step is green, the badge is green, and no file has been looked at. In the codebase this tool was extracted from, that line had been passing for the life of the pipeline while 107 of 273 files would have been reformatted.

The || true is not carelessness. It is there because the pipeline gates on a later step that publishes test results, so the check must not abort the job. The mistake is that the mechanism cannot tell "the tool found nothing wrong" from "the tool never ran".

coldframe keeps those two answers apart everywhere.

Three outcomes

Outcome Meaning Exit
PASSED The tool ran and found nothing 0
FAILED The tool ran and found problems 1
ERRORED The tool did not run, so nothing was judged 2
SKIPPED Not applicable yet, for example no tests exist 0

Exit 2 outranks exit 1. If a run reports both, the failures may be an artefact of the broken gate, so the exit code points at the cause rather than the symptom.

JUnit XML already draws the same distinction, and coldframe uses it: FAILED becomes <failure>, ERRORED becomes <error>. Both render red in Azure Pipelines and GitHub Actions, so a gate that could not run stays visible instead of disappearing.

Configuration

One file, the one that is already there.

[tool.coldframe]
gates = ["format", "lint", "typecheck", "test"]
coverage-min = 80

That is the whole of it. There is no BUILD file, no lockfile of its own, and no second description of the project to drift out of step with the first. Dependencies stay in [project] where pip and Poetry already look, and each tool keeps its own table untouched, so ruff check src typed by hand behaves exactly as it does under coldframe check.

Settings already stated elsewhere are read rather than asked for again:

Read from Used for
[tool.ruff] line-length, target-version reported by info, written into scaffolds
[tool.pyright] include, pythonVersion which paths to check
[tool.pytest.ini_options] testpaths where the tests are

Gates

Name Tool Passes when
format ruff format --check every file matches the formatter
lint ruff check no rule violations
typecheck pyright no static type errors
test pytest the suite passes and coverage clears the floor
audit pip-audit no known vulnerabilities

audit is off by default because it needs network access. A pipeline that fails when the package index is briefly unreachable teaches people to ignore it, so a connection failure is reported as ERRORED rather than as a vulnerability.

In CI

coldframe check --junit-dir .quality writes one junit-<gate>.xml per gate. Publish them and gate on the publish step:

- script: coldframe check --junit-dir .quality
  continueOnError: true

- task: PublishTestResults@2
  inputs:
    testResultsFiles: ".quality/junit-*.xml"
    failTaskOnFailedTests: true

continueOnError does what || true was doing, but the information is no longer thrown away. A gate that could not run arrives as <error> and fails the publish step exactly as a real failure does.

--format github emits ::error file=...,line=... annotations instead, so findings appear inline on a pull request.

coldframe new --ci azure or --ci github writes a working pipeline.

Commands

Command Does
coldframe check run the configured gates
coldframe check --gate lint run one gate
coldframe fix ruff format and ruff check --fix
coldframe new NAME scaffold a project
coldframe info show what would run and where the settings came from
coldframe gates list every available gate

Requirements

Python 3.10 or newer. coldframe has no runtime dependencies beyond tomli on 3.10, where tomllib is not yet in the standard library. A tool that needed its own dependency tree resolved before it could bootstrap a project would be arguing against its own premise.

The gates need the tools they drive. pip install "coldframe[gates]" brings in ruff, pyright and pytest, or a project can pin its own versions and coldframe will use those.

The name

A cold frame is a glazed box in a garden that shelters young plants until they are strong enough to go outside. coldframe does the same for a new project: it starts it with coldframe new and keeps it behind the same gates locally and in CI.

It was called pybootstrap during development; that name belongs to another project on PyPI. Projects from that time keep working unchanged. The pybootstrap command is still installed, a [tool.pybootstrap] table is read when there is no [tool.coldframe] table, and PYBOOTSTRAP_FORCE_COLOR is honoured alongside COLDFRAME_FORCE_COLOR.

License

Apache License 2.0. See LICENSE.

Metadata

Release files for coldframe 0.1.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 coldframe 0.1.0
File Size Uploaded Provenance Actions
coldframe-0.1.0.tar.gz 50.3 kB With provenance Details for coldframe-0.1.0.tar.gz

Built distribution (wheel)

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

Total release size: 95.2 kB

Release files / coldframe-0.1.0.tar.gz

Download URL coldframe-0.1.0.tar.gz
Size 50.3 kB
Tags Source
SHA-256 checksum
How to use checksums
16293d159c2ce3393f662b059153dcb7b10e2d556d9e70e5cc4895b680a3ab51
BLAKE2b-256 checksum
How to use checksums
989f43608c2bc6cb266dd5a714fb60fa9824fc6be8b830d50285e332dd35ef36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 3, 2026.

Transparency log

Release files / coldframe-0.1.0-py3-none-any.whl

Download URL coldframe-0.1.0-py3-none-any.whl
Size 44.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5321b566034653c4e58762d48b03be53aafdd838f46ba3ee02c2734a5b4a9e7
BLAKE2b-256 checksum
How to use checksums
9eac0ff064d41c7be0f83068a3d45d5023eae2e9fe866190fa30eb0efdd6f470
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 3, 2026.

Transparency log

Security for coldframe 0.1.0

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.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for coldframe-0.1.0.tar.gz

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 Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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