CLI reference
For installation and a first calculation, follow the quickstart.
Common commands
Replace structure.cif with your CIF or POSCAR:
uv run goldilocks inspect structure.cif --json
uv run goldilocks explain structure.cif --json
uv run goldilocks run structure.cif --out silicon-run
inspect reports structure metadata, including the site labels a
starting_magnetization takes. explain runs analysis and every
advisor, printing each decision and its source (human, ml, llm, or
heuristic), then a notice: <message> line for each setting given without a
step that reached several steps, then the checks run applies, printing one
blocked: <message> line for each finding run would refuse to generate an
input for, followed by a try: line per remedy that resolves it: the --set
flags to use, each in place of any --set of the same key, then
remove --set KEY for each override to drop, since --set cannot clear a
key. run prints the same blocked: and try: lines on stderr
when it refuses. explain never writes anything, even without --json, and
exits 0 whether or not it is blocked.
run generates a complete runnable input (Quantum ESPRESSO by default) and
publishes it to silicon-run because -o/--out was given; omit -o/--out
for a memory-only preview instead. Use uv run goldilocks --help or a
subcommand's --help for full syntax.
run and explain share the same seven flags: the structure path,
--code,
--task {scf_single_point,dos,band,relax,vc-relax,phonon,relax-phonon,vc-relax-phonon},
--hpc, --set KEY=VALUE (repeatable), --config FILE.toml, and --json;
both also accept --fetch-missing, and only run additionally accepts
-o/--out. --task is validated against the eight listed choices; --code
is passed through unchecked — only quantum_espresso is a registered code
today, so an unrecognised --code silently produces a Quantum-ESPRESSO-shaped
bundle instead of failing.
uv run goldilocks capabilities --json dumps the same full payload HTTP's
GET /capabilities and the MCP capabilities tool return: codes, tasks
(with descriptions, step counts, and executables), facts, settings,
pseudopotential_tables, hpc_profiles, models, warnings, and sources.
Narrower slices are also available directly:
uv run goldilocks settings --json— every--set-able key, its type, default, and sources:{"settings": [...], "facts": [...]}, the same objects ascapabilities'ssettings[]and its overridablefacts[](is_metal,is_magnetic, ...); run this command for the current key count rather than trusting a number in these docs.uv run goldilocks models --json— every modelml/registry.tomlregisters, whether or not it is actually installed (see Scientific controls).uv run goldilocks assets status --json— installed pseudopotential-table and model assets.
See Serve HTTP and Serve local MCP for the
HTTP/MCP equivalents. uv run goldilocks examples path locates the bundled
example structures.
Save output or print JSON
explain never writes anything, regardless of flags — it has no -o/--out.
run writes only when you pass it:
| Flag | Output |
|---|---|
-o/--out DIRECTORY |
Publish a new calculation directory (must not already exist) |
-o/--out FILE.zip |
Publish the same contents as a ZIP archive |
(omit -o/--out) |
Memory-only preview to stdout; nothing is written to disk |
Explicit destinations must not already exist; run raises an error rather
than overwrite one. Without -o/--out, run always builds the full bundle in
memory and prints a preview listing each file's path and byte size — there is
no auto-picked output directory (v1's goldilocks_out, goldilocks_out_1, …
naming no longer exists in any form).
A bundle's goldilocks.json records the request it answers under request:
--code, --task, the HPC profile used, the goldilocks-core version, the
overrides as submitted (--config then --set, typed, with any
steps.<step>. prefix) and the structure file's name, format, sha256 and size.
HTTP and MCP run record the same block for the same structure and overrides.
Its steps list the task's steps in the order submit.sh runs them, each with
the input files it reads, and the bundle's README.md lists the inputs in that
order, then submit.sh, the pseudopotentials and the licences. README.md then
says how to run the bundle: copy and unpack it, check the walltime and account
submit.sh asks for, submit it from its directory, follow each step's output,
and, for a phonon task, resume at a later step.
--json changes the shape of run's output rather than being combined with
an output flag: without -o/--out it prints {"files": [...], "records":
{...}, "warnings": [...], "layout": {...}}; with -o/--out it prints
{"files": [...], "kind": "directory"|"archive", "path": "..."}. explain
--json prints {"records": {...}, "warnings": [...], "blocking": [...],
"layout": {...}}, where blocking lists the findings run would refuse to
generate an input for, one per root cause, and is empty when its checks pass.
Each finding is {"code", "fields", "message", "remedies", "summary"}: a
stable code (advice.blocked for a decision that could not be made, whose
message is the root cause), the settings it concerns, the full text to show,
the override patches that each resolve it, where null clears that override,
and a summary of the decision it asks for in at most 200 characters. layout names
each record's tier and step: analysis (what the structure alone decides),
system (what every step shares), then steps, one {"name", "records"}
per step of the task in run order -- the task's one job with its first step,
a dos task's nscf decisions under their nscf_ names, a band task's
bands-step path as k_path and its other decisions under their bands_
names, and a phonon task's fft_grid (and, for a relaxation, relax) with
its first step, then q_sampling and phonon under ph, q2r under q2r,
phonon_dos under phonon_dos and the dispersion path as k_path under
dispersion. Every record is in exactly one list.
warnings holds every record's warnings, for every task, each as {"code",
"level", "category", "message", "record"}, where record names the record
it came from (nscf_parallelisation for a dos task's nscf step,
bands_parallelisation for a band task's bands step), then the request's
routing notices under the record overrides (below); goldilocks.json
carries the same list.
--json output and the published goldilocks.json are strict JSON: a value
with no finite number is null, never Infinity or NaN. For example, the
Gamma-only mesh (k_index 1) holds for every k-distance above its lower
bound, so its k_distance_interval is [low, null].
A command writes only its own output to stdout: the --json document, or the
plain-text report without --json. Anything else printed while it runs, such
as the notice mace prints when it loads, output from a C extension, or a
child process's output, goes to stderr, so --json output always parses as
one JSON document. serve is the exception: serve mcp speaks JSON-RPC on
stdout itself.
Scientific controls
Defaults are Quantum ESPRESSO single-point SCF, PBEsol, and efficiency-tier pseudopotentials. See scientific conventions for numerical defaults and override rules.
Every scientific parameter is reached through --set KEY=VALUE (repeatable)
or --config FILE.toml (same KEY=VALUE pairs, TOML-format, merged the same
way) — there are no dedicated per-parameter flags. uv run goldilocks
settings (or --json) is the single source of truth for every override key,
its type, default, and description; a selection of commonly used keys:
| Setting | Meaning |
|---|---|
functional |
Exchange-correlation functional (default PBEsol) |
pseudo_table_id |
Pin a registered pseudopotential table id instead of automatic selection |
is_metal, is_magnetic |
Correct a classification: metal/non_metal, magnetic/non_magnetic (the record's own values, not true/false) |
k_grid |
Explicit Monkhorst-Pack mesh, e.g. --set 'k_grid=[8,8,8]' |
k_distance |
Target k-point spacing along each periodic axis; axes the point group mixes share the larger count, and a vacuum axis always gets one k-point (heuristic default 0.15 for metals or when metallicity is unknown, 0.30 for a confirmed non-metal) |
smearing_type |
Smearing function when occupations=smearing: gaussian, mp (Methfessel-Paxton), cold (Marzari-Vanderbilt) or fd (Fermi-Dirac); default cold |
degauss |
Smearing width in Ry (default 0.01) |
spin_polarized, spin_orbit_coupling |
Force spin polarization / spin-orbit coupling; spin_orbit_coupling is the only SOC switch (the needs_soc fact is read-only advice) |
moment_direction |
Lattice direction of the uploaded cell the moments of a magnetic spin-orbit run start along, e.g. --set 'moment_direction=[1,1,0]' (default [0,0,1]) |
use_vdw, method |
Force a dispersion correction; only d3bj is implemented, for PBE and PBEsol |
isolation |
Electrostatic boundary: periodic, slab (Quantum ESPRESSO's 2D truncation, assume_isolated='2D') or isolated (Martyna-Tuckerman); see boundary conditions |
conv_thr, mixing_beta, electron_maxstep |
SCF energy-convergence threshold, density-mixing factor, max SCF iterations |
u_by_element |
Hubbard U_eff per element in eV, replacing the built-in table, e.g. --set 'u_by_element={"Ti": 4.0}' |
hubbard_needs_correlation |
false runs without Hubbard +U; true applies the built-in U table |
hubbard_projectors |
Projectors of the HUBBARD card when an element gets +U: ortho-atomic (default) or atomic, the only type the phonon tasks run +U with; see Hubbard +U |
forc_conv_thr |
Force threshold of a relaxation in Ry/Bohr: Quantum ESPRESSO's 1e-3 for relax and vc-relax, 1e-4 for the relaxation of relax-phonon and vc-relax-phonon, where a looser value gets a warning |
delta_e, emin, emax, broadening, ngauss |
dos.x settings of the dos task: energy step and window in eV, broadening in Ry, broadening function (-99, -1, 0..10; dos.x reads it only with a broadening width, so it needs broadening unless the nscf step uses smearing) |
k_path_distance |
Largest spacing between neighbouring points of the high-symmetry path of a band task's bands step and a phonon task's dispersion step, in 1/Å with 2π included (default 0.025); see the band structure path |
q_grid, q_distance |
A phonon task's ph.x q-point mesh: an explicit Γ-centred mesh, e.g. --set 'q_grid=[4,4,4]', or a spacing in 1/Å with 2π included (default 0.3); see the phonon tasks |
tr2_ph, alpha_mix, nmix_ph |
ph.x's linear-response threshold, mixing factor and number of mixed iterations (defaults 1e-18, 0.4 and 8) |
asr |
Acoustic sum rule of q2r.x and matdyn.x: simple (default) or crystal; see the phonon tasks |
dos_q_distance |
Spacing of the mesh matdyn.x interpolates a phonon task's phonon DOS on, in 1/Å with 2π included (default 0.10) |
Each setting applies to the steps that read it, and goldilocks settings
--json lists them (tasks, steps, scope). A task's steps are named by
purpose: scf (scf_single_point); relax; vc-relax; scf, nscf,
dos (--task dos); scf, bands, bands_x (--task band: pw.x
with calculation='bands', then bands.x); and scf, relax or
vc-relax, then ph, q2r, phonon_dos, dispersion (--task phonon,
relax-phonon and vc-relax-phonon: the first pw.x step, then ph.x,
q2r.x, and matdyn.x for the phonon DOS and for the dispersion, with
d3hess.x before ph.x under DFT-D3).
- A step setting given as
KEY=VALUEreaches every step of the task it applies to. On adostask,k_gridsets both the scf and the nscf step, with anoverrides.applies_to_multiple_stepsnotice naming them: anotice:line inexplain's text output, and awarningsentry withrecordoverridesin--jsonoutput andgoldilocks.json. The SCF-loop settings (mixing_beta,mixing_mode,mixing_fixed_ns,electron_maxstep) set the scf step only: the nscf step runs no SCF loop, so pw.x does not use them there. - A
bandtask's bands step runs its band path with the scf step's occupations and no SCF loop, so the k-mesh settings (k_grid,k_distance,k_index,shift),occupations,smearing_type,degaussand the SCF-loop settings set its scf step only, without a notice, andk_path_distancesets its bands step only.nbnd,extra_bands,conv_thr,npoolandndiagreach both pw.x steps, with the notice. - A phonon task's first step is its only pw.x step, so the pw.x settings
(the k-mesh, occupations, SCF-loop,
conv_thr,nbnd,npoolandndiagsettings) set it without a notice, and ph.x runs with itsnpoolandndiag. The relaxation settings reach the first step ofrelax-phononandvc-relax-phonon.q_grid,q_distance,tr2_ph,alpha_mixandnmix_phset thephstep,asrtheq2rstep,dos_q_distancethephonon_dosstep andk_path_distancethedispersionstep, each without a notice.d3hess.xtakes no setting and is not a step a key can name. steps.<step>.KEY=VALUEsets one step only and wins over the plain key for that step:--task dos --set 'k_grid=[10,10,10]' --set 'steps.nscf.k_grid=[30,30,30]'gives the scf 10×10×10 and the nscf 30×30×30, and--task band --set steps.bands.nbnd=40gives the bands step 40 bands and leaves the scf step's default. In--config, a[steps.nscf]or[steps.bands]table does the same. A plain key that every step it applies to also sets this way would reach no step, and is refused.- System settings (functional, cutoffs, magnetism, ...) describe the system
every step runs on, and the job settings (
partition,nodes,ntasks,walltime_h,account) the one allocation all of a task's steps run in: both are set once per task, andsteps.<step>.is refused for them. - A setting no step of the task reads is refused (exit 2, HTTP 422):
pressandcell_dofreeapply to avc-relaxstep only (thevc-relaxandvc-relax-phonontasks),nstep,etot_conv_thrandforc_conv_thrtorelaxandvc-relaxsteps, thedos.xsettings todos,k_path_distancetobandand the phonon tasks, and the other ph.x, q2r.x and matdyn.x settings to the phonon tasks. So issteps.<step>.KEYfor a step that does not read it, such assteps.nscf.mixing_beta,steps.bands.k_grid,steps.bands.occupations,steps.ph.k_gridorsteps.phonon_dos.k_path_distance, and anysteps.bands_x.KEY:bands.xtakes no setting. A step the task does not have is refused too:steps.scf.KEYonrelax-phonon, whose first step isrelax.
Each setting's structure_specific says whether its value is a judgement
about the structure it was set for — its elements, magnetism, geometry, size
or k-mesh, such as k_grid, u_by_element, starting_magnetization or
spin_orbit_coupling — rather than a method, accuracy or job choice, such as
functional, conv_thr or account. When another structure is opened, the
Workbench keeps the values of the settings that are not structure-specific
and clears the others and every fact override (is_metal, ...).
Each setting's resolved_in says where explain and run publish its
resolved value: record, the record of the decision it feeds, and path,
the keys of its value inside that record's value. Most settings resolve in
their group's record under their own name (conv_thr in
convergence.conv_thr, and k_path_distance in k_path.k_path_distance,
the path of a band task's bands step or of a phonon task's dispersion
step); functional is the functional record itself
(path []), pseudo_table_id resolves in pseudo_table.id,
spin_orbit_coupling in magnetic.spin_orbit_enabled, magnetic_ordering
in magnetic.ordering.applied (null for a run without spin polarization,
which applies no ordering), moment_direction in
magnetic.moment_direction.uvw, k_grid in k_sampling.mesh,
hubbard_projectors in hubbard.projectors (null without +U) and
q_grid in q_sampling.mesh. path is null where the record holds no
value of the setting: extra_bands only shifts nbnd, and
hubbard_needs_correlation and u_by_element decide which U values the
hubbard record lists.
Quote --set values that contain brackets or braces (e.g. --set
'k_grid=[8,8,8]') so the shell does not glob-expand them; array and object
values must be valid JSON. Numbers must be finite: inf, nan and values
that overflow, such as 1e999, are rejected as invalid settings. See
Pseudopotentials for how tables are chosen, pinned, and
checked for compatibility.
is_metal, is_magnetic, and k_distance (v2 epic 11) each resolve through
a human > ml > llm > heuristic priority: explain --json's
records[...].source says which tier actually produced a value, and
records[...].field_sources which tier produced each setting of a compound
record (a --set shift=... reads human beside QRF95's ml k_distance).
When a model decided the value or one of its settings, records[...].model
names the model (model_id, and asset, the
installed release as <id>@<version>) and keeps what it returned
(details, such as a classifier's score and threshold or QRF95's
interval, and warnings), and records[...].citations says what to cite.
is_metal/k_distance become ML-backed once their PSDI-hosted asset is
installed (uv run goldilocks assets install <id> — see Install and check
assets); is_magnetic's asset also carries the
mMACE backbone it embeds structures with, the one the magnetic
orderings --rank-with-mmace flag uses below, and
mace-torch, e3nn and sphericart come with goldilocks-ml.
GOLDILOCKS_MACE_BACKBONE overrides the installed backbone for both (see
mMACE). A model
that is not set up (its asset not installed or failing verification, or
for is_magnetic the packages or checkpoint missing) leaves the value to
the next tier. Once a model is set up, an error
loading or running it fails the command instead of being replaced by the
heuristic answer. is_magnetic runs in a separate worker process, so mMACE
never changes the torch settings of the command or server that asked for
it. There is still no flag to point run/explain at a custom
model file of your own. uv run goldilocks models --json reports every
model, installed or not, so it also confirms whether one you expect to
be usable actually is.
Submit and resume a phonon job
A phonon task's submit.sh runs all its steps in one job: the first pw.x
step, d3hess.x under DFT-D3, ph.x, q2r.x, and matdyn.x for the
phonon DOS and again for the dispersion. No input carries max_seconds.
Instead the script starts a timer that creates pwscf.EXIT
(<prefix>.EXIT) in the working directory at job.timer_seconds, 95% of
walltime_h, and pw.x or ph.x, whichever is running, stops cleanly there.
The script deletes a leftover pwscf.EXIT before the first step and stops
the timer when it ends. The other tasks' scripts have no timer: their pw.x
inputs keep their max_seconds share of the walltime
(job.max_seconds_by_step).
The script checks every step and stops with a goldilocks: line on stderr
when one did not finish. The ph step passes only when ph.x exited with 0 and
wrote a complete dynamical matrix for every q-point pwscf.dyn0 lists.
Otherwise the message names why ph.x stopped (the job timer, a linear system
that did not converge, or its exit code) and the q-points still without a
matrix, and the next line gives the command that resumes the job at the ph
step:
sbatch --export=ALL,GOLDILOCKS_FROM_STEP=ph submit.sh
d3hess.x, q2r.x and both matdyn.x steps pass when their output says
JOB DONE. These programs exit non-zero on an error, so the script's
set -e ends the job at that step's launch, before its check, and no
goldilocks: line is printed: the error is in the step's output, such as
dispersion.out, and in CRASH, or, for a Fortran runtime error such as a
missing pwscf.fc, in the job's own output file.
GOLDILOCKS_FROM_STEP names the step the job starts at, the first when it
is unset. It must be one of the job's step names, which the script lists in
goldilocks_steps (relax d3hess ph q2r phonon_dos dispersion for a
relax-phonon task under DFT-D3); any other value, an empty one too, stops
the script before a step runs.
The steps before it are skipped, so a resumed job never repeats the
relaxation, and ph.x continues from the data its earlier run saved in
out/_ph0 and the dynamical matrices it wrote.
GOLDILOCKS_FROM_STEP=dispersion reruns the dispersion alone, on one task,
from the pwscf.fc the earlier job wrote: after a dispersion.in written
again for another k_path_distance, for instance. A job that starts at the
first step, as a plain sbatch submit.sh does, deletes out/_ph0 and
pwscf.dyn* before it runs anything, since they belong to the save that
step rewrites. A resumed job starts a new timer on its own walltime. A pw.x
step the timer stopped cannot resume: its message says to raise
walltime_h. Only the phonon tasks' scripts read GOLDILOCKS_FROM_STEP;
the other tasks ignore it. See
running and resuming phonons for why.
Magnetic orderings
uv run goldilocks magnetic-orderings structure.cif --json
uv run goldilocks magnetic-orderings structure.cif --rank-with-mmace
Lists a ferromagnetic guess plus any antiferromagnetic
candidates enumlib finds (see Check magnetism and spin-orbit
coupling) for a
human or agent to choose among before generating any input file. Each
candidate is named by its label (fm, afm-1, afm-2, ...), and its
--json overrides generate it, spin-polarized, from the same structure
file:
uv run goldilocks run structure.cif --hpc scarf --set magnetic_ordering=afm-2
The run enumerates again, applies the candidate of that label through the
same steps as magnetic_ordering=afm (which applies afm-1, the smallest
and most symmetric), and records the label in records.magnetic next to the
cell's formula and atom count, with why it was written (criterion) and
the other candidates of its size (alternatives). For a slab, wire or
molecule in a box, only candidates that keep its vacuum vectors are listed
and applied, so every label writes one slab with the uploaded vacuum.
--rank-with-mmace relaxes every candidate's magnetic moments on a frozen
mMACE potential energy surface and recommends the lowest energy-per-atom
one -- needs the mMACE backbone, installed with is_magnetic's asset or
named by GOLDILOCKS_MACE_BACKBONE, as described above. Missing it, or an
error inside the relaxation itself, degrades to an unranked listing
with a warning. Each ranking runs in its own process, one ranking at a time,
so a long ranking never holds up explain or run; a ranking process that
dies fails the request.
Install and check assets
uv run goldilocks assets install default
uv run goldilocks assets status default
uv run goldilocks assets verify default
Use a profile, asset ID, or table ID. default installs the four prediction
models (qrf-kpoints, metallicity-cgcnn, is-metal-classifier,
is-magnetic-classifier) and a PBEsol efficiency PseudoDojo table;
workbench installs all registered models and tables. install also
repairs corrupt installations.
run --fetch-missing (or explain --fetch-missing) installs a missing
pseudopotential table instead of failing, then retries; it does not apply to
any other kind of missing dependency. See
asset storage for locations.
Serve HTTP
uv run goldilocks assets install workbench
uv run --extra http goldilocks serve http
The server defaults to http://127.0.0.1:8000. --host and --port change
the address. --static-root DIRECTORY also serves a built Workbench; a relative
DIRECTORY is resolved against the launch directory once, at startup.
| Endpoint | Purpose |
|---|---|
GET /capabilities |
Codes, tasks, facts, settings, pseudopotential tables, HPC profiles, models, warnings |
POST /inspect |
Structure inspection (inline structure_content, not a path) |
POST /explain |
Analysis and advisor decisions with their layout, plus blocking: the findings /run would refuse with; never writes anything |
POST /run |
Generate a runnable input; respond_with: "json" (default) returns a JSON summary, respond_with: "archive" returns ZIP bytes; a refusal is a 422 advice_incomplete with the findings in error.details.findings |
GET /health |
Process health |
GET /ready |
Asset readiness; 503 for missing or corrupt assets |
GET /openapi.json |
Request and response schemas |
Interactive API documentation is at /docs.
HTTP security
Keep the default localhost binding for local use. The server has no built-in authentication; restrict network access with a firewall or authenticated reverse proxy before exposing it. Configure TLS and request limits there.
HTTP and MCP accept inline structures and registered table IDs, not local
structure paths or publication paths. Server operators control installed
assets. /run never writes to the server's disk: on request it can return
ZIP bytes directly (respond_with: "archive") or a JSON summary (the
default), but it always builds and serves the bundle in memory.
Serve local MCP
Configure your MCP client to launch this command from the repository root:
uv run --extra mcp goldilocks serve mcp
The stdio tools are capabilities, inspect_structure, explain, and run.
MCP's explain tool returns the same records, warnings, blocking and
layout as POST /explain; when run refuses, its error lists the same
findings, each followed by its remedies as JSON override patches. MCP's run
tool never writes to the server's
filesystem — it always returns only the published file list, every resolved
decision (with its source) and their layout, and a warnings array the caller
must relay verbatim. To obtain actual file bytes, use the CLI (goldilocks run
... -o/--out) or the HTTP transport's /run endpoint with respond_with:
"archive".