Headless execution of Calango orchestration workflows — for HPC clusters, batch queues and anywhere else without a display.
Build a pipeline on the Calango canvas, export it to a single JSON file, copy that file to the cluster, run it there.
pip install calango-cli
calango-cli run workflow.json -o results/The Calango GUI's Orchestration panel is a node canvas: structures enter through a Structure Container, flow along links into simulations and structure transforms, and fan out so the whole pipeline runs once per structure. That is exactly the shape of work you want on a cluster and exactly the shape of work you do not want to babysit through a remote desktop.
Orchestration → Export Workflow writes the pipeline as one JSON document.
The document is:
- self-contained — structures travel inside it as extended-XYZ text, so there is nothing else to copy and nothing to re-point at a different path;
- self-describing — each node carries its own family and its own input-slot table, so this tool never keeps a second copy of the GUI's module knowledge and cannot drift away from it;
- versioned —
"schema": "calango.workflow/1", checked on load.
calango-cli reads it, rebuilds the DAG, and executes it: transforms in
process through ASE, simulations as subprocesses running the same generated
scripts the GUI would have run. The results land in the same directory layout
the GUI produces, so they load straight back into its Results panel.
pip install calango-cliRequires Python 3.9+ and ASE. Everything else a workflow needs — GPAW, a MACE
model, VASP, Quantum ESPRESSO — belongs to the environment the job runs
under, which on a cluster is usually a module load rather than a pip
install, so it is deliberately not declared as a dependency here.
# Will this run? What will it do? Both are instant and need nothing but the file.
calango-cli validate workflow.json
calango-cli info workflow.json
# Stage every directory and print the commands, without running anything.
calango-cli run workflow.json --dry-run
# For real.
calango-cli run workflow.json -o results/Inside a scheduler script:
#!/bin/bash
#SBATCH --nodes=1 --ntasks=8 --time=04:00:00
module load gpaw
calango-cli run workflow.json -o "$SLURM_SUBMIT_DIR/results" \
--cores "$SLURM_NTASKS" \
--launch "srun -n {cores} gpaw python {script}" \
--keep-going| Option | What it is for |
|---|---|
--launch TEMPLATE |
Override every node's launch line. Placeholders: {python}, {script}, {cores}. This is the "everything here runs under srun" flag. |
--cores N |
What {cores} expands to. |
--python PATH |
Interpreter for the generated scripts. Defaults to the one running calango-cli, which is normally the environment that has ASE. |
--keep-going |
A failure on one container structure should not end a twelve-structure sweep. |
--timeout S |
Kill a single node after S seconds. |
--dry-run |
Stage everything, launch nothing. |
A workflow file says what to compute; these say how to launch it here. Keeping them apart is what lets one exported file run unedited on a laptop, a login node and inside a batch script.
results/
├── workflow.json the document that was run, copied verbatim
├── orchestration.json the graph and every node's state, rewritten as it goes
├── batch_1_Cu/ one folder per container item (absent when there is one pass)
│ ├── node_1_container/
│ │ ├── transformed.extxyz
│ │ └── provenance.json
│ └── node_2_geometry_optimization/
│ ├── structure.extxyz staged from the parent
│ ├── run.py
│ ├── stdout.log
│ ├── geometry_optimization.json
│ └── provenance.json
├── batch_2_Au/
└── batch_3_Pt/
Copy results/ back to your machine and open the runs from Calango's
Processes panel.
Every node leaves a provenance.json with two kinds of record:
- logical — where the node sits in the graph, which parent filled which named input, the SHA-256 of the script it ran, the parameters a transform applied, which batch item it is;
- data — for every input: the path it was copied from, the name it was staged as, its size and its SHA-256; for every output, the same.
Either alone can mislead. Logical provenance says a node inherited "the pristine host"; only the checksum says which pristine host.
The same ones the GUI enforces, restated here because the CLI is where a hand-edited workflow shows up — and because on a cluster the alternative to failing at load time is failing after the queue wait:
- A node with a parent inherits from it or does not run. Falling back to anything else computes the right calculation on the wrong structure.
- A node with no parent and no structure of its own is refused, naming the Structure Container it needs.
- Containers must hold the same number of structures. Taking a maximum and clamping the shorter ones would silently re-use their last structure.
- An analysis node linked to too few parents is refused, naming the slots it wanted.
- A defect recipe that matches no atom, or has no operations at all, is an error — forwarding the pristine cell is how a study reports a formation energy of exactly zero with nothing anywhere complaining.
- Cycles are refused.
git clone https://github.com/seixas-research/calango-cli
cd calango-cli
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytestMIT — see LICENSE.