Contributor setup, fresh-clone bootstrap and rebuild discipline¶
End-user installation lives at installation.md;
the clone-and-bootstrap path there also applies to contributors.
This page covers the contributor-specific bits: per-clone venvs,
the editable-install rebuild loop, and the silently-stale-.so
failure mode the binding-sanity test now catches.
Clone and bootstrap¶
After installing the system prerequisites listed in
installation.md § Requirements for
your platform (Homebrew on macOS; apt / dnf / pacman package
groups on Linux), clone the source and bootstrap the native/Python environment:
Clone the public source over HTTPS; no account or deploy key is required:
git clone https://github.com/vibyverse/vibe-qc.git
Authorized maintainers use their separately configured upstream remote. Private access recipes belong in the external operations documentation.
Then enter the new checkout and install:
cd vibe-qc
./scripts/install.sh --dev --extras test --venv .venv \
--python /opt/homebrew/bin/python3.14
The repository directory lists public GitHub source snapshots for all four projects; they can be cloned anonymously. Canonical maintainer development access is configured separately. Public snapshots have separate commit history, so keep contributions based on the selected host and project. See CONTRIBUTING.md for the GitLab merge-request path for GitHub contributions.
install.sh drives, in order: preflight (verify build prerequisites
on $PATH) → vendored native deps (libint, libxc, spglib, FFTW3,
libecpint, basis library, idempotent, each per-dep script
short-circuits when its third_party/<dep>/install/ tree is
present) → .venv creation → editable pip install -e .[<extras>]
→ banner. A clean native build can take hours: the default 5_4_4 Libint
recipe alone is estimated at 1.5 to 2 hours in installer help. Incremental
builds reuse current dependencies and compiler outputs; elapsed time depends
on the machine, selected kernels and cache state.
The command above is the tested macOS development bootstrap. On another
platform, select your installed Python with --python.
The release branch advances only from a tagged core release;
--dev follows main, which is where contributions land. For a pinned
install, choose a tag actually present in this repository; pre-split branches
and historical tags were not transferred. Viewer and queue contributors clone their respective
repositories separately. vibe-basis/ remains here.
If you already have the prereqs installed and only need a different
branch / venv / extras combination, install.sh --help enumerates
the flags.
Per-clone venvs¶
Reuse the existing checkout and its environment when they are appropriate
for the task. If independent checkouts already exist, each needs its own
installation; a linked worktree also needs correctly associated dependencies
and build state. An editable pip install -e . records source paths, and the
native extension uses the dependency trees selected at build time. Sharing a
venv across checkouts can load Python from one tree and native code from another.
Run install.sh once per fresh clone; it lands the venv at
<checkout-root>/.venv by default. To keep multiple branches in
one tree with side-by-side venvs, use --venv .venv-<name>.
Choose the smallest useful check¶
Before changing source, inspect git status --short and fetch incoming work.
Preserve other sessions’ changes, environments and running jobs. Source
synchronization and runtime rebuilding are separate operations:
Change |
Check or rebuild |
|---|---|
Documentation prose |
Check text, links and anchors; no native rebuild |
Python behavior |
Run the affected test with the intended interpreter |
C++ implementation or bindings |
Incrementally rebuild the core, then run the affected test |
Native dependency recipe |
Rebuild the affected dependency and any core code that consumes changed headers or ABI |
No relevant source/runtime change |
Reuse qualifying passing evidence |
Check both Python and native module paths when a test depends on the compiled core. The troubleshooting checklist provides commands and explains what to record. An import check establishes loadability, not numerical correctness. Scientific acceptance uses a complete calculation and matched reference under the testing policy.
Rebuild after upstream binding changes¶
The editable install rebuilds the C++ extension only when you ask
it to. So when upstream lands a commit that adds a new pybind11
binding, e.g. 39bf8629 adding compute_nuclear_with_charges to
both cpp/src/bindings.cpp and the from ._vibeqc_core import (...)
block in python/vibeqc/__init__.py, your locally-built
_vibeqc_core.so is silently stale until you rebuild. The next
import vibeqc then fails partway through the module body:
ImportError: cannot import name 'compute_nuclear_with_charges'
from 'vibeqc._vibeqc_core'
The recovery is one command:
.venv/bin/pip install -e . --no-build-isolation
--no-build-isolation keeps pip from spinning up a fresh build
environment, which would re-download every build dep and discard
the incremental CMake cache. Without it the rebuild takes minutes
instead of seconds.
tests/test_binding_sanity.py
catches this mechanically, it walks every from ._vibeqc_core import X site in the package and asserts each symbol resolves
against the loaded .so. If it fails, the assertion message tells
you exactly which rebuild to run and which files referenced the
missing symbol. Run this test first when import vibeqc starts
failing after a git pull:
.venv/bin/python -m pytest tests/test_binding_sanity.py
Rebuild Libxc after its recipe changes¶
The vendored Libxc recipe patches the PBE and r2SCAN correlation kernels so
they evaluate 1 ± zeta without cancellation at full spin polarization
(scripts/patch_libxc_spin_fractions.py). The editable install never re-runs
the dependency scripts, so a clone whose third_party/libxc/install/ predates
the patch keeps the old kernels after a git pull and a core rebuild. The test
session then refuses with STALE LIBXC and exit status 97, the same refusal
as a stale core. Rebuild Libxc with:
scripts/build_libxc.sh
It rebuilds an unpatched install and admits a patched one unchanged. The core loads Libxc at run time, so it needs no rebuild afterwards. A Libxc outside the checkout, such as a system installation, is not checked.
Libint capabilities required during configuration¶
The vendored Libint recipe applies header fixes for the Boys-table endpoint and for scratch allocation in the short-range Coulomb evaluator. The latter keeps the evaluator’s object layout and arithmetic, uses local scratch through order 31, and retains dynamic storage at higher orders. Run the normal dependency update and rebuild vibe-qc after a recipe change: updating a header does not change an already compiled native extension. System Libint installations are not patched by this recipe.
Libint builds with the same version can contain different generated kernels.
The selected Libint2::cxx target must expose ordinary one-body integrals
(LIBINT2_SUPPORT_ONEBODY=1) and their geometric derivatives through at
least order 1 (LIBINT2_DERIV_ONEBODY_ORDER>=1). CMake compiles and links a
small witness against that target’s headers and library before building
the core. Missing capability macros or first-derivative overlap, kinetic
or electrostatic symbols cause a configuration error with compiler/linker
details and the selected Libint2_DIR. The witness is not executed.
If configuration rejects a system installation, run
scripts/build_libint.sh and set Libint2_DIR to the CMake package directory
in its third_party/libint/install/ tree when reconfiguring. A cached
Libint2_DIR can keep selecting an older system dependency despite a newly
created local install. The capability check runs on every configure, including
after replacement at the same path. Setting VIBEQC_REQUIRE_VENDORED=OFF
permits system discovery but does not bypass the capability requirement.
The probe log is cpp/CMakeFiles/vibeqc-libint-onebody.log beneath the build
directory.
The standard build recipe retains its existing order-2 and property-derivative settings. This minimum check for ordinary first derivatives does not certify Hessians, property derivatives, every angular momentum or numerical accuracy. Continue to verify the built core and the library actually loaded at runtime after a rebuild; configuration cannot protect against a later library swap.
Vendored headers come first, and a stale libecpint is refused¶
The compiler searches the vendored third_party/<dep>/install include
directories before every other dependency’s. Imported packages otherwise
contribute include directories in link order, and on macOS libint’s installed
package links Boost, whose include directory is the whole Homebrew prefix. A
Homebrew libecpint, libxc, spglib or FFTW there used to shadow the vendored
header of the same name (#461): with Homebrew’s libecpint installed, the
build stopped in cpp/src/ecp.cpp with “no member named
‘shell_pair_negligible’”. Nothing needs to be uninstalled.
A header can still resolve to another copy through a CPATH entry or an
-I in CXXFLAGS or CMAKE_CXX_FLAGS, which the compiler searches before
every system directory unless it repeats one. The build then fails with a
message that names the header: cpp/src/xc.cpp and cpp/src/basis.cpp
compare libxc’s and libint’s version macros with the packages CMake selected,
and cpp/src/ecp.cpp checks for the vendored libecpint’s patched API, since
that copy keeps upstream’s version number. Remove the directory from those
variables and rebuild. spglib and FFTW have no version macro and rely on the
search order alone.
scripts/build_libecpint.sh records the version of its libecpint patch in
third_party/libecpint/install/.vibeqc-radial-quadrature. The editable
rebuild above does not rerun that script, and a patch that changes only
libecpint’s sources would otherwise be linked from an older install without
notice (#460). Configuration therefore compares the record with the script’s
RADIAL_PATCH_VERSION. A mismatch is an error under
VIBEQC_REQUIRE_VENDORED and a warning otherwise. Run
scripts/build_libecpint.sh, which rebuilds only libecpint in a few minutes,
then the editable rebuild again.
Native sources from a local mirror, and clones that cannot hang¶
scripts/build_<dep>.sh fetches libint, libxc, spglib, OpenBLAS and
libecpint’s sources with git clone, pinned to a commit SHA that the
build verifies. Three environment variables control that step; all of
them are read by scripts/_verify_source.sh and none changes what is
built.
VIBEQC_GIT_REFERENCE_DIR names one or more directories (colon
separated) that may already hold the pinned source. Point it at another
checkout’s third_party/ directory, or at a directory of mirrors named
after the upstream repositories (libint, libint.git, libint/src and
libint-src are all recognised). A local repository is used only when it
already contains the pinned commit, and the result still passes the same
HEAD check as a network clone, so a mirror can never substitute a
different commit. This turns a GitHub outage, or a transfer that keeps
resetting, into a non-event on a machine that has built vibe-qc before:
VIBEQC_GIT_REFERENCE_DIR=/path/to/other-checkout/third_party ./scripts/update.sh
VIBEQC_GIT_CLONE_ATTEMPTS (default 3) bounds how often a network clone
is retried, and VIBEQC_GIT_CLONE_TIMEOUT (default 1800, seconds per
attempt) bounds how long one attempt may run. A clone past its deadline
receives SIGTERM and, ten seconds later, SIGKILL for its whole process
tree; a stalled HTTP transfer is cut earlier by git’s own low-speed
limit (1 KiB/s over 60 s unless GIT_HTTP_LOW_SPEED_LIMIT and
GIT_HTTP_LOW_SPEED_TIME are set). The failure message names the
override to reach for. Ctrl-C on the build script still stops the clone.
When the editable install fails on pybind11¶
If pip install -e . errors out at the CMake configure step with
Could not find a package configuration file provided by "pybind11"
your venv is missing the pybind11 Python package (which ships the
pybind11Config.cmake file CMake reads via
pybind11::get_cmake_dir()). On a fresh python3 -m venv-created
environment this can happen if pip install -e . skips the
build-system isolation that would normally pull pybind11 from
pyproject.toml’s build-system.requires. Fix:
.venv/bin/pip install pybind11
.venv/bin/pip install -e . --no-build-isolation
install.sh and update.sh handle this automatically: before the
editable install they put the build requirements into the venv:
scikit-build-core and pybind11 for the core, and meson-python,
meson, cffi and setuptools for the dftd3 / dftd4 source
distributions that the dispersion, test and dev extras can pull in.
--no-build-isolation applies to those dependency builds as well, so a
manual --no-build-isolation install with those extras needs the same
packages (.venv/bin/pip install meson-python meson cffi setuptools). Manual paths
(see installation.md § Manual bootstrap)
should always run the editable install without
--no-build-isolation the first time so pip pulls the build
prereqs; only switch to --no-build-isolation for the
incremental-rebuild loop above.
Pre-commit hook¶
CONTRIBUTING: pre-commit hook
covers activation. The hook enforces the current
personal-information policy: author
home paths, private LAN IPs and the employer string are blocked at commit
time. The prose policy also rejects
em and en dashes outside its documented exemptions. Never bypass hooks with
--no-verify; follow the
branch and checkout policy.
For website and companion documentation work, follow the site publishing and CSS export contract.
See also¶
installation.md, full per-platform recipe, build prerequisites, BLAS-backend selection, verifying the install with the banner.../CONTRIBUTING.md, where to report what, MR / patch flow, pre-commit hook activation.Current contributor policies, branch and checkout rules, privacy hygiene and documentation prose.
release_process.md, branch model in depth, release procedure, Patch-candidate trailer.
Queue cooperation during builds¶
The install and update scripts probe the local vq daemon before heavy
compilation. When it is available, they pause only local running jobs with a
vibeqc-build-<pid> tag and resume only that tag at exit. Existing operator
pauses remain in place. Nested dependency builds share the outer build’s pause;
the outer build owns its cleanup. An empty queue is a successful no-op.
Set VIBEQC_VQ_COOPERATE=0 to skip this coordination, or VQ_BIN to choose the
queue executable. A missing local daemon is reported as a skip. Probe failures,
command failures and incomplete/error summaries produce a warning; check the
local jobs carrying the build tag if resume reports a problem.
FFTW, libxc, spglib and OpenBLAS cache identity¶
FFTW, libxc, spglib and OpenBLAS cache reuse check that the version entry point
comes from the requested library, using its resolved path and SHA-256 digest. An unloadable or substituted
library stops setup and ordinary updates before a stamp refresh or automatic
rebuild. Inspect the cache before explicitly selecting a rebuild with
scripts/update_native_deps.sh --dep fftw, --dep libxc, --dep spglib, --dep openblas, or
--all. Selecting one dependency does not authorize replacing another invalid cache. The dry-run forms only
preview that selection.
The reported exported version is distinct from the recipe source pin. Upstream FFTW 3.3.10’s CMake build exports 3.3.9; the string alone does not identify the source release or build options. Cache admission reports those as not attested. Existing qualified recipe stamps remain recipe records; legacy unknown source provenance is not upgraded into a source/build attestation.
For libxc, the loaded image owning xc_version is checked before the version
function is called. Its reported version is also an observation, not source or
build-option attestation. Other dependency gates retain their existing checks.
For spglib, the image owning spg_get_version is bound before calling it.
Its exported version is kept separate from the source recipe pin; successful
artifact admission does not establish source/build-option provenance.
OpenBLAS also requires lapacke.h and binds the BLAS, LAPACK and LAPACKE
exports to the requested image before calling openblas_get_config. Header-only
or unloadable installs cannot satisfy cache admission. The current consumer uses
LP64 indices, so an exported USE64BITINT configuration is refused. Runtime
version and configuration (including threading) are reported separately from the
recipe pin; they do not attest the source release or build options. Optional
OpenBLAS remains opt-in, and an explicit REBUILD=1 builder request or
update_native_deps.sh --dep openblas can replace a refused cache.
Libint cache reuse requires the C shared library that Libint2::cxx links
through its header-only C++ interface. The admission probe binds
libint2_static_init, libint2_cleanup_eri and the storage address of
libint2_build_eri to that requested image without calling initialization or
integral kernels. A config/marker-only, static-only, ambiguous or unloadable
cache stops before installed-header patches. The optional compiled C++ library
is not a substitute for the required C image. Runtime version and generated
max-AM are not attested; marker values remain recorded settings. Proven valid
caches retain header patches and max-AM rebuild decisions. Fetch-only staging
bypasses the installed runtime, and update_native_deps.sh --dep libint remains
the explicit recovery route for a refused cache.
Optional native build receipts¶
Fresh FFTW, libxc and spglib CMake builds can call an external provenance
collector. Set VIBEQC_NATIVE_BUILD_COLLECTOR to its absolute executable path
and VIBEQC_NATIVE_RECEIPT_DIR to an existing absolute directory outside the
product checkout and install tree. Each build uses <dependency>.json there;
choose a fresh directory to preserve earlier receipts. No collector is bundled.
With both variables unset, the existing build commands are unchanged. Cache hits
and VIBEQC_FETCH_ONLY=1 do not call the collector or create historical receipts.
The collector is invoked once, after configuration and before build/install:
COLLECTOR record --source NAME=SOURCE --recipe BUILDER --recipe HELPER ...
--cmake-build BUILD --install INSTALL
--artifact-manifest BUILD/install_manifest.txt
--cwd PRODUCT --output RECEIPT_DIRECTORY/NAME.json
-- cmake --build BUILD --target install
Arguments are passed directly, without shell evaluation. Configuration enables
CMAKE_EXPORT_COMPILE_COMMANDS=ON. The recipe arguments include the builder,
collector adapter, build-pressure helper, source verification helper and build
lock helper. The install manifest produced by the actual install identifies the
artifacts, including platform-specific names and lib or lib64 locations.
The external collector must observe the configured build, preserve source,
compiler and option identities, and verify the resulting install. Its nonzero
exit stops the builder without retry: the build may already have run.
These receipts do not themselves prove which image a process loaded or whether its data files work from a copied prefix. Those checks remain separate. This hook does not cover libint’s generated-library build, OpenBLAS Make, or the libecpint multistage build. Existing installs without a qualified build-time receipt retain unknown source and build provenance.
Generated basis overlay integrity¶
Setup requires Python >=3.11. A nonempty PYTHON_BIN explicitly selects the
interpreter; otherwise setup tries a usable project .venv/bin/python, then
$VIRTUAL_ENV/bin/python, then python3 on PATH. An incompatible explicit
override fails without falling back. Interpreter refusal occurs before any
output is changed. To select a supported interpreter, use
PYTHON_BIN=/path/to/python bash scripts/setup_basis_library.sh.
After changing or copying a generated build/basis_library directory, run
bash scripts/setup_basis_library.sh. Setup records the actual content of every
committed orbital basis and ECP sidecar in a readable receipt. Imports check all
recorded file identities and content digests without writing to the installation.
If shared-filesystem clients assign different device numbers to the same files,
the guard re-reads their content and verifies the recorded SHA256 values; all
other identity fields must still match. This read-only fallback does not reseal
the receipt. Its cost scales with the catalog size on each importing process;
the ordinary same-client path uses the prepared receipt without rehashing files.
Missing, corrupt, unreadable or changed receipts refuse overlay selection;
ordinary imports do not regenerate them. Explicit LIBINT_DATA_PATH overrides
retain their existing behavior and remain the caller’s responsibility.
Library callers receive BasisOverlayIntegrityError, a RuntimeError subclass.
The vibeqc and vibe-qc commands, and their supported python -m entry points,
use exit status 78 for this integrity refusal, before native integral evaluation.
This is a filesystem freshness check for ordinary writes and replacements, not
a security boundary against forged receipts or privileged metadata changes.
Filesystems without usable POSIX change times refuse cached selection.
Resume an interrupted libint build¶
A matching interrupted build now reuses its Ninja objects. The saved contract binds tracked libint source content, the build recipe, compiler bytes and CMake configuration. A changed input refuses without deleting the retained build. Use the explicit native-dependency rebuild workflow when changing the recipe; do not remove locks or edit build markers to force reuse.
For an older build with no resume contract, the supported recovery command is:
bash scripts/recover_libint_build.sh /path/to/original/source EXACT_COMMIT_SHA
bash scripts/recover_libint_build.sh /path/to/original/source EXACT_COMMIT_SHA --apply
The first command verifies and previews; the second repeats those proofs under the original checkout’s build lock and resumes its existing CMake build. The recovery script may run from a newer checkout: it does not edit the old product source or change its commit identity. Legacy adoption is deliberately limited to the reviewed libint 2.13.1 recipe, default orbital/fitting limits, and the recorded GNU compiler version whose executable predates configuration. It checks the exact source patches and configuration, then records current content hashes; it does not claim that historical compiler bytes were cryptographically recorded. Unsupported or ambiguous configurations remain preserved for explicit review.
On success the original builder’s artifact checks and angular-momentum metadata finalization run, followed by a loaded-library identity check and the original partial-build provenance writer. Legacy recovery refuses other existing native installations rather than restamping their unproven history. Continue with the original product installer to build remaining dependencies, record its normal provenance, and verify the native core before activation. A failed recovery never claims a completed installation. Keep healthy runtime generations serving jobs throughout this process. A small, frequently evicted compiler cache is not a substitute for retaining compatible build objects.