---
description: Use matmelt doctor to check backends, per-stage dependencies, enumeration size and the screening model before committing a machine to a run.
---

# Check that a machine can do the work

`matmelt doctor` answers one question — *would a run start right now?* — and it
answers it for the machines the run would actually use, not for the interpreter
MatMelt happens to be installed in.

```console
$ matmelt doctor
```

Exit `0` means ready. Exit `1` means it found problems and printed them. Exit
`2` means the config file itself is wrong, so nothing was checked.

## Read the two tables

The first table probes each configured backend. The second probes each stage's
science dependency **in that stage's own interpreter**, on whichever machine
that stage runs on.

```text
                              Backend reachability
┏━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Backend ┃ Kind         ┃ Status  ┃ Detail                                    ┃
┡━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ laptop  │ LocalBackend │ healthy │ work_dir ~/matmelt-demo/materials-jobs    │
│         │              │         │ writable                                  │
└─────────┴──────────────┴─────────┴───────────────────────────────────────────┘
                                Stage readiness
┏━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
┃ Stage     ┃ Needs       ┃ Interpreter ┃ Where ┃ Status ┃ Detail              ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
│ compose   │ smact       │ python3     │ local │ ok     │ smact importable    │
│ structure │ pyxtal      │ python3     │ local │ ok     │ pyxtal importable   │
│ screen    │ mace        │ python3     │ local │ ok     │ mace importable     │
│ extract   │ stdlib only │ python3     │ local │ ok     │ standard library    │
│           │             │             │       │        │ only -- always      │
│           │             │             │       │        │ ready               │
└───────────┴─────────────┴─────────────┴───────┴────────┴─────────────────────┘
Seed enumeration: 2 element(s) -> 3 combination(s) (size 1: 2, size 2: 1).
doctor: all checks passed.
```

Three lines are worth reading rather than skimming:

- **`Where`** says which machine the dependency was probed on. `local` is this
  machine; a remote stage shows `user@host`, because the science stack has to be
  where the job runs, not where you typed the command.
- **`extract` is always ready.** Its runner is standard-library only. That is a
  contract the test suite enforces, not a coincidence.
- **`Seed enumeration`** is the size of the search you are about to start,
  reported before any work happens.

## Fix a missing dependency

A stage whose package is missing is `MISSING`, and the command to fix it is
printed under the table — pointed at the right interpreter:

```text
│ compose   │ smact       │ /usr/bin/pyth… │ local │ MISSING │ ModuleNotFound… │
│           │             │                │       │         │ No module named │
│           │             │                │       │         │ 'smact'         │
│ screen    │ mace        │ /usr/bin/pyth… │ local │ MISSING │ ModuleNotFound… │
│           │             │                │       │         │ No module named │
│           │             │                │       │         │ 'mace'          │
└───────────┴─────────────┴────────────────┴───────┴─────────┴─────────────────┘
To fix the missing requirements, run:
  /usr/bin/python3 -m pip install smact
  /usr/bin/python3 -m pip install mace-torch
```

Copy those lines rather than composing your own: the import name and the package
name differ more often than you would like — `mace` is installed by
`pip install mace-torch`.

If the interpreter is wrong rather than the environment, fix the stage's
`python` option instead ({doc}`../reference/config`).

## Diagnose a remote

For a stage wired to an `ssh_exec` backend, both tables reach across the
network, and the fix hint becomes a remote one:

```text
│ cluster │ SshExecBackend │ DOWN    │ alice@cluster.example.org: work dir     │
│         │                │         │ /tmp/matmelt-jobs not usable (ssh exit  │
│         │                │         │ 255) ssh: Could not resolve hostname    │
│         │                │         │ cluster.example.org: Name or service    │
│         │                │         │ not known                               │
...
│ screen    │ mace        │ /opt/scien… │ alice@clust… │ MISSING │ ssh: Could  │
...
To fix the missing requirements, run:
  ssh alice@cluster.example.org /opt/science-venv/bin/python -m pip install
mace-torch
```

The `Detail` column carries the SSH client's own message, so the usual causes —
unknown host, refused key, wrong username — are distinguishable without turning
on any debugging. Connections use `BatchMode=yes`, so key-based access must
already work non-interactively; MatMelt never prompts for a password.

## Check the screening model

When `screen` has no `model_path`, `doctor` says what will be downloaded, how
big it is, and where it will land:

```text
Screen model: ok -- no model_path configured: the MACE-MP foundation model
(size=medium) will be downloaded on first use into the mace cache
(~/.cache/mace) -- a one-time download on the order of hundreds of MB. It will
NOT be downloaded without your consent.
```

That is informational, not a problem. A `model_path` that is **set but missing**
is a problem, and is reported as one. When the stage runs remotely, the file is
checked on the remote.

## Script it

`--json` prints the same findings as data, with nothing else on stdout:

```console
$ matmelt doctor --json
```

```text
top-level keys: ['aiida', 'backends', 'config', 'enumeration', 'model', 'ok', 'requirements']
```

Each entry under `requirements` carries the stage, the interpreter, the
requirement (`null` for `extract`), whether it is satisfied, where it was
probed, and the exact `install_command` when it is not:

```console
$ matmelt doctor --json | python3 -c "
import json, sys
for r in json.load(sys.stdin)['requirements']:
    if not r['satisfied']:
        print(r['stage'], '->', r['install_command'])
"
```

```text
compose -> /usr/bin/python3 -m pip install smact
screen -> /usr/bin/python3 -m pip install mace-torch
```

`ok` is the same verdict as the exit code, so a CI gate is
`matmelt doctor --json | jq -e .ok`.

## Related

- `run` performs the same preflight before it starts, and refuses rather than
  failing material after material — see {doc}`diagnose-a-failure`.
- Every key mentioned here: {doc}`../reference/config`.
- The `calculate` stage adds an AiiDA probe (profile loads, code found) to this
  report; see {doc}`../tutorials/t6-calculate-dftb`.
