Skriuw Documentation
Self-hosting and operations

Release pipeline

How a Skriuw version becomes a pullable Docker image, what the GHCR publish workflow automates, what stays a manual tag, tag conventions, and the one-time public-package setup.

How a Skriuw version becomes a pullable Docker image. This is the maintainer view of the Self-host with Docker story: what CI does, what stays manual, and the one-time setup that makes the image public.

What is automatic

The image publish is CI. .github/workflows/publish-docker.yml triggers on any v*.*.* tag push (and on manual workflow_dispatch), then:

  1. Sets up QEMU + Buildx for multi-arch.
  2. Logs in to GHCR with the built-in GITHUB_TOKEN.
  3. Builds the root Dockerfile for linux/amd64 and linux/arm64.
  4. Pushes to ghcr.io/remcostoeten/skriuw with tags derived from the git tag.

For tag v0.22.1 that publishes three tags: :0.22.1, :0.22, and :latest. Every subsequent vX.Y.Z tag re-publishes and moves :latest forward. GitHub Actions layer caching (type=gha) keeps rebuilds fast.

What stays manual

Cutting the tag. There is no semantic-release or changesets, versioning is manual, matching the desktop flow (desktop-v* tags). To ship a release:

# bump "version" in package.json first, then:
git tag v0.22.1
git push origin v0.22.1

That single push is the whole release action; the workflow does the rest.

Tag conventions

PrefixTriggersProduces
v*.*.*publish-docker.ymlThe self-host web image on GHCR
desktop-v*release-desktop.ymlNative desktop installers + a GitHub release

The two prefixes fire different pipelines: a v* tag does not build the desktop installers, and a desktop-v* tag does not build the Docker image. Since 0.22.1 the number is unified: web, desktop, Tauri, and Cargo packages all carry one version, so a full release means cutting both tags at the same commit:

git tag v0.22.1 && git tag desktop-v0.22.1
git push origin v0.22.1 desktop-v0.22.1

Letting them drift is how desktop-v0.22.0 came to be cut from a branch that never landed on daddy, publishing a desktop feature the mainline did not have.

Publishing the install channels

release-desktop.yml only drafts the GitHub release. Publishing that draft is what triggers publish-linux-repos.yml, which fans the artifacts out to apt, dnf, AUR, Homebrew, Scoop, winget, and Snap. A draft that is never published ships nothing to any channel.

The DevTUI (scripts/devtui) is cross-compiled in the same workflow and its skriuw-dev binaries are attached to the desktop release as assets.

One-time setup: make the package public

After the first successful publish, the GHCR package defaults to private. Flip it to public (repo → Packages → skriuw → Package settings → Change visibility → Public). Otherwise docker pull demands a docker login ghcr.io, which breaks the self-host quick start.

End-user update model

Publishing :latest does not push onto anyone's running container. Self-hosters upgrade deliberately with docker compose pull && docker compose up -d; the entrypoint applies migrations on the next boot. Auto-update (Watchtower) is intentionally left out of the default Compose because unattended migrations have no rollback.

On this page