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

# Runs

> Monitor and manage executions on Lyceum Cloud

A **run** (also called an **execution**) is a single, ephemeral invocation of code on Lyceum Cloud. You submit some code or a container, the platform schedules it onto a machine matching the hardware profile you asked for, streams logs back, and bills you per second of wall-clock time. When the code finishes, successfully or otherwise, the machine is released.

Runs are the right tool when:

* The work has a clear start and end (a training step, a batch transform, a one-off job)
* You don't need to keep the environment around between invocations
* You'd rather not manage a long-lived server

For interactive sessions over SSH, use [Instances](/docs/instances/vms). For long-running model serving, use [Dedicated Inference](/docs/inference/dedicated).

## Execution types

Three submission paths produce the same kind of run record:

| Type               | When to use it                                                                        | Endpoint                          |
| ------------------ | ------------------------------------------------------------------------------------- | --------------------------------- |
| **Python**         | A `.py` file or a snippet, with optional `requirements.txt` and bundled local imports | `POST /execution/streaming/start` |
| **Docker image**   | You already have a container image with your environment baked in                     | `POST /execution/image/start`     |
| **Docker Compose** | A multi-service stack defined in `docker-compose.yml`                                 | `POST /execution/compose/start`   |

All three return an `execution_id` and a streaming URL. From that point on you interact with the run through the same set of read/abort endpoints, regardless of how it was submitted.

## Lifecycle

A run moves through these states:

`pending` → `starting` → `running` → `completed` (or `failed`, `system_failure`, `cancelled`, `aborted`)

`pending` and `starting` cover queueing and machine provisioning. `running` is what it sounds like. The terminal states are mutually exclusive, `aborted` means a user (or the API) hard-stopped it, `cancelled` is a graceful stop (used for notebooks), `failed` is a non-zero exit, `system_failure` is an infra problem, and `completed` is a clean finish.

You can list runs by status to monitor the queue or to find recently failed runs to investigate.

## CLI

```bash theme={null}
lyceum workloads list                       # active runs
lyceum workloads history                    # recent runs
lyceum workloads abort <execution_id>       # hard stop
```

`abort` marks the run `aborted` and kills the underlying job. The graceful-stop variant (which marks the run `completed`, used for notebook sessions you're ending normally) is API-only, see the workloads `/stop` endpoint below.

## REST API

| Method   | Endpoint                            | Purpose                                                |
| -------- | ----------------------------------- | ------------------------------------------------------ |
| `GET`    | `/workloads/list`                   | List your executions                                   |
| `GET`    | `/execution/{execution_id}`         | Full execution record (status, stdout, stderr, result) |
| `GET`    | `/execution/{execution_id}/timing`  | Start, end, duration                                   |
| `GET`    | `/execution/{execution_id}/metrics` | GPU and system metrics                                 |
| `GET`    | `/logs/execution/{execution_id}`    | Logs from Loki                                         |
| `POST`   | `/workloads/abort/{execution_id}`   | Hard-stop                                              |
| `POST`   | `/workloads/stop/{execution_id}`    | Graceful stop                                          |
| `DELETE` | `/execution/{execution_id}`         | Delete the execution record                            |

## GPU and system metrics

For runs on GPU machines, the platform records per-execution metrics from DCGM and system telemetry. The metrics endpoint exposes:

* **GPU**, utilisation %, memory utilisation %, temperature °C, power draw and limit (W), SM and memory clocks (MHz), PCIe RX/TX throughput
* **System**, total and used RAM, CPU usage %

The query supports `start`, `end`, and `step` (default `15s`) so you can pull the whole run or a window. This is the same data the dashboard charts; you can use it to attribute time, debug stalls, and confirm a job actually used the GPU it was billed for.

## Logs

Logs are stored in Loki and queryable by execution. By default the logs endpoint returns the last 24 hours of output for an execution (max 10,000 entries), adjust with `limit` and `hours` query parameters.

### Streaming logs live

When you launch a run, the response includes a streaming URL (`stream_url`, also called `streaming_url`) that delivers stdout and stderr live over Server-Sent Events while the run executes. This is separate from the Loki query above, which serves historical logs after the fact.

Connect with an HTTP `POST` and the header `Accept: text/event-stream`. Each message is a `data:` line carrying a JSON object. Three shapes occur:

| Event (JSON in the `data:` line)                                         | Meaning                                                              |
| ------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| `{"output": {"content": "..."}}`                                         | One chunk of stdout or stderr                                        |
| `{"jobFinished": {"job": {"result": {"returnCode": 0, "error": null}}}}` | Run finished, carries the exit code and error. The stream ends here. |
| `{"type": "output" \| "completed" \| "error", ...}`                      | Legacy format, still parsed for backward compatibility               |

```python theme={null}
import httpx, json

with httpx.stream("POST", stream_url, headers={"Accept": "text/event-stream"}, timeout=600.0) as resp:
    for line in resp.iter_lines():
        if not line.startswith("data: "):
            continue
        event = json.loads(line[6:])
        if "output" in event:
            print(event["output"]["content"], end="")
        elif "jobFinished" in event:
            code = event["jobFinished"]["job"]["result"]["returnCode"]
            print(f"\nrun finished, exit code {code}")
            break
```

## GPU selection runs

In addition to the three standard execution types, Lyceum Cloud supports a **GPU selection** flow where the platform fans your code out across multiple GPU types and hands back results from each. The use case is benchmarking: you want to know which GPU is fastest or most cost-effective for a given workload before committing to a hardware profile.

The flow is asynchronous: you submit code, get back an `execution_id` plus a callback token, and poll the status endpoint until the parent execution and its sub-jobs complete.

### CLI

```bash theme={null}
lyceum gpu-selection run script.py
lyceum gpu-selection status <execution_id>
```

### REST API

| Method | Endpoint                                         | Purpose                                                         |
| ------ | ------------------------------------------------ | --------------------------------------------------------------- |
| `POST` | `/execution/gpu_selection/start`                 | Submit code for GPU selection                                   |
| `GET`  | `/execution/gpu_selection/{execution_id}/status` | Get the current status of the parent execution and any sub-jobs |

The parent execution gets recorded like any other run, and sub-jobs appear as related executions you can query individually.

## Inspecting an end-to-end workflow

For a worked example that submits a run, polls until it's done, and pulls logs and metrics, see [End-to-End API Workflow](/examples/api-integration).

<Columns cols={2}>
  <Card title="Launch a run" icon="play" href="/docs/serverless/launch-run">
    Submit a Python or Docker workload.
  </Card>

  <Card title="Manage secrets" icon="lock" href="/docs/serverless/secrets">
    Inject environment variables into runs.
  </Card>
</Columns>
