Releases: mpostument/bootstrap
Release list
bootstrap v2026.09.28-3
Windows 1.48.0
Added
- ILSpy is back in the dev group, dropped in 1.47.0: decompiles any .NET
assembly to C# - a NuGet package with no source, a Unity plugin, a build's
Assembly-CSharp.dll. From winget,icsharpcode.ILSpy. On a machine with a
saved -Select pick it is new to the manifest, so the next manual run asks
whether to install it; the scheduled run leaves it out until then.
Linux 1.41.0
Added
--select: choose which packages this machine has, the same design as
macOS 1.43.0 and Windows 1.47.0: a menu of every apt package, flatpak and uv
tool by group, plus a releases section for the release binaries, which
belong to no group. Unticked and installed is uninstalled after one
confirmation - apt-get remove through sudo, flatpak uninstall, uv tool
uninstall, or the binary deleted from ~/.local/bin.- apt removals are simulated first. apt-get remove takes everything that
depends on a package with it - python3 would take half the system - so a
removal that would take anything but the package itself is not run, and the
result names what would have gone. - The pick lives in /var/lib/bootstrap-linux/selection, not under $HOME:
the systemd timer runs as root and has to read the pick a person made. An
interactive run writes it through sudo, which it already has for apt.
REQUIRED in packages.conf - zsh, git and uv - is always installed and locked
in the menu. New packages are asked about once on a manual run; the timer
installs none of them and reports each as deselected, and a section with
nothing ticked counts as switched off. - The run history records a removal as -pkg, and the summary counts
removed, would-remove and deselected.
macOS 1.44.0
Added
- ILSpy is back in the dev group, dropped in 1.43.0: decompiles any .NET
assembly to C# - a NuGet package with no source, a Unity plugin, a build's
Assembly-CSharp.dll. From the Homebrew cask. Linux still has none - its
build is an amd64-only .deb. On a machine with a saved --select pick it is
new to the manifest, so the next manual run asks whether to install it; the
scheduled run leaves it out until then.
Fixed
- The summary counts what --select did. 1.43.0 added the removed,
would-remove and deselected results but left them out of the summary's list,
so a run that uninstalled something reported nothing of it at the end.
bootstrap v2026.09.28-2
Windows 1.47.0
Added
- A release archive is a whole install now. It used to hold the platform
directory alone, without the configs the script deploys from the repo root -
starship.toml, the tool themes, mise/, tools/cli-parity.conf - so an install
from it could not finish its shell and theme phases. Each archive now
unpacks to one bootstrap/ directory laid out as the repo: the platform's own
directory and every top-level entry but the other two platforms. It also
carries a RELEASE file naming the tag and the repo. - An archive install updates itself like a checkout: when a newer release
is out, a run you are sitting at offers it, downloads that release's zip,
checks it against the published .sha256, unpacks it into a temp directory
and copies it over the install - the same directory, so the daily task still
finds the script. A download that fails or does not match leaves the install
as it was. An archive from before this release has no RELEASE file; unpack
this one once by hand and it updates from then on. - Update from a run: when preflight finds a newer release, a run you are
sitting at asksUpdate to vX and rerun? [y/N]. Yes fetches, moves the
checkout to the tag - a branch fast-forwards, a detached checkout of a tag
moves to the new one - and reruns the new script with the same arguments and
-SkipUpdateCheck. Local changes, or a branch with commits the release
lacks, and it refuses and says why rather than guessing. The daily task,
-WhatIfand-Doctoronly print the line, as before. -Select: choose which packages this machine has. A menu of every
winget package and uv tool in the manifest, drawn by the script itself: a
section per group with its packages beneath, each with a[x]or[ ]box,
the installed version and the current pick pre-ticked. Space on a package
ticks it; on a section it ticks all of it - or clears it, when all of it was
ticked - and the section shows[x],[-]or[ ]for all, some or none.
Not fzf: fzf marks only ticked lines, with no empty box for the rest, and a
whole-section toggle from inside it takes a shell command per keypress. It
needs no fzf, so it works on a first run too. Ticked is installed; unticked
and installed is uninstalled, after one confirmation listing all of it.
Declining abandons the whole pick rather than saving it without the
removals, which would leave those packages installed but unwanted, and
never offered for removal again.- The pick is saved to
%LOCALAPPDATA%\windows-bootstrap\selection.json,
besidelast-run, and every later run follows it, the daily task included.
It keeps two lists:Selected, what was ticked, andKnown, everything the
menu offered - so an unticked package can be told from one the manifest
gained since. With no file every package is wanted, exactly as before. Requiredinpackages.psd1: ids that are always installed and show
locked in the menu - pwsh, git, uv and mise, which other phases stand on.
Optional, so an older manifest still loads; an id no group lists fails the
run up front.- New packages are asked about, not assumed. A manual run asks once per
package the manifest gained since the last pick and remembers the answer
either way. An unattended run installs none of them and reports each as
deselected, so nothing arrives on the machine that nobody chose. A
section with nothing ticked counts as switched off: its newcomers are left
out without asking. - User-scope packages uninstall from an elevated run. winget refuses
(0x8A15007D) to remove a package installed per user - most portable CLIs -
from an administrator process. That one call is rerun un-elevated as the
same user, through a throwaway scheduled task withRunLevel Limitedthat is
removed when it finishes. - What the menu offers to remove follows the machine: anything unticked
and still installed that a menu has offered before. A removal that failed
is offered again on the next-Selectinstead of being stranded as
unticked-but-installed. - Result actions
removed,would-removeanddeselected, and the run
history now records a removal as-id.
Removed
- ILSpy, added in 1.46.0: dropped before anyone depended on it. Taking it
out of the manifest stops installs and upgrades; a copy already installed
stays untilwinget uninstall icsharpcode.ILSpy. - Sysinternals Suite, added in 1.46.0: winget's manifest pins the hash of
SysinternalsSuite.zip, which Microsoft replaces in place at the same URL
without a new version, so the install fails the hash check - and an
elevated winget rightly refuses to skip it - every time the zip moves until
the manifest catches up.
Linux 1.40.0
Added
- A release archive is a whole install now. It used to hold the platform
directory alone, without the configs the script deploys from the repo root -
starship.toml, the tool themes, mise/, tools/cli-parity.conf - so an install
from it could not finish its shell and theme phases. Each archive now
unpacks to one bootstrap/ directory laid out as the repo: the platform's own
directory and every top-level entry but the other two platforms. It also
carries a RELEASE file naming the tag and the repo. - An archive install updates itself like a checkout: when a newer release
is out, a run you are sitting at offers it, downloads that release's
tarball, checks it against the published .sha256, unpacks it into a temp
directory and copies it over the install - the same directory, so the
systemd timer still finds the script. A download that fails or does not
match leaves the install as it was. An archive from before this release has
no RELEASE file; unpack this one once by hand and it updates from then on. - Update from a run: when preflight finds a newer release, a run you are
sitting at asksUpdate to vX and rerun? [y/N]. Yes fetches, moves the
checkout to the tag - a branch fast-forwards, a detached checkout of a tag
moves to the new one - and reruns the new script with the same arguments and
--skip-update-check. Local changes, or a branch with commits the release
lacks, and it refuses and says why rather than guessing. The systemd timer,
--dry-run,--doctorand a run as root only print the line: git writing
into your checkout as root would leave files you could not change. The rerun
is anexec: bash reads a script as it runs, so the old process must not go
on over a file that just changed under it.
macOS 1.43.0
Added
- A release archive is a whole install now. It used to hold the platform
directory alone, without the configs the script deploys from the repo root -
starship.toml, the tool themes, mise/, tools/cli-parity.conf - so an install
from it could not finish its shell and theme phases. Each archive now
unpacks to one bootstrap/ directory laid out as the repo: the platform's own
directory and every top-level entry but the other two platforms. It also
carries a RELEASE file naming the tag and the repo. - An archive install updates itself like a checkout: when a newer release
is out, a run you are sitting at offers it, downloads that release's
tarball, checks it against the published .sha256, unpacks it into a temp
directory and copies it over the install - the same directory, so the
launchd agent still finds the script. A download that fails or does not
match leaves the install as it was. An archive from before this release has
no RELEASE file; unpack this one once by hand and it updates from then on. - Update from a run: when preflight finds a newer release, a run you are
sitting at asksUpdate to vX and rerun? [y/N]. Yes fetches, moves the
checkout to the tag - a branch fast-forwards, a detached checkout of a tag
moves to the new one - and reruns the new script with the same arguments and
--skip-update-check. Local changes, or a branch with commits the release
lacks, and it refuses and says why rather than guessing. The launchd agent,
--dry-runand--doctoronly print the line. The rerun is anexec: bash
reads a script as it runs, so the old process must not go on over a file
that just changed under it. --select: choose which packages this Mac has, the same design as
Windows 1.47.0. A menu of every formula and cask in the manifest, drawn by
the script: a section per group with its packages beneath, each with a
[x]or[ ]box and its installed version, the current pick pre-ticked.
Space on a section ticks all of it, or clears it when all of it was ticked,
and the section shows[x],[-]or[ ]. Keys are read from/dev/tty
a byte at a time; everything else - the rows, a toggle, a frame - is plain
functions over indexed arrays, since bash 3.2 has no associative ones.- Unticked and installed is uninstalled with
brew uninstall, after one
confirmation listing all of it; declining keeps everything and saves
nothing. What is offered follows the machine - unticked, installed, offered
before - so a formula brew refused to remove because another depends on it
is offered again next time. - The pick is saved to
~/.local/state/bootstrap-macos/selectionas plain
yes/nolines, and every later run follows it, the launchd agent
included. A line that is neither makes the file untrusted, and every package
is wanted - a garbled file never unticks everything. No file, no change. REQUIREDinpackages.conf- git, mise and uv - always installed and
locked in the menu. Optional, so an older manifest still loads; an id no
group lists fails the run up front.- New packages are asked about once on a manual run and the answer kept;
the agent installs none of them and reports each asdeselected. A section
with nothing ticked counts as switched off, and its newcomers are left out
without ...
bootstrap v2026.09.27-2
Windows 1.46.0
Added
- Sysinternals Suite in the apps group - Process Explorer for what holds a
file or DLL open, Autoruns for everything that starts with the system,
Procmon for every file and registry access a process makes. winget versions
it by date (2026-07-09) rather than semver; it upgrades like any other
package, since winget compares its own version strings. - UniGetUI, beside it - one window for what is outdated across winget,
pip, npm and dotnet tools. It can update packages on its own schedule too;
leave that off if the daily bootstrap task is meant to be the only updater. - HWiNFO - hardware and sensor inspection: temperatures, clocks, voltages
and WHEA memory errors, with a sensor log for a run under load. - CrystalDiskInfo - SMART health for SSDs and HDDs, wear and reallocated
sectors behind a Good / Caution / Bad verdict. - Bulk Crap Uninstaller - everything installed, including orphans with no
uninstaller and what a removal left behind, and removes them in bulk. - Portmaster - which app connects where: domains, countries and
connection counts per process, with a per-app block list. It installs a
network filter driver and answers DNS itself, so if WSL, Rancher Desktop or
a VPN loses name resolution after install, that is the first place to look. - ILSpy in the dev group, beside the .NET SDK - decompiles any .NET
assembly back to C#: a NuGet package with no source, a Unity plugin, a
build'sAssembly-CSharp.dll, without opening a solution in Rider first. - mitmproxy in the dev group - an HTTP(S) proxy that shows every request
and response an app makes: Bruno sends requests, mitmproxy watches what your
app, game or CLI sends.mitmproxy(TUI),mitmweb(browser UI) and
mitmdump. HTTPS needs its CA certificate trusted, which stays a manual
step - visit mitm.it through the proxy - since a bootstrap that silently
trusts an interception CA is the wrong default.mitmproxy.mitmproxy.
Not added
- popeye and k8sgpt, which Linux 1.39.0 and macOS 1.42.0 gained: neither
publishes a winget package.packages.psd1says so beside the cloud group.
Linux 1.39.0
Added
- popeye, in the cloud group next to k9s - same author, other half of the
job: k9s is for looking at a cluster, popeye scans one and grades it -
orphaned ConfigMaps and Secrets, pods without limits, services with no
endpoints. A release binary; it answers onlypopeye version,
whichbinary_versionalready tries last, so it needs noVERSION_ARGS. - k8sgpt, beside it - the other question: popeye grades what is sloppy,
k8sgpt lists what is broken right now (CrashLoopBackOff, Pending pods,
unbound PVCs, an Ingress pointing at nothing). The scan is local; only
--explainsends findings to an LLM backend, and--anonymizemasks
resource names before they leave the machine. A release binary,
with the sameversion-only answer as popeye. - Windows gets neither: no winget package exists for either tool.
- mitmproxy in the dev group - an HTTP(S) proxy that shows every request
and response an app makes: Bruno sends requests, mitmproxy watches what your
app, game or CLI sends.mitmproxy(TUI),mitmweb(browser UI) and
mitmdump. HTTPS needs its CA certificate trusted, which stays a manual
step - visit mitm.it through the proxy - since a bootstrap that silently
trusts an interception CA is the wrong default. Throughuv tool, in a
newGROUP_dev_UV: the archive's package trails upstream by majors.
Not added
- ILSpy, which macOS 1.42.0 and Windows 1.46.0 gained: upstream's Linux
build is an amd64-only .deb, and there is no general installer for a .deb
from a release yet - only ghostty's own block.
macOS 1.42.0
Added
- popeye, in the cloud group next to k9s - same author, other half of the
job: k9s is for looking at a cluster, popeye scans one and grades it -
orphaned ConfigMaps and Secrets, pods without limits, services with no
endpoints. From Homebrew core. - k8sgpt, beside it - the other question: popeye grades what is sloppy,
k8sgpt lists what is broken right now (CrashLoopBackOff, Pending pods,
unbound PVCs, an Ingress pointing at nothing). The scan is local; only
--explainsends findings to an LLM backend, and--anonymizemasks
resource names before they leave the machine. From Homebrew core. - Windows gets neither: no winget package exists for either tool.
- mitmproxy in the dev group - an HTTP(S) proxy that shows every request
and response an app makes: Bruno sends requests, mitmproxy watches what your
app, game or CLI sends.mitmproxy(TUI),mitmweb(browser UI) and
mitmdump. HTTPS needs its CA certificate trusted, which stays a manual
step - visit mitm.it through the proxy - since a bootstrap that silently
trusts an interception CA is the wrong default. From the Homebrew cask;
there is no formula. - ILSpy in the dev group - decompiles any .NET assembly back to C#: a
NuGet package with no source, a Unity plugin, a build's
Assembly-CSharp.dll. Cross-platform since 11.0; from the Homebrew cask.
bootstrap v2026.09.17-3
Windows 1.41.1
Fixed
-
-Doctorstopped at its first check.okandbroken, the two
verdicts the doctor exists to give, were never added to theValidateSet
onAdd-Result, so the probe shell's ownokthrew before a single tool
was looked at. Both are in the set now, green and red. -
starship promptreported "no prompt function" with the profile
loaded. A function'sDefinitionstarts with a newline, and the probe
answers onekey=valueper line - sofn:prompt=always arrived empty.
The definition is flattened onto one line before it is sent. -
The mise checks looked in the Linux data directory. Windows mise keeps
its shims under%LOCALAPPDATA%\mise\shims, which is what the mise phase
puts on the userPATH; the doctor looked in~\.local\share\mise\shims
and reported it missing on every machine. Andnode,goandjava
resolving tomise\installs\...ismise activateworking as intended -
it puts those ahead of the shims - so that isoknow, not a note. Only a
runtime from outside mise is flagged. -
Housekeeping threw on an empty download cache. On PowerShell 7,
Measure-Objectemits nothing at all for empty input, so
(... | Measure-Object -Sum).Sumis$null.Sum, which strict mode rejects.
That ran before the "nothing to prune" check, so a clean cache - the usual
case - was enough. Sizes are summed byFormat-Sizeinstead, which is
0.0 MBfor no files.
Linux 1.34.2
Fixed
-
Housekeeping still stopped mid-phase, past the journal fix in 1.34.1.
The actual point of failure was the very next line:flatpak uninstall --unused --dry-run.uninstallhas never had a--dry-run- that flag
exists only onflatpak prune, for an unrelated purpose (pruning the
OSTree object store, not listing installed-but-unused runtime refs) - so
the command errored withUnknown option --dry-runevery time, and the
samepipefail/set -e/2>/dev/nullcombination silenced it. There is
no safe read-only substitute:--noninteractiveimplies--assumeyeson
--unused, so scripting around the missing flag risked doing the removal
this phase promises never to do. The check is gone;flatpak uninstall --unusedby hand is still there to run and review before answering yes. -
--doctormisjudged three things that were actually fine.7zip's
expected command was hardcoded to7zz- that name is macOS's; apt's own
7zippackage puts7zon PATH here.~/.dotnet/toolswas checked
against PATH unconditionally, when the shell fragment itself only adds it
oncedotnet tool install -ghas created the directory - its absence is
the fragment working as intended, not broken. And carapace's completer
was checked for a function named_carapace; carapace 1.7 defines
_carapace_completerinstead, so a working completer was reported as
never initialised. -
@releasestools disappeared under WSL and other NAT'd or shared
addresses. Each one calls GitHub's API once, unauthenticated, to read
its latest tag - 60 requests/hour per source IP, easy to spend across the
20-plus tools this platform installs that way, and every one queued
behind the first failure came backfailedand was never installed, not
just delayed.GITHUB_TOKEN/GH_TOKEN(read the same asghitself
reads them) or agh auth loginraise that to 5000/hour; either is now
picked up automatically, computed once per run rather than per tool.
macOS 1.37.1
Fixed
-
github_latest_tagwas unauthenticated. GitHub's API allows 60
requests/hour per source IP without a token, shared with anything else on
the same address; every release-tracked tool this call is used for is
one more request against that budget.GITHUB_TOKEN/GH_TOKEN(read the
same asghitself reads them) or agh auth loginraise that to
5000/hour; either is now picked up automatically, computed once per run
rather than per tool. -
--doctor's carapace check looked for the wrong function. carapace
1.7 defines_carapace_completer, not_carapace- the fragment
registers it withcompdef _carapace_completer <every command it covers>. A working completer was reported as never initialised.
bootstrap v2026.09.17-2
Windows 1.41.1
Fixed
-
-Doctorstopped at its first check.okandbroken, the two
verdicts the doctor exists to give, were never added to theValidateSet
onAdd-Result, so the probe shell's ownokthrew before a single tool
was looked at. Both are in the set now, green and red. -
starship promptreported "no prompt function" with the profile
loaded. A function'sDefinitionstarts with a newline, and the probe
answers onekey=valueper line - sofn:prompt=always arrived empty.
The definition is flattened onto one line before it is sent. -
The mise checks looked in the Linux data directory. Windows mise keeps
its shims under%LOCALAPPDATA%\mise\shims, which is what the mise phase
puts on the userPATH; the doctor looked in~\.local\share\mise\shims
and reported it missing on every machine. Andnode,goandjava
resolving tomise\installs\...ismise activateworking as intended -
it puts those ahead of the shims - so that isoknow, not a note. Only a
runtime from outside mise is flagged. -
Housekeeping threw on an empty download cache. On PowerShell 7,
Measure-Objectemits nothing at all for empty input, so
(... | Measure-Object -Sum).Sumis$null.Sum, which strict mode rejects.
That ran before the "nothing to prune" check, so a clean cache - the usual
case - was enough. Sizes are summed byFormat-Sizeinstead, which is
0.0 MBfor no files.
Linux 1.34.1
Fixed
- Housekeeping stopped mid-phase, without a word, on WSL and anywhere else
the journal is not persistent. The disk-usage check piped
journalctl --disk-usagestraight intosed, andjournalctlexits
non-zero when there is no/var/log/journalto report on - which
pipefailturned into the whole pipeline failing, andset -ethen
ended the run right there.2>/dev/nullon the same line hid the only
clue. Guarded with|| true, the same fix already applied to the stale
.debcount just above it: no journal to report on is not a failure.
macOS 1.37.0
Removed
-
docker-desktop. Docker Desktop's own installer owns it on this machine -
every run found/Applications/Docker.appalready there and reported it as
installed by something else, which is a line about software this manifest
does not manage. Out of theappsgroup, and out of the README passages that
used it as the example of a cask. -
flameshot. Homebrew disabled the cask: it does not pass the macOS
Gatekeeper check, sobrew install --cask flameshotnow fails outright and
every run reported it as a failed step. Screenshots arecmd-shift-5in the
meantime. The winget package on Windows is unaffected and stays.
Added
-
--doctor: is it actually in effect? Every phase in this script asserts
that a package is installed. Nothing asserted that it works, and the
difference is where this changelog's bugs live:~/go/binmissing from
PATH,~/.dotnet/toolsmissing fromPATH, the mise shims missing from
PATH, a leftover aptfd-findshadowing the realfd,formatand
right_formatinstarship.tomlnever in effect, Tab never opening fzf.
Every one of those was found by somebody noticing, months later, because a
phase that installs a package has no idea whether the shell you type into can
see it.So
--doctorasks the only environment that can answer: a real login shell.
Onezsh -licprobe emits every fact at once - what eachclitool resolves
to, which widget Tab and the up arrow are bound to, whether starship, atuin,
carapace, zoxide and compinit initialised, whatnode,goandjava
resolve to, what is onPATH, whether the deployed config still matches the
repo, whether the launchd agent is loaded. About a second for all of it; a shell
per check would take a minute to say the same thing.Three verdicts, not two.
brokenis wrong,okis right, andpresentis a
judgement call left to the reader: a mise shim in front of a binary runs the
same program through one more exec, and a config file that differs from the
repo is only going to be replaced by the next run. Making thosebroken
would have meant a doctor that cries wolf, which is a doctor nobody runs.It changes nothing and exits 1 if anything is broken, so it works as a check.
Running it on the machine it was written on found a stale mise shim foryq
sitting in front of Homebrew's, and a launchd agent that had never been
installed. -
--history: and what did it move?--statusanswers "did last night's
run work". This answers the other half. A snapshot ofbrew list --versions, formulae and casks both is taken
before the packages phase and another after the upgrades, and the difference -
node 24.20.0>24.21.0,+ripgrep 14.1.1- goes into the run record and into
one line per run inhistory, next to it.The snapshot is allowed to fail, in pieces. A package listing can exit
non-zero for reasons that have nothing to do with this run, and one that
fails prints nothing at all rather than a shorter list - so taking the
formulae and the casks together meant losing both. Worse, underset -ea
snapshot taken for the history could end the run before it installed
anything, which is exactly what it did on the machine this was written on,
between the taps phase and the first package. Each listing now runs
separately and each may fail; what still answers is recorded, and the run
carries on either way.That is what actually moved, rather than what scrolled past in the output:
Homebrew keeps no log of what it upgraded. One line per run, oldest first, capped at 200 lines, which is
eight months of nightly runs.--history=nfor a narrower window; unattended
runs are marked, because those are the ones nobody watched.
bootstrap v2026.09.17
Windows 1.41.1
Fixed
-
-Doctorstopped at its first check.okandbroken, the two
verdicts the doctor exists to give, were never added to theValidateSet
onAdd-Result, so the probe shell's ownokthrew before a single tool
was looked at. Both are in the set now, green and red. -
starship promptreported "no prompt function" with the profile
loaded. A function'sDefinitionstarts with a newline, and the probe
answers onekey=valueper line - sofn:prompt=always arrived empty.
The definition is flattened onto one line before it is sent. -
The mise checks looked in the Linux data directory. Windows mise keeps
its shims under%LOCALAPPDATA%\mise\shims, which is what the mise phase
puts on the userPATH; the doctor looked in~\.local\share\mise\shims
and reported it missing on every machine. Andnode,goandjava
resolving tomise\installs\...ismise activateworking as intended -
it puts those ahead of the shims - so that isoknow, not a note. Only a
runtime from outside mise is flagged. -
Housekeeping threw on an empty download cache. On PowerShell 7,
Measure-Objectemits nothing at all for empty input, so
(... | Measure-Object -Sum).Sumis$null.Sum, which strict mode rejects.
That ran before the "nothing to prune" check, so a clean cache - the usual
case - was enough. Sizes are summed byFormat-Sizeinstead, which is
0.0 MBfor no files.
Linux 1.34.0
Added
-
--doctor: is it actually in effect? Every phase in this script asserts
that a package is installed. Nothing asserted that it works, and the
difference is where this changelog's bugs live:~/go/binmissing from
PATH,~/.dotnet/toolsmissing fromPATH, the mise shims missing from
PATH, a leftover aptfd-findshadowing the realfd,formatand
right_formatinstarship.tomlnever in effect, Tab never opening fzf.
Every one of those was found by somebody noticing, months later, because a
phase that installs a package has no idea whether the shell you type into can
see it.So
--doctorasks the only environment that can answer: a real login shell.
Onezsh -licprobe emits every fact at once - what eachclitool resolves
to, which widget Tab and the up arrow are bound to, whether starship, atuin,
carapace, zoxide and compinit initialised, whatnode,goandjava
resolve to, what is onPATH, whether the deployed config still matches the
repo, whether the systemd timer is loaded. About a second for all of it; a shell
per check would take a minute to say the same thing.Three verdicts, not two.
brokenis wrong,okis right, andpresentis a
judgement call left to the reader: a mise shim in front of a binary runs the
same program through one more exec, and a config file that differs from the
repo is only going to be replaced by the next run. Making thosebroken
would have meant a doctor that cries wolf, which is a doctor nobody runs.It changes nothing and exits 1 if anything is broken, so it works as a check.
Running it on the machine it was written on found a stale mise shim foryq
sitting in front of Homebrew's, and a launchd agent that had never been
installed. -
--history: and what did it move?--statusanswers "did last night's
run work". This answers the other half. A snapshot of every dpkg package and every flatpak is taken
before the packages phase and another after the upgrades, and the difference -
node 24.20.0>24.21.0,+ripgrep 14.1.1- goes into the run record and into
one line per run inhistory, next to it.The snapshot is allowed to fail, in pieces.
flatpakis not on every
machine, and a command that is missing entirely exits 127 - which, under
set -eand a pipeline, would end a run over a snapshot taken for the
history. Each listing now runs separately and each may fail; what still
answers is recorded, and the run carries on either way.That is what actually moved, rather than what scrolled past in the output:
and it is every dpkg package, not only the ones this manifest names, becauseapt-get upgrademoves plenty this script never mentions. A dist-upgrade that moves a hundred packages is summarised rather than printed in full. One line per run, oldest first, capped at 200 lines, which is
eight months of nightly runs.--history=nfor a narrower window; unattended
runs are marked, because those are the ones nobody watched.
macOS 1.37.0
Removed
-
docker-desktop. Docker Desktop's own installer owns it on this machine -
every run found/Applications/Docker.appalready there and reported it as
installed by something else, which is a line about software this manifest
does not manage. Out of theappsgroup, and out of the README passages that
used it as the example of a cask. -
flameshot. Homebrew disabled the cask: it does not pass the macOS
Gatekeeper check, sobrew install --cask flameshotnow fails outright and
every run reported it as a failed step. Screenshots arecmd-shift-5in the
meantime. The winget package on Windows is unaffected and stays.
Added
-
--doctor: is it actually in effect? Every phase in this script asserts
that a package is installed. Nothing asserted that it works, and the
difference is where this changelog's bugs live:~/go/binmissing from
PATH,~/.dotnet/toolsmissing fromPATH, the mise shims missing from
PATH, a leftover aptfd-findshadowing the realfd,formatand
right_formatinstarship.tomlnever in effect, Tab never opening fzf.
Every one of those was found by somebody noticing, months later, because a
phase that installs a package has no idea whether the shell you type into can
see it.So
--doctorasks the only environment that can answer: a real login shell.
Onezsh -licprobe emits every fact at once - what eachclitool resolves
to, which widget Tab and the up arrow are bound to, whether starship, atuin,
carapace, zoxide and compinit initialised, whatnode,goandjava
resolve to, what is onPATH, whether the deployed config still matches the
repo, whether the launchd agent is loaded. About a second for all of it; a shell
per check would take a minute to say the same thing.Three verdicts, not two.
brokenis wrong,okis right, andpresentis a
judgement call left to the reader: a mise shim in front of a binary runs the
same program through one more exec, and a config file that differs from the
repo is only going to be replaced by the next run. Making thosebroken
would have meant a doctor that cries wolf, which is a doctor nobody runs.It changes nothing and exits 1 if anything is broken, so it works as a check.
Running it on the machine it was written on found a stale mise shim foryq
sitting in front of Homebrew's, and a launchd agent that had never been
installed. -
--history: and what did it move?--statusanswers "did last night's
run work". This answers the other half. A snapshot ofbrew list --versions, formulae and casks both is taken
before the packages phase and another after the upgrades, and the difference -
node 24.20.0>24.21.0,+ripgrep 14.1.1- goes into the run record and into
one line per run inhistory, next to it.The snapshot is allowed to fail, in pieces. A package listing can exit
non-zero for reasons that have nothing to do with this run, and one that
fails prints nothing at all rather than a shorter list - so taking the
formulae and the casks together meant losing both. Worse, underset -ea
snapshot taken for the history could end the run before it installed
anything, which is exactly what it did on the machine this was written on,
between the taps phase and the first package. Each listing now runs
separately and each may fail; what still answers is recorded, and the run
carries on either way.That is what actually moved, rather than what scrolled past in the output:
Homebrew keeps no log of what it upgraded. One line per run, oldest first, capped at 200 lines, which is
eight months of nightly runs.--history=nfor a narrower window; unattended
runs are marked, because those are the ones nobody watched.
bootstrap v2026.09.16
Windows 1.39.0
Added
-
TerminalSetPwshDefaultin theShellmanifest (default$true).
merge-terminal-settings.ps1now writes Windows Terminal's
defaultProfileto the PowerShell 7 profile guid it already creates, so
a new terminal tab opens PowerShell 7 instead of whatever Windows
Terminal picked on its own. -
F2 flips PSReadLine predictions to
ListViewfor the current line -
see Changed below for whyInlineViewis now the default.F2runs
SwitchPredictionView, so the full dropdown of matches is still one key
away without it appearing unprompted.
Changed
-
PSReadLine
PredictionViewStyle:ListView→InlineView.ListView
rendered a dropdown of every history/plugin match for whatever was in the
buffer, typed or pasted - pasting a multi-line command flooded the
terminal with a page of unrelated history entries.InlineViewshows one
greyed suggestion on the current line instead, the same shape as zsh's
zsh-autosuggestionson the other two platforms. -
Prompt renders on one line.
starship.toml(shared by all three
platforms) had a hardcoded leading newline informat, on top of
add_newline = false, forcing a blank line above every prompt regardless
of that setting. Removed, so the prompt is one dense line like a typical
Mac/Linux shell.
Linux 1.32.0
Fixed
-
Temp files no longer survive an interrupted run. Every
mktempwent
through a bare command substitution and was cleaned up only on the happy
path, so a Ctrl-C between themktempand themvleft the half-written
file behind - two~/.zshrc.bootstrap.XXXXXXfiles from interrupted runs
were sitting in$HOMEon this machine when this was found. Every temp path
now goes throughmktemp_tracked, andtrapon EXIT, INT and TERM removes
whatever is still there; INT and TERM re-exit with 130 and 143 rather than
resuming where they were interrupted.mktemp_trackedassigns to a variable named by its first argument instead of
printing the path: a command substitution would run the array append in a
subshell, and the parent would forget the path - which is the whole point.
Added
-
~/go/binonPATH.go installand the VS Code Go extension put
gopls,dlvandstaticcheckthere, and nothing was adding it - the
tools installed fine and then were not onPATH. Unrelated to wherego
itself comes from; it was missing before this release too. -
~/.dotnet/toolsonPATH, next to the existingDOTNET_ROOTline.
dotnet tool install -ginstalls there. macOS gets this from the SDK
installer's/etc/paths.dentry and Windows from the installer's user PATH;
only Linux was missing it. -
node, go and java come from mise on all three platforms, declared once in
mise/tools.confat the repo root. They used to come from three different
places - brew on macOS, winget on Windows, and nothing at all on Linux,
wheregrep -cE "nodejs|golang-go|openjdk" packages.confreturned 0 and a
fresh machine simply had no Node until somebody ranmise use -gby hand.
mise was installed everywhere and managing nothing:mise ls -gwas empty.mise use -gmerges into the user's global config rather than replacing it,
so a tool added by hand survives a bootstrap run. Removing the packages from
the manifests does not uninstall them -brew uninstall node go,
brew uninstall --cask microsoft-openjdk@21and the winget equivalents are
yours to run when you want the disk back.Python is deliberately not in the list: OS packages link against the system
python3, and a mise shim in front of it breaks them. -
The mise shims directory on
PATHin the zsh fragment.mise activate
covers interactive shells,JAVA_HOMEincluded, but never sees a
non-interactivessh host command, a cron job, or a Makefile an IDE runs.
Activation still takes precedence where both apply. -
Seven git defaults, set the same way the delta and difftastic keys
already are - only where the key is unset, so an existing value stays:
push.autoSetupRemote(push a new branch without the--set-upstream
dance),fetch.prune(stop completing months of deletedorigin/*),
diff.algorithm=histogram(better on moved and reindented code, and it is
what delta and difftastic then render),rebase.autoStash,
column.ui=auto,merge.conflictStyle=zdiff3(the common ancestor in a
conflict, not just the two endings) andtag.sort=-version:refname
(v1.10.0abovev1.9.0).The tag field is
version:refname; a plain-versionis rejected at use
withfatal: unknown field name: version. -
lazygitinRELEASES. A git TUI: stage hunks, rebase, stash and
branch without leaving the terminal. A release binary, not an apt package -
Debian's trails upstream. Its assets arelinux_x86_64/linux_arm64, so the
entry uses{GORELEASER_ARCH}rather than the{ARCH}that expands to
amd64. -
Catppuccin Mocha for bat, delta and fzf. The palette was already deployed
for starship, ghostty and atuin, and stopped at the three tools you read
output in:batrendered in its own default theme,deltain bat's, and
fzfin its own colours.bat/configandbat/themes/Catppuccin Mocha.tmThemeat the repo root,
deployed to bat's config directory by a new bat config phase - the
same shared-file shapestarship.tomlandatuin/already use. bat since
0.24 reads the themes directory at startup, so thebat cache --build
fallback is a no-op on anything current.delta.syntax-theme=Catppuccin Mochain the git config phase, set only
when bat is installed: delta highlights through bat's theme store, so a
diff and abatof the same file now match.FZF_DEFAULT_OPTSwith the Catppuccin colours. fzf-tab shells out to fzf
and inherits them.
-
MANPAGERthrough bat, so man pages get the same theme.col -bx
strips the overstrike backspaces groff emits for bold and underline, which
bat would otherwise render literally. Set forbatcatas well as
bat, the same way thecatalias above it already is - Debian's apt
package installs the binary under that name.
macOS 1.34.0
Fixed
-
Temp files no longer survive an interrupted run. Every
mktempwent
through a bare command substitution and was cleaned up only on the happy
path, so a Ctrl-C between themktempand themvleft the half-written
file behind - two~/.zshrc.bootstrap.XXXXXXfiles from interrupted runs
were sitting in$HOMEon this machine when this was found. Every temp path
now goes throughmktemp_tracked, andtrapon EXIT, INT and TERM removes
whatever is still there; INT and TERM re-exit with 130 and 143 rather than
resuming where they were interrupted.mktemp_trackedassigns to a variable named by its first argument instead of
printing the path: a command substitution would run the array append in a
subshell, and the parent would forget the path - which is the whole point.
Added
-
macOS note on the mise JDK: it is not registered with
/usr/libexec/java_home, so the JetBrains IDEs, Android Studio and anything
else that auto-detects a JDK need the path once -
~/.local/share/mise/installs/java/temurin-21, a symlink mise maintains
across patch bumps. Shells are unaffected:mise activateexports
JAVA_HOME. Registering it properly would mean asudosymlink into
/Library/Java/JavaVirtualMachines, and this script does not use sudo. -
~/go/binonPATH.go installand the VS Code Go extension put
gopls,dlvandstaticcheckthere, and nothing was adding it - the
tools installed fine and then were not onPATH. Unrelated to wherego
itself comes from; it was missing before this release too. -
node, go and java come from mise on all three platforms, declared once in
mise/tools.confat the repo root. They used to come from three different
places - brew on macOS, winget on Windows, and nothing at all on Linux,
wheregrep -cE "nodejs|golang-go|openjdk" packages.confreturned 0 and a
fresh machine simply had no Node until somebody ranmise use -gby hand.
mise was installed everywhere and managing nothing:mise ls -gwas empty.mise use -gmerges into the user's global config rather than replacing it,
so a tool added by hand survives a bootstrap run. Removing the packages from
the manifests does not uninstall them -brew uninstall node go,
brew uninstall --cask microsoft-openjdk@21and the winget equivalents are
yours to run when you want the disk back.Python is deliberately not in the list: OS packages link against the system
python3, and a mise shim in front of it breaks them. -
The mise shims directory on
PATHin the zsh fragment.mise activate
covers interactive shells,JAVA_HOMEincluded, but never sees a
non-interactivessh host command, a cron job, or a Makefile an IDE runs.
Activation still takes precedence where both apply. -
Seven git defaults, set the same way the delta and difftastic keys
already are - only where the key is unset, so an existing value stays:
push.autoSetupRemote(push a new branch without the--set-upstream
dance),fetch.prune(stop completing months of deletedorigin/*),
diff.algorithm=histogram(better on moved and reindented code, and it is
what delta and difftastic then render),rebase.autoStash,
column.ui=auto,merge.conflictStyle=zdiff3(the common ancestor in a
conflict, not just the two endings) andtag.sort=-version:refname
(v1.10.0abovev1.9.0).The tag field is
version:refname; a plain-versionis rejected at use
withfatal: unknown field name: version. -
lazygitin thecligroup. A git TUI: stage hunks, rebase, stash and
branch without leaving the terminal. Same tool on all three platform...
bootstrap v2026.09.15
Windows 1.37.0
Removed
vim.vimfromcli. 1.36.0 added it to close a documented parity GAP,
but the winget package installs to%LOCALAPPDATA%\Programs\Vimand never
puts itself onPATH, sovimwas never actually runnable after a fresh
bootstrap. Pulled back out until there's a phase to fix itsPATH(or a
package that does it itself).tools/cli-parity.confcarries the GAP note
again.
Linux 1.30.0
Changed
- The
Manual - reported onlyphase is skipped whenMANUALis empty,
instead of printing a header with nothing under it in every run.MANUAL
has been empty here since before this entry, so the phase never had anything
to say.
Added
sd,xhanddoggoinRELEASES. Asedreplacement that takes
literal strings, an HTTP client that speaks JSON without a row of curl
flags, and adigthat prints a readable table - on a fresh Debian or
Ubuntu boxdoggois the only DNS client here, sincednsutilsis not in
the apt list. All three are release binaries: none is in the archive. The
zsh fragment aliasesdigtodoggoand addshttp/httpsforxh
(upstream shipsxhsas a symlink inside the tarball, which
install_release_binsdoes not copy);sddeliberately gets nosed
alias, since its pattern syntax is not sed's and anything pasted from a
script would quietly do something else.
macOS 1.32.0
Changed
-
The
Manual - reported onlyphase is skipped whenMANUALis empty,
instead of printing a header with nothing under it in every run. -
MANUALis empty.masandcolimawere the only entries; neither is
wanted on this machine, and both were reportedmissingon every run.
Added
-
jetbrains-toolboxin thedevgroup, andrider/datagripin
HELD. Toolbox installs and self-updates both IDEs, so arideror
datagripcask would fight it - the same reasoning theManagedsection of
windows/packages.psd1already carried for Toolbox, Rider and Android
Studio.HELDwas empty until now, which made the omission look like an
oversight rather than a decision. -
sd,xhanddoggoincli. Asedreplacement that takes literal
strings, an HTTP client that speaks JSON without a row of curl flags, and a
digthat prints a readable table. The zsh fragment aliasesdigto
doggoand addshttp/httpsforxh;sddeliberately gets nosed
alias, since its pattern syntax is not sed's and anything pasted from a
script would quietly do something else.
bootstrap v2026.09.11
Windows 1.32.0
Added
Bitwarden.CLIin theappsgroup, beside the desktop app.bwreads
and writes the vault from a terminal or a script -bw get password <item>,
orbw unlockonce and a session token for the rest. Requested directly;
1.31.0 had left it out until secrets were being copied into a terminal by
hand.
Linux 1.27.0
Added
GROUP_<name>_UV- Python CLIs installed withuv tool install, each in
its own environment, and kept current withuv tool upgrade. Entries are
nameorname|extra arguments. The phase runs after the release binaries,
which bring uv, and honours--groups,--dry-runand--skip-upgrade.GHOSTTY_DEB_REPO- where Ghostty's.debcomes from; see Changed.- The Bitwarden CLI (
bw) as a release binary, for x86_64 and aarch64.
In neither archive. Requested directly; 1.26.0 had left it out. RELEASE_<name>_TAG_PREFIX- for a repository that releases several
products under one "latest". bitwarden/clients tags web, desktop, browser
and cli releases side by side, and its latest is whichever shipped last; with
cli-vthe newest CLI tag is taken instead.verify-manifests.ymldoes the
same.RELEASE_<name>_ASSET_<arch>- an asset name for one architecture, by
dpkg --print-architecture, overRELEASE_<name>_ASSET. Bitwarden names its
x86_64 zip without an architecture and its arm64 zip with one, which no
placeholder spells for both.
Changed
-
atuin and trippy are release binaries, not apt packages. Ubuntu 24.04
carries neither, so on a noble host (WSL included) both were reported
missing and never installed. On Debian the archive lagged: trixie's atuin is
18.6.1 against the self-hosted sync server's 18.22.0, and its trippy 0.12.2.
Both now come from upstream's musl builds, for x86_64 and aarch64, into
~/.local/binlike starship and uv.A copy apt installed earlier is not removed, and
~/.local/binis ahead of
it on PATH in the zsh fragment;sudo apt remove atuin trippytidies it. -
The modern CLI bundle is release binaries too: bat, delta, eza, fd,
ripgrep, zoxide, fzf, jq, yt-dlp, btop, procs, dust, duf, glow and lnav, plus
gping and shellcheck. Ubuntu 24.04 has no procs, dust or glow, and trails
upstream on the rest by one to three years - yt-dlp from April 2024, which
YouTube has long since broken, and fzf 0.44, from beforefzf --zsh. trixie
is closer, never current. musl builds where upstream makes them for both
architectures; eza and delta are gnu, needing glibc 2.18 and 2.34 on x86_64.
yt-dlp is upstream's zipapp, one file for every architecture, run by
python3.tools/cli-parity.confmarks them@releases.Tags such as
jq-1.8.2andgping-v1.21.0resolve to their version, here
and inverify-manifests.yml;${tag#v}alone would have reinstalled both
on every run. -
gh comes from GitHub's own apt repository (
REPO_githubcli): 2.100.0,
where Ubuntu 24.04 has 2.45 and trixie 2.46. Its key is a binary keyring,
whichgpg --dearmorrejects, sosetup_reponow converts only
ASCII-armoured keys and installs binary ones as they are. -
Node and Go leave the apt list for mise, as OpenTofu did on Windows:
Ubuntu 24.04 ships Node 18, past end of life, and Go 1.22. Run once:
mise use -g node@lts go@latest. -
ansible, ansible-lint, pre-commit and yamllint are
uv toolinstalls in
theinfragroup, which keeps its name: Ubuntu 24.04 has ansible-lint 6.17
against 26.8 upstream.ansiblebrings ansible-core's commands through
--with-executables-from ansible-core. -
Ghostty comes from the community .deb that ghostty.org's Debian and
Ubuntu instructions point to,mkasberg/ghostty-ubuntu. It sat in the
appsapt list, which neither archive carries before Ubuntu 26.04, so it
never installed. The.debis chosen as that project's install.sh chooses -
Ubuntu by version, Debian by codename - and handed to apt, instead of piping
the script into bash. Releases it does not build for, bookworm among them,
are reported missing. -
Nothing apt installed earlier is removed.
~/.local/binis ahead of
/usr/binon a login's PATH, so the new copies win. To tidy up:sudo apt remove bat eza git-delta fd-find ripgrep zoxide fzf jq yt-dlp btop \ procs du-dust duf glow lnav gping shellcheck nodejs npm golang-go \ ansible ansible-lint pre-commit yamllint
Fixed
tripwould have failed as a release binary. The alias was
sudo trip, and sudo'ssecure_pathleaves out~/.local/bin. It now
resolves the full path when the alias is defined.- The script puts
~/.local/binon its own PATH. It never had, so a step
that looked for a release binary by name - delta for the git config, atuin
and carapace for theirs - missed one installed earlier in the same run, or
under the timer, and skipped. The one-offRELEASE_BIN_DIRchecks that
worked around it are gone. - A leftover apt
fd-findshadowed the realfd. The fragment aliased
fdtofdfindwheneverfdfindexisted; it now does so only when there is
nofd.
macOS 1.29.0
Added
-
A
networkgroup:trippy,gpingandnmap. Per-hop loss and
latency in one live view, a ping graph for one host or several, and what a
host exposes. The zsh fragment aliasestriptotrip -u: macOS is the one
platform where trippy traces without root. -
The
flameshotcask inapps. Screenshots annotated before they are
copied: arrows, boxes, numbered markers, blur. macOS asks for the Screen
Recording permission on first capture. -
kubecolorincloud,uvindev,carapaceinshell.kubectlis now an alias forkubecolor, which passes every argument
through and only adds colour, andkone forkubectl.- carapace completes the CLIs zsh has nothing for. git is excluded
(CARAPACE_EXCLUDES=git): zsh's own completion for it is better. - uv handles Python packages and venvs; mise still picks the Python version.
-
difftasticincli, and git settings for it. A structural diff: it
compares syntax, so a reformat is not a change. delta stays the pager for
git diff,show,logandadd -p; difftastic is asked for per command:git difftoolorgit dft(diff.tool=difftastic, no prompt, paged)git ddiff,git dshow <rev>,git dlog- difftastic in place of the
patch
Never
diff.externalglobally: its output is not a patch, so
git diff > x.patchandgit applywould stop working. delta passes
difftastic's output through byte for byte, so the pager needs no exception.
Like delta's, each key is set only when unset. -
git sdiff- the delta view side by side
(-c core.pager='delta --side-by-side' diff), set with delta's keys. -
Completion for the CLIs carapace has no completer for.
- stern and yq: carapace specs in
carapace/specs/, deployed to
~/Library/Application Support/carapace/specs- Go's config directory on
macOS, which carapace uses unless$XDG_CONFIG_HOMEis an absolute path.
Both are Cobra apps, so each spec is one line handing Tab to the tool's
own__complete. - mise:
mise completion zshin the fragment - small, and it asks mise. - uv: its zsh script is ~570 KB, so the fragment registers a stub that
loads it on the first Tab afteruvand replaces itself with the real
_uv; a new shell pays nothing for it.
- stern and yq: carapace specs in
-
The
onlyofficecask inapps. An office suite built around .docx,
.xlsx and .pptx, so files from Microsoft Office keep their layout more often
than in LibreOffice. AGPL-3.0: free for personal and company use.
Changed
-
atuin/config.tomlpoints sync at the self-hosted server
(sync_address = "http://192.168.50.6:8087") instead of atuin's own
api.atuin.shdefault. That isroles/atuinon raspberrypi_master in
mpostument/raspberry-setup, on the house LAN only - 8087 because the
OpenTelemetry collector holds 8888 there.Sync is still off until you run
atuin register(oratuin loginwith the
keyatuin keyprints): this says where, not whether. Off that network a
machine records locally and syncs when it is back.
bootstrap v2026.09.10
Windows 1.31.0
Added
-
Bitwarden.Bitwardenin theappsgroup. The desktop app: the vault
outside the browser, and what lets the browser extension unlock with
Windows Hello rather than the master password. Autofill itself comes from
the extension, which winget cannot install - it comes from the Chrome Web
Store.Bitwarden.CLIis deliberately not added: it only pays off once secrets
are being copied into a terminal by hand, and it is one line away when
that happens. -
A
networkgroup:FujiApple.Trippyandorf.gping. Per-hop loss and
latency in one live view, and a ping graph for one host or several. Tracing
needs an elevated shell on Windows, so the profile runstripthrough
gsudo.nmap is deliberately absent: winget's
Insecure.Nmapis stuck at 7.80, from
2019. -
Flameshot.Flameshotin thecreativegroup, beside ScreenToGif.
Screenshots annotated before they are copied: arrows, boxes, numbered
markers, blur, or pinned on screen. Windows 11 still hands the Print Screen
key to Snipping Tool until that is switched off in Settings > AccessibilityKeyboard.
-
rsteube.Carapaceinshell. Completion for 1000+ CLIs through one
engine - flags and subcommands for kubectl, gh, az, helm and the rest, where
PowerShell otherwise offers file names. git is excluded
(CARAPACE_EXCLUDES=git) and stays with posh-git. Colour is off
(CARAPACE_COLOR=0): PSFzf's Tab list prints completion labels verbatim,
and carapace's colour codes showed up there as raw escape sequences.The trailing space carapace puts on each value is off
(CARAPACE_NOSPACE=*): PSFzf quotes any completion containing whitespace and
adds a space of its own, so pickinggetfromkubectl <Tab>inserted
kubectl "get "and kubectl answeredunknown command "get ".PowerShell 7 only. Windows PowerShell 5.1 drops empty arguments to native
programs, including the''carapace's completer passes for the word under
the cursor; carapace answers[], its script throws on that, and 5.1 fell
back to file names after a wasted carapace run on every Tab. -
astral-sh.uvindev. Python packages and venvs; mise still picks the
Python version. -
kforkubectlin the profile. kubecolor, which the Linux and macOS
fragments aliaskubectlto, has no winget package. -
Wilfred.difftasticincli, and git settings for it. A structural
diff: it compares syntax, so a reformat is not a change. delta stays the
pager forgit diff,show,logandadd -p; difftastic is asked for
per command:git difftoolorgit dft(diff.tool=difftastic, no prompt, paged)git ddiff,git dshow <rev>,git dlog- difftastic in place of the
patch
Never
diff.externalglobally: its output is not a patch, so
git diff > x.patchandgit applywould stop working. delta passes
difftastic's output through byte for byte, so the pager needs no exception.
Like delta's, each key is set only when unset, andGit.DifftasticEnabled
turns them off.toolslists it, from its new row intools/cli-parity.conf. -
git sdiff- the delta view side by side
(-c core.pager='delta --side-by-side' diff), set with delta's keys. -
Completion for the CLIs carapace has no completer for.
- stern and yq: carapace specs in
carapace/specs/, deployed to
%APPDATA%\carapace\specs(or an absoluteXDG_CONFIG_HOME) through
Deploy-ManagedFile. Both are Cobra apps, so each spec is one line handing
Tab to the tool's own__complete. - uv: its PowerShell script is ~750 KB and took ~200 ms to load, so the
profile registers a stub that loads it on the first Tab afteruvand
answers through it from then on (8 ms a Tab afterwards). The real completer
is captured by shadowingRegister-ArgumentCompleterwhile the script runs,
because a completer cannot re-run completion from inside itself. - mise: loaded the same way, with a fix. mise 2026.9's script cuts the
command at the cursor withExtent.Text, which ends at the last word, so
mise <Tab>completed the wordmiseagain and offered file names. The
profile pads the text out to the cursor first;mise <Tab>now lists its
99 subcommands.
- stern and yq: carapace specs in
-
ONLYOFFICE.DesktopEditorsinapps. An office suite built around
.docx, .xlsx and .pptx, so files from Microsoft Office keep their layout more
often than in LibreOffice. AGPL-3.0: free for personal and company use.
Changed
-
atuin/config.tomlpoints sync at the self-hosted server
(sync_address = "http://192.168.50.6:8087") instead of atuin's own
api.atuin.shdefault. That isroles/atuinon raspberrypi_master in
mpostument/raspberry-setup, on the house LAN only - 8087 because the
OpenTelemetry collector holds 8888 there.Sync is still off until you run
atuin register(oratuin loginwith the
keyatuin keyprints): this says where, not whether. Off that network a
machine records locally and syncs when it is back.
Removed
-
OpenTofu.Tofufrom thedevgroup - mise owns OpenTofu, as on Linux and
macOS. Terraform projects pin a required version, and a wingettofu
upgraded on every daily run drifts from it; mise switches version per
directory. The other winget runtimes stay: Windows tooling looks for
Python, Node and Java where their installers put them.Run once:
mise use -g opentofu@latest. The bootstrap installs what the
manifest lists and never uninstalls, so an existing copy stays until
winget uninstall OpenTofu.Tofu.
Fixed
-
Tab never opened fzf.
Set-PsFzfOption -TabExpansiononly reaches git,
through PowerShell's legacyTabExpansionhook; it does not bind the key.
Tab stayed onMenuComplete, which prints a flat, unselectable list once the
menu outgrows the window -kubectl <Tab>, 46 described subcommands, did.
Tab is now bound toInvoke-FzfTabCompletion: an fzf list for every command,
a single match inserted directly. Ctrl+Space is stillMenuComplete. -
git settings with double quotes in them lost the quotes under Windows
PowerShell 5.1, which hands"inside an argument to a native program
unescaped.mergetool.unityyamlmerge.cmdwas stored as
... merge -p $BASE $REMOTE $LOCAL $MERGED, never matched what the script
wanted, and was rewritten on every run. Quotes are now escaped for git's
parser on 5.1 and 7.0-7.2; 7.3+ already passes them intact.
Linux 1.26.0
Changed
-
atuin/config.tomlpoints sync at the self-hosted server
(sync_address = "http://192.168.50.6:8087") instead of atuin's own
api.atuin.shdefault. That isroles/atuinon raspberrypi_master in
mpostument/raspberry-setup, on the house LAN only - 8087 because the
OpenTelemetry collector holds 8888 there.Sync is still off until you run
atuin register(oratuin loginwith the
keyatuin keyprints): this says where, not whether. Off that network a
machine records locally and syncs when it is back.
Added
-
com.bitwarden.desktopfrom Flathub in theappsgroup. Not in the
Debian archive, so Flathub it is, beside Obsidian, Bruno and DBeaver. The
desktop app is the vault outside the browser; autofill itself comes from the
browser extension. Like the rest ofapps, it is skipped on a headless
machine.The CLI is deliberately not added: it only pays off once secrets are being
copied into a terminal by hand. -
A
networkgroup:trippy,gpingandnmap. Per-hop loss and
latency in one live view, a ping graph for one host or several, and what a
host exposes. trippy and gping arrive with trixie; on bookworm they are
reported missing, as eza already is. The zsh fragment aliasestripto
sudo trip: trippy needs raw sockets and has no unprivileged mode on Linux. -
org.flameshot.Flameshotfrom Flathub in thecreativegroup, beside
OBS. Screenshots annotated before they are copied: arrows, boxes, numbered
markers, blur. Flathub rather than apt because Debian's is 12.1.0 and
Flathub's 14.0.0, and the Wayland fixes are in between. It does not take the
Print key by itself: on GNOME, bind a custom shortcut to
flatpak run org.flameshot.Flameshot gui. -
kubecolor,uvandcarapaceas release binaries. Debian's kubecolor
is 0.0.20, from before the kubecolor/kubecolor fork; uv and carapace are not
in the archive at all.kubectlis now an alias forkubecolor, which passes every argument
through and only adds colour, andkone forkubectl.- carapace completes the CLIs zsh has nothing for. git is excluded
(CARAPACE_EXCLUDES=git): zsh's own completion for it is better. - uv handles Python packages and venvs; mise still picks the Python version.
-
difftasticas a release binary, and git settings for it. A structural
diff: it compares syntax, so a reformat is not a change. Not in the Debian
archive; the gnu build, because upstream's musl build is x86_64 only. delta
stays the pager forgit diff,show,logandadd -p; difftastic is
asked for per command:git difftoolorgit dft(diff.tool=difftastic, no prompt, paged)git ddiff,git dshow <rev>,git dlog- difftastic in place of the
patch
Never
diff.externalglobally: its output is not a patch, so
git diff > x.patchandgit applywould stop working. delta passes
difftastic's output through byte for byte, so the pager needs no exception.
Like delta's, each key is set only when unset. -
git sdiff- the delta view side by side
(-c core.pager='delta --side-by-side' diff), set with delta's keys. -
org.onlyoffice.desktopeditorsfrom Flathub inapps. An office suite
built around .docx, .xlsx and .pptx, so files from Microsoft Office keep
their layout more often than in LibreOffice. Not in the Debian archive.
AGPL-3.0: free for...