cosmos-runThe one command an experimenter needs. Everything it does could be done with a long ansible-playbook invocation; the point is that nobody should have to know that invocation, or know Ansible at all, to run an experiment.
usage: cosmos-run [-h] [--version] [-i INVENTORY] [--resolve-only] [--check]
[-e EXTRA_VARS] [--vault-password-file VAULT]
[--ask-vault-pass] [-v]
[description]
The positional argument is either a path, or a name relative to the experiment directories — the short form is what the tutorials use:
cosmos-run sdr/ofdm-ber-sb5.description.yml # packaged, or your own copy
cosmos-run ./my-experiment.yml # a path, anywhere
Names resolve against ~/cosmos-experiments first, then /usr/share/cosmos-experiments. Your copy therefore wins, which is how you edit an experiment without root. A name that matches neither is reported with both directories listed rather than a bare "not found".
| Option | What it does |
|---|---|
--resolve-only |
Answer "could this run here, and on which nodes" and stop. Reads only the inventory, touches no hardware, and needs no reservation. |
--check |
Dry run. Reports what each step would do without doing it. Destructive steps — imaging above all — never execute. |
--detach |
Start the run in its own session and return the prompt. The experiment survives logging out. |
--status [RUN_ID] |
List recorded runs and their state, or show one in detail with the tail of its log. Starts nothing, needs no reservation. |
--tail N |
Lines of log to show with --status RUN_ID (default 40). |
-e, --extra-vars |
Override a parameter. Repeatable. -e sub=qpsk, or JSON for structure. |
-i, --inventory |
Use a different inventory config. Rarely needed. |
--version |
Print the version and the path in use — see below. |
--vault-password-file, --ask-vault-pass |
Supply a vault password for encrypted values. |
-v |
More output. Repeat for more still. |
-- |
Everything after it goes to ansible-playbook unchanged. |
That last one matters: the wrapper is a convenience, not a cage. When you need something it does not expose, it is still ansible-playbook underneath.
--detach, then --statusA sweep can run for hours, and a foreground cosmos-run dies with your SSH session — a closed laptop or a dropped VPN takes the experiment with it. Anything longer than a coffee break should be detached:
cosmos-run fr3/ofdm-ber.description.yml --detach
detached: fr3-ofdm-ber-20260806T001704Z
log /home/you/cosmos-artifacts/fr3-ofdm-ber-20260806T001704Z/console.log
status cosmos-run --status fr3-ofdm-ber-20260806T001704Z
Come back whenever — and from whichever console you happen to reach, because ~/cosmos-artifacts is shared across them all:
cosmos-run --status
RUN STATE ELAPSED WHERE
fr3-ofdm-ber-20260806T001704Z succeeded 0:14:26 console.sb1.cosmos-lab.org
fm-broadcast-20260805T130022Z running 0:03:11 console.sb6.cosmos-lab.org
Four states, and the last two are the ones worth understanding:
| State | Meaning |
|---|---|
running |
The recorded process is alive on this console. |
succeeded / failed |
It finished, and the exit status was recorded. |
killed |
It was terminated — normally your reservation expiring, not a crash. |
died |
It claimed to be running and its process is gone. Nothing recorded an outcome, so the stored state was stale and is reported as such. |
running? |
Started on a different console. Process IDs are per-machine, so the claim cannot be checked from here — it is not guessed at. |
cosmos-run --status <run-id> adds the detail and the tail of the log:
cosmos-run --status fr3-ofdm-ber-20260806T001704Z
Do not wrap
cosmos-runinnohup … &yourself. That was the old habit;--detachreplaces it, and unlike a barenohupit records why a run stopped, hands the playbook a chance to run its teardown first, and leaves a status any console can read.
A sweep writes each measured point to its results file as it is taken, not at the end. If a run is cut short — a timeout, an interrupt, an expiring reservation — every point already measured is still there and still a valid CSV.
--resolve-only is the one to try firstIt is the cheapest possible question and the most useful early answer:
seskar@console-grid:~$ cosmos-run sdr/ofdm-ber-grid.description.yml --resolve-only
"msg": "ofdm-ber-grid on grid: tx=node18-2.grid.cosmos-lab.org; rx=node18-19.grid.cosmos-lab.org "
localhost : ok=10 changed=0 unreachable=0 failed=0 skipped=1
Because it consults only the read-only inventory, you can use it to explore what a sandbox can support before booking time on it, and to check a description you are writing without owning any hardware yet.
--check before anything destructive--check is the rehearsal. Imaging is the reason it exists: an experiment that requests an image will reimage a node, and a node's contents are not yours to assume.
cosmos-run sdr/ofdm-ber-sb4.description.yml --check
Steps that cannot be simulated are skipped and say so rather than failing — a dry run reports what would happen, so a clean --check is meaningful.
Anything under parameters: in the description:
# simple values
cosmos-run sdr/ofdm-ber-sb5.description.yml -e sub=qpsk -e amplitude=0.06
# lists and structures need JSON
cosmos-run sdr/ofdm-drive-probe-sb4.description.yml \
-e '{"amplitudes": [0.02, 0.04, 0.06, 0.08]}'
Overriding one parameter can invalidate another. Transmit drive is per modulation, not a global setting: an amplitude that is right for BPSK will destroy a QPSK constellation, and the resulting BER sits flat near 0.1 no matter what else you change. If you change
sub, revisitamplitude— see the drive window in the OFDM laboratory.
--version prints a path on purposeThe collection can be installed twice — system-wide by the package, and per-user in ~/.ansible/collections, which comes first on the search path. So "which version is installed" is an ambiguous question, and the honest answer names the copy that will actually run:
seskar@console-grid:~$ cosmos-run --version
cosmos-run (cosmos_lab.orchestration 0.1.0)
loaded from: /usr/share/ansible/collections/ansible_collections/cosmos_lab/orchestration
ansible-playbook [core 2.16.3]
When a per-user copy is shadowing the packaged one, a shadowing: line names it. Anyone debugging "my fix did not take effect" is almost always looking at this.
0 on success. Non-zero when the experiment failed, when the description could not be resolved onto hardware, or when the description itself is invalid — the message distinguishes them, and a resolution failure names what was wanted and what was found. See resources and feasibility.
~/cosmos-artifacts/<name>-<timestamp>/, containing whatever collect: named plus run.json and a verbatim copy of the description that ran. See artifacts and reproducibility.
Last verified: 2026-08-03 on console.grid.cosmos-lab.org.