This example demonstrates using Porringer to bootstrap a complete Python development environment from scratch — the same chain a developer would follow manually.
The manifest executes in phased order:
runtimes.python→ installs Python 3.14 viapim(Windows) orpyenv(macOS / Linux). The resolved interpreter path is propagated to all downstream phases.packages.python→ installspipxinto the current Python environment viapiporuv.tools.python→ installspdmas an isolated CLI tool viapipx. The pipx backend is deferred at preview time — it becomes available only after Phase 2 installs it.post_sync→ runspdm installin the manifest directory, creating the project virtualenv and installing all dependencies frompyproject.toml.
runtimes.python ─► pim / pyenv ─► Python 3.14
packages.python ─► pip / uv ─► pipx
tools.python ─► pipx ─► pdm (deferred resolution)
post_sync ─► pdm install (project sync)
porringer sync --path examples/python-bootstrap --dry-runporringer sync --path examples/python-bootstrapporringer sync --path examples/python-bootstrap --yesPorringer's execution engine splits PACKAGE-type actions into sub-phases:
- Phase 1 (Runtime): Runtime providers (pim / pyenv) run first. The
resolved interpreter is forwarded to all
RuntimeConsumerplugins so that subsequent pip / uv commands target the correct Python. - Phase 2a (Package): Regular package installs (pip / uv). This is where pipx gets installed.
- Phase 2b (Tool): After Phase 2a the engine re-discovers
available plugins. Pipx is now on PATH, so the
tools.pythonsection resolves to the pipx backend and pdm is installed. - Phase 3 (Project Sync): Project-environment plugins (pdm, uv, poetry) run their native sync / install command.
- Phase 4 (Post-sync): Arbitrary shell commands execute in the manifest directory.
If a tool backend is not available at preview time (e.g. pipx is not yet installed), the action is created with a deferred installer. Resolution happens just before Phase 2b, after packages have been installed.