QVF job containers: one file, whole lifecycle

A QVF archive can describe a calculation before it has run. Such a job container carries the structure, a declarative job.spec section (method, basis, functional, charge, multiplicity, k-mesh, tasks, engine options), and provenance.run_status = "pending". Running it updates the same file in place: results sections are added, a complete run.record (the executed spec, the full log, and the .system / .perf / structured-event sidecars) is embedded, and the status settles to converged or failed. The one file is then a complete, portable record of the calculation — no sidecar needed to understand it.

The job.spec payload is declarative data, never code: running a container never executes an embedded script (QVF spec § 5.9).

Build a pending container

import vibeqc as vq

mol = vq.Molecule([vq.Atom(1, [0, 0, 0]), vq.Atom(1, [0, 0, 1.4])], 0, 1)
vq.write_pending_qvf(
    mol, "job",
    method="rhf", basis="sto-3g",
    tasks=["single_point"],            # or ["optimize", "hessian"]
    options={"perf_log": True},        # any run_job/run_periodic_job kwarg
)
# -> job.qvf, run_status "pending"

Periodic systems work the same way — pass a PeriodicSystem (its charge/multiplicity are recorded) plus kpoints=[n1, n2, n3]. options takes any keyword the target runner understands; unknown keys are refused at run time rather than silently dropped.

Run it locally

vibeqc run job.qvf

(python -m vibeqc run job.qvf is equivalent.) The runner reconstructs the job from the spec, streams the ordinary .out and sidecar files to the output stem (default: the container’s own stem), and finishes by atomically rewriting job.qvf itself: during execution the archive reads running; afterwards it is converged or failed with a complete, sequenced run.record. A run that fails before producing output settles with an empty embedded log — that is a complete record of that invocation, not a defect.

A settled container is a record; re-running it must be explicit:

vibeqc run job.qvf --force

appends another sequenced run.record, preserving the earlier runs as history. --output STEM redirects the sidecar files without moving the container.

Ship it through vq

The container is the whole payload and the updated container is the whole result. With a managed runtime (fleet hosts):

vq submit HOST job.qvf --program vibeqc-dev --expected-sha FULL_40_HEX_SHA
vq fetch HOST JOBID --name job.qvf -o results/

The daemon resolves the pinned runtime, runs python -m vibeqc run job.qvf, and vq fetch --name retrieves just the settled container. vq status --json reports the container’s qvf_lifecycle (status, sequence, terminal completeness). On a host without a managed program entry, the directory form works with any interpreter:

vq submit HOST -d jobdir/ -- vibeqc run job.qvf

See Queue and vibe-queue/docs/agent_interaction.md for queue mechanics.

Open it in vibe-view

vibe-view renders the whole lifecycle: a pending container opens with an amber “pending” chip and a Job Spec panel stating the job has not yet run; with auto-reload enabled the chip follows the file through running to its terminal state. A settled container shows the results plus a Run Record panel per run — the executed spec, the complete log, the rendered system manifest, performance log, and structured event table — labeled “Run #k of N — latest” when the container has been re-run. A terminal container whose latest record is missing its input or log is flagged with an explicit warning rather than silently reading as done.

What lives where

Content

In the container

Sidecar file

Structure + job.spec (the request)

always, preserved verbatim

Results (energies, wavefunction, …)

canonical sections

assorted (.molden, .xyz, …)

Full log

run.record log member

.out

References

citations section

.references / .bibtex

System manifest

run.record attachment.system

.system

Performance / structured logs

attachment.perf / attachment.structured (when requested)

.perf / .scf.jsonl

Sidecar files still land at the output stem — the container makes them redundant, it does not suppress them. Individual writers are switched off with the usual runner keywords (write_xyz_file=False, …), which a container can carry in its options.

Format details: QVF design and the QVF specification (qvf-writer/spec/qvf-format-spec.md, § 3.2 and § 5.9).