Every first-party native host must compile in pull-request CI. A Racket-only test job, schema check, or package dry run does not prove that WinUI, SwiftUI, or GTK source still compiles. Waiting for a tagged release to perform the first native compilation turns ordinary compiler errors into release incidents.
Use the same runner image class and toolchain family in CI that the release job uses:
- Windows:
windows-latestfor the WinUI 3 host; - macOS: both
macos-latestandmacos-15, so current Swift and the pinned Xcode 16 release environment both compile the SwiftUI/AppKit host; - Linux:
ubuntu-24.04with GTK 4.10+ development files and an embeddable Racket CS runtime.
raco rivet build is the required host-compilation gate. Add package and
verify when the job should also validate the distributable layout. Publisher
certificates and notarization credentials do not belong in pull-request CI;
use development packaging there and reserve --production for a protected
release environment.
The following workflow pins Rivet 0.9.0. Update every Rivet package source and the Linux setup action to the same tag (or full commit) in one review. A direct Git source is intentional: the Racket Package Catalog has one current entry for a package name and cannot select an older Rivet release.
name: Native hosts
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
windows-host:
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- uses: Bogdanp/setup-racket@v1.15
with:
architecture: x64
distribution: full
variant: CS
version: '9.3'
- run: raco pkg install --auto --no-docs 'https://github.com/turinglambdaai/rivet.git#v0.9.0'
- run: raco rivet doctor
- run: raco rivet schema check rivet-schema.json
- run: raco rivet build
macos-host:
strategy:
fail-fast: false
matrix:
runner: [macos-latest, macos-15]
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v7
- uses: Bogdanp/setup-racket@v1.15
with:
architecture: x64
distribution: full
variant: CS
version: '9.3'
- run: raco pkg install --auto --no-docs 'https://github.com/turinglambdaai/rivet.git#v0.9.0'
- run: raco rivet doctor
- run: raco rivet schema check rivet-schema.json
- run: raco rivet build
linux-host:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- name: Set up embeddable Racket CS
uses: turinglambdaai/rivet/.github/actions/setup-embed-racket@v0.9.0
- name: Install GTK4 development files
run: |
sudo apt-get update
sudo apt-get install --yes libgtk-4-dev
- name: Install the matching Rivet package and dependencies
run: raco pkg install --auto --no-docs 'https://github.com/turinglambdaai/rivet.git#v0.9.0'
- run: raco rivet doctor
- run: raco rivet schema check rivet-schema.json
- run: raco rivet buildThe Linux order is load-bearing: install the Rivet package after
setup-embed-racket. The action's minimal Racket build intentionally ships
without packages; installing Rivet afterward resolves cext-lib, crypto-lib,
keel, and the rest of the dependency closure into the package directory that
the embeddable runtime actually uses. Installing Rivet earlier under a full
Racket distribution can make those dependencies appear satisfied there while
leaving the minimal runtime incomplete; a later backend bundle then fails, for
example because raco ctool is supplied by cext-lib.
For an intentionally moving development channel, replace the direct Git source
with the catalog name rivet and use the setup action from @main. Do not use
that pair as a release pin: catalog installation follows the catalog's current
checksum and there is no raco pkg install rivet@<version> selector. The
standard hold-back form is the tag-pinned Git source shown above. Racket treats
the fragment as the Git revision while retaining normal dependency resolution.
Rivet itself additionally launches the generated GTK4 package inside a
headless Weston compositor with GDK_BACKEND=wayland. This is a native
Wayland gate: DISPLAY is unset, so the application cannot silently pass by
using X11 or XWayland. Products supporting Linux should keep an equivalent
Wayland launch in their release matrix; see Linux display policy.
Rivet's own Ubuntu jobs run provisioning apt-get commands through
.github/scripts/apt-retry.sh. Each attempt is non-interactive, applies APT's
network and lock retries, and has a three-minute wall-clock limit; one fresh
attempt is allowed before the job fails. Product CI should use the same bounded
principle so a stalled package mirror cannot consume the whole native-build
budget. Package installation lifecycle tests themselves stay unwrapped because
their raw transaction outcome is the behavior under test.
The separate Native UI End-to-End workflow packages the maintained Taskboard
and drives its real WinUI 3, SwiftUI/AppKit, and GTK4 accessibility surfaces.
It covers activation, an RPC mutation, an Event, State rendering, and orderly
close while retaining bounded failure evidence. See
native UI end-to-end testing for the application-level
extension contract.
For a security-sensitive product, replace the action tag with the full commit
SHA for that tag and use the same commit in the package URL fragment. The action downloads the official minimal
Racket CS source archive, verifies its SHA-256, builds and caches the static
embedding runtime by version/OS/architecture, and exports
RIVET_RACKET_INCLUDE, RIVET_RACKET_LIB_DIR, RIVET_RACKET_LIBRARY, and
RIVET_RACKET_BOOT_DIR. Product workflows should not copy those discovery
rules.
For local Rivet development, a linked checkout remains appropriate. Pin that checkout and the setup action to the same revision in CI. A host compiled against one Rivet revision and released with another is not a useful gate.
Before pushing a tag, require all native-host jobs above and the product's Racket tests. The protected release job can then add production packaging, signing, notarization, update-manifest signing, and artifact publication. It should not be the first job that invokes the native compiler.
If the release workflow intentionally pins an older runner or Xcode image, keep that exact image in the pull-request matrix until the release environment is upgraded. Runner labels can change over time; parity with the product's actual release workflow is the contract.