Skip to content

Release pipeline

A devhost release publishes two things from one Git tag: the binaries and this documentation site. The site is deployed only by a release, so it describes the released version and not unreleased work on main.

The guide videos and the promo on the landing page follow a separate, manual track. No workflow records or renders video. A release downloads the videos that were published earlier and checks each against the hash pinned in the repository.

ReleaseMergeGuide films: by hand, only when a demo changedyesnopinned videospinned videosjust demo audio-guidesgenerate the narrationjust demo guidesrecord and render thefilmsFilmsapproved?just docs publish-mediaupload videos, rewritepinsCommit pins, posters,captions, guide pagesGitHub release mediavideo assets, neverreplacedPull requestci.yml: just checkverifies the pinnedvideosmainno docs deploySet the version,push tag v*publish.yml job publishcheck, build, createreleasepublish.yml job docsbuild the site from thetagGitHub Pages

The diagram has three stages. The films are made and published by hand, and only when a demo changed. A merge to main runs the checks and deploys nothing. A v* tag publishes the binaries and then the site. The dotted arrows are the pinned videos, which every docs build downloads from the media release.

Pushing a tag such as v0.0.2 starts .github/workflows/publish.yml. The workflow fails unless the tag matches the version in apps/devhost/metadata.json. The hosted Linux runner installs Playwright Chromium, FFmpeg (including ffprobe), unzip, and Xvfb for the native media and headed-browser tests. It then runs just check, builds the release archives, creates the GitHub release for the tag, and uploads the archives to it.

The Go checks include logpolicy, a type-aware analyzer that enforces the shared internal/cliout output boundary. Run just devhost lint-logging to check it alone. Diagnostics use the shared logger; machine-readable command results, child logs, HTTP responses, and file contents retain their separate output contracts.

just devhost test runs go test -count=1 ./..., including when invoked through just check locally or in CI. Every Go test runs afresh because the integration suite observes live processes, ports, and kernel state. This also prevents Go from recording and later validating millions of Linux /proc observations as test-cache inputs. Compiled packages still use Go’s build cache.

The docs job of the same workflow runs after the release exists. It calls .github/workflows/docs.yml, which checks out the tag, builds packages/docs, and deploys the result to GitHub Pages. A failed release deploys nothing.

A push to main does not deploy the site; documentation merged to main, corrections included, is published with the next release.

The github-pages environment accepts deployments only from main and from tags that match v*. The Deploy docs to GitHub Pages workflow can also be run by hand, within those limits: a run from a release tag deploys that release’s documentation again, unchanged, and a run from main deploys everything on main, including documentation of unreleased behavior. A branch that holds only a correction cannot be deployed.

The videos are assets of a GitHub release named media, not files in the repository. packages/docs/demo-media.json pins each one by name, release asset, SHA-256, and size. Every docs build downloads the pinned videos and rejects a file whose hash differs.

A tag carries its pins. The site built for a release therefore shows the videos that were pinned in the tagged commit, and an asset is never replaced, so an earlier tag still builds with the videos it pinned.

New videos need a Linux host with the recording tools, an operator to approve the coding agent’s requests during recording, an ElevenLabs key, and a review of the result. For that reason they are made by hand before the release:

  1. just demo audio-guides generates the narration of changed lines.
  2. just demo guides records each guide and renders its film. just demo record does the same for the promo.
  3. After the films are reviewed, just docs publish-media uploads them and rewrites their pins.
  4. The pins, posters, captions, and guide pages are committed together.

A change to the interface does not update a video. When a release changes what a guide shows, the film has to be recorded again before the tag is pushed; otherwise the release ships the earlier video beside the new text.