Skip to content

Lockfiles ​

An update that leaves a stale lockfile behind is not an update. When a changed manifest has a committed lockfile, the Count regenerates it with the ecosystem's real tool, and the manifest and lockfile go into the same verified commit. If the tool fails, nothing is published.

Tools by lockfile ​

LockfileToolCommand
pnpm-lock.yamlaubeaube install --lockfile-only --ignore-scripts
package-lock.json, npm-shrinkwrap.jsonaube, or npmnpm install --package-lock-only --ignore-scripts
yarn.lockYarn Classic or Berryyarn install --ignore-scripts, or --mode=update-lockfile
bun.lockBunbun install --lockfile-only --ignore-scripts
Cargo.lockCargocargo update -p <crate>@<old> --precise <target>
go.sumGogo get <module>@<target>, then go mod download or go mod tidy
.terraform.lock.hclTerraformterraform providers lock
uv.lockuvuv lock --upgrade-package <package>
poetry.lockPoetrypoetry lock --no-plugins
packages.lock.jsondotnetdotnet restore --force-evaluate
Gemfile.lockBundlerbundle lock --update <gems>
composer.lockComposercomposer update <packages> --with-all-dependencies --minimal-changes --no-install --no-scripts --no-plugins
mise.lockmisemise lock with the lockfile's recorded platforms

Lifecycle scripts never run. A lockfile that does not change after an edit that changed recorded dependencies fails the branch, so a tool that says "up to date" without re-resolving cannot publish a stale lock. An edit that cannot affect the lock, such as a description, is not a failure. Where the Count can read the lock back (npm, Bun, Cargo, uv, Poetry, Bundler, Composer, Terraform providers), the requested version must be the one the new lock records.

Binary bun.lockb is not supported, and neither is regenerating Chart.lock or gradle.lockfile. Updates to those hold as lockfile-pending.

Why aube for npm and pnpm ​

The package manager sets a floor on how fast an update can be. Manifest edits and API commits take milliseconds; the lockfile tool takes seconds.

aube reads and writes pnpm and npm lockfiles in place. On a project with 265 locked packages, refreshing the lock after a manifest edit took 0.11 s with aube on the pnpm lock and 0.12 s on the npm lock, against 2.48 s with pnpm 10 and 1.46 s with npm 11, all with warm metadata caches. So the Count uses aube for both, and we think npm projects should move to pnpm or aube anyway.

The trade-offs are honest ones. aube's npm lockfiles stay valid for npm ci, but a later npm install may rewrite a few lines (hoisting and funding metadata). On larger pnpm graphs aube may keep a second copy of a package pnpm would deduplicate. lockfiles.npmEngine = "npm" restores native npm for package-lock.json. Native npm is also used automatically for format v1 locks, which aube cannot read. Trees with local file: dependencies stay with aube, which keeps them valid since 2.8.1 (aube#1796).

yarn.lock stays with Yarn, because aube's Yarn Berry output is rejected by Yarn (aube#1794, aube#1795). Yarn's version comes from packageManager in package.json, then a yarn pin in mise.toml, then the committed lock's format. bun.lock stays with Bun.

Which tool version ​

Tools run through mise exec with an explicit version. A repository's own pins win: mise.toml and .tool-versions entries for the relevant tool, .python-version, .ruby-version, global.json, packageManager, and the highest of the pin and go.mod's go/toolchain lines for Go. Repository tasks, environment blocks and hooks are never loaded. Otherwise the runner's pinned defaults apply:

ToolDefault
Node24.21.0
aube2.8.1
Yarn1.22.22 (Classic), 4.18.1 (Berry)
Bun1.4.3
Rust1.99.0
Go1.27.2
Terraform1.14.7
Python, uv, Poetry3.14.8, 0.13.1, 2.5.1
.NET SDK9.0.319
Ruby3.4.11
PHP, Composer8.5.8, 2.10.3

PHP ​

lockfiles.php = "static" (the default) downloads a prebuilt static-php CLI through mise's http backend: no compiler or system libraries, but it needs an exact x.y.z version. "compiled" uses mise's php tool, which builds PHP from source on first use and needs a C toolchain and PHP's build dependencies.

The tool store ​

Tools install into the Count's own mise data directory, separate from yours: PATCHULA_TOOLS_DIR, or <cache>.tools beside the SQLite cache. It persists between runs, so keep it on a volume. Each successful tool run records its tool@version and a timestamp.

  • patchula tools install prewarms every pinned default, for example in an image build.
  • patchula tools prune --days 30 uninstalls versions no run has used for 30 days. Pinned defaults stay.
  • A version the store has never run successfully is reinstalled from scratch on first use, with a 30-minute install allowance. An install cut short by a timeout or crash can leave a directory mise treats as installed but which has no binaries, and this is how the Count recovers from it.
  • Known versions keep a 180-second limit per command.

Isolation ​

Each tool runs in a scratch tree checked out from a persistent partial clone, containing only the files the tool reads. Every process starts from an allowlisted environment with its own HOME, npm config, Cargo home and Go paths. Parent tokens, cloud credentials, Git helpers and your tool configuration are not inherited. Git alone gets a temporary credential header for the installation token, kept out of URLs, arguments and stored config. Yarn runs on a copy of .yarnrc.yml without yarnPath, plugins or ${VAR} interpolations, since a committed Yarn release and plugins are repository code.

Output is kept only when something fails, at most 4 KiB of each stream. Private registries do not work yet, because credentials are scrubbed on purpose. Scoped registry credentials will be a separate, explicit opt-in.

Lockfile maintenance ​

pkl
lockfiles {
  refresh = true
  waitHours = 168
}

refresh = true keeps one patchula/lock-file-maintenance branch that refreshes every lockfile within the manifests' ranges, at most once per ISO week, and no sooner than waitHours after the last successful refresh. The default window is Monday 00:00 to 04:00 UTC; explicit update windows replace it. The CLI does not schedule itself, so run it during the window. Failures do not count as a completed refresh, and a closed maintenance PR can come back the following week.

tidyGo = true runs go mod tidy instead of go mod download after Go updates.

MIT licensed. Clean-room: no Renovate source was read in the making of this bat.