Project-level standing rules for Claude chats working on vibe-qc

This file is auto-injected for every Claude Code session in this repository. It carries project-level discipline that every contributor (human or AI) needs to follow. User-level specifics (planetx access, per-laptop venv conventions, no-SSH-to-bayes etc.) live in ~/.claude/projects/.../memory/ and are intentionally NOT here — those don’t generalise across machines / contributors.

If you’re a Claude chat on this repo, read this whole file before your first edit. It’s short.

1. Licensing discipline (NON-NEGOTIABLE)

vibe-qc is MPL 2.0 and we ship to academic + open-source users. Getting licensing wrong has real consequences for the project.

Before bundling, vendoring, or fetching anything new:

  • Check the redistribution terms. Original publication’s license, BSE entry’s notes, third-party LICENSE/COPYING files. Don’t assume “open” means “redistributable”.

  • If the terms are unclear or restrictive: don’t bundle. Use the on-demand fetcher pattern (modeled on vqfetch): pull from source on first use, cache locally per XDG, surface per-record provenance + license string in the SCF log + .system manifest.

  • For citation-required content (basis sets, ECPs, functionals): preserve the per-publication reference in file headers and ensure the citation is reachable from user-facing output.

The full per-component inventory is at docs/license.md. When in doubt, expand that page rather than silently shipping new bundled data.

Known caveats already documented:

  • FFTW3 is GPL v2. vibe-qc dynamic-links it for the FFT-Poisson solver. Combined binary is effectively GPL v2. Roadmap entry: FFT backend abstraction (VIBEQC_FFT_BACKEND={fftw3,pocketfft,kissfft}) for commercial-friendly binaries.

  • basissetdev’s 87 BSE-fetched basis sets are NOT shipped in v0.8.0 (see § 4 below). On-demand BSE fetcher is the intended architecture once basissetdev merges.

2. Branch model + push discipline

vibe-qc has two long-lived branches (docs/release_process.md):

  • main — active development. Every feature, fix, refactor lands here first. CI must pass. Daily commits expected. Maintainers + agents may push after CI green.

  • release — public-facing. Fast-forward only, only from a tagged commit on main.

Pushing from a Claude worktree:

  1. The standard pattern is rebase-then-push:

    git fetch origin --quiet
    git pull --rebase origin main
    git push origin HEAD:main
    

    Other chats push to main in parallel; without rebase your push will be rejected.

  2. Never git push --force to main or release.

  3. Never git commit --amend on a commit you’ve already pushed.

  4. Never skip pre-commit hooks (--no-verify, --no-gpg-sign) unless the maintainer explicitly asks. If a hook fails, fix the underlying issue — don’t bypass.

  5. Tag commits are made by the release chat per docs/release_process.md § “Cutting a release”. Don’t tag from arbitrary chats.

Checking CI after a push (glab api):

On a machine with the glab CLI authenticated against gitlab.peintinger.com (the maintainer’s machines are), chats can query pipeline status directly:

# recent pipelines (status / sha / web_url)
glab api "projects/19/pipelines?per_page=5"

# jobs of one pipeline; trace of one job
glab api "projects/19/pipelines/<pipeline-id>/jobs"
glab api "projects/19/jobs/<job-id>/trace"

Use the numeric project id (19 = mpei/vibeqc). Path-based lookups (glab ci list, -R mpei/vibeqc, projects/mpei%2Fvibeqc) return 404 or the sign-in page on this instance: the URL-encoded slash is decoded before it reaches the API, so every glab ci convenience subcommand is broken here. Stick to glab api with the id.

Main moves fast and GitLab auto-cancels pipelines superseded by a newer push to the same ref. A canceled status on your commit’s pipeline means replaced, not failed; what counts is green on the current head pipeline, whose tree contains your commit.

What a green pipeline means: the build-test job is a build-break gate only (canonical bootstrap, import vibeqc, pytest --collect-only; cache-warm runs take ~20 min). It executes no tests. Full-suite verdicts come from scripts/test_gate/ on a dev box, per § 14.

3. Multi-chat coordination — the drop-box convention

vibe-qc development is split across multiple parallel Claude chats (periodic SCF, molecular methods, basissetdev, vqfetch, docs, vq queue, …). Coordination happens through a structured status-file convention, not through ad-hoc inter-chat messaging.

Per release (v0.X.0), the release chat opens a directory at .release-status/v0.X.0/. Each contributing dev chat writes one status file: .release-status/v0.X.0/<chat-id>.md. Drop-box files are gitignored, local-only, deleted post-tag (Phase E of the release-chat runbook).

The drop-box file follows a fixed template:

  • Self-id, branch + tip SHA, last-verified-green-tests metadata.

  • Deliverables claimed in CHANGELOG [Unreleased] — per-item: SHA, tests, open issues blocking tag.

  • Tag-ready? YES/NO with the gating reason if NO.

  • Slips out of v0.X.0 — what moves to a later release.

  • Upstream dependencies on other dev chats.

  • Asks pending to other chats.

  • Anything not in CHANGELOG that should be.

  • Codename objection? (yes/no with reasoning).

The docs chat is the one consumer that needs drop-box content to outlive the deletion — extract any quotes / numbers / SHAs into permanent docs (docs/release_v0_X_0_prep.md, docs/license.md, user-guide pages) before Phase E runs.

4. The basissetdev standing rule

Mike’s standing rule (2026-05-07):

“All this shall be kept in a basissetdev branch that is always rebased on main when features land, but I shall not be merged into main before we are done. We want to write papers from that.”

Implications:

  • basissetdev does NOT merge into main for v0.8.0 (or v0.8.x). It stays a paper-writing branch.

  • The Phase 14e vq.auto_ecp_centers(...) auto-discovery helper and the 87 BSE-fetched basis sets are basissetdev-conditional — document them as such (see docs/user_guide/ecp.md § Phase-14e for the pattern).

  • Shipped on main (maintainer decision, 2026-06-21): the Phase 14f CRYSTAL INPUT-format ECP-block parser (basis_crystal.py CrystalECP) and the Phase 14g periodic ECP application (compute_ecp_lattice_from_primitives plus the pob-TZVP-REV2 auto-attach in run_periodic_job) are on main as the maintainer-approved supported subset (option (a) of HANDOVER_COHESIVE_ECP_APPLY.md). They are not basissetdev-conditional. An earlier revision of this rule listed the 14f parser as conditional, which was superseded when that subset landed.

  • The basic ECP machinery (manual ECPCenter recipe via libecpint) is on main and ships in v0.8.0. Don’t conflate “ECP support” with “basissetdev features”.

If a chat needs basissetdev features for its own work, rebase basissetdev on main and work from the basissetdev tip — but don’t propose merging basissetdev into main without explicit maintainer approval.

5. Documentation cadence — when to refresh what

Codified in docs/release_process.md:

  • Per-tag mechanical sprint (~3 hours, every release) — copy-and-adapt the docs/release_v0_8_0_prep.md playbook; pre-staged copy is the norm. CHANGELOG promotion, homepage admonition swap, roadmap “shipped” sweep, version bumps, banner refresh.

  • Per-quarter deep audit (~6–8 hours) — tutorial parity re-walk (docs/roadmap.md § Tutorial parity), stale-link audit, stale-API audit, features.md regen, user-guide coverage audit, cross-link audit.

  • Lightweight ongoing (every session) — new bug → homepage admonition update same session; behaviour change → user- guide cross-reference same session. Don’t queue.

If you’re touching docs and not sure which cadence applies, default to “lightweight ongoing” — fix what you see while you’re there.

7. Periodic SCF oscillation = bug, not convergence problem

If a periodic SCF oscillates, lands at impossible energies (over-bound by Madelung-scale shifts, e.g. ~0.5 Ha on H₂/STO-3G in a 30-bohr box), or converges to a stationary point disagreeing with PySCF.pbc.GDF by more than µHa: that’s a bug, not a convergence aid problem.

Don’t paper over with:

  • Damping / level-shift / quadratic-fallback as primary fix.

  • Empirical auto_optimize_truncation thresholds.

  • Tightening DIIS until the oscillation hides.

Do:

  • Reproduce against PySCF.pbc.GDF on the same system.

  • Check the gauge / Madelung / image-summing carefully.

  • File a regression test capturing the symptom.

  • Bring it to the periodic-SCF chat or the regression-suite chat; don’t fix-then-forget.

The v0.7.0 Madelung self-image leak (over-bound by ~0.587 Ha on H₂/STO-3G in a 30-bohr box, fixed in Löwdin’s Compass) is the canonical example of why this discipline matters.

8. Citation discipline

For published work using vibe-qc, the citation surface is mandatory:

  • vibe-qc itself: per CITATION.cff + the JCC release paper once published.

  • Basis sets used: per the .g94 file headers (preserved through the libint / BSE pipeline).

  • ECPs used: per the libecpint per-element references.

  • Functionals used: libxc convention (Lehtola 2018 + per-functional originals; see docs/user_guide/functionals.md § Citations).

  • External data fetched via vqfetch: per the per-record Provenance bundle (source DB + DOI + license carried through to the SCF log).

When writing tutorials, sample scripts, or docs that surface numerical results: cite the source. Don’t quote benchmarks against papers without naming the paper.

When you implement something citable — the implementing chat’s job

If your work adds (or routes for the first time) anything in the mandatory list above — a new method, functional, basis set, ECP, dispersion model, accelerator, dependency, or any other piece of code that traces to a publication or a third-party package — the same merge that lands the code must:

  1. Add the citable entry to the citation database at python/vibeqc/output/citations/database.toml. New [entries.<key>] block per the schema documented in the file header. If the work is basissetdev-conditional, the entry goes in the sibling database_basissetdev.toml (see § 4 + AGENTS.md § 8) — not on main.

  2. Wire the route in the appropriate [routes.*] table so assemble(plan) fires the citation when a job actually uses the feature. A new dispersion correction lands a routes.methods.<dispkey> line; a new functional lands a routes.functionals.<funcname> line; a new linked library lands a routes.libraries.<libname> line; a new basis ships under routes.basis_sets.<lowercase-name> or relies on its inline ! Originating publication: header. A citation without a route is silently dead weight.

  3. Mark the print flag on the entry. The optional print field on [entries.<key>] is the user-visibility gate:

    • print = true (the default) — the entry appears in the end-of-run references block (.out / .references / .bibtex) that users copy-paste into a paper. Pick this for anything a paper’s “Methods” section should cite (methods, functionals, basis sets, ECPs, scientific algorithms, …).

    • print = false — the entry is confined to the .system manifest as internal provenance only. Pick this for link-time-only infrastructure that is not a scientific dependency (pybind11, header-only utility libraries, build- time tooling). When in doubt, default to true.

    The runtime collector lives in python/vibeqc/output/citations/registry.pyCitationDatabase.assemble(...) walks the routes for a job, deduplicates, and returns an AssembledCitations. The .printable view (filtered to print = true) feeds the references block and the .bibtex sibling; the full .citations view feeds the .system manifest. Implementing chats don’t normally call the collector directly — they make the route fire by putting the entry + route in the database and let the SCF log assemble at end-of-run.

  4. Update the coverage tests. If your basis / functional pin sits in tests/test_basis_citation_coverage.py or a sibling, extend the pinned set in the same commit so the gate captures your addition rather than leaving the next chat to backfill it.

  5. Verify the citation reaches the destinations you marked before pushing: a tiny SCF should land your print = true entries in the .out references block + the .bibtex / .references siblings, and every entry regardless of flag in the .system manifest.

Rationale: the citation database is the single source of truth for what vibe-qc claims it cites. Letting a feature commit land without its citation entry is how attribution silently breaks between releases. The pob-* audit thread on 2026-05-24 (commits 22aface38267c9c90e6f6df4f2a7419cd422dc2c) is the canonical example of the cost: a README-pointer header survived review because no test pinned the DOI mechanically, and the affected bases shipped with broken attribution until the audit caught it.

Inline formula + reference-value comments in code

When a chat is implementing math from a published paper, the formula and any published numerical values the implementation is validated against go into inline comments at the relevant code sites. The maintainer often keeps PDFs of the cited papers in a gitignored references/ folder at the project root for personal use during development; the inline comments are the only public-facing record of what equation the code is implementing and how anyone can verify it without leaving the source file.

Pattern — the equation citation goes immediately above the implementation it derives, naming the paper + equation / section / page:

# Eq. 17 of Sun, Berkelbach, McClain & Chan, J. Chem. Phys. 147,
# 164119 (2017), doi:10.1063/1.4998644:
#   L_pq(k) = sum_R exp(-i k·R) L_pq(R)
def build_lpq_at_k(...):
    ...

Pattern — the published target value for validation goes immediately at the constant or in the test, naming the paper

  • table / figure row:

# Published target: E_HF = -1.12013988 Ha for H₂/STO-3G/12-bohr
# at kmesh (2,1,1) (Sun-Berkelbach 2017, Table II row 3).
E_HF_REF = -1.12013988

# Within 5 mHa of PySCF KRHF.density_fit() on the same system.
TOL_MHA = 5e-3

The .bibtex sidecar above records WHY the paper is cited for the user-facing audit trail; these inline comments record WHAT the code is doing and HOW it is verified — for future maintainers, for cross-code parity reviewers, and for audit cycles by external reviewers (including LLM-based audits) who shouldn’t have to re-derive the math from a PDF that’s only in someone’s local references/ folder.

Doesn’t apply to textbook equations with no single canonical source (Schrödinger equation, basic linear algebra), or constants from CODATA / NIST / well-known reference tables that are part of the field’s shared background.

When a chat adds an inline reference number it didn’t already have access to, the same merge that lands the reference value should add the paper to the citation database (database.toml, per the previous subsection) — the inline comment and the .bibtex entry are two ends of the same provenance chain.

9. Scope + dependency discipline

vibe-qc maintains a small, deliberate footprint:

  • No grand refactors without maintainer approval. Even good refactors cost review time; surface the proposal before starting the work.

  • Every commit ships green — pre-commit hooks must pass; CI must pass; tests must pass. If a hook fails, fix the cause and re-commit; don’t --no-verify past it.

  • Don’t add dependencies casually. New native deps (libxxx) need a roadmap conversation; new Python deps belong in optional extras ([fetch], [ase], etc.) unless truly core. Every dependency adds a build-matrix entry, a licensing question, and ongoing maintenance burden.

  • Asks back to the maintainer — be specific. “Should X ship in v0.8.0 or slip?” beats “thoughts on X?”. Concrete questions with framed alternatives close fastest.

10. External programs vs vendored libraries

vibe-qc has its own implementation of every quantum-chemistry method we ship. No part of vibe-qc’s runtime depends on another QC program’s runtime to compute energies, gradients, properties, or anything else user-facing.

Allowed imports / runtime dependenciesnumerical + infrastructure libraries that we link against:

  • libint — Gaussian integrals (LGPL 3.0 library; vendored)

  • libxc — 500+ XC functionals (MPL 2.0; vendored)

  • spglib — crystal symmetry (BSD 3-Clause; vendored)

  • libecpint — ECP integrals (MIT; vendored)

  • Eigen — linear algebra (MPL 2.0; header-only)

  • FFTW3 — FFT (GPL v2; vendored — see § 1 for the GPL combined-binary caveat)

  • pybind11 — Python bindings (BSD 3-Clause; header-only)

  • ASE — atomic-structure dataclasses + file I/O + the Calculator interface (LGPL 2.1+; used as a Python library, not as a QC engine)

  • NumPy / SciPy — base scientific-Python stack

These are libraries — function calls you make into for a specific numerical service. They don’t compute SCF energies on their own; they give you the building blocks.

Forbidden imports / runtime dependenciesother QC programs:

  • PySCF, Psi4, ORCA, Turbomole, CRYSTAL, NWChem, GAMESS, Q-Chem, Molpro, ADF, CP2K, VASP, Quantum Espresso, xTB, …

These are programs — they run on their own and compute their own SCF energies. vibe-qc never imports any of them inside python/vibeqc/ or cpp/. The litmus test is simple: “does this run on its own as a quantum-chemistry program?” If yes, it’s external; if no, it’s a library.

Parity testing — the subprocess pattern

When we need to compare against an external program for parity or benchmark validation, we execute it out-of-process via a subprocess runner that parses the program’s output. The pattern lives at examples/regression/runner_<program>.py:

# examples/regression/runner_pyscf.py — spawns PySCF as a
# subprocess; parses its output; never imports pyscf inside
# vibe-qc's core code.

This is what landed in commits 545db04 Retire in-process PySCF periodic backend + 7ab9384 Run PySCF references out of process + d451b84 Record external validation boundary in manifest. The .system manifest records which external programs were involved in any parity check, so the provenance is preserved.

Build-time tooling is allowed

Tools used at build/dev time — e.g. basis_set_exchange (BSE) in scripts/basisset_dev/fetch_from_bse.py, pytest in tests, sphinx-build for docs — are fine because they’re not on the runtime path. The rule is about what import vibeqc and the C++ core link against, not about what helps us develop.

Why this matters

  • No external runtime requirement — end users pip install vibe-qc and the code runs. No “you also need PySCF installed”.

  • Clean licensing surface — every runtime dependency has a documented license in docs/license.md. No transitive PySCF / Psi4 / ORCA license concerns.

  • No silent algorithm imports — if vibe-qc says it computes RKS-PBE periodic energies, that means vibe-qc’s own C++ + Python computes them. It doesn’t mean “we wrapped PySCF and called its KRKS for you”.

  • Validation against external programs is honest — subprocess runners produce reproducible artefacts the external program would have produced anyway, parsed independently. We’re comparing two implementations, not the same implementation against itself.

If you’re tempted to add import pyscf (or any other external QC program) to anything in python/vibeqc/ or cpp/: stop and ask the maintainer first. See § 11 below.

Pre-trained model engines (MLIPs) — admitted by exception

Machine-learning interatomic potentials (e.g. ACEsuit MACE, method="mace", python/vibeqc/mlip/) are an explicit, maintainer-approved exception to the “own implementation” rule above. Unlike libint/libxc (numerical building blocks vibe-qc orchestrates) or the semiempirical platform (vibe-qc’s own code), an MLIP is the whole calculation: vibe-qc marshals geometry in and reads energy/forces/stress out of a third-party pre-trained model. The discipline for these:

  • Optional extras, never core. The heavy ML stack ships behind an extra ([mace]) and is import-gated.

  • Attribute, never claim. vibe-qc names the model and cites its papers in every run; outputs must not present the energy as vibe-qc’s own (it is the model’s reference-shifted DFT-surface value, not a vibe-qc total electronic energy).

  • Weights fetched on demand, never bundled, with each model’s license surfaced (MIT ungated; academic/ASL gated behind a non-commercial acknowledgment).

This admits pre-trained model inference as an attributed external engine. It does not relax the ban on importing external QC programs (PySCF, ORCA, …) to compute energies — those remain forbidden.

11. When to escalate to the maintainer

If you hit any of these, stop and ask, don’t decide unilaterally:

  • Licensing question on a new bundled dataset.

  • Branch-policy edge case (force-push, hook bypass, tag).

  • Decision affecting CHANGELOG / release notes wording.

  • Anything that contradicts a standing rule above.

  • Anything you’d describe as “I’m pretty sure this is fine but…”

Asking has very low cost. Wrong-and-pushed has high cost.

12. Privacy / personal-info hygiene

vibe-qc is public on gitlab.peintinger.com/mpei/vibeqc. Before committing, make sure nothing in the diff would expose:

  • Credentials — passwords, API keys, tokens, bearer/auth headers, SSH private keys, .env files, anything from ~/.ssh/. Treat any leak here as a security incident per SECURITY.md.

  • Real IP addresses — especially private LAN IPs (192.168.x.x, 10.x.x.x). Use <host> or a documented hostname alias.

  • Author home paths — never write /Users/<name>/... or /home/<name>/... into committed content. Use ~/, /home/USER/, or a placeholder (<vibe-qc-checkout>, <your-orca-install>). This applies to reference outputs that captured a real run too — sanitize before committing.

  • Identity — the public maintainer identity is mpei@vibe-qc.com (per CONTRIBUTING.md / SECURITY.md). Don’t introduce other names / emails / employer affiliations into repo content.

A pre-commit hook at .githooks/pre-commit enforces a subset (<home>, /home/mpei, smart-steel-technologies). Activate once per clone — see CONTRIBUTING.md § “Pre-commit hook”. The hook bypass rules from § 2 apply: --no-verify only when the maintainer explicitly asks, with the reason in the commit message.

Historical author/committer email metadata is display-normalized to mpei@vibe-qc.com via .mailmap. Default git log, git blame, git shortlog, GitLab UI all honor it. Raw git log --pretty='%ae' (lowercase) still shows the stored email; that’s intentional — main’s “never force-push to main” rule (§ 2) precludes a history rewrite. Append a line to .mailmap to remap an additional historical email.

13. Release operations are release-chat-owned

Tagging vX.Y.Z and advancing the release branch are exclusively the release chat’s job. To request inclusion of a commit in a patch release, add a Patch-candidate: trailer to the commit body — same format as Signed-off-by: / Co-Authored-By::

fix(scf): handle near-null overlap on degenerate basis

Pre-fix, the SAD constructor crashed at min(eig(S)) < 1e-10.
Falls back to Hcore guess.

Patch-candidate: v0.7.x
Co-Authored-By: ...

Valid trailer values:

  • v0.7.x — next patch on the 0.7 line (e.g. v0.7.12)

  • v0.8.x — next patch on the 0.8 line, once v0.8.0 ships

  • v0.8.0 — specifically the upcoming minor release

  • (omitted) — not patch-target; rides to the next minor

Multiple targets allowed, comma-separated: Patch-candidate: v0.7.x, v0.8.0.

For commits already pushed (can’t amend without rewriting history, which § 2 forbids on main), attach the trailer via git notes:

git notes add -m "Patch-candidate: v0.7.x" <SHA>
git push origin refs/notes/commits

Or simply message the release chat with the SHA + reasoning; they’ll add the note for you and treat it the same.

The release chat scans main for trailered commits when cutting each patch, cherry-picks the curated candidates onto a hotfix branch off the previous tag, tags from there, and fast-forwards release to the new tag. See docs/release_process.md for the full flow (§ “Cutting a patch release” + § “How candidates are flagged”).

Do not:

  • push directly to release

  • create vX.Y.Z tags

  • open MRs targeting release

GitLab protected-branch + protected-tag rules (landed 2026-05-15) enforce this mechanically: release allows no merges and no non-Maintainer pushes; tags matching v* require Maintainer role to create. The trailer is the only correct channel for asking “include my commit in the next patch.”

This rule exists because three release-process violations between 2026-05-08 and 2026-05-15 each caused a recovery cycle (orphan tags v0.7.5 / v0.7.9 / v0.7.10 on origin are the dormant monuments). The shortcut pattern: chats treated release as the destination they should aim at, rather than the destination that main tag ff’s into automatically. The trailer + branch protection together reverse that intuition.

14. Stay wired into main — land small, ship release-ready

The v0.8.x and v0.9 releases were painful because dev chats drifted from main and landed work that compiled but left main half-finished — stale docs, an inaccurate CHANGELOG [Unreleased], ungated incomplete features. The release chat then had to gate, audit, and clean up before it could tag. The discipline below makes that audit unnecessary: every chat keeps its slice of main release-ready as it goes.

Land small, landable increments

  • Break work into milestones that are each independently shippable — a coherent change that builds green and could be tagged on its own.

  • Keep each milestone small enough to review in one sitting.

  • Land each milestone on main (rebase-then-push, § 2) before starting the next. Don’t stack multiple un-landed milestones — that is how branches diverge.

Definition of done — main stays release-ready

A milestone is not done until, repo-wide (not just the files you touched), all of these hold. Verify them before every push:

  • Full build + full test suite green — C++ and Python. If you touched shared code, run its consumers, not just your area.

  • CI green on main after the push. The build-test job is the build-break gate; if your push reds it, fixing that is your only next task.

  • No half-finished code paths. Every path you added either fully works or is unreachable.

  • Incomplete-by-design work is gated by you, now — feature flag, experimental marker, or basissetdev-conditional (§ 4) — with the gating decision documented. Never leave the release chat to discover that something needs gating.

  • CHANGELOG [Unreleased] reflects reality: it lists what you actually landed and claims only what is done and tested. Don’t over-claim — the release chat audits this against the tree.

  • Docs are in parity this milestone, per the lightweight-ongoing cadence (§ 5): user guide, API docs, banner / sample output (§ 6), roadmap “shipped” sweep, docs/license.md if deps or data changed.

  • No papered-over bugs (§ 7); privacy + licensing surface clean (§ 1, § 12).

This checklist is a gate, not a wishlist — a push that can’t pass it is not ready to land.

Review what moved on main — after every sync

A clean git rebase resolves textual conflicts only. It will not catch a changed API signature, a shared helper whose behaviour changed, or an assumption that no longer holds — other chats land on main in parallel (§ 3). After every git pull --rebase:

  • Read what landed since your last sync: git log --oneline <last-sync-SHA>..origin/main and git diff <last-sync-SHA>..origin/main -- <your files>.

  • Decide explicitly whether any of it touches your area. If it does, re-read the changed code, re-run the affected tests against the new main, and reconcile your plan. If the move is large enough that your plan no longer fits, stop and re-plan rather than forcing stale work on top.

  • This matters most when a chat resumes after being idle — assume main has moved a lot and review accordingly.

Keep a persistent handover file

Maintain one always-current handover file so any other agent or session can resume cold:

  • During a release cycle, that is your drop-box file .release-status/v0.X.0/<chat-id>.md (§ 3).

  • For a long-lived workstream, that is a handover under handovers/ (handovers/HANDOVER_<TOPIC>.md; see handovers/HANDOVER_META_GGA.md, handovers/HANDOVER_MP2_PARITY.md, …). handovers/README.md is the index; concluded workstreams are retired (deleted) there once landed, recoverable via git history.

  • Update it at every milestone. It must carry: current progress

    • branch tip SHA + the main SHA you last synced to; completed work (per item: what, SHA, tests); next steps in priority order; blockers, assumptions, and key decisions with their reasoning; anything gated or deferred and why.

If a milestone can’t be made release-ready — CI won’t go green, a conflict needs another chat, a feature can’t be cleanly gated — stop and resolve it before building further (§ 11: asking is cheap, wrong-and-pushed is expensive).

15. Running anything on planetx or mars — use vq, don’t write to the git checkouts

The shared compute hosts (planetx, mars) host /home/USER/gitlab/vibeqc-{dev,release,queue}/ git checkouts that are managed exclusively by vq admin update. Hand-edits, untracked files, or local commits in those trees break the next deployment (2026-05-25 incident: 108-file untracked-dir collision on planetx, 141 modified basis files on mars, each costing an hour to untangle).

The rule for every dev chat that needs to run something on planetx or mars: submit work via vq with a payload. The daemon gives you:

  • A clean per-job workspace (your submitted source).

  • A per-job scratch workdir at $VQ_WORKDIR (the env var the daemon injects). Write all intermediate / large data there.

  • Result readback via vq logs JOBID / vq fetch JOBID / vq status JOBID (the workdir path is in the status output).

To request a code or example landing in vibe-qc itself, submit with --tag pr-request and a descriptive --job-name; the maintainer reviews terminal jobs with that tag.

Forbidden on planetx + mars (will be reverted without notice):

  • Writing to /home/USER/gitlab/vibeqc-*/.

  • Running git pull / git checkout / bash scripts/update.sh on those repos.

  • Running pip install / make / build commands inside them.

  • Modifying anything under /etc/vq/, /opt/vq/, or another user’s /var/lib/vq/users/<uid>/.

Full protocol + recipe table: vibe-queue/docs/agent_interaction.md. Read it once before your first vq invocation on those hosts. The queue chat owns updates to that doc; if it’s ambiguous, submit a pr-request against the queue chat to clarify it rather than inventing your own workflow.

See also

  • docs/release_process.md — branch model, release procedure, documentation cadence, Patch-candidate consumption flow.

  • docs/license.md — full licensing + bundled-data inventory.

  • docs/roadmap.md — long-term plan + tutorial parity audit.

  • docs/release_v0_8_0_prep.md — canonical example of the per-tag mechanical-sprint playbook (copy-and-adapt for future releases).

  • vibe-queue/docs/agent_interaction.md — protocol for running work on planetx + mars (per § 15).

  • ~/.claude/projects/-Users-mpei-mpei-documents-vibeqc/memory/MEMORY.md — user-level / per-machine specifics (NOT a substitute for this file).