> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metaphi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Keep state

> Run jobs, transactions and terminals on one persistent system; checkpoint it and restore it.

A system is a named mainframe state that outlives any one call: its catalog and data sets, its Db2 tables and its region's queues. Name it as `system` on `run_unit`, `submit`, `start` or `open_terminal`. The call starts from the state the system's last call left, and the state it leaves becomes the system's next. Needs `harwell:runs:write` and `harwell:systems:write`.

## 1. Start a system

The first call that names a system starts it on a fresh volume, with the site's data sets and tables from the codebase's `harwell.toml`.

```json theme={"dark"}
submit {"repo": "acme/billing", "ref": "main", "path": "mainframe", "deck": "LOADJOB", "system": "billing-dev"}
```

A system name is 1 to 63 characters: lowercase letters, digits and `-`, starting with a letter or digit.

The result names the system and where its state now stands:

```json theme={"dark"}
{"status": "ok", "system": {"name": "billing-dev", "head": "r-20261103T120000Z-...", "from": ""}, ...}
```

`head` is the run the system's next call starts from. It is also a `work_id`.

## 2. Keep working on it

```json theme={"dark"}
start  {"repo": "acme/billing", "ref": "main", "path": "mainframe", "transid": "CB00", "screens": [...], "system": "billing-dev"}
submit {"repo": "acme/billing", "ref": "main", "path": "mainframe", "deck": "EODJOB", "system": "billing-dev"}
```

The transaction reads what `LOADJOB` wrote, and `EODJOB` reads what the transaction wrote. Data persists from call to call. The CICS region starts cold on every call, and programs come from `repo` at `ref` each time, so an edit shows on the next call.

A failed run's state becomes the system's state too, as a failed job's writes stay on a mainframe.

## 3. Read it

`sql`, `list_datasets` and `read_dataset` take `system` in place of `work_id` and read its current state:

```json theme={"dark"}
sql {"system": "billing-dev", "statement": "SELECT COUNT(*) FROM ACCOUNTS"}
```

`systems` lists your organization's systems, or describes one: its head, when it last moved, its size, the last calls that moved it, its checkpoints, the terminal holding it, and what is running on it now.

```json theme={"dark"}
systems {"system": "billing-dev"}
```

## 4. Checkpoint and restore

```json theme={"dark"}
checkpoint {"system": "billing-dev", "label": "before-eod"}
submit     {"repo": "acme/billing", "ref": "main", "path": "mainframe", "deck": "EODJOB", "system": "billing-dev"}
restore    {"system": "billing-dev", "label": "before-eod"}
```

`restore` moves the system back to the checkpoint. Nothing is lost: the state it moved from stays in the system's lineage. Using a label again moves it to the current state.

## 5. Delete it

```json theme={"dark"}
delete_system {"system": "billing-dev"}
```

The system and its checkpoints are forgotten.

## One writer at a time

A call on a system is refused while another call runs on it, naming what holds it:

```text theme={"dark"}
system 'billing-dev' is busy: submit since 2026-11-03T12:00:00Z; call again when it ends
```

Call again when it ends. `systems` shows the same under `busy`.

## A person at a terminal

`open_terminal` with `system` gives a person a live system: every transaction the codebase installs, on the system's data. While the terminal is open it holds the system:

| Call on the system | While a terminal holds it |
| - | - |
| `submit` | Runs on the terminal's region, between the person's keys. A data set the region holds in a conflicting mode keeps the job from running and says why (`IEF861I`). `CEMT SET FILE(x) CLOSED` at the terminal frees it |
| `checkpoint`, `sql`, `list_datasets`, `read_dataset`, `systems`, `read_terminal` | Take in what the person has done so far |
| `run_unit`, `start`, `open_terminal`, `restore`, `delete_system` | Refused, naming the terminal, until the person closes it |

## Without a system

To carry state without a name, set `return_work` on a run and pass the `work_id` it returns to the next call. See [Query Db2 and data sets](https://docs.metaphi.ai/harwell/guides/db2-and-data-sets.md#3-keep-the-volume).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.