denver
Development Environments as code — reproducible, flexible, simple and fast.
Development Environment Launcher — declares dev environments in a
denver.yml: reproducible and layerable to fit your project's needs.
What problem does this solve?
Every project needs some setup before you can build it — and how much
varies enormously. A setup.sh is only a suggestion nobody re-runs after a
git pull; whatever happens to already be installed on your machine quietly
covers for the steps that were never written down. denver declares that
setup instead, in a denver.yml, and runs it the same way every time —
anywhere from a one-stage script replacement to a five-stage cross-compile
toolchain relocated into a container. You only pay for the stages your
project actually needs — nothing here is mandatory, and denver has no
opinion about which tools you use.
Read the full walkthrough →
— the problem built up one step at a time, from that first script to
import:-based inheritance across a whole fleet of projects.
Documentation
The built site (search, sidebar nav, one page per topic — and a plain-Markdown
mirror of every page under /markdown/ for AI tools/LLMs) is published from
doc/ by
.github/workflows/docs.yml.
Browsing on GitHub instead:
| Document | What's in it |
|---|---|
doc/README.md |
Documentation index — start here |
doc/introduction/index.md |
What problem denver solves, what an environment is, how flexible it is |
doc/introduction/install.md |
Installing denver, all the ways |
doc/quickstart/five-minutes.md |
End-to-end walkthrough of a complete bundled example |
doc/quickstart/creating-environments.md |
Step-by-step: build that same environment yourself, one stage at a time |
doc/quickstart/examples.md |
The eight bundled environments, smallest to largest |
doc/concepts/glossary.md |
Every term denver uses, defined once |
doc/concepts/philosophy.md |
The design principles behind it |
doc/cli/arguments.md |
Every denver --help flag, grouped by what you reach for it for |
doc/cli/environment-variables.md |
The variables denver reads and exports, and where env state lives |
doc/configuration/denver-yml.md |
The denver.yml schema and how the system works |
doc/providers/ |
One key reference per provider: uv, conan, docker, zephyr, custom |
doc/contributing/development.md |
Contributing: tests, coverage, adding a provider, releasing |
examples/ |
Eight working environments, smallest to largest, each with its own README |
Install
pip install denver-tool # or: uv tool install denver-tool
Also available: a standalone executable that needs no Python at all, an editable install for hacking on denver itself, and vendoring straight into your own monorepo via git-nested — see Install denver →.
Try it
denver examples/howto-env -- pytest examples/howto-env/tests
A minute or two later (much less on repeat runs) that command has built a
container, a Python venv, a hand-installed tool, a conan-installed toolchain
and a team convention — and run tests proving all five actually work — from
that one denver.yml, on your machine or your colleague's, identically. See
Denver in 5 minutes →
for the full walkthrough (pre-conditions, what each stage does, the flags
you'll actually use), or CLI arguments →
/ denver --help for every flag.
Known limitations
Every place denver runs needs import yaml to work. denver is a Python
program with exactly one runtime dependency, PyYAML, so installing it from
PyPI covers the host automatically. What it cannot cover is a wrapped
environment: a docker stage relocates the rest of the stack into the
container and re-invokes denver in there with the image's own bare python3
— an interpreter that knows nothing about the install on your host. That
image must supply PyYAML itself:
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-yaml \
&& rm -rf /var/lib/apt/lists/*
If it doesn't, denver stops with an error naming the interpreter that
failed to import yaml.
Which PyYAML that is, is deliberately not pinned. The host copy and the
image copy are resolved by two different package managers and will drift
apart in general. denver accepts that: it calls exactly two functions from
the library, yaml.safe_load and yaml.safe_dump, whose behaviour has been
stable across PyYAML releases for years. So any reasonably recent PyYAML is
fine, and denver imports whatever it finds instead of demanding a particular
version and forcing every image to track it. The declared dependency is a
floor (pyyaml>=6), not a pin — and it constrains only the host install
anyway, never the image's.
Contributing
Bug reports, feature requests and pull requests are welcome — see
doc/contributing/development.md for the workflow (uv run poe all
runs lint, format, mypy and the test suite; denver keeps 100% coverage).
License
Apache License 2.0 — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file denver_tool-1.4.1.tar.gz.
File metadata
- Download URL: denver_tool-1.4.1.tar.gz
- Upload date:
- Size: 485.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5f1e6bc2fa52d632d1b4b4ba9a6c7e5cde5eff2685ba3db99660e04cb89b709
|
|
| MD5 |
23478829ba0c3a64d86b96b0a536b62c
|
|
| BLAKE2b-256 |
94f81c7501d2f8dacdd54e643e23b370d850a6119d121394fa571935f9c9dc4d
|
Provenance
The following attestation bundles were made for denver_tool-1.4.1.tar.gz:
Publisher:
publish.yml on thorsten-klein/denver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
denver_tool-1.4.1.tar.gz -
Subject digest:
f5f1e6bc2fa52d632d1b4b4ba9a6c7e5cde5eff2685ba3db99660e04cb89b709 - Sigstore transparency entry: 2490225056
- Sigstore integration time:
-
Permalink:
thorsten-klein/denver@071efeff6d901935ee672ba97e9a10d648ea2cdc -
Branch / Tag:
refs/tags/1.4.1 - Owner: https://github.com/thorsten-klein
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@071efeff6d901935ee672ba97e9a10d648ea2cdc -
Trigger Event:
push
-
Statement type:
File details
Details for the file denver_tool-1.4.1-py3-none-any.whl.
File metadata
- Download URL: denver_tool-1.4.1-py3-none-any.whl
- Upload date:
- Size: 135.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
154587bacaedd559ea95f7e6645ecc126568e97292debe44e0f767037543f49f
|
|
| MD5 |
bb07b69ebdfe4bfb11f055fa1659849e
|
|
| BLAKE2b-256 |
dff6449fdd36735601f7acefae3f84241935786a5133ba07547b2c809af7c073
|
Provenance
The following attestation bundles were made for denver_tool-1.4.1-py3-none-any.whl:
Publisher:
publish.yml on thorsten-klein/denver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
denver_tool-1.4.1-py3-none-any.whl -
Subject digest:
154587bacaedd559ea95f7e6645ecc126568e97292debe44e0f767037543f49f - Sigstore transparency entry: 2490225203
- Sigstore integration time:
-
Permalink:
thorsten-klein/denver@071efeff6d901935ee672ba97e9a10d648ea2cdc -
Branch / Tag:
refs/tags/1.4.1 - Owner: https://github.com/thorsten-klein
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@071efeff6d901935ee672ba97e9a10d648ea2cdc -
Trigger Event:
push
-
Statement type: