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/vibe-qc/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. Total wall-clock on a fresh box: ~15-40 min for native
deps, ~30 s for the editable install.
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¶
Every independent checkout needs its own .venv at the checkout
root, and a linked git worktree is not a substitute for a checkout when
you build or measure. The editable
pip install -e . pins the C++ extension to that checkout’s own
third_party/<dep>/install/ trees and to its cpp/ source,
sharing a venv across checkouts loads the wrong native libraries.
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>.
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
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 handles this automatically because it installs the
test extras explicitly before the editable install. 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.