Release process

vibe-sketcher is independently versioned. Changes land on main through the process in AGENTS.md. Released tags are immutable: do not rewrite published history or move a release tag to repair documentation or packaging metadata.

Contributor evidence

A change needs the relevant tests, with the commands named in the commit message. Record a user-visible change as a changelog fragment, one file per change: changelog.d/<slug>.<type>.md, where <type> is added, changed, deprecated, removed, fixed or security and the text is one paragraph in the user’s words. Fragments never conflict between parallel changes, which a shared [Unreleased] section did. They are folded into CHANGELOG.md when a release is cut (step 3 below).

Release checklist

The maintainer approved the release sequence and names through 1.0 in the roadmap and codename plan. The latest published release is 0.6.0 — Negishi’s Funnel, at immutable tag v0.6.0 and source df9a478c30181fe115663d1daa2272bf6f362f4d (2026-10-25). Final candidate CI, installed macOS ARM64/Linux x86-64 qualification, original-result campaign acceptance and independent replay passed under #42, #66 and #109. The roadmap release record links the public downloads and scientific data and states the retained review/signing limits.

The 0.4 and 0.5 gates (#84 and #89) are also complete. Version 0.7 remains unreleased: later source changes and feature acceptance do not qualify a new package. Scope and codename approval alone do not authorize publication. Preserve every historical candidate and published software artifact. Keep local qualification builds separate from published artifacts, even when they still carry the previous development version. Never upload those bytes under an existing release’s filename.

The version and catalogue changes below land in one commit on a release-candidate/vX.Y.Z branch taken from the selected main commit. Record included changes and unfinished later-milestone capabilities honestly; features merged ahead of schedule do not establish their milestone’s acceptance. tests/test_version.py and tests/test_codenames.py fail if any version surfaces disagree. Qualification must identify the exact candidate and package bytes; a previous build’s evidence is not inherited after a source change.

  1. Version. Set X.Y.Z in each of these files:

    • pyproject.toml: version.

    • src/vibesketch/__init__.py: __version__, and the codename in its trailing comment.

    • web/package.json: version.

    • web/package-lock.json: both version entries, the top-level one and the one under packages[""].

    • electron/package.json: version.

    • electron/package-lock.json: both version entries, the top-level one and the one under packages[""].

  2. Codename. When a release starts a new name, add its X.Y.Z entry to RELEASE_CODENAMES in src/vibesketch/codenames.py with its rationale comment, set FALLBACK_CODENAME in electron/main.js, and add the row to the catalogue table in the codename catalogue. Later patches inherit the most recent named version in the same minor line. For 0.1.2, retain 0.1.0: Couper's Coati for the historical 0.1.0/0.1.1 candidates and add 0.1.2: Dötz’s Flask; do not alter their published artifacts.

  3. Changelog fragments. Run python scripts/fold_changelog.py. It moves every changelog.d/ fragment into ## [Unreleased] under its ### heading and deletes the fragment files. Edit the folded entries into release notes if they need it.

  4. Changelog heading. Rename ## [Unreleased] to ## [vX.Y.Z] - YYYY-MM-DD - *Codename* and add a new empty ## [Unreleased] above it.

  5. Local proof. Run ruff check ., ruff format --check ., mypy, the test suite, npm ci && npm run check && npm run build in web/, and make strict in docs/. Use CI’s pinned QVF corpus and require the browser tests. Complete the real-program and packaged-desktop acceptance checks for the candidate. On the reference machine, re-measure the corpus with python scripts/benchmark.py --browser --output perf.json and check it with python scripts/benchmark.py --check perf.json; an exceeded budget blocks the release (performance budgets). Keep the record with the release evidence, outside this repository.

  6. Candidate pipeline. Push the release-candidate/vX.Y.Z branch. Its pipeline runs every gate job, builds the docs strictly, and retains reproducible wheel/source artifacts with checksums. Plain topic branches and main pushes or merge requests do not run full CI. Run focused owner checks for development; candidate refs run the complete gate once. Browser-marked tests run only in the Chromium job. Documentation builds start immediately rather than waiting for unrelated test jobs.

  7. Tag and publish. When the candidate pipeline is green, tag vX.Y.Z at the candidate commit and fast-forward release onto it. The release pipeline builds the documentation for publication without repeating the gate. Site-specific publication steps live in the private operations repository, never here.

Build and validate distributions

From a clean candidate checkout with its development environment active:

python -m pip install -e '.[release]'
(cd web && npm ci && npm run check && npm run build)
python scripts/build_release_artifacts.py --output-dir dist/release

The web build records hashes of its inputs and complete output tree. The release builder refuses stale or missing assets, notices, the reviewed WASM or its corresponding source. Wheels include the browser and document schema; source archives include the built browser and the files needed to rebuild it. No Node.js or checkout is needed to serve an installed wheel.

The builder uses the candidate commit time as SOURCE_DATE_EPOCH (an explicit environment value overrides it). It builds a wheel and source archive twice, normalises source-archive owner/time metadata, and compares their bytes. Metadata, payloads, wheel RECORD hashes and twine check must pass. It then installs the wheel into a fresh virtual environment outside the checkout, checks the CLI, serves its packaged UI/WASM/notices/schema, and imports and exports a molecule through REST. Only then are the artifacts and SHA256SUMS written to the requested output directory. Build and validation failures leave existing outputs untouched; operators must treat a nonzero exit as a failed candidate.

scripts/make_wheel.sh runs those checks and also stages the wheel in docs/_static/downloads/. Select its interpreter with VIBESKETCH_RELEASE_PYTHON if necessary. It refuses changed bytes at an already-staged version and retains older versioned wheels. Generated artifacts are ignored by Git; transfer the qualified candidate artifacts through the operator publication process. Never replace a published wheel or installer with different bytes under the same version.

Desktop and hosting

Build native desktop artifacts with electron/build-desktop.sh; use --dir for an unpacked test. The macOS Apple Silicon package bundles Electron, Python, RDKit, QVF and the approved PNG/PDF backend, together with their notices and required source archives. It uses ad-hoc signing without notarization. Linux x86-64 runtime and AppImage builds are implemented, but their platform acceptance is separate from macOS qualification. Windows does not yet have a bundled runtime; do not advertise it as a qualified self-contained package.

Follow packaged macOS acceptance on both the unpacked app and a separately installed copy from the candidate’s installer. Confirm offline launch with no development environment, scene SVG/PNG/PDF export, embedded PDF fonts, PNG dimensions and DPI, QVF reopen, file safety, notices and backend shutdown. Record unobserved checks as pending. Source-launcher onboarding and successful runtime builds are separate evidence.

The approved public locations are:

  • Documentation: https://vibyverse.com/vibe-sketcher/docs/.

  • Wheels: https://vibyverse.com/vibe-sketcher/docs/_static/downloads/vibesketch-X.Y.Z-py3-none-any.whl.

  • Desktop update feed: https://vibe-qc.com/updates/vibe-sketch/.

Before publishing the desktop update manifest, publish and verify the matching wheel and installers with their checksums. Keep previous wheel URLs available for older desktop bootstrap and repair commands. Test a downloaded installer, offline bundled-runtime startup, file open/save, notices and server shutdown using the packaged-app acceptance procedure. Desktop delivery issues #9 and #11–#14 were completed for the initial release. Each later candidate repeats its affected checks and meets the exit criteria of its approved roadmap milestone.

Building and staging do not upload anything. Credentials, deployment targets and operational evidence remain in private operator tooling. The release version and actual publication remain explicit maintainer decisions.

Refresh tutorial illustrations

The manual’s screenshots come from the real served app, using public sample chemistry and a fresh browser profile. After building web/, install the optional browser tooling and capture them from the checkout root:

python -m pip install -e '.[browser]'
python -m playwright install chromium
python scripts/capture_doc_screenshots.py
make -C docs strict

The capture script starts and stops its own local server, uses temporary app and queue state, and exercises the illustrated import, embedding and input download. It does not submit jobs. --output-dir selects another directory for comparison. Inspect every image and the rendered tutorial pages before committing changed screenshots; keep local paths, hostnames and personal documents out of the images. Re-run the downloadable examples when their API calls or commands change.

The reaction-to-publication tutorial has a separate capture workflow:

python scripts/capture_reaction_tutorial.py

It draws the hydrogenation using the visible ring, bond, atom, arrow and text tools; verifies the species and reaction roles; exports SVG; embeds the three geometries; and checks the downloaded vibe-qc scripts. By default it isolates queue state and submits nothing. It refreshes the drawing and Inputs images and the pristine downloadable VSK/SVG in docs/_static.

To refresh the completed Calculations image too, first configure a separate local queue with a working vibeqc program and start its daemon as in the tutorial. Then run the capture in that environment with explicit submission enabled:

python scripts/capture_reaction_tutorial.py --submit

This submits three real single points, waits up to ten minutes for successful completion, captures their states and verifies that saving retains the run records. A timeout does not cancel the queued jobs: follow them with vq before deciding whether to retry. Retrieve and inspect their output/QVF files using the tutorial commands, then stop the temporary daemon. Keep execution evidence in the issue tracker; commit only the public example chemistry and reviewed screenshots. --output-dir redirects all capture artifacts for comparison. Build the manual strictly and inspect the light/dark and narrow page layouts after refreshing it.

The full feature catalogue has its own generator and capture command:

python docs/_static/examples/named_reactions.py tutorial-examples
python scripts/capture_feature_tutorials.py --examples tutorial-examples

This verifies the named-reaction documents, publication downloads, geometry, writer refusals and the downloadable REST/MCP clients against the real app. It submits no calculations. To capture existing completed and cancelled test runs, pass --queue-server URL --completed-document ID --cancelled-document ID using the actual server document ids from the queue lifecycle example. The native desktop illustrations are captured separately from the packaged candidate during desktop acceptance. Review every image, refresh the downloadable archive after changing its scripts, and run the strict documentation build before publication.

Platform packages

See distribution builds for Linux supporter packages and paid Apple/Microsoft Store editions, runtime requirements and channel acceptance.