Find container image updates in Quadlet files.
Small Go CLI for finding container images in Quadlet files and checking registry tags for newer compatible versions.
quadwatch recursively scans Quadlet files, extracts registry image references, lists remote tags, and reports the newest compatible tag using conservative prefix/suffix matching.
- Quadlet-aware scanning: reads
*.container,*.image, and*.volumefiles. - Registry lookup: checks public registries with a 30-second request timeout and uses Docker credential auth through the default Docker keychain.
- Automation-friendly output: supports
json,csv, and human-readabletableformats. - Update-only by default:
fetchreports only images with available updates unless--allis used. - Colorized human output: table output and
--progressstatuses use terminal colors by default. - Progress reporting:
--progressshows lookup status on stderr while keeping machine-readable output on stdout. - Conservative tag matching: compares version-like tags with the same prefix and suffix shape.
- Supports prefixed tags: handles tags such as
release-4.0.16.2944,v2.7.0, and1.2.3-alpine.
curl -fsSL https://raw.githubusercontent.com/pgilad/quadwatch/main/scripts/install.sh | shOr build from source:
go build -o quadwatch ../quadwatch images --format table /path/to/quadlets./quadwatch fetch --format csv /path/to/quadlets./quadwatch fetch --all --progress --format table /path/to/quadlets| Command | Purpose |
|---|---|
images PATH |
List detected images and current tags |
fetch PATH |
List images with newer compatible remote tags |
self-update |
Check the latest GitHub release and update the installed binary |
uninstall |
Remove the current quadwatch binary |
version |
Print the current version |
help |
Print usage |
Common options:
--format json|csv|table--color auto|always|never: colorize human-readable table/progress output (defaultauto)--allforfetch: show all images, including those without updates--config PATHforfetch: load a YAML config file. If omitted, lookup uses./quadwatch.yaml, then$XDG_CONFIG_HOME/quadwatch/config.yaml(typically~/.config/quadwatch/config.yaml).--progressforfetch: show remote lookup progress on stderr
images and fetch recursively scan PATH for:
*.container*.image*.volume
The scanner extracts image references from:
[Container] Image=[Image] Image=[Volume] Image=
The parser intentionally mirrors the subset used by Renovate's Quadlet manager:
- Skips local/non-registry transports like
dir:,oci:,docker-archive:,oci-archive:,containers-storage:, andsif:. - Strips
docker://anddocker-daemon:prefixes. - Applies Docker-style defaults:
docker.ioregistry andlatesttag when omitted. - Detects digest-pinned references such as
repo:tag@sha256:...;fetchskips them withskip_reason=digest-pinned imagebecause the digest, not the tag, controls what runs.
Version selection is heuristic. Tags are split into this shape:
<prefix><version><suffix>
prefix: any non-numeric prefix, including an empty prefixversion: 1 to 4 dot-separated numeric segments, for example1,1.2,1.2.3,1.2.3.4suffix: anything after the version, including an empty suffix
Examples:
| Tag | Prefix | Version | Suffix |
|---|---|---|---|
v2.7.0 |
v |
2.7.0 |
empty |
release-4.0.16.2944 |
release- |
4.0.16.2944 |
empty |
nightly-1.2.3 |
nightly- |
1.2.3 |
empty |
foo_bar_10.5-alpine |
foo_bar_ |
10.5 |
-alpine |
2026.04.25.123345 |
empty | 2026.04.25.123345 |
empty |
Candidate tags must keep the same prefix and suffix as the current tag.
For current tag release-4.0.16.2944, accepted candidates include:
release-4.0.17.2952release-4.1.0.0000
Ignored candidates include:
nightly-4.0.17.29524.0.17.2952release-9831336
For non-empty prefixes other than v, the candidate version must also have the same number of numeric segments as the current version. This avoids treating commit-like tags such as release-9831336 as newer versions of tags like release-4.0.16.2944.
fetch can use a YAML config to source selected image updates from GitHub Releases instead of registry tag listing. This is useful for GHCR repositories with very large tag lists.
Default config lookup order:
./quadwatch.yaml$XDG_CONFIG_HOME/quadwatch/config.yaml(typically~/.config/quadwatch/config.yaml)
Use --config PATH to load a specific file instead.
github_releases:
ghcr.io/immich-app/immich-server: immich-app/immich
ghcr.io/immich-app/immich-machine-learning: immich-app/immichConfig keys must use quadwatch's normalized repository name, not necessarily the image text as it appears in the Quadlet file. Quadwatch applies Docker-style defaults while scanning: Docker Hub images are normalized to index.docker.io, official Docker Hub images include the library/ namespace, and tags are not part of the config key.
Examples:
Quadlet Image= value |
Config key |
|---|---|
postgres:16 |
index.docker.io/library/postgres |
docker.io/library/postgres:16 |
index.docker.io/library/postgres |
ghcr.io/immich-app/immich-server:v2.1.0 |
ghcr.io/immich-app/immich-server |
quay.io/prometheus/prometheus:v3.0.0 |
quay.io/prometheus/prometheus |
You can run quadwatch images --format table PATH to see the exact repository names to use as config keys.
Configured entries run gh release view -R <repo> --json tagName -q .tagName, then compare that release tag using the same compatibility rules as registry tags. The gh CLI must be installed and authenticated if the GitHub request requires it.
quadlet,image_name,current_tag
/path/app.container,index.docker.io/library/postgres,18.4-trixiequadlet,image_name,current_tag,newest_tag,update,skip_reason,error
/path/sonarr.container,ghcr.io/hotio/sonarr,release-4.0.16.2944,release-4.0.17.2952,true,,Table output uses STATUS (ok, update, skipped, or error) and DETAILS columns for skip reasons or errors. CSV output includes both skip_reason and error columns.
Non-version-like current tags, such as latest, are skipped before any registry/GitHub lookup and reported with skip_reason=unsupported tag shape when included with fetch --all; they are not treated as lookup errors.
Install the latest release:
curl -fsSL https://raw.githubusercontent.com/pgilad/quadwatch/main/scripts/install.sh | shInstall a specific release:
curl -fsSL https://raw.githubusercontent.com/pgilad/quadwatch/main/scripts/install.sh | sh -s -- --version 2026.05.23-5Update or uninstall later:
quadwatch self-update
quadwatch uninstallgo test ./...
go build -o quadwatch .