Running jobs¶
Audience: you have work to run and a machine to run it on. Nothing here assumes you administer that machine.
The shape of it¶
vq has four verbs you will use constantly and about forty you will not.
vq submit compute -- python optimise.py # queue it
vq queue # see what is happening
vq status <jobid> # see one job in detail
vq fetch <jobid> -o results/ # bring the results back
compute there is an SSH alias, not a hostname. vq resolves it through
your ~/.ssh/config, so a job goes to the same place ssh compute does. Set
default_host in ~/.config/vq/config.toml and you can drop it entirely.
Submitting does not run anything. It writes a durable job spec, uploads your
workspace, and returns a job id. The daemon on the far side dispatches it when
the host’s CPU, memory and concurrency budgets all allow. That gap between
“submitted” and “running” is the point of a queue, and vq status will tell
you which budget you are waiting on.
Submitting¶
The form depends on what you are running:
vq submit HOST input.py # implies: python input.py
vq submit HOST --python /path/to/py input.py # a specific interpreter
vq submit HOST -d DIR -- python run.py # a whole directory as workspace
vq submit HOST -c ARCHIVE -- bash run.sh # a tarball as workspace
Everything vq needs goes before --; everything after it is the command
to run. The separator is required whenever your own arguments could look like
vq options. vq refuses a payload that begins with an option rather than
queueing something malformed.
Declare what the job needs, and it will be scheduled honestly:
vq submit HOST --cpus 8 --mem-mb 16000 --time-limit 04:00:00 -- python run.py
An undeclared job is not free: the daemon charges it an assumed footprint, so declaring is how you get scheduled sensibly rather than conservatively.
Resource estimation explains vq estimate, a
read-only preview of an existing vibe-qc dry-run manifest with explicit unknowns
and memory aggregation semantics.
Calculation campaigns describes chains of jobs whose verified
outputs feed each other (calculate, validate, render): the campaign file,
artifact manifests, how vq campaign status decides what may run next, and
vq campaign run, which runs a campaign on this machine and can be stopped
and restarted at any point, and vq campaign cleanup, which frees what a
run directory no longer needs.
Watching¶
vq queue # the live queue, archived jobs hidden
vq queue --all # every configured host, failures shown inline
vq queue --active # everything not yet terminal
vq queue -s running # one state
vq status <jobid> # one job, with the tail of its output
vq logs <jobid> # stdout and stderr
vq tail <jobid> FILE # live-tail any file in the workspace
vq top # live CPU and memory per job
vq wait <jobid> # block until terminal
To cap how long you wait, use vq wait JOBID --timeout 30m. The timeout accepts
seconds (90 or 0.5) or a number with one lowercase suffix: s for seconds,
m for minutes, h for hours, or d for days. Fractions such as 1.5h work;
the minimum is 0.1 seconds. If the time runs out, the command exits 124 and
leaves the job running. Without --timeout, it waits until the job ends.
vq queue --all walks every host you have configured. A host that is
unreachable is reported in place rather than taking the whole listing down.
vq events JOBID shows the job’s lifecycle timeline: submission, dispatch,
state transitions and kill requests. To focus on recent transitions:
vq events JOBID --kind state_transition --tail 10
vq events HOST JOBID --kind kill_requested --kind watchdog_kill --json
Repeat --kind to include several exact event names. -n / --tail selects
the last N matching events and keeps them in timeline order; 0 (the default)
shows all matches. The same selection works with --json. For a remote job,
the host serving its events must support these options; scheduler jobs use
their driver’s event timeline.
Getting results back¶
vq fetch <jobid> -o results/ # the workspace
vq fetch --workdir <jobid> # the per-job scratch directory
vq fetch-all HOST -o results/ # every terminal job on a host
On a host that runs its own vq daemon, a job has two places it may have written
to: the workspace, where it runs and where your script’s relative paths
land, and a separate scratch directory, $VQ_WORKDIR. A plain vq fetch
copies the workspace and succeeds when the host proves the scratch directory
is empty. If that directory contains files, or its contents cannot be checked,
the command copies the workspace but exits with a hint to choose explicitly:
--workdir for scratch results, or --workspace when only the workspace is
wanted. A PBS or Slurm job has no separate scratch directory, so a plain
vq fetch needs no flag for it.
A file vq cannot read, or a symlink it must not follow, costs that entry and
not the job: the rest of the workspace still arrives, the fetch prints
PARTIAL, and the tree’s _vq/fetch-exclusions.json names what is missing.
vq fetch-all also writes <output_dir>/_vq/fetch-all-report.json listing
every job it swept and how each one went, so you can check the coverage of a
batch without re-reading the command’s output.
When something goes wrong¶
A job that will not start:
vq statusnames the gate it is waiting on. If it is a budget, either the host is busy or your declaration is larger than the host’s cap.A job you want to stop: aborting a job.
A job that failed for a reason that will not recur: retrying.
A job that is running but should yield:
vq pause/vq resume, and throttling.
If you are reporting a bug, vq doctor output plus the job id is what makes a
report actionable.
Beyond one job¶
vq submit HOST --array 25 -- python sweep.py # 25 parallel siblings
vq submit HOST --chain 5 -- python neb.py # 5 in strict sequence
vq submit HOST --depends-on JOBID -- python next.py
vq submit HOST --rerun-until CONVERGED -- ./iterate.sh
--array is parallel siblings; --chain is a strict sequence where each step
waits for the previous to succeed. --rerun-until re-submits until your script
writes a flag file, with a cap so a non-converging loop cannot run forever.
--chain and --rerun-until are accepted for a local submit and for a PBS or
Slurm host. vq refuses them for an ordinary remote host, because that host’s
daemon never receives the chain or the flag; submit from the machine that will
run the jobs instead. --array works everywhere.
To hold a job until a time, give --at an ISO 8601 timestamp with an explicit
timezone:
vq submit HOST --at 2026-05-20T22:00:00Z -- python run.py # not before 22:00 UTC
vq submit HOST --at 2026-05-20T17:00:00-05:00 -- python run.py
The daemon dispatches the job no earlier than that time, and the host’s usual budgets still apply. vq rejects a timestamp with no timezone rather than guess which clock you meant, and a time in the past means ready now.
If you know SLURM¶
Four verbs have SLURM-style names. Each is the same command under a second name, so its flags stay vq’s own:
SLURM-style |
vq |
|---|---|
|
|
|
|
|
|
|
|
Particular programs¶
Running VASP: a complete input directory through a scheduler, the whole workspace fetched back, restarts done explicitly. It says plainly what has been qualified (on real hosts at two sites, and against a stand-in binary in the test suite) and what has not been established.
TREXIO through the queue: opt-in export and READ of TREXIO data as a job’s output or input format.