For the complete documentation index, see llms.txt. This page is also available as Markdown.

Running and managing Inference

The mithrl CLI handles the complete inference lifecycle through the platform origin. Your bearer token or API key is sent only to the platform control-plane routes. File uploads and artifact downloads use time-limited object-store URLs, so the bytes do not transit the platform.

1. Sign in

mithrl login

Headless callers can activate an API key previously registered with mithrl keys add:

mithrl keys use --name ci-agent

2. Discover a workflow and its inputs

mithrl workflows
mithrl workflows --id upstream-regulator-analysis

The detail response includes run_inputs. Each entry names the key accepted by mithrl run --input; workflow inputs are reusable artifact file_ref values. An entry's columns names the header the uploaded file must have — for example background_csv requires a single curie column of canonical KG CURIEs, unlike omics_csv, whose identifiers are resolved and may be symbols.

3. Run with automatic staging

Prefix a local path with @ to upload it before submission:

mithrl run upstream-regulator-analysis \
  --input omics_csv=@cohort.csv \
  --input background_csv=@background.csv \
  --label cohort-a

The @ is required for a local file. A bare value is treated as an existing file_ref, so a path passed without it is rejected before submission with the corrected flag to use.

The CLI prints the run label and a shell-safe retry command before submission. If the connection drops after the platform accepts the run, use that exact command; it reuses the staged file_ref values and label, reproducing the idempotency key instead of creating duplicate work.

Use --no-wait to return immediately:

Polling is bounded so the command always terminates. The budget outlasts the presets' measured runtimes, but if a run is still active when it expires, mithrl run exits 3 (incomplete) rather than 0: it prints its usual payload, with data.poll_exhausted: true, the run_id, and the mithrl status ... --watch command to reattach with. Re-running that resumes watching from wherever the run has reached. Exit 3 is not a failure — nothing needs re-submitting, and the run is still executing — but it is not success either, so a script chaining on mithrl run ... && ... correctly stops instead of processing results that do not exist yet. --no-wait asks only for the acceptance envelope, so it exits 0.

mithrl status <run_id> --watch's own watch is bounded the same way, but it always exits 0 — whether it reached a terminal state or its own bounded watch expired first — so do not use its exit code the way you can mithrl run's: check data.run.status for terminal state instead, and re-run the same command to keep watching. And exit 0 is not a verdict on either command: a run that reaches failed is a finished run and still exits 0, with the failure in data.run.status / data.results.

4. Reuse an uploaded file

Upload once when several runs share the same input:

If an upload is interrupted, its structured error includes an upload_id and resume command:

5. Manage runs

rerun forks a completed run with the same resolved configuration. retry is for a failed run whose failure is retryable. Both return a child run ID and a status command.

Each fork prints its own --idempotency-key before submitting. Running rerun twice forks twice, which is the intent; if the connection drops before a fork's response arrives, pass the printed key back instead of re-running the bare command, and the already-created child is returned rather than a duplicate:

A reused key that already resolved says so on stderr, so a replay is never mistaken for new work.

A fork whose request hits a transient upstream failure (a 5xx, or a dropped connection) is retried automatically, up to three attempts with backoff. Every attempt sends the same key, so a fork the first attempt actually created is returned rather than duplicated. Anything else — a run that is still active, a failure that is not retryable, a run that does not exist — fails immediately, since a second identical request only repeats the same refusal.

Only the first attempt waits out the full multi-minute budget a healthy-but-long fork can need; a retry, which is replaying that same key against a decision the upstream has very likely already made, uses a much shorter timeout — so three attempts cost close to one long wait plus two short ones, not three long waits back to back. If the internal retry itself is what surfaces the already- created child (rather than a key you passed), the CLI says so plainly instead of warning that a key "was already used" — no key was reused; the retry just did its job.

cancel reports whether it cancelled anything: cancellation is requested when the run was still active, or noop_terminal when the run had already finished on its own and nothing was stopped. The status alone cannot say — cancellation is cooperative, so a cancel that landed often reports a still-running run.

6. Fetch findings and artifacts

Downloads stream to disk and never overwrite an existing file. If a presigned link expires, the CLI asks the platform for one fresh link and retries once. Artifacts that are transient or past retention are reported as unavailable rather than fabricated as empty files.

7. Validate a custom graph

Dry-run a JSON or YAML graph without creating a run:

Validation returns the workflow service's complete warnings/errors envelope. A successful response contains valid: true; blocking graph or input problems exit with the CLI's structured error shape.

Last updated

Was this helpful?