---
description: Every package in src/matmelt, what belongs in it, and the dependency rule that keeps the layers apart.
---

# Module map

```text
src/matmelt/
├── cli.py  __main__.py        Typer app — a thin dispatcher, no logic
├── commands/                  one module per command, each run_<name>() -> int
│   init  doctor  run  status  monitor  results  retry  cif  update
├── core/
│   ├── jobspec.py             JobSpec / Handle / JobResult / Resources / …
│   ├── stages/                the funnel
│   │   ├── base.py            the Stage contract
│   │   ├── registry.py        FUNNEL_ORDER, OPTIONAL_STAGES, STAGE_OUTPUT_STATE
│   │   ├── compose.py structure.py screen.py calculate.py extract.py
│   │   └── *_runner.py        self-contained scripts, shipped per job
│   ├── orchestrator.py        the pass loop
│   ├── state.py               MaterialState + StateStore (SQLite)
│   ├── preflight.py           dependency / backend / model / AiiDA probes
│   ├── monitor.py             build_snapshot — pure, no Rich, no SQL
│   ├── cpusample.py           /proc + nvidia-smi sampling, best-effort
│   ├── cif.py                 stdlib .gen → CIF writer
│   └── seeds.py               element_combinations
├── backends/  base.py registry.py local.py ssh_exec.py
├── config/    schema.py loader.py
└── ui/        console.py monitor.py monitor_live.py
```

## The dependency rule

Arrows point inward, and there is exactly one direction:

```text
cli.py → commands/ → core/ , backends/ , config/
                       ↑
                      ui/  (rendering only; core never imports it)
```

`core/` never imports `commands/`, `cli.py` or `ui/`. That is what lets the
orchestrator, the stages and the state store be tested without a terminal, and
what keeps a rendering change from being able to break a pipeline.

**All human-facing output goes through `ui/`.** No `print()` in `core/`, no Rich
console constructed anywhere else. The point is not tidiness: it is that
`--json` output stays parseable because nothing else can write to stdout behind
its back. Deprecation notices and progress go to a separate stderr console for
the same reason.

## What belongs where

**`cli.py`** wires Typer options to `run_<command>()` functions and returns
their exit codes. When it starts containing logic, that logic belongs in
`commands/`.

**`commands/`** is the only layer allowed to know about both config and core. A
command loads config, builds a runtime, calls into core, and hands values to
`ui/` for display. Each returns an `int` — the exit code — rather than calling
`sys.exit`, which is what makes commands testable as functions.

**`core/`** is the tool. It takes plain objects: the orchestrator receives a list
of stages and a `{stage_name: backend}` mapping, and has no idea a YAML file
exists. `config/loader.py` is the seam that turns a file into those objects.

**`core/stages/*_runner.py`** are not library modules. They are programs, staged
to a backend and executed there, and they import the standard library plus their
own science package — never `matmelt`. A test parses each runner's imports and
fails if that is violated, because the property is invisible until a remote job
breaks.

**`backends/`** knows how to run an argv somewhere and bring files back. It
knows nothing about materials, stages or science.

**`ui/`** turns values into Rich renderables. It computes nothing: `core/monitor.py`
builds the snapshot, `ui/monitor.py` draws it.

## Where a change usually goes

| Change | Where |
|---|---|
| New CLI flag | `cli.py` + the matching `commands/` module |
| New stage option | that stage's `__init__` (the signature is the contract) |
| New science step | a new `*_runner.py` + a thin `Stage` class + registry entry |
| New compute target | a `ComputeBackend` subclass + `register(kind, cls)` |
| New config key | `config/schema.py`, then `reference/config.md` (a guard enforces it) |
| New displayed value | `core/monitor.py` for the value, `ui/` for the drawing |

## Related

- {doc}`contracts` — the two ABCs those extension points implement.
- {doc}`../api/index` — the generated reference for every module above.
