Handover — basissetdev (2026-05-14)¶
Read this first¶
You are picking up the basis-set development chat from a
predecessor session. The work track is on a long-lived branch
called basissetdev that never merges into main during
v0.8.x (CLAUDE.md § 4 standing rule — paper-writing branch).
Everything below was pushed to origin/basissetdev on
2026-05-14.
Three docs you should read before touching anything (all live on
basissetdev, in docs/basisset_dev/):
PLAN.md— the goal list (Goals 1-8) + branch mechanics.GOAL8_MPEI_TZVP.md— the active goal: HF-optimized basis set design doc with methodology table, architecture diagram, wall-time budget, Stage 0-4 acceptance gates.REQUIREMENTS-PERIODIC.md— the periodic-SCF feature punch list (R1-R12); Goal 8 deliberately avoids depending on most of it by using CRYSTAL14 as the SCF engine.
Two memory notes (user-level, at
~/.claude/projects/-Users-mpei-mpei-documents-vibeqc/memory/):
reference_planetx_vibeqc_basis.md— the dedicated planetx checkout at/home/mpei/gitlab/vibeqc-basis/, the setup recipe, and the coexistence rule with other planetx checkouts.reference_crystal14_via_vq.md— thevq+run-crystal.shrecipe for CRYSTAL14 jobs on planetx.
State as of 2026-05-14¶
What’s done¶
Goal 1 (pob basis-set audit) — closed.
The S d-polarisation column-swap bug in pob-TZVP / pob-TZVP-rev2 was caught and fixed (commit
861e2d0).
Goal 2 (periodic-SCF feature handover) — closed.
REQUIREMENTS-PERIODIC.mdshipped with R1-R12 + PW1PW citation.
Goal 3 (self-contained test-set inputs) — Phases 1+2+3 landed. 39 cubic compounds covered:
Phase 1 — 13 cubic ionics (PT2013 T4 + T14)
Phase 2 — 24 cubic semiconductors / carbides / nitrides / AFM TM oxides
Phase 3 — Cu₂O, Cu₃N
Each compound has a
.pyvibe-qc input + (for non-AFM) a.d12CRYSTAL14 parity sidecar inexamples/basisset_dev/inputs/.Phase 4 (hex/tet) is blocked on REQUIREMENTS-PERIODIC R1 and stays parked.
Goal 7 (BSE library expansion) — 87 basis sets fetched from
the Basis Set Exchange and bundled (commit 8964a98).
Phase 14a-14h libecpint integration — closed. Banner,
splitter, total_ncore valence-electron accounting in SCF, the
auto_ecp_centers helper, Python bridge between CRYSTAL ECP
blocks and libecpint inline arrays. Phase 14g proper (the
C++ binding for compute_ecp_matrix_inline) is parked for a
focused C++ session — not on the Goal 8 critical path.
Goal 8 (mpei-TZVP) — design + plumbing, the active work track.
Design doc opened (
GOAL8_MPEI_TZVP.md), 4 stages with explicit acceptance gates.User-confirmed choices (2026-05-13):
Seed basis: pob-TZVP-rev2.
SCF engine: CRYSTAL14 on planetx via
vq— recorded rationale (“too slow, no symmetry, periodic SCF still buggy”) in §3.1.Optimizer: NLopt BOBYQA primary + iminuit MIGRAD/HESSE for error bars.
LD handling: hard exponent floor 0.15 (rev2 inheritance).
Outreach gate: Stage 2 (LiH one-compound MIGRAD) success triggers university outreach.
vibe-basis package spun up (2026-05-13) — separate
top-level monorepo subdir, parallel to vibe-queue/. Owns the
optimizer / orchestration; never imports vibeqc; independently
pip install -e .-able with extras [nlopt|iminuit|scipy|vq|all].
CLI vb. Module layout:
vibe-basis/src/vibe_basis/
├── __init__.py __version__ = "0.1.0.dev0"
├── cli.py `vb --version`, `vb parse <backend> <out>`
├── backends/
│ ├── __init__.py
│ └── crystal14.py parse_output / parse_output_file / emit_input
├── transports/
│ ├── __init__.py
│ ├── base.py Transport ABC + JobHandle/JobResult/wait/run
│ ├── vq.py VqTransport — planetx via vq CLI
│ └── local.py LocalTransport — laptop smoke
├── io/
│ ├── __init__.py
│ └── structures.py 39-compound DB (migrated from
│ examples/basisset_dev/_structures.py)
└── recipes/
└── __init__.py (empty — pob_parity.py is the next file)
Test counts (last green: 6718d1b)¶
tests/basisset_dev/ (vibe-qc side): 38 passed, 2 skipped
vibe-basis/tests/ : 61 passed
Combined : 99 passed, 2 skipped
vibe-basis tests run via:
cd vibe-basis && ../.venv/bin/python -m pytest -q
vibe-qc tests run from the repo root with .venv/bin/python -m pytest tests/basisset_dev/.
State of the planetx checkout¶
Per reference_planetx_vibeqc_basis.md:
Path:
/home/mpei/gitlab/vibeqc-basis/(basissetdev branch checked out).venv:
/home/mpei/gitlab/vibeqc-basis/.venv/— Python 3.14, has vibe-basis installed editable withclick + numpy + pytest.Status as of last user contact:
vb --versionworks,vb parse --helpprints, 39 vibe-basis tests pass (count was 39 before the structure-DB migration; pull the latest and rerun, should be 61).vibe-qc itself is not installed in that venv (and doesn’t need to be — vibe-basis is standalone).
The
vqdaemon (on planetx, out ofvibeqc-queue/’s install) is the shared queue — submitting fromvibeqc-basis/uses it the same way any chat does.
Pull command for the next chat to land at the current tip¶
ssh planetx
cd /home/mpei/gitlab/vibeqc-basis
git pull --ff-only origin basissetdev
cd vibe-basis && ../.venv/bin/python -m pytest -q # expect 61 passed
Rebase status (deferred)¶
basissetdev is ~160 commits behind origin/main as of this
handover. The predecessor chat attempted a rebase at handover
time; it hit a conflict on the very first basissetdev commit
(861e2d0, the pob S d-polarisation fix on pob-tzvp.g94) and
was aborted cleanly rather than fight 160 commits of
conflict resolution while writing the handover. basissetdev’s
tip is internally consistent and the test suite is green — the
rebase is just deferred.
When you do rebase (recommended before writing Stage 0+ code, so you’re working against current main):
git fetch origin
git switch basissetdev
git pull --rebase origin main
# Expect ~5-10 conflicts. Known overlap zones:
# * pob-tzvp.g94 (someone added Ne for a Ne-fcc regression
# test on main; the S d-polarisation fix on basissetdev
# touches a different region — keep both edits).
# * CHANGELOG.md (basissetdev touches it; main touches it).
# * cpp/src/{rhf,rks,uhf,uks}.cpp (basissetdev has the
# total_ncore ECP work; main has the scf_mixing.hpp shared
# helpers — keep both, per CLAUDE.md § 10 "no duplicate
# implementations").
.venv/bin/python -m pytest tests/basisset_dev/ -q
(cd vibe-basis && ../.venv/bin/python -m pytest -q)
git push origin HEAD:basissetdev # NOT --force; if it refuses,
# something pushed concurrently
# — fetch + repeat
If the rebase is too painful, an alternative is to cherry-pick just main’s “must-have” commits onto basissetdev rather than the full 160. For Goal 8 specifically, nothing on main is required: vibe-basis is standalone, the structure DB doesn’t depend on vibe-qc internals, and CRYSTAL14 is the SCF engine. The 160-behind is a hygiene gap, not a blocker — Stage 0 can run on the current tip.
If the new chat wants the optimizer extras, install incrementally
as stages need them (avoids Python-3.14 wheel availability
surprises on nlopt / iminuit blocking the whole setup):
# Stage 0 — needs vq
../.venv/bin/python -m pip install -e '.[vq]'
# Stage 1+ — needs nlopt + iminuit
../.venv/bin/python -m pip install -e '.[nlopt,iminuit]'
What’s next — the immediate task on resume¶
Goal 8 Stage 0 driver: vibe-basis/src/vibe_basis/recipes/pob_parity.py.
All four prerequisites are in place:
✅ Structure DB (
vibe_basis.io.structures.STRUCTURES)✅ Input emitter (
vibe_basis.backends.crystal14.emit_input)✅ Transport (
vibe_basis.transports.VqTransport.run)✅ Output parser (
vibe_basis.backends.crystal14.parse_output_file)
The driver is conceptually small — it wires the pieces together
and compares against PT2013 SI Table 2 reference energies (the
HF totals already encoded as PT2013_T2_HF in
examples/basisset_dev/_generator.py — should migrate that
constant to vibe-basis too while you’re there, probably to
vibe_basis.io.references or similar).
Pseudocode (the design doc is GOAL8_MPEI_TZVP.md §5 Stage 0):
def run_pob_parity(
structures: list[Structure], # default: 13 cubic ionics
transport: Transport, # default: VqTransport()
crystal_wrapper: Path, # path to run-crystal.sh on planetx
workdir_root: Path, # dest for per-compound dirs
) -> StageReport:
for s in structures:
deck = emit_input(s, "pob-tzvp", "rhf")
if deck is None: continue # skip AFM / unsupported
wd = workdir_root / s.name
wd.mkdir(parents=True, exist_ok=True)
(wd / f"{s.name}.d12").write_text(deck)
cmd = ["bash", str(crystal_wrapper), f"{s.name}.d12"]
result = transport.run(wd, cmd, wd / "fetched", cpus=14, wall_time_s=1800)
parsed = parse_output_file(result.output_dir / f"{s.name}.out")
delta = (parsed.energy - PT2013_T2_HF[s.name]) if parsed.ok else None
report.add(s, parsed, delta)
return report
Acceptance gate: Σᵢ|ΔEᵢ| < 0.1 mHa across the 13 cubic
ionics. If it fails, the pipeline is wrong (basis-file encoding,
SHRINK / TOLDEE / TOLINTEG defaults, or output parsing) — fix
before proceeding to Stage 1+.
Note: 13 sequential submissions × ~30 s CRYSTAL14 wall =
~7 min total at --max-jobs 1. Cheap.
After Stage 0 passes, the order is:
Stage 1 — single-atom H HF BOBYQA (~30 evals, < 1 min wall)
Stage 2 — LiH single-compound HF BOBYQA + iminuit MIGRAD/HESSE (outreach gate, ~17 min wall)
Stage 3 — 13-compound joint HF fit (~6.7 h wall at
--max-jobs 1)Stage 4 — full test set, ATOMBSSE counterpoise (after R3)
All stages defined with acceptance gates in GOAL8_MPEI_TZVP.md §5.
Open todos (carried forward)¶
In rough priority order:
Goal 8 Stage 0 driver (
recipes/pob_parity.py) — see above.Goal 8 Stage 0 run on planetx — fire it; gate Σ|ΔE| < 0.1 mHa.
parametrize.pyin vibe-basis — basis ↔ flat log-space vector with hard bounds. Migrate from the in-vibe-qc scaffolding atpython/vibeqc/basis_optimization/parametrise.py(still on basissetdev; was the Goal 4 design’s piece).optimize.pyin vibe-basis — NLopt BOBYQA + iminuit MIGRAD/HESSE + scipy L-BFGS-B wrappers with a commonOptResult.Goal 8 Stages 1-4 — the actual optimization runs.
Phase 14g proper — C++ libecpint inline-primitive feed (deferred; focused C++ session).
Goal 3 Phase 4 — hex/tet test set (blocked on R1).
Goal 4 stages 2-4 — the pob-TZVP DFT reproduction via vibe-qc itself, deferred until vibe-qc periodic SCF reaches CRYSTAL14 parity. Goal 8 takes priority because HF unblocks today (no R4 PW1PW dep).
Goal 5 — pob-*-jk aux basis design. Memory says this is DF-dev-chat territory; basissetdev coordinates but doesn’t own.
Goal 6 — periodic metal basis (paper-worthy, parked).
Things you should NOT do¶
Don’t push basissetdev to
origin/main. CLAUDE.md § 4 is explicit: basissetdev doesn’t merge into main during v0.8.x. If a discrete bug fix on basissetdev (like the S d-polarisation fix) ought to land on main, that’s a cherry-pick decision the maintainer makes — not a merge from this chat.Don’t
import vibeqcfromvibe_basis. vibe-basis is deliberately standalone. The only allowed direction isvibe-qc → vibe-basis(the_generator.pyshim).Don’t add
import pyscf/psi4/orca/crystal/ any other QC program inside vibe-basis. CLAUDE.md § 10 applies recursively — vibe-basis treats CRYSTAL as an external program too; we shell out tovq submit ... bash run-crystal.sh ..., never link/import.Don’t speculatively install
vibe-basis[all]on planetx. Python 3.14 wheel availability fornloptandiminuitis not guaranteed — install incrementally per the recipe above.Don’t speculatively chase the “missing” gitignore for
.release-status/. That’s the v0.8.0 release chat’s housekeeping; flagged in the predecessor chat’s reply but not basissetdev’s to fix.
Cross-chat coordination state¶
v0.8.0 release chat — owns
.release-status/v0.8.0/drop-box. basissetdev’s drop-box file (if it exists) documents this tip; the release chat reads it during Phase E.periodic-SCF chat — owns the R1-R5 + R7 + R9 work in
REQUIREMENTS-PERIODIC.md. They unblock Goal 8 Stage 4 (AFM via R3) and Goal 4 stages 2-4 (multi-k + PW1PW + lattice opt).gradient-routing / cross-code parity chat (
fix/grad-2e-uhfuks-routingbranch) — ownsHANDOVER_CROSS_CODE_PARITY.md(not on basissetdev). Predecessor chat received a misdirected v0.7.7 heads-up about a DF-gradient residual closure; redirected to the gradient chat without action. If you receive a similar ping, do the same.DF dev chat — owns AutoAux + Goal 5 (pob-*-jk aux basis).
Documentation chat — owns
docs/cadence (CLAUDE.md § 5). When basissetdev features land on main eventually, the docs chat picks them up.
Where the work lives¶
Branch:
origin/basissetdev(rebased onto freshorigin/main; do agit pull --rebase origin mainwhen you start to absorb any new main commits).Worktree on the laptop (this session’s): per the user’s worktree convention. The actual checkout the predecessor used is at
.claude/worktrees/nostalgic-vaughan-1f3e11/— feel free to ignore and start your own worktree.Checkout on planetx:
/home/mpei/gitlab/vibeqc-basis/, with.venv/activated.
Files you’ll touch first¶
vibe-basis/src/vibe_basis/recipes/pob_parity.py— create.vibe-basis/tests/test_pob_parity_recipe.py— create. Mock the transport (so tests run without vq / CRYSTAL14 / planetx access).vibe-basis/src/vibe_basis/io/references.py— create, lift thePT2013_T2_HFdict fromexamples/basisset_dev/_generator.py.vibe-basis/src/vibe_basis/cli.py— extend with avb fit --recipe pob-parity ...verb that wraps the driver.
Sanity checklist when you start¶
# 1. Be on the right branch + tip.
git fetch origin
git checkout basissetdev # or git switch basissetdev
git pull --rebase origin main
# 2. Confirm tests pass.
.venv/bin/python -m pytest tests/basisset_dev/ -q
(cd vibe-basis && ../.venv/bin/python -m pytest -q)
# 3. Confirm planetx vibe-basis install is current.
ssh planetx 'cd /home/mpei/gitlab/vibeqc-basis && git pull --ff-only origin basissetdev \
&& cd vibe-basis && ../.venv/bin/python -m pytest -q'
# 4. Re-read GOAL8_MPEI_TZVP.md §5 (Stage acceptance gates).
If any of those fail, fix before writing new code.
— predecessor chat (basissetdev), 2026-05-14