Nightly snapshots¶
Every night the newest green commit on develop is built into the same binaries,
WebAssembly assets and Python distribution a release ships, plus the npm packages, and
published as the prerelease nightly-<yyyymmdd>-<commit>, kept for 14 days, with
nightly as the moving
alias of the newest night. The Python and Node clients built from the same commit go to PyPI
and npm as development versions. It is a development build: what a change looks like the day
it lands, before the next stable release
(latest, installed as described in
the install guide) carries it.
| Where | |
|---|---|
| The newest snapshot | github.com/Open-MBEE/OpenSysML/releases/tag/nightly — assets, the commit it was built from, and a line per unreleased changelog entry it contains |
| The last 14 nights | the releases page, one nightly-<yyyymmdd>-<commit> prerelease each |
| The Python client | PyPI, as opensysml <next>.dev<yyyymmdd> versions; pip install opensysml ignores them |
| The Node client | npm, as <next>-nightly.<yyyymmdd>.g<commit> versions under the nightly dist-tag; latest is the stable release |
| Whether last night's run passed | the badge above, and the workflow runs |
| What has landed since the last release | develop's changelog fragments, or the compare link in the release notes |
What a snapshot is¶
- Built from the newest green
developcommit. The workflow walksdevelop's own commits (its first-parent history, one per merged pull request) from the head and takes the first whose CircleCIbuild-testworkflow — the Go suite, the corpus gates and the client tests — passed. A red head is skipped, so a snapshot can be a few commits behinddevelop; the release notes name the commit and link the compare against the last stable tag. The walk ends at the commit the current snapshot was built from, so the snapshot never moves backwards, and a green commit that predatesscripts/build-release-artifacts.shorclient/python/scripts/snapshot_version.pyis skipped, since the workflow cannot build it. Snapshots built from commits predating the WASM build do not include WebAssembly assets. - Kept for 14 days, under two names. Each night publishes its own prerelease,
nightly-<yyyymmdd>-<commit>, and recreates the aliasnightlyat the same commit with the same assets. A link toreleases/tag/nightlyalways names the newest night; a link to an asset of a particular night is stable under that night's own tag until the workflow deletes it, tag and all, 14 days after it was published. The client packages pin the night they were built from by its own tag, so they keep working for those 14 days however many nights follow. A night on which no commit newer than the snapshot is green publishes nothing and the previous snapshot stands; the night the alias stands at is never deleted, however old. - Never the latest release. Every snapshot is a prerelease and is not marked latest, so
releases/latest,go install …@latest, the Homebrew tap and the Windows installer all keep following the stablev*line. On PyPI the snapshot is a development version, whichpip install opensysmlskips unless asked for it by exact version or with--pre; on npm it is published under thenightlydist-tag, andlateststays where the release left it. Maven Central and crates.io get no snapshot at all. Nothing on the stable release path changes because a snapshot exists. - Identified by its version. Every binary reports
nightly-<yyyymmdd>-<commit>from--version, with the commit and build time on the following lines, and the release title and tag carry the same string; the VS Code extension shows it after its own version. The clients report the development version of the release the snapshot leads to —0.9.3.dev20261006fromopensysml.__version__,0.9.3-nightly.20261006.gabc1234from the npm manifest — whose date and commit name the night. Quote it when reporting a problem.
What it contains¶
The assets are the ones a stable release ships, laid out the same way (see the release procedure's asset list):
opensysml-<os>-<arch>.tar.gz(.zipon Windows) —sysmlandsysml-lspunder their plain names, with their manual pages, for linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 and windows/amd64;sysml-<os>-<arch>.tar.gzandsysml-lsp-<os>-<arch>.tar.gz— each binary on its own;sysml-grpc-<os>-<arch>with a.sha256sidecar — the gRPC service, raw;wasm/sysml-wasm.wasmandwasm/wasm_exec.jswith.sha256sidecars — the combined WebAssembly module and matching Go runtime;opensysml-<version>-py3-none-any.whlandopensysml-<version>.tar.gz— the Python client, the same files published to PyPI, with that night'ssysml-grpcdigests pinned inside;SHA256SUMS.txtover all of the above and its cosign bundleSHA256SUMS.txt.bundle.
The nightly checksum manifest is cosign-signed; nightly assets do not have SLSA provenance, just like the other assets in the snapshot.
And one a stable release does not ship:
opensysml-sysml.vsix— the VS Code extension packaged from the same commit (asmake vscode-packagedoes). The extension is side-loaded rather than published to a marketplace, so the snapshot is where a build of it is picked up. Its version is the extension manifest's with the snapshot version appended as the pre-release part —0.9.0-nightly-<yyyymmdd>-<commit>— so VS Code tells one night's build from the next, installs a later night over an earlier one without--force, and ranks any stable0.9.0above them all. It is inSHA256SUMS.txtwith the rest.
The npm packages are not release assets: the seven tarballs go to the registry, where npm verifies them against the registry's integrity hashes and the provenance the workflow signs.
Not in a snapshot: the Windows installer, the Authenticode-signed Windows binaries, the Homebrew formula, and the Maven and crates.io client packages. Those belong to the stable release.
Installing one¶
The archives install like a release's: unpack opensysml-<os>-<arch> and put sysml and
sysml-lsp on your PATH. On macOS, Gatekeeper treats a snapshot exactly as it treats a
direct release download — fetch it with curl, not a browser, and see
macOS: Gatekeeper.
curl -fsSLO https://github.com/Open-MBEE/OpenSysML/releases/download/nightly/opensysml-linux-amd64.tar.gz
curl -fsSLO https://github.com/Open-MBEE/OpenSysML/releases/download/nightly/SHA256SUMS.txt
sha256sum -c --ignore-missing SHA256SUMS.txt
tar xzf opensysml-linux-amd64.tar.gz
./sysml --version
To hold on to a particular night, use its own tag in place of nightly in those URLs — the
version the binary prints is the tag.
The install script does the same for the platform it runs on, into a directory of your choosing:
curl -fsSL https://opensysml.org/install.sh | sh -s -- --version nightly --bin-dir ~/opensysml-nightly
Keep a snapshot beside your installed release rather than over it: the version string tells the two apart, and the release is the one to go back to when the snapshot breaks.
The extension installs from its .vsix and finds the snapshot's sysml-lsp on your PATH
or at the path opensysml.server.path names (a checkout's bin/sysml-lsp is found on its
own, see the editors guide):
curl -fsSLO https://github.com/Open-MBEE/OpenSysML/releases/download/nightly/opensysml-sysml.vsix
sha256sum -c --ignore-missing SHA256SUMS.txt
code --install-extension opensysml-sysml.vsix
VS Code installs a later night over an earlier one as an update. To go back to an earlier
night, or from a snapshot to a stable build of the extension whose version is lower, add
--force.
The client packages¶
The clients are versioned as development builds of the release develop is heading for:
the release segment of the version the tree declares
(client/python/opensysml/_version.py, matched by client/node/package.json), bumped to
the next patch once that release is tagged, with the night appended. With 0.9.2 released
and declared, the night of 2026-10-06 built from commit abc1234 is:
| Version | Install | |
|---|---|---|
| PyPI | 0.9.3.dev20261006 |
pip install opensysml==0.9.3.dev20261006 |
| npm | 0.9.3-nightly.20261006.gabc1234 |
npm install @openmbee/opensysml@nightly, or that exact version |
| GitHub | nightly-20261006-abc1234 |
the release both packages were built with |
Both package versions rank below 0.9.3 and any 0.9.3 release candidate, so the next
release supersedes every snapshot before it. pip install opensysml and
pip install --upgrade opensysml never select a development version — only an exact pin,
or --pre, does — and npm install @openmbee/opensysml installs latest, which no
snapshot moves. A PyPI version is immutable and the date is the version, so a day's first
snapshot of the Python client is the one PyPI keeps if the workflow is run again that day;
the npm version carries the commit, so a rerun publishes a new one under nightly.
Each package starts the sysml-grpc of its own night. The npm platform packages carry the
binaries, as they do for a release. The wheel pins the digests of that night's five
sysml-grpc assets under its nightly-<yyyymmdd>-<commit> tag, the same way a release's
wheel pins its release, so opensysml.connect() downloads and verifies the matching
service with no environment variables set — the pin, not the signed manifest, is what
admits it, since the nightly manifest is signed by the workflow's GitHub identity rather
than the CircleCI identity the client trusts for a release. That download stops working
when the night's release is deleted 14 days on; by then a newer snapshot exists, and a
sysml-grpc already cached stays in use. To pair an older snapshot of the client with
another service, put a sysml-grpc on your PATH or point OPENSYSML_BINARY at it, as
the service guide describes.
Snapshots of the clients are for trying what has landed, not for depending on: the next night's build may change behavior without a changelog entry, and a published snapshot is never republished or fixed in place. Pin the exact version in a lockfile only for as long as you mean to.
Verifying one¶
SHA256SUMS.txt is signed keylessly with cosign by the workflow that built the snapshot, so
a download can be checked back to that run. The identity is the workflow file on develop,
not the CircleCI identity a stable release is signed with:
cosign verify-blob SHA256SUMS.txt --bundle SHA256SUMS.txt.bundle \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity https://github.com/Open-MBEE/OpenSysML/.github/workflows/nightly.yml@refs/heads/develop
sha256sum -c --ignore-missing SHA256SUMS.txt
The wheel and sdist on PyPI are the files in that manifest, so a downloaded wheel checks the
same way. The npm packages carry provenance attestations signed from the same workflow run,
which npm audit signatures verifies.
What to expect¶
A snapshot passed the same suite a release does before it was built, but it has not been
through the pre-tag gate:
no performance record, no recount of the figures a release quotes, no adjudication of what
moved. Behavior can change between nights without a changelog entry until the fragment for it
lands, and a snapshot may carry a defect the next night's build fixes. Report one as an issue naming
the nightly-… version it printed; a snapshot never becomes a release, so nothing is
re-published under its name.
How it is produced¶
.github/workflows/nightly.yml
runs at 03:23 UTC and on demand (workflow_dispatch, with a force input that publishes
the same commit again as a new night, under today's date — for instance after the workflow
itself changed). A night already published, the same commit under the same date, is never
rebuilt, forced or not: the packages on PyPI and npm pin the digests of its binaries, which
a rebuild would not reproduce byte for byte, so the run publishes nothing. To retry a
night's PyPI or npm publication, re-run the failed jobs of the run that published it; they
republish the distributions that run kept. The workflow picks the commit as described
above and, in one job, derives the versions with the commit's own
client/python/scripts/snapshot_version.py
and stamps them into the checkout's _version.py and package.json (nothing is
committed); builds the assets with
scripts/build-release-artifacts.sh
— the same targets, platforms, layout and version check as the CircleCI build-release
job; packages the VS Code extension with its own npm run package stamped with the
snapshot version (not through the Makefile, which the older selected commit may lack the
knob for) and checks the .vsix carries it; pins the digests of the sysml-grpc binaries
it just built under the night's tag in the wheel's table with
pin_release_checksums.py --from-binaries, builds the wheel and sdist, and checks the
installed wheel reports the snapshot version, names the night's release as the one it was
built against and pins all five digests, as the release pipeline checks a release's wheel;
builds the platform and WASM packages from the same binaries and packs all seven npm
tarballs; signs the manifest, which now lists the wheel, with its own GitHub OIDC
identity; keeps the wheel, sdist and tarballs as workflow artifacts; and publishes the
per-night release with the repository's own GITHUB_TOKEN. A second job recreates the
alias at the same commit from the night's own assets, title and notes, then deletes the
per-night releases published more than 14 days ago. Two further jobs, each in the nightly GitHub
environment, publish the wheel and sdist to PyPI with
pypa/gh-action-pypi-publish and the
seven tarballs to npm under the nightly dist-tag — platform and WASM packages first, the
client last, as the release does — and check afterwards that latest still names the
stable release. Both skip a version the registry already has rather than fail, since a
version can never be replaced. The release notes are generated: the commit, the count since
the last v* tag, the install lines for the packages, the verification commands, and one
line per unreleased changelog entry (python3 scripts/changelog.py summary) — the lead
sentence of each changes/unreleased/ fragment as it stands at that commit.
There is no secret to configure. The releases are made with the repository's GITHUB_TOKEN,
and both registries accept the workflow's short-lived OIDC token through trusted publishing,
registered once by a maintainer:
- PyPI — in the
opensysmlproject's publishing settings, add a GitHub Actions publisher with ownerOpen-MBEE, repositoryOpenSysML, workflownightly.ymland environmentnightly. The stable release keeps publishing from CircleCI with its token; the two coexist. - npm — for each of
@openmbee/opensysml, the five@openmbee/opensysml-sysml-grpc-*packages and@openmbee/opensysml-wasm, open the package's settings on npmjs.com, choose GitHub Actions under Trusted Publisher, and enter organizationOpen-MBEE, repositoryOpenSysML, workflow filenamenightly.ymland environmentnightly. A package configured for trusted publishing still accepts the release's token publish from CircleCI. - GitHub — the
nightlyenvironment is created on the workflow's first run; nothing need be added to it. Protection rules on it (required reviewers, a wait timer) gate the two registry jobs without affecting the GitHub release.
Until a publisher is registered, its job fails with the registry's authentication error and nothing else changes: the release is already published by then, and the other registry's job runs on its own.
The nightly and nightly-<yyyymmdd>-<commit> tags are the only tags that are not versions.
The Makefile's default VERSION describes a checkout against v* tags only, so a fetched
snapshot tag does not turn a local build's version into nightly-…, and neither the CircleCI
release workflow (tags v*) nor the Windows signing workflow reacts to one.