Installation

vibe-qc is a Python package with a C++ core. The C++ core links against libint (Gaussian integrals), libxc (XC functionals), spglib (crystal symmetry), FFTW3 (Ewald long-range Hartree), libecpint (effective-core potentials), plus a pinned snapshot of pugixml + libcerf inside libecpint’s tree, and an optimised BLAS + LAPACK (Apple Accelerate on macOS, OpenBLAS / MKL on Linux) that Eigen delegates dense linear algebra to — see BLAS backend below.

Note

vibe-qc is not on PyPI yet. There is no pip install vibe-qc. The install path is: clone the repo, install your platform’s build prerequisites, run ./scripts/setup_native_deps.sh to fetch and build the vendored native libraries, then pip install -e . inside a virtualenv. The full recipe is below.

See also

Once installation is done, good practices covers the working conventions for actually using vibe-qc — where to put your calculations (hint: not inside the source tree), naming, reproducibility, performance hygiene, and what to try when SCF diverges. Worth a five-minute read before your first production run.

All native dependencies are vendored. scripts/setup_native_deps.sh fetches each one from upstream, configures it the way vibe-qc needs (e.g. libint with max_am=5 + 1st derivatives), builds, and installs into third_party/<name>/install/. Vendoring eliminates the “which version of libxc / spglib / FFTW does this distro happen to ship?” failure mode — every checkout produces an identical native ABI.

Each fetched tarball / git tag is verified against a pinned SHA-256 / commit SHA before use (see the per-script comment blocks in scripts/build_*.sh for the resolved values and the re-resolve recipe), so a moved upstream tag or a network-level tamper fails loudly rather than silently changing what vibe-qc links against.

If a third_party/<dep>/install/ is missing, the top-level CMake configure silently falls back to system discovery for that one dependency. That is convenient for development, but it weakens the vendored-ABI guarantee. CI and release builds that need the guarantee should set VIBEQC_REQUIRE_VENDORED (either -DVIBEQC_REQUIRE_VENDORED=ON at configure time or the matching env var), which turns the fallback into a hard error for the five always- vendored deps (libint, libxc, spglib, fftw, libecpint). OpenBLAS is opt-in (WITH_OPENBLAS=1) and stays excluded from the strict check.

Requirements

System tools the build needs:

  • Python ≥ 3.11 (3.11–3.14 all work; 3.14 is what the macOS install recipe below uses). On macOS, Apple’s stock /usr/bin/python3 is currently 3.9 and is too old — install Homebrew’s python@3.14 and make sure it wins on PATH (see the macOS section below).

  • C++17 compiler — AppleClang 13+, GCC 10+, Clang 13+

  • CMake ≥ 3.20 and Ninja

  • git, make, curl, tar, pkg-config

  • OpenMP — comes with GCC / Clang on Linux; on macOS it’s libomp from Homebrew (AppleClang ships without OpenMP support and several vendored deps hard-require it).

  • An optimised BLAS + LAPACK — Apple Accelerate ships with macOS; on Linux install OpenBLAS or MKL (system package or vendor it via WITH_OPENBLAS=1, see BLAS). Reference netlib BLAS is functional but slow and not recommended.

Plus three small system libraries that libint’s code generator uses during its own build (we deliberately don’t vendor these — GMP has arch-specific assembly, and Boost / Eigen are header-only and on every distro):

  • Eigen (3.4+ or 5.0+) — header-only. Both major versions work; libint 2.13.1’s bundled CMake module handles either header layout. As of mid-2026, Homebrew’s eigen formula and Arch’s eigen package are both 5.0.x — that’s the version vibe-qc builds against on macbook + planetx today. Debian/Ubuntu still ship libeigen3-dev 3.4.x, which also works fine.

  • Boost — header-only

  • GMP with C++ bindings (gmpxx)

scripts/setup_native_deps.sh runs a preflight check that verifies every one of the above is present before it starts building anything, and prints the exact per-distro install command for whatever is missing. If you’ve never installed vibe-qc on a given machine before, just run the script — it will tell you what to brew install / pacman -S / apt install first.

Python deps (pybind11, scikit-build-core, numpy, pytest, pyscf, ase) come in through pip from pyproject.toml automatically.

One-shot bootstrap

After installing the system tools below, the easiest path on every platform is:

git clone https://gitlab.peintinger.com/mpei/vibeqc.git
cd vibeqc
./scripts/install.sh                  # preflight → native deps → venv → pip install → banner

install.sh drives the full bootstrap and prints the banner so you can confirm the C++ extension loaded. It accepts the same branch / extras / venv flags as update.sh:

./scripts/install.sh --dev                        # bleeding-edge main
./scripts/install.sh --branch basissetdev         # paper-writing branch
./scripts/install.sh --branch v0.9.0              # pin to a tag
./scripts/install.sh --extras dev                 # tests + dispersion + py-spy
./scripts/install.sh --python python3.13          # force a specific interpreter
./scripts/install.sh --venv .venv-bsd --branch basissetdev   # side-by-side per branch
./scripts/install.sh --with-openblas              # vendor OpenBLAS
./scripts/install.sh --force                      # overwrite an existing .venv

install.sh --help prints the full surface. Internally it calls the same setup_native_deps.sh + pip install -e you’d run by hand — the wrapper just handles the branch checkout, venv creation, pip self-upgrade, and banner verification in one shot.

Note

Worktree-private venvs. If you keep multiple checkouts (one per branch you actively develop on), run install.sh inside each checkout so each gets its own .venv pinned to that checkout’s third_party/ trees. Never share a venv across checkouts — the editable pip install pins the C++ extension to one specific third_party/ tree, and a venv from a different checkout will load the wrong native libraries.

Manual bootstrap

If you’d rather invoke the steps by hand (e.g. on a stripped-down machine, or to integrate with your own provisioning):

git clone https://gitlab.peintinger.com/mpei/vibeqc.git
cd vibeqc
./scripts/setup_native_deps.sh       # preflight → 15–40 min build, idempotent
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/pip install -e '.[test]'

setup_native_deps.sh first runs the preflight check (a few seconds) that verifies every build prerequisite is present. If anything is missing it bails with a copy-pasteable per-distro install command; if everything is present it proceeds straight into the vendored builds.

git clone lands you on release (the project’s default branch), which is the latest tagged release. The banner reads Release vX.Y.Z to match the tag. For active development on main instead, add git checkout main after the clone — main is the higher X.Y.dev0 development version and rebuilds with every push. Pin to a specific tag (git checkout v0.4.6) for fully reproducible calculations.

setup_native_deps.sh calls (in order):

  1. build_libint.sh — libint 2.13.1

  2. build_libxc.sh — libxc 7.0.0

  3. build_spglib.sh — spglib 2.7.0

  4. build_fftw.sh — FFTW3 3.3.10

  5. build_libecpint.sh — libecpint + pugixml + libcerf

  6. setup_basis_library.sh — populate python/vibeqc/basis_library/basis/ from libint’s standard set plus our custom additions

After the build, setup_native_deps.sh probes which BLAS the system has and prints a tip if it would benefit from an upgrade. See BLAS backend below.

Each per-dep script is idempotent — re-running after an interrupted build, or after a git pull that changes only one of them, only rebuilds what’s needed.

BLAS backend

vibe-qc’s C++ core uses Eigen for dense linear algebra. At build time, CMake links Eigen against whatever optimised BLAS+LAPACK is available so dense matrix products, eigendecompositions, and Cholesky factorisations delegate to it (EIGEN_USE_BLAS / EIGEN_USE_LAPACKE). Without an optimised BLAS, Eigen’s generic-C++ kernels run instead — correct, but several × slower at SCF size. The print-banner’s linked: line carries the chosen backend (blas Accelerate, blas OpenBLAS, etc.) so a persisted SCF log records which BLAS produced the calculation.

Backend selection happens automatically:

  • macOS: Apple Accelerate (system framework, no install needed).

  • Linux: system OpenBLAS / MKL / netlib BLAS via CMake’s FindBLAS auto-detect.

  • All platforms (opt-in): a vendored OpenBLAS built into third_party/openblas/install/ — see below.

To install an optimised BLAS via your system package manager (simpler, lighter):

  • Arch / Manjaro: sudo pacman -S blas-openblas

  • Debian / Ubuntu: sudo apt install libopenblas-dev liblapacke-dev

  • Fedora / RHEL: sudo dnf install openblas-devel lapack-devel

  • macOS: nothing — Accelerate already provides what we need.

To vendor OpenBLAS into the checkout (no sudo needed, useful for HPC / locked-down workstations / CI reproducibility, needs a Fortran compiler):

WITH_OPENBLAS=1 ./scripts/setup_native_deps.sh

This invokes scripts/build_openblas.sh which clones OpenBLAS 0.3.33 from upstream, builds it with DYNAMIC_ARCH=1 (runtime CPU detection), USE_LAPACK=1 USE_LAPACKE=1 (bundles LAPACK + LAPACKE into libopenblas.so), and installs into third_party/openblas/install/. The next pip install -e . picks up the vendored install automatically (CMake’s find_package(BLAS BLA_VENDOR=OpenBLAS) resolves it via CMAKE_PREFIX_PATH), with the banner reading linked: ... · blas OpenBLAS +LAPACKE.

To disable BLAS linkage entirely and force Eigen’s generic kernels (mainly for debugging numerical issues), pass -DVIBEQC_USE_BLAS=OFF to the vibe-qc CMake configure.

See user_guide/blas for the full surface: how to read the linkage off the banner, the threading model, when the vendored path is worth it (and when it isn’t), and a candid note on which perf problems BLAS linkage does not solve.

Per-platform: install the system tools

These are the commands the preflight check in ./scripts/setup_native_deps.sh will print if anything is missing on your box. You can run them up-front or wait for the preflight to point out what to install — either path lands at the same place.

macOS (Homebrew)

brew install cmake ninja pkg-config libomp boost eigen gmp git python@3.14
# Optional but recommended for the OpenBLAS escape hatch:
brew install gcc                                   # provides gfortran

No separate BLAS package — Apple Accelerate ships with macOS and is what Eigen links against. The preflight check will confirm Accelerate is reachable and tell you if the framework is somehow missing (extremely unusual; happens on stripped-down corporate images).

Note

Homebrew’s eigen formula is currently Eigen 5.0.1 — that’s expected and fine. libint 2.13.1 (vendored under third_party/libint/) ships a CMake module that handles both the Eigen 3 and Eigen 5 header layouts, so vibe-qc builds cleanly against the brew install with no path-mangling on your end. If brew info eigen shows you 5.x and you’ve seen guidance elsewhere warning to pin Eigen 3, ignore it — that guidance is stale.

If Homebrew isn’t installed yet, install it first (/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)") — the preflight check will detect its absence and refuse to start.

Python on macOS. Apple’s stock /usr/bin/python3 is currently Python 3.9 (the Xcode Command Line Tools stub) and does not meet vibe-qc’s ≥3.11 minimum. Homebrew’s python@3.14 is the recommended runtime — the brew install line above pulls it in.

After installing, make sure python3 on your $PATH resolves to the new install rather than Apple’s stub. The canonical Homebrew shell setup does this — verify and persist it once per shell:

eval "$(/opt/homebrew/bin/brew shellenv)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zshrc

Then check:

python3 --version       # expect 3.14.x (or whichever brew installed)
which python3           # expect /opt/homebrew/bin/python3

If python3 --version still shows 3.9.x, Homebrew’s bin isn’t winning on PATH — force the symlink:

brew link --overwrite --force python@3.14

The preflight in setup_native_deps.sh catches the stale-Apple- python case explicitly so you’ll get a clear error rather than a cryptic CMake or pybind11 failure later.

Apple Silicon note. Homebrew lives at /opt/homebrew on ARM Macs. vibe-qc’s CMake configuration runs brew --prefix and adds that to CMAKE_PREFIX_PATH automatically, so no manual path setup is needed.

libomp is not optional on macOS. AppleClang ships without OpenMP support, and several vendored deps (spglib in particular) hard-require it. brew install libomp puts the headers + library at $(brew --prefix libomp); vibe-qc’s setup_native_deps.sh auto-detects this on main (commit 973c8f3 and later). On older release branches that pre-date the auto-detect, also export the hint env var before running setup_native_deps.sh / scripts/update.sh:

export OpenMP_ROOT=$(brew --prefix libomp)

Add it to ~/.zshrc if you want it to persist across sessions. Without it, CMake’s FindOpenMP errors out with Could NOT find OpenMP_C (missing: OpenMP_C_FLAGS OpenMP_C_LIB_NAMES) and the spglib configure stops there.

Linux — Arch / Manjaro

sudo pacman -S base-devel cmake ninja pkg-config git curl \
    gmp eigen boost python blas-openblas
# Optional but recommended for the OpenBLAS escape hatch:
sudo pacman -S gcc-fortran

base-devel is the meta-group that carries gcc/g++/make/binutils. python on Arch is 3.13+ as of mid-2026 and bundles pip and the venv module out of the box — no separate python-pip / python-virtualenv needed. curl is used by setup_native_deps.sh to fetch libint / libxc / spglib / FFTW / libecpint tarballs.

blas-openblas is the OpenBLAS+LAPACK package; without an optimised BLAS, Eigen’s generic-C++ kernels run at SCF size and you lose a multiple-× of performance. The default Arch BLAS slot ships as reference netlib BLAS, which is functional but doesn’t beat Eigen-generic — blas-openblas is the right pick.

Note

Arch’s eigen package is currently version 5.0.1. This works fine — libint 2.13.1 (which we vendor in third_party/libint/) shipped a CMake module that handles both the Eigen 3 and Eigen 5 header layouts. Arch keeps Eigen 5’s headers under /usr/include/eigen3/ for backward compatibility with dependent packages, so no path-mangling is needed on your end.

If you previously installed the AUR eigen3 (3.4.x) package as a workaround, you can safely switch back to the standard eigenyay -S eigen and accept the conflict prompt.

If you’d rather not install anything system-wide, an AUR helper like yay or paru works the same way:

yay -S base-devel cmake ninja pkg-config git curl \
    gmp eigen boost python blas-openblas

If you need a specific Python version that differs from Arch’s rolling-release default, pyenv (yay -S pyenv) builds an isolated interpreter under ~/.pyenv without touching the system Python.

Linux — Debian / Ubuntu

sudo apt update
sudo apt install \
    build-essential cmake ninja-build pkg-config git curl \
    libeigen3-dev libboost-dev libgmp-dev libgmpxx4ldbl \
    libopenblas-dev liblapacke-dev \
    python3 python3-dev python3-venv
# Optional but recommended for the OpenBLAS escape hatch:
sudo apt install gfortran

libopenblas-dev brings the BLAS+LAPACK Eigen wants; liblapacke-dev adds the C interface so Eigen’s dense solvers (LLT, SelfAdjointEigenSolver, …) also delegate.

Linux — Fedora / RHEL

sudo dnf install \
    @development-tools cmake ninja-build pkgconfig git curl \
    eigen3-devel boost-devel gmp-devel gmp-c++ \
    openblas-devel lapack-devel \
    python3 python3-devel
# Optional but recommended for the OpenBLAS escape hatch:
sudo dnf install gcc-gfortran

What each step does

Step

Purpose

OS-package install

C++ compiler, CMake/Ninja, plus the headers libint’s code generator needs at build time (Boost, Eigen, GMP) and the BLAS+LAPACK Eigen delegates dense linear algebra to.

setup_native_deps.sh

Fetches and builds libint, libxc, spglib, FFTW3, libecpint into third_party/<dep>/install/. Each dep short-circuits silently if already built.

setup_basis_library.sh

Copies libint’s 90 standard .g94 basis files plus anything in basis_library/custom/ into python/vibeqc/basis_library/basis/. The bundled basis library ships inside the Python package so a stock pip install gets every basis set without the user setting LIBINT_DATA_PATH.

python3 -m venv .venv

Isolates vibe-qc from your system Python.

pip install -e '.[test]'

Drives CMake via scikit-build-core, picks up the vendored libs from third_party/, compiles the pybind11 module, installs in editable mode plus test deps (pyscf, ase, dftd3).

Verifying

.venv/bin/python -c "import vibeqc; vibeqc.print_banner()"

Should print a labeled box with vibe-qc’s version, the build’s git provenance, and every linked native library:

╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Release v0.11.0 "Sun's Stingray"  —  Quantum chemistry for molecules and solids                                           ║
║ © Michael F. Peintinger · MPL 2.0  ·  https://vibe-qc.com                                                                 ║
║ linked: libint 2.13.1 · libxc 7.0.0 · spglib 2.7.0 · libecpint 1.0.7 (vendored, MAX_L=5) · fftw3 3.3.10 · blas Accelerate ║
╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝

When the optional [dispersion] extra is installed (pip install -e '.[dispersion]'), the banner gains a second linkage line listing the dftd3 and dftd4 PyPI-wheel versions whose bundled binary libraries vibe-qc loads at runtime:

║ linked: libint 2.13.1 · libxc 7.0.0 · spglib 2.7.0 · libecpint 1.0.7 (vendored, MAX_L=5) · fftw3 3.3.10 · blas Accelerate ║
║ dispersion: dftd3 1.4.0 · dftd4 4.2.0                                                                                     ║

If you cloned from `main` instead of `release`, the first line
reads `dev X.Y.Z.devN (main @ <sha>)` (with a ``dirty`` flag if the
working tree has uncommitted changes). The exact
``libint`` / ``libxc`` / ``spglib`` / ``libecpint`` / ``fftw3``
versions match what ``setup_native_deps.sh`` vendored
(``libecpint`` annotates its bundled angular-momentum cutoff
``MAX_L=5`` so a build can be matched to a ``MAX_L`` mismatch at a
glance). The trailing ``blas …`` field records which BLAS backend
Eigen got linked against — `Accelerate` on macOS, `OpenBLAS
+LAPACKE` for an optimised Linux install, etc. See
[BLAS](#blas-backend) for the full label table. The banner
exercises the C++ extension under the hood (each linked library
reports its own version through the pybind11 module), so seeing it
is proof both that the Python side imports and that the native
side loaded.

If even that crashes, fall back to the minimal smoke test that
isolates the C++ extension load from anything else:

```sh
.venv/bin/python -c "import vibeqc; print(vibeqc.hello())"
# vibeqc core alive

Then run the regression suite:

.venv/bin/python -m pytest tests/

855+ tests should pass in about two minutes on a recent machine (the count grows with each phase).

Optional terminal viewer (MolTUI)

Vibe-qc writes Molden files by default for any calculation that calls run_job(...). Those files render in any of Avogadro, Jmol, VMD, PyMOL, Molden, or ChimeraX — but if you’d rather inspect orbitals inline in the terminal (handy on a remote SSH session, or when you’re iterating fast), MolTUI is the right tool. Pure Python; renders geometries, orbitals, and normal modes via Unicode block characters.

Two ways to install it alongside vibe-qc:

1. As a vibe-qc extra — single command, captures the dependency in your install record:

.venv/bin/pip install '.[viewer]'           # from the repo checkout

(pip install 'vibe-qc[viewer]' will become the right command once vibe-qc lands on PyPI — not yet.)

2. Interactive script — run any time after the venv is set up; re-runnable, asks before installing each tool:

./scripts/install_optional_tools.sh
# → "Install moltui? [Y/n]"

Pass --yes for non-interactive (CI / Docker) use, or a tool name to install just that one (./scripts/install_optional_tools.sh moltui).

After install:

.venv/bin/python water.py                       # produces water.molden
.venv/bin/moltui water.molden                   # render in the terminal

MolTUI also supports .cube (vibe-qc’s grid output), .fchk, .xyz, .gbw (ORCA), and .hess (ORCA normal modes), so the same install lets you view files from external codes too.

Common issues

“Preflight: the following build prerequisites are missing” setup_native_deps.sh aborts upfront if a build tool / header / library it needs isn’t on the box. The message names every missing item and ends with the exact per-distro install command — copy it, run it, re-run ./scripts/setup_native_deps.sh. The check runs at the very top of the script so you never end up halfway through a libint build before discovering pkg-config was missing.

Set VIBEQC_SKIP_PREFLIGHT=1 only if you know the message is a false positive (e.g. a custom-prefix install the heuristic doesn’t find); the underlying CMake errors are much less actionable.

“python ≥3.11 on PATH (found python3 = 3.9 — likely Apple’s stub)” You’re on macOS and /usr/bin/python3 wins over Homebrew’s install. Fix:

brew install python@3.14                            # if not already
eval "$(/opt/homebrew/bin/brew shellenv)"            # current shell
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zshrc  # persist
brew link --overwrite --force python@3.14           # if still not first
python3 --version                                    # confirm 3.14.x

The preflight detects this case explicitly because the Apple stub silently breaks the venv-and-pip step later with a much less obvious message.

./scripts/build_libint.sh: line N: brew: command not found You’re on Linux but the script tried the macOS path. This was fixed in 0.1.0+; pull main and re-run. The script now sniffs uname -s and uses the right toolchain per platform.

“Could not find Libint2 / Libxc / Spglib / FFTW3” CMake didn’t find one of the vendored installs. The most common cause is that setup_native_deps.sh was interrupted partway through. Re-running it is safe — finished deps short-circuit, only the unfinished one rebuilds.

If you genuinely want to point at a system install instead of the vendored one, simply don’t run that dep’s build script. CMake silently falls through to system discovery if third_party/<dep>/install/ is absent.

“error: externally-managed-environment” on macOS You’re trying to pip install against Homebrew’s system Python. PEP 668 blocks this; always use a virtualenv:

python3 -m venv .venv && .venv/bin/pip install -e '.[test]'

libint build is slow The libint code generator produces a large amount of source for max_am=5 plus first derivatives (several thousand files). The compile phase uses Ninja which parallelizes; expect 10–30 min on a modern 8-core machine, longer on Mac minis / small VMs.

On Linux the install scripts automatically cap parallelism to prevent the OOM-kill pattern that hung planetx on 2026-05-16. The cap is min(nproc, max(2, mem_mb // 15000), 8) — 15 GB/worker budget, hard ceiling of 8 even on monster boxes. Concretely:

Host (Linux)

nproc

RAM

parallelism

planetx (32 th, 125 GB)

32

125 GB

8

mars (16 th, 62 GB)

16

62 GB

4

small VM (4 th, 16 GB)

4

16 GB

2

The same scripts also self-re-exec under nice -n 19 ionice -c 3 on Linux so the build runs at idle CPU + IO priority — the box stays responsive while compiling. The mechanism is in scripts/_safe_build_env.sh (sourced by every entry-point script that triggers heavy compilation).

To override either side-effect:

# Pin parallelism to a specific value (skips the formula).
CMAKE_BUILD_PARALLEL_LEVEL=12 ./scripts/setup_native_deps.sh

# Skip the nice/ionice re-exec (use full CPU + IO priority).
VIBEQC_BUILD_NICED=1 ./scripts/setup_native_deps.sh

# Silence the cap-announcement banner.
VIBEQC_BUILD_ENV_QUIET=1 ./scripts/setup_native_deps.sh

On macOS the cap doesn’t engage (no /proc/meminfo, no ionice) — set CMAKE_BUILD_PARALLEL_LEVEL manually if your dev box is RAM-constrained.

Python 3.14 + some dependency refuses to build Most scientific packages have wheels for 3.11–3.13; 3.14 is bleeding edge and occasionally missing binary wheels (numpy, pyscf, scipy typically catch up within a few weeks). Stick to 3.12 or 3.13 if you hit this.

rm -rf + rebuild If everything goes sideways, the easy button is update.sh --clean:

./scripts/update.sh --clean

which wipes third_party/*/install, build/, the basis-library cache, and .venv/, then rebuilds everything from source. Or by hand:

rm -rf third_party .venv build python/vibeqc/basis_library/basis
./scripts/install.sh

“Is my install OK?” — doctor.sh Run ./scripts/doctor.sh for a read-only health report: working-tree state, which vendored third_party/<dep>/install/ trees exist, build-stamp drift against the current build_*.sh files, venv health (broken python / stale pip shebang / pyvenv.cfg mismatch), and the banner. No builds, no installs — safe to run at any time, including during an in-flight calculation.

Updating

./scripts/update.sh             # → latest tagged release
./scripts/update.sh --dev       # → bleeding-edge main (X.Y.devN banner)

The wrapper handles git pull + setup_native_deps.sh (idempotent on existence) + pip install -e '.[test]' + the new-banner print in one shot — and refuses to run if the working tree is dirty (stashing-without-asking is worse than failing loud).

The vendored deps rarely need rebuilding — only if a build_*.sh script bumps its pinned version, which we do as a deliberate commit (visible in git log scripts/). When that happens, pass --rebuild-native-deps to force a clean rebuild rather than the idempotent existence check:

./scripts/update.sh --rebuild-native-deps
./scripts/update.sh --dev --rebuild-native-deps

If you keep two checkouts side-by-side (one for production runs, one for dev), use update.sh (or --release) inside the release tree and update.sh --dev inside the dev tree. The full option set

  • the manual-equivalent recipe (for debugging an update that didn’t take) are in updating.md.

Picking a build to test against

vibe-qc’s runtime banner records which git revision produced any output (see release_process.md). When you want to run calculations against a specific build for testing — comparing against release, validating a topic-branch fix, etc. — update.sh --ref takes any branch or tag:

./scripts/update.sh --ref v0.9.0                 # pin to a tag
./scripts/update.sh --ref feature/some-topic     # try a branch

The banner on the next run will then read e.g. Release v0.9.0 or dev 0.9.0 (feature/some-topic @ abc1234), which is what you’ll see prepended to every persisted SCF log.