User-facing summary of what 0.2.0 brings, what changes, and what
to check before upgrading.
For the full machine-readable changelog, see
CHANGELOG.md. For the contribution mechanics
that landed alongside this release, see
onboarding.md.
Three new tools, end-to-end:
shimkit dns macOS DNS resolver recovery
shimkit adguard AdGuard Home port-conflict fixer (Linux)
shimkit docker-clean Docker resource cleanup (Linux + macOS + WSL)
All three are Python ports of shell scripts. The shell predecessors are removed from the source tree; the Python versions fix several bugs the bash versions had silently.
Plus a uniform CLI surface (--dry-run, --json, --quiet,
--verbose, --log-file, --timeout, --yes, --no-input)
across every new subcommand, and severe-tier confirmation tokens
for destructive operations.
The "ping works, browser doesn't" recovery tool. Targets the
failure mode where Network.framework's resolver state is
corrupted but mDNSResponder's cache and the underlying network
are fine.
shimkit dns diagnose read-only: resolver chain, active
service, interference (Tailscale,
Docker Desktop, VPN tunnels)
shimkit dns flush the 80% case (dscacheutil + HUP)
shimkit dns fix 6-step escalation; stops at the
first step that resolves
shimkit dns show / set / reset inspect / mutate networksetup
shimkit dns test [domain...] resolve via three paths
shimkit dns profile list installed Encrypted-DNS profiles
shimkit dns rollback restore the latest plist backup
shimkit dns diagnostics export bundle for a support ticket
AdGuard Home port-conflict fixer. Handles systemd-resolved,
NetworkManager, known-safe DNS daemons (dnsmasq, bind, named,
unbound), and pi-hole.
shimkit adguard scan read-only port owners + conflicts
shimkit adguard fix [--dry-run] apply the remediation
shimkit adguard verify loopback DNS + /control/status
shimkit adguard ports show/set inspect/set via API or yaml
shimkit adguard config validate AdGuardHome --check-config
shimkit adguard service ... start/stop/restart/status
shimkit adguard logs journalctl -u AdGuardHome
shimkit adguard rollback restore yaml + resolv.conf backups
Prefers the HTTP control API when reachable; falls back to a
ruamel.yaml round-trip edit with the daemon stopped (so AGH
doesn't overwrite the edit on its shutdown).
Docker resource cleanup. Uses the docker-py SDK for daemon ops
and Docker Desktop CLI for lifecycle on macOS.
shimkit docker-clean status disk usage breakdown
shimkit docker-clean quick stop + prune common
shimkit docker-clean nuke --confirm DELETE remove EVERYTHING
shimkit docker-clean restart daemon restart
shimkit docker-clean stop-all stop running containers
shimkit docker-clean prune-{images,volumes,networks,builders}
shimkit docker-clean orphans dangling + unused only
shimkit docker-clean inspect <kind> detailed listing
shimkit docker-clean compose-down PATH per-project teardown
shimkit docker-clean schedule emit (don't install) a
launchd/systemd/cron unit
The three new tools each ship behind an optional extra so the base install stays lean.
# Pick what you need:
uv tool install 'shimkit[dns]'
uv tool install 'shimkit[adguard]'
uv tool install 'shimkit[docker-clean]'
# Or all of them:
uv tool install 'shimkit[extra-tools]'
# Add an extra to an existing install:
uv tool install --upgrade 'shimkit[adguard]'
# or
pipx inject shimkit ruamel.yaml requests psutilIf you run a tool whose extra isn't installed, shimkit exits 69
with a message naming the install command for your platform.
These were silently broken in the bash versions:
fixdns.shdetect_serviceusedgrep -E '\d+'. BSD grep doesn't support\d; the function silently fell through to the fallback on every macOS. The Python port uses real regex.fixdns.shWi-Fi power-cycle ransetairportpower "$INTERFACE"unconditionally — silent no-op when the active service was Ethernet. The port branches onnetworksetup -listallhardwareports.fix-adguardhome-ports.shran a full DNS cleanup even when AGH was absent; you could end up withsystemd-resolveddisabled and no replacement DNS. The port exits 69 unless--dns-cleanup-onlyis explicitly passed.fix-adguardhome-ports.shawk-editedAdGuardHome.yamlwhile the daemon was still running. AGH overwrites the yaml on shutdown per its wiki — the edit could be lost. The port stops AGH first (or uses the HTTP control API entirely).fix-adguardhome-ports.shonly warned that NetworkManager would clobber/etc/resolv.conf. The port writes the canonicaldns=nonedrop-in andnmcli general reloads.docker-nucker.shbuild-cache + system-prune read$?immediately afterlocal x=$(...). That readslocal's exit code (always 0), not the command's. Both prune operations always reported success regardless of actual outcome.docker-nucker.shverify_dockerused((attempt++))underset -e. The first iteration evaluates to 0, returns non-zero, and aborts the loop — so the daemon-health verifier ran at most once. The port uses a real loop with a config-driven timeout.docker-nucker.shbuilder pruning randocker builder prune -af, which only touches the legacy local builder. The port iteratesdocker buildx ls --format jsonand prunes each named builder.
config.package_managers.definitions rows now accept argv lists
instead of strings — and defaults.json ships with argv lists for
every PM:
Argv-list mode runs commands with shell=False, so a malicious
package name can't inject shell metacharacters. If you have a
custom shimkit.json with string templates, they continue to work
unchanged.
Destructive subcommands now require a literal token via
--confirm <token>. The token comes from config; --yes does
not bypass it.
shimkit dns reset --confirm RESET
shimkit dns fix --nuclear --confirm REGENERATE
shimkit docker-clean nuke --confirm DELETE
You can customise the tokens — for example, requiring
DESTROY-DEV-ENV instead of DELETE — by setting
tools.docker_clean.nuke_confirm_token in shimkit.json. See
docs/configuration.md.
Brew.install_self (used by shimkit java when Homebrew is
absent) no longer interpolates the config-supplied install URL
into a /bin/bash -c "..." shell command. The installer is now
downloaded to a tempfile (with HTTPS-scheme validation), chmod'd
to 0o700, and executed via /bin/bash <tmpfile> with no shell.
doctor now reports:
dns probe 9 resolver(s); top: 1.1.1.1,8.8.8.8,8.8.4.4
adguard /opt/AdGuardHome/AdGuardHome (or <absent>)
docker 28.5.2 (or <not running>)
…on the platforms where each makes sense.
The release workflow now generates SPDX SBOMs (wheel + container
image) and actions/attest-build-provenance attestations (pushed
to the GHCR registry). The guard job validates that the tag, the
pyproject.toml::version, AND the __init__.py::__version__ all
match — and that the CHANGELOG has a section for the new tag.
A new adguard-integration CI job runs a real AdGuard Home daemon
(version-pinned, on non-default ports) and exercises
scan/verify/ports show/fix --dry-run/ports set --dry-run
with JSON-asserted output. Closes the "are we sure shimkit works on
real Linux" question for the read-only adguard paths.
- Base image pinned by manifest digest (
python:3.12-slim@sha256:401f6e1a…). Dependabot'sdockerecosystem opens PRs when the digest changes. - New
HEALTHCHECK ["shimkit", "version"]— orchestrators get an authoritative ready signal.
- No breaking changes to the existing
java/shell/config/doctor/self-updatesurfaces. - Existing
shimkit.jsonuser configs continue to work — the new tool sections (tools.dns,tools.adguard,tools.docker_clean) have sensible defaults so partial configs aren't required. - If you have custom string-template PM definitions in
shimkit.json, they're still supported. To benefit from the shell-injection-free argv form, convert them per the example above.
shimkit --version # 0.1.0 before upgrade
shimkit doctor # baseline output
# Upgrade
shimkit self-update # auto-detects uv/pipx/brew/pip
shimkit --version # 0.2.0
shimkit doctor # the three new probes now appear
shimkit --help # the three new sub-apps now appearThis release validates on:
- macOS (Apple Silicon + Intel), Python 3.10–3.13 — CI matrix plus a manual smoke on Apple Silicon.
- Ubuntu 22.04 / 24.04 LTS — CI matrix plus the
adguard-integrationjob and a manual Phase 7 sign-off on a real Ubuntu host before cutting the tag (seedocs/validation-scope.md).
Other systemd-based Linuxes (Debian 12+, Fedora 40+, Arch, …) are
expected to work but aren't formally validated in CI. File an issue
with lsb_release -a + shimkit doctor output if anything misbehaves.
Not supported: WSL2 (systemd-resolved and NetworkManager don't
behave like bare Linux there; the affected tools exit 69 with a
clear message). Windows native is also unsupported.
This release ports three previously-internal shell scripts (fixdns.sh,
fix-adguardhome-ports.sh, docker-nucker.sh) into shimkit's
typed-Python kit. The bugs they had — and the docs they didn't have —
were the motivation. Each tool's docs/tools/<name>.md page lists
the specific defects the port closes.
The release workflow publishes:
shimkit-0.2.0-py3-none-any.whl+shimkit-0.2.0.tar.gzon PyPI (via OIDC trusted-publisher; no token in the workflow).shimkit-sbom.spdx.jsonas a GitHub Release asset (SPDX SBOM for the wheel).ghcr.io/simtabi/shimkit:0.2.0(multi-arch: linux/amd64 + linux/arm64), withactions/attest-build-provenance-signed manifests pushed to the registry.- The Homebrew formula bump PR in
simtabi/homebrew-tap.
To verify the wheel locally:
pip download --no-deps shimkit==0.2.0 -d /tmp
cd /tmp
sha256sum shimkit-0.2.0-py3-none-any.whl
# Compare against the SBOM-listed checksums (or against your prior
# pinned hash if you maintain one).