Those badges are dates rather than a build status on purpose. A workflow that
stops being triggered keeps its last green tick forever -- which is exactly
what happened here for three weeks, and to vitasdk/buildscripts for two
months, without anything ever turning red. A stale date cannot lie.
$ docker run --rm -it -v "$PWD:/workspace" vitasdk/vitasdk:2026.08The image is a consumer of the published SDK, not a second way of installing
it: it bootstraps from the signed channel manifest at vitasdk.org/channels,
exactly as a person does on their own machine, and vdpm inside it is already
refreshed on that series.
A tag is a release series plus, optionally, the day it was published.
| tag | what it is |
|---|---|
2026.08 |
the series, moving: rebuilt when its packages move or the base gets security updates |
2026.08-20260813 |
the same series frozen on that date, never rewritten |
latest |
the newest supported series |
nightly, nightly-20260813 |
the development channel, rebuilt as it moves |
and two axes on top of any of them:
| suffix | what changes |
|---|---|
-minimal |
the core and the tools to build with it, without the ~130 target packages (764 MB against 1.6 GB) |
-non-root |
the same filesystem, running as vitasdk instead of as root |
So 2026.08-minimal-non-root-20260813 is a thing, and so is minimal, which
follows the newest supported series like latest does.
Every tag is a multi-architecture manifest covering linux/amd64 and
linux/arm64, both built natively.
The dated tags of a series are kept indefinitely. The dated tags of
nightly are not: they are produced daily by definition and may be pruned
later. Pin a series if you need the pin to survive.
Two tag names change meaning the first time this pipeline publishes.
latest and non-root used to be a nightly. They were rebuilt every
night from the tip of the toolchain, so docker run vitasdk/vitasdk handed
you whatever had been built that morning. They now follow the newest
supported release series, which is what most people wanted from them and
what latest means for the images they already use.
$ docker run vitasdk/vitasdk:nightly # the previous behaviour
$ docker run vitasdk/vitasdk:nightly-non-rootNothing about the tag names disappears: :non-root still exists and still
means the same variant, only of a series rather than of the nightly. Pin a
series -- or a series and a date -- if you want the ground to stop moving
altogether.
Two other things worth knowing, both consequences of the images being built from the published channel rather than from a toolchain compiled in place:
- The base is Ubuntu 24.04, not Alpine. The SDK published for Linux is built against glibc, so an Alpine image could only ever have carried a toolchain that does not run. If you build musl binaries on top of these images, that is the change that affects you.
arm64is native. Both architectures are built on their own hardware and published in one manifest, so Apple Silicon and ARM runners stop emulating.
The plain tag runs as root, which is what a derived RUN apt-get install ...
and the container jobs of most CI systems expect. It is not a root-only image:
the vitasdk user (UID 1000) exists in every variant, the SDK belongs to it
with group 0 and g+rwX, so all of these work without a rebuild:
$ docker run --rm --user vitasdk vitasdk/vitasdk:2026.08 # by name
$ docker run --rm --user 4242:0 vitasdk/vitasdk:2026.08 # any UID, as a cluster assigns
$ docker run --rm vitasdk/vitasdk:2026.08-non-root # or the tag, for runAsNonRootThe -non-root tag exists for the one case --user cannot cover: Kubernetes
with runAsNonRoot: true reads the USER configured in the image and refuses
to start a container whose image declares root, whatever the pod says.
A non-root user is also what vita-makepkg needs -- it ships inside the SDK
and refuses to run with EUID 0, like the makepkg it descends from.
The full variant carries every package of the series and build-essential,
for projects that compile a helper tool of their own during the build. What
each variant contains is recorded in its labels:
$ docker inspect vitasdk/vitasdk:2026.08 --format '{{ json .Config.Labels }}'The dated tag says when an image was published. The labels say what it contains: the channel, its sequence, the SHA-256 of the manifest it was built from, and the exact core and packages releases.
.github/workflows/publish.yml builds one image per live series read from the
signed channels/index.json -- the same file the client reads. A series that
goes end-of-life stops being rebuilt without anything here changing.
It runs on two triggers. A repository_dispatch from vitasdk/autobuilds
when a channel is published, which is the one that keeps the images following
the packages; and a daily cron for base image security updates. Nothing is
pushed unless the channel manifest or the base image digest actually changed,
so a quiet day produces no tags.
Before anything is published, every built image compiles and links a real
.vpk inside itself, as root and as an arbitrary UID.
$ docker build --target full --build-arg VITASDK_CHANNEL=2026.08 -t vitasdk:probe .
$ tests/smoke.sh vitasdk:probe
$ tests/test-plan.sh