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

# Run Lifecycle

> Start, resume, and end a Pluto run from Python.

A run starts with `pluto.init()` and ends with either `run.finish()` (mark it complete on the server) or `run.close()` (release local resources without changing the run's server-side state). This page covers the parameters for each, plus how to resume a finished run.

## Starting a Run

```python theme={null}
import pluto

run = pluto.init(
    project="my-project",
    name="experiment-1",
    config={"lr": 1e-3, "batch_size": 32},
    tags=["baseline"],
)
```

Common parameters:

| Parameter        | Type         | Description                                                                               |
| ---------------- | ------------ | ----------------------------------------------------------------------------------------- |
| `project`        | `str`        | Project name (auto-created if it doesn't exist).                                          |
| `name`           | `str`        | Human-readable run name. Pluto also auto-generates a sequential display ID like `MMP-42`. |
| `config`         | `dict`       | Hyperparameters. Snapshot at init; for in-run edits use `run.update_config()`.            |
| `tags`           | `list[str]`  | Initial tag set. Edit later with `run.add_tags()` / `run.remove_tags()`.                  |
| `run_id`         | `int \| str` | Resume an existing run by numeric ID or display ID. Used with `resume=True`.              |
| `resume`         | `bool`       | If `True`, re-open a previously finished run instead of creating a new one.               |
| `fork_run_id`    | `int \| str` | Fork from a parent run. See [Run Forking](/pluto/forking).                                |
| `fork_step`      | `int`        | Required with `fork_run_id`. Step number to fork at.                                      |
| `inherit_config` | `bool`       | When forking, deep-merge the parent's config into the child's. Defaults to `True`.        |
| `inherit_tags`   | `bool`       | When forking, copy the parent's tags. Defaults to `False`.                                |

## Resuming a Finished Run

```python theme={null}
run = pluto.init(project="my-project", run_id="MMP-42", resume=True)
run.log({"eval/accuracy": 0.94}, step=10000)
run.finish()
```

Both numeric IDs (`12345`) and display IDs (`"MMP-42"`) are accepted.

## Ending a Run

The SDK exposes two teardown methods:

| Method         | Local cleanup | Marks the run on the server                                              | Use when                                                                  |
| -------------- | ------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
| `run.finish()` | Yes           | **Yes** — transitions to `COMPLETED` (or `FAILED` on uncaught exception) | The training loop is done and you want the run to leave the active state. |
| `run.close()`  | Yes           | No — server status is unchanged                                          | A short-lived process attached to an ongoing run and shouldn't end it.    |

Both stop the monitor thread, drain the sync queue, and close HTTP clients. `run.finish()` also fires automatically on interpreter shutdown via `atexit`. `run.close()` **unregisters** the `atexit` hook, so a process that calls `close()` won't accidentally complete the run when it exits.

### When to Use `close()` Instead of `finish()`

`close()` supports multi-process workflows where one process attaches to an active run and shouldn't take it down on exit. Two common cases:

* **Eval job appending to a live training run.** The training loop holds the "real" `finish()`. The eval process opens the same run with `resume=True`, writes metrics, and `close()`s — leaving the run active.
* **Side process uploading artifacts** while the main run is still producing data elsewhere.

```python theme={null}
# In a side process attaching to a still-running training job
run = pluto.init(project="my-project", run_id="MMP-42", resume=True)
run.log({"eval/loss": 0.32}, step=current_train_step)
run.close()  # local teardown only, run stays active on the server
```

`close()` is idempotent and thread-safe; subsequent `finish()` calls on a closed run are no-ops.
