Skip to content

Pipelines, versions and releases

How every SpaceWorks-Labs repository checks, versions and ships its work, with the rules that all of them follow, the way each kind of stack does it, and an honest table of where each repository stands today.

Researched 13 November 2026 from the live GitHub organisation (workflows, branch protection, releases) and, for the main SpaceWorks repository, from the current integration branch, which is one release ahead of main (it has the version-bump check, the signed installer assets and docs/release-0.12.0.md; main on GitHub is still at 0.9.3). Where something could not be verified it says not checked.

Current rule (v2.0.1, 2026-11-13): Observed at 2026-11-13: organisation tables below retain the original research snapshot, not live promises. The design-system VERSION/tag/release correction is recorded beside §§6–8; no new remote organisation audit was run by batch 1A. (1A-N30) — supersedes the line above; see docs/current-rules.md#cr-delivery-01.

Plain words used below: a workflow is a script GitHub runs for us (GitHub Actions); a job is one step-group inside it; a required check is a job that must be green before GitHub allows a merge; ghcr.io is GitHub’s container registry, where our Docker images live; a tag is a permanent label on one commit; semver is the three-number version MAJOR.MINOR.PATCH.

Rule What it means
Branch model Work happens on a branch from dev. A pull request (PR) goes into dev. The maintainer promotes dev to main with a second PR. Nobody pushes to main.
Checks run on every PR A PR into dev or main runs the repository’s checks. Nothing merges red.
Required checks are named and stable Branch protection matches job names, so a job that is required is never renamed casually.
Zero reds A failing test is a new regression, never “background noise”. Tests are kept; a test for an unshipped feature is skipped with a written reason, never deleted.
Semver in a VERSION file The root VERSION file holds MAJOR.MINOR.PATCH. It is raised (strictly higher than main) on every PR into main.
A release note per version docs/release-<version>.md (SpaceWorks) or the changelog entry says what changed, in plain English.
Tags are vX.Y.Z-main.<run>.<sha> The build tag combines the series, the CI run number and the commit. Servers pin that exact tag, so an update always means one known build. The person-facing title is <Product> X.Y.Z.
Releases are built by CI only The first time a new VERSION reaches main, CI builds the images and creates the GitHub Release. Nobody builds or uploads a release by hand.
Artifacts per kind Server products: two Docker images (backend, frontend) for linux/amd64 and linux/arm64, plus installer files. Android: APK and app bundle. iOS: an app build. Static sites: a Pages deployment.
Security audits Dependencies are audited in CI (pip-audit for Python, npm audit for Node), on PRs and weekly where the dependency files rarely change.
Caching Every workflow caches its package manager or build layers so a PR check stays fast. The cache is never the source of truth.
Secrets only in GitHub Tokens and keys live in GitHub secrets and environments, never in a file. Test keys are generated fresh in each run. Releases are signed without a stored key where possible (keyless signing).
Least permission Workflows start with contents: read and ask for more (packages: write, pages: write) only in the one job that needs it.
Concurrency A newer run on the same branch cancels the older check run. A release run never cancels itself halfway.
Maintainer merges CODEOWNERS asks the maintainer to review every path, and branch protection (applied to admins too) lets only the maintainer merge or push to main. Agents prepare the merge and stop.
Pages deploys Static sites build on every PR (to catch broken pages) and publish to GitHub Pages only from main.
flowchart LR
feat["Feature or fix branch from dev"] -- "pull request" --> dev["dev"]
dev --> pr_checks["PR checks: build, lint, types, tests, audit"]
pr_checks -- "all green" --> promote["Maintainer opens PR dev to main"]
promote --> bump["version-bump check: VERSION strictly higher, release note exists"]
bump -- "green" --> merge["Maintainer merges to main"]
pr_checks -. "red: fix and push again" .-> feat
merge --> release["Release workflow on main"]
release --> new{"New VERSION?"}
new -- "yes" --> images["Build and push images to ghcr.io"]
images --> assets["Installer files, signed checksums"]
assets --> gh["GitHub Release created"]
gh --> latest["Marked latest, rolling tags promoted"]
latest --> deploy["Optional: deploy to our own server"]
new -- "no" --> imgonly["Images only, no GitHub Release"]