Changelog¶
Note
Until the Python API has stabilised, venvstacks is using
ZeroVer (starting from 0.1.0).
Refer to Version Numbering for additional details on the way releases are versioned.
Unreleased¶
See the fragment files in the changelog.d directory.
0.8.0 — 2025-11-20¶
Changed¶
As part of switching to cross-platform layer locks, the generated lock files are now checked to ensure relevant wheel entries are present for all target platforms nominally supported by the layer (resolved in #326).
0.8.0b2 — 2025-11-15¶
Added¶
Added linux_target to support per-layer configuration of Linux wheel selection based on the target libc variant and version (added in #338)
Running on CPython 3.14 is now tested in CI. Note that due to changes in the
zlibstandard library module implementation, Windows layer archives built using CPython 3.14 to run the build will typically be smaller than those produced by previous versions (added in PR #247).
Fixed¶
The Python implementation name is now set correctly when evaluating environment markers (resolved in #331).
Resolved a number of issues related to incorrect layer dependency filtering for different combinations of environment markers, layer target platforms, and package provenance details (initial problem reported in #333, additional issues found when updating the test suite to ensure the example stacks are producing the expected layer lock and package summary details).
0.8.0b1 — 2025-11-08¶
Added¶
A
venvstacks.uv.tomlfile located alongside the stack definition file is now incorporated into the configuration passed touvwhen locking environments (added in #144). This configuration may alternatively be supplied via the[tool.uv]table in the stack definition file.Each layer definition may now contain a priority_indexes section that is used to adjust the
uvindexconfiguration when locking that layer (added in #144).Each layer definition may now contain a package_indexes section that is used to adjust the
uvsourcesconfiguration when locking that layer, or any layer that depends on it (added in #270).Each layer definition may now contain a index_overrides section that allows apparent inconsistencies in layer package index configurations to be marked as expected and acceptable (added in #269).
Added macosx_target to support per-layer configuration of
MACOSX_DEPLOYMENT_TARGET(added in #292)Setting
MACOSX_DEPLOYMENT_TARGETin the calling environment now affects the way layers that do not specifymacosx_targetare built on macOS. If this environment variable is not specified at all, the default macOS version target is the default portable target set byuvrather than the version of the system runningvenvstacks(resolved in #292)The target GNU libc version for Linux layer builds is now the default portable target set by
uvrather than the libc version of the system runningvenvstacks(resolved in #292)If
UV_EXCLUDE_NEWERis set in the environment, orexclude-neweris set in theuvtool configuration, the given time is used as the recorded lock time for all updated layer locks (proposed in #10).Layer environments now provide a
targets_platform()query method that indicates whether that layer will be built and published for the current (or specified) platform (added in #265).
Changed¶
Layer dependency locking is now cross-platform, using the
pylock.tomlformat rather than a flat list of dependencies (proposed in #254). While not part of the published release, an example script is available in thevenvstackssource repository to remove or rename previously generated platform specific files (this is particularly necessary to preserve version numbering if using implicit layer versioning)Locking operations are no longer filtered by platform. This means the
BuildEnvironment.all_environmentsiterator now reports all defined layers with at least one target platform configured, not just those for the current platform. Iterate overBuildEnvironment.environments_to_buildwithout any layer filtering configured to obtain a list of layers specific to the current platform (resolved in #265).Layer target platforms are now inferred from the layers they depend on. An exception is raised if a layer specifies targets that are not also targets for the lower layers it depends on (changed in #244).
Hidden files and folders (those with names starting with
.) created at the top level of layer build environments are no longer included in the corresponding deployed environments (whether exported locally or published as a deployable layer archive).The handling of shadowed packages across framework layers has changed, so unconditionally shadowed packages are no longer treated as constraints by higher layers. Environment marker conditions are also listed for shared packages from lower layers in layer summaries (resolved in #292).
To improve type hints reported in IDEs and errors reported by static type checking, enums now use their singular form as their canonical name, with the plural form available as an alias (changed in PR #308).
All build environment manipulation is now handled with
uv(part of resolving #144). Previously, requirements compilation was handled withuv, while actually adding and removing packages was handled withpip. Due to related differences in package installation metadata (e.g.INSTALLERcontaininguvrather thanpip), layer archive hash values will change.
Fixed¶
Layer dependency declarations are now eagerly parsed and stored as structured requirements. Invalid requirements are now reported as specification errors rather than as cryptic locking command failures (resolved in #101).
Using
pbs-installer2025.8.27 or later ensures that the smaller CPython base runtime installations that omit debug symbols are consistently preferred (reported in #242). No explicit lower bound is set on the dependency declaration to allowvenvstacksto be updated without causing conflicts with existingpbs-installerpins to older versions.Omitting all arguments now reports a non-zero exit code (reported in #246).
0.7.0 — 2025-07-05¶
Added¶
showsubcommand to display layer definitions (added in #159).--showoption on subcommands (other thanshow) to display the selected layers and operations before executing the command (added in #159).--show-onlyoption on subcommands (other thanshow) to display the selected layers and operations without executing the command (added in #159).--jsonoption on subcommands to display the selected layers and operations as JSON rather than as a human-readable tree. For commands other thanshow, implies--show-onlyif--showis not passed explicitly (added in #159).
Changed¶
Recursive source tree processing now excludes files excluded from version control when building from a git repository, and excludes
__pycache__folders otherwise. This exclusion affects both module hash calculations and the inclusion of files in built environments (resolves #203).RECORDfiles for installed packages are now largely retained in published artifacts and locally exported environments, with only the entries corresponding to omitted files removed (resolved in #28). This allows packages that inspect the metadata for installed packages at runtime to work correctly when deployed withvenvstacks.Default CLI console output has been substantially reduced, with new
-q/--quietand-v/--verboseoptions added to adjust the message volume (changed in #5).Library level messages are now emitted via the
loggingmodule rather than being written directly tostdout. The CLI configures the logging subsystem appropriately based on the given verbosity options (changed in #5).
Fixed¶
When using the
--includefiltering option for layer builds, existing “build if needed” environments are now correctly updated if they have not previously been successfully built with the current layer specification and environment lock details (reported in #222).Implicit versioning of runtime layers no longer breaks deployed layered environments using that layer (reported in #188).
Implicit versioning of framework layers no longer breaks loading dynamic libraries from those layers on non-Windows systems (reported in #189)
Layer locks are now marked as valid if the lock is successfully regenerated without changes after being marked as invalid due to a lower layer having an invalid lock (resolved in PR #227)
0.6.0 — 2025-06-07¶
Added¶
A new optional field,
support_modules, has been added to application layer specifications. This field allows application layers to embed copies of common unpackaged support libraries without needing to duplicate that code in the source tree (proposed in #202).The
locksubcommand now accepts an--if-neededoption that skips locking layers that already have a valid layer lock (added in PR #200).
Changed¶
Added a
--lock-if-neededoption to thebuildsubcommand that ensures layers are only locked if they don’t already have valid transitive environment locks.--lockis now a deprecated alias for this option rather than being equivalent to running thelocksubcommand (proposed in #196).Changes to lock inputs that only affect the implicit layer versioning are now tracked separately from changes to the additional inputs that affect the result of the transitive dependency lock generation step. These changes are now ignored for layers that do not use implicit layer versioning (proposed in #201).
Prefer the creation of hardlinks over full copies when locally exporting environments. Depending on the filesystem, this can make local exports significantly faster when the installed packages contain large files (proposed in #205).
Fixed¶
Launch module existence checks are now skipped for layers that will not be built for the target build platform (reported in #204).
0.5.1 — 2025-05-26¶
Changed¶
Build failures for invalid layer locks now provide more details on the discrepancies that result in the lock being considered invalid (changed in PR #181).
Fixed¶
launch_moduleis now correctly set in the internalvenvstacks_layer.jsonconfiguration file shipped as part of application layers (resolved in PR #174).Layer locks are no longer incorrectly marked as invalid solely because the lock input cache files for the declared requirements are missing (reported in #175).
Layer lock metadata generated by versions prior to 0.5.0 is now accepted as valid as long as the locked requirements file hasn’t changed (resolved in PR #187).
Resetting runtime and framework layer locks no longer prevents locking layers that depend on the affected layers (resolved in PR #187).
Repeated local builds for environments using the dynamic library loading wrapper scripts no longer corrupt the base Python environment link (reported in #184).
0.5.0 — 2025-05-12¶
Changed¶
Layer locks are now invalidated for launch module changes. This also means that implicit versioning will update the layer version (resolves #89).
The exception raised when reporting dynamic library symlink conflicts in a layer now reports all ambiguous library targets in the layer instead of only reporting the first ambiguity encountered (resolved in PR #158).
Fixed¶
Previously defined layer locks are now correctly invalidated in the following cases (resolves #149):
the layer’s declared input requirements have changed
the major Python version of the layer’s base runtime has changed
the layer depends on a layer that does not currently have a valid layer lock
the relative paths from the layer to the layers it depends have changed (including additions and removals of layer dependencies)
implicit layer versioning is enabled or disabled for the layer
Attempting to lock a layered environment now fails if any layer it depends on does not have a currently valid layer lock (resolves #161).
CLI arguments on Windows are no longer unexpectedly resolved as filesystem glob patterns (resolved in PR #160).
Dynamic library symlinks are now correctly removed if the dynamic library is no longer included in the built layer (resolved in PR #163).
As it affects launch module execution, application layer launch module hashes now incorporate the file name in addition to the file contents (resolved in PR #164).
Application layer launch packages are now consistently archived using the layer’s lock timestamp, even when that is more recent than the file’s local modification time (resolved in PR #148).
0.4.1 — 2025-04-25¶
Added¶
Locking layers now emits package summary files for each layer, which should make it easier to see what has changed when locks are updated (suggested in #108).
Changed¶
The exception raised when reporting dynamic library symlink conflicts in a layer now suggests using the
dynlib_excludesetting to resolve the conflict (changed in PR #141).
Fixed¶
The
--reset-lockoption now propagates to derived layers as intended (reported in #137).
0.4.0 — 2025-04-11¶
Added¶
Framework layers may now specify
frameworksto depend on one or more framework layers instead of depending directly on a runtime layer. Framework dependencies must form a directed acyclic graph (DAG), and framework layers must be defined after any framework layers they depend on (proposed in #18, implemented in PR #119).Application layers may now specify
runtimeto depend directly on a a runtime layer with no intervening framework layers (added as part of resolving #18).All layers may now specify
dynlib_excludeto indicate dynamic libraries which should not be symbolically linked into theshare/venv/dynlib/environment subfolder on Linux and macOS (added as part of resolving #38).
Changed¶
To enable loading of shared objects from other environment layers, framework and application environments on Linux and macOS now run Python via a suitably capable shell environment (
bashon Linux,zshon macOS) that can be expected to be consistently installed (changed in #38).
Fixed¶
Extension modules on Linux and macOS that rely on shared objects published by their dependencies (for example, PyTorch depending on CUDA libraries) now work correctly even if those dependencies are installed in a lower environment layer. See How does dynamic linking work across layers? for additional details (resolved in #38).
0.3.0 — 2025-03-28¶
Added¶
The
buildandlocksubcommands accept a new--reset-lockCLI option. This multi-use option requests that any previously created layer lock file be removed before locking the selected layers (thus ignoring any previous version pins or artifact hashes). This option uses the same wildcard pattern matching as the--includeoption. Only layers that are locked by the given command will have their previous lock files removed, as excluded layers will be excluded from both locking and having their lock files reset (added in #22)."win_arm64"and"linux_aarch64"are now accepted as target platforms. ARM64/Aarch64 refer to the same CPU architecture, but Python reports it differently depending on the OS, and this is reflected in their respective platform tags (added in #107).
Changed¶
A Python API instability
FutureWarningis now emitted at runtime (added while resolving #22).The previous
BuildEnvironment.get_unmatched_patterns()method has been replaced by the newBuildEnvironment.filter_layers()method, which returns both the matching layer names and the unmatched patterns (changed in #22).BuildEnvironment.select_layers()now accepts an iterable of environment names rather than an iterable of filter patterns to be matched (changed in #22).
Fixed¶
0.2.1 — 2024-12-05¶
Fixed¶
Fix Typer 0.14.0+ incompatibility when setting app name (reported by Rugved Somwanshi in #96).
0.2.0 — 2024-11-14¶
Added¶
Setting
versioned = Truein a layer definition will now append a lock version number to the layer name that automatically increments each time the locked requirements change for that layer (layer@1,layer@2, etc). Refer to Layer names and versioning for details on when the versioned and unversioned layer names are used (implemented in #24).Added documentation for the Environment Stack File Formats (part of #78).
Added
python_implementationto the published layer metadata (part of #78).Added
bound_to_implementationto the published layer metadata (part of #78).
Changed¶
Enabled rendered previews for documentation PRs (requested in #43).
Enabled link validity checks when rendering documentation (requested in #62).
Renamed
EnvironmentExportRequesttoLayerExportRequest(part of #33).Exposed
LayerSpecBase,LayeredSpecBaseas public classes (part of #33).Exposed
LayerEnvBase,LayeredEnvBaseas public classes (part of #33).Added leading underscores to several private functions and methods (part of #33).
Added docstrings to all remaining public functions and methods (part of #33).
Updated docs to actively discourage using
@in layers names (part of #78).Renamed
fully_versioned_nameruntime layer specification field topython_implementation(part of #78).Renamed
runtime_nametoruntime_layerin the layer metadata (to align with therequired_layersfield), and simplified it to always refer to the runtime layer’s install target name (part of #78).
Fixed¶
Post-installation scripts for layered environments now work correctly even when run with a Python installation other than the expected base runtime (resolved in #66)
0.1.1 — 2024-11-01¶
Changed¶
Update docs URL to https://venvstacks.lmstudio.ai
Add OpenGraph metadata to docs landing page
Resolved several broken links in the documentation
Documentation is now marked as being unversioned (it is published directly from the main branch)
0.1.0 — 2024-10-31¶
Changed¶
Further documentation fixes and improvements
0.1.0rc1.post0 — 2024-10-30¶
Changed¶
Included project URLs in project metadata
Added installation instructions to README.md
Linked to main documentation from README.md
Improved the content split between the project overview page and the top level docs landing page
0.1.0rc1 — 2024-10-29¶
Added¶
Initial export of
venvstacksfrom Project Amphibian.Adopted
scrivforCHANGELOGmanagement.