homebrew-cooldown is a small standalone brew_outdated_cooldown.py script for people who
want to wait a few days before upgrading newly released Homebrew packages.
This can help reduce stability issues and supply chain attacks. Keep Homebrew's convenience without pulling in very fresh releases the moment they land.
The script shows the age of outdated formulae and casks, then proposes a brew upgrade ... command only for leaf
formulae and leaf casks whose own age and transitive Homebrew dependencies are old enough. Leaf formulae are installed
formulae that no other installed formula or cask depends on. Leaf casks are installed casks that no other installed cask
depends on. The default cooldown is 7 days. The script never executes upgrades for you.
For formulae, dependency checks include required dependencies of the current upgrade candidate, including packages that
Homebrew would newly install.
Prerequisites:
PATHgit in PATHRun:
brew update
./brew_outdated_cooldown.py
To use a different cooldown window:
./brew_outdated_cooldown.py --min-age-days=14
Homebrew makes it easy to upgrade everything right away. That is convenient, but it also means you can pull in dependency changes that are only hours old.
This script adds a cooldown filter similar in spirit to:
uv --exclude-newer-thanpip --uploaded-prior-toThe goal is simple: keep using brew outdated and brew upgrade, but make it easier to defer upgrades that still sit
too close to a new release or a newly changed dependency chain.
Ideally, brew would grow a feature like this. Until then, this script can serve as a proof of concept.
brew update
./brew_outdated_cooldown.py --min-age-days=7 # default is also 7 days
See example output.
That sample reflects the actual state observed on April 12, 2026. In that run, many installed packages were outdated,
but only b3sum and parallel qualified for the default 7-day cooldown across their transitive runtime dependency
chain.
For example, node itself was old enough, but its newest transitive runtime dependency was not, so the script did not
propose upgrading it:
node (25.8.2) < 25.9.0_1 (8 days ago, sqlite 0 days ago)
pkg (old) < new (12 days ago) means the local Homebrew definition for that upgrade target last changed 12 full days
ago.pkg ... (10 days ago, dep 1 day ago) means the package itself is older, but its newest transitive Homebrew
dependency is only 1 day old.unknown age means the tap git history could not be resolved for that entry. Unknown ages are excluded from the
proposed upgrade command.brew update explicitly when you want fresh tap metadata.brew outdated,
brew leaves, and brew info --json=v2.--min-age-days;--min-age-days.brew upgrade ... command.If a relevant age cannot be determined, that package is not proposed for upgrade.
brew upgrade ... command is advisory only. Review it, then run it yourself if it matches your risk
tolerance.8 commits
Hacker News (2)
Python
100.0%
homebrew-cooldown is a small standalone brew_outdated_cooldown.py script for people who
want to wait a few days before upgrading newly released Homebrew packages.
This can help reduce stability issues and supply chain attacks. Keep Homebrew's convenience without pulling in very fresh releases the moment they land.
The script shows the age of outdated formulae and casks, then proposes a brew upgrade ... command only for leaf
formulae and leaf casks whose own age and transitive Homebrew dependencies are old enough. Leaf formulae are installed
formulae that no other installed formula or cask depends on. Leaf casks are installed casks that no other installed cask
depends on. The default cooldown is 7 days. The script never executes upgrades for you.
For formulae, dependency checks include required dependencies of the current upgrade candidate, including packages that
Homebrew would newly install.
Prerequisites:
PATHgit in PATHRun:
brew update
./brew_outdated_cooldown.py
To use a different cooldown window:
./brew_outdated_cooldown.py --min-age-days=14
Homebrew makes it easy to upgrade everything right away. That is convenient, but it also means you can pull in dependency changes that are only hours old.
This script adds a cooldown filter similar in spirit to:
uv --exclude-newer-thanpip --uploaded-prior-toThe goal is simple: keep using brew outdated and brew upgrade, but make it easier to defer upgrades that still sit
too close to a new release or a newly changed dependency chain.
Ideally, brew would grow a feature like this. Until then, this script can serve as a proof of concept.
brew update
./brew_outdated_cooldown.py --min-age-days=7 # default is also 7 days
See example output.
That sample reflects the actual state observed on April 12, 2026. In that run, many installed packages were outdated,
but only b3sum and parallel qualified for the default 7-day cooldown across their transitive runtime dependency
chain.
For example, node itself was old enough, but its newest transitive runtime dependency was not, so the script did not
propose upgrading it:
node (25.8.2) < 25.9.0_1 (8 days ago, sqlite 0 days ago)
pkg (old) < new (12 days ago) means the local Homebrew definition for that upgrade target last changed 12 full days
ago.pkg ... (10 days ago, dep 1 day ago) means the package itself is older, but its newest transitive Homebrew
dependency is only 1 day old.unknown age means the tap git history could not be resolved for that entry. Unknown ages are excluded from the
proposed upgrade command.brew update explicitly when you want fresh tap metadata.brew outdated,
brew leaves, and brew info --json=v2.--min-age-days;--min-age-days.brew upgrade ... command.If a relevant age cannot be determined, that package is not proposed for upgrade.
brew upgrade ... command is advisory only. Review it, then run it yourself if it matches your risk
tolerance.Hacker News (2)
8 commits
Python
100.0%