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

# Apps

> Functions and deployments, their calls in order, logs and an execution timeline

**Apps** is where your code shows up. An app is one script's worth of functions and deployments, grouped the
way you wrote them.

## Run an example without writing anything

**Run an example** on the Apps page holds runnable templates: a function, a four-step pipeline, an HTTP
endpoint, a queue, a GPU benchmark, four trainings one card each, and one training on two cards. **Run** executes the template on this cluster as your workspace,
exactly as `python app.py` would, and the output streams into the dialog. What it creates appears in Apps like
any other work, with its containers, logs and timeline.

Each card says whether it needs a CPU or a GPU and roughly how long it takes. GPU templates check the cluster's
pools first and warn when there is none, instead of leaving a task pending with no explanation.

**Code** shows the file that runs, to read, copy or download. That is the hand-off: run it here once, then save
it as `app.py` and run the same thing from your own machine. A first-time workspace also gets three lines
explaining that sequence, dismissible for good.

Routes: `GET /api/templates`, `GET /api/templates/{id}`, `POST /api/templates/{id}/run`,
`GET /api/templates/runs/{run_id}`.

## Where your run goes

Every `python app.py` (and `levers9 deploy`, `serve`, `run`) prints one line before it builds anything:

```
=> Workspace 068b18 · context default · https://levers9-app.uselevers.com/apps
```

That is the workspace the run lands in and the dashboard that shows it. If the workspace is not the one you
are signed into, you are using another context (`levers9 config list`; delete strays with
`levers9 config delete NAME`) or an environment token, and the dashboard you are looking at will not show
the run.

## Blueprint builds

The first run of a script with new packages builds a blueprint on the cluster before any call exists. While
that happens the Apps page shows a **Building a blueprint** card with the build container and when it
started, and **Build log** streams the build output (the same lines the terminal shows). The app card appears
when the build finishes and the first call is scheduled; later runs reuse the blueprint.

## The list

Each app card shows its state, its resource badge (`CPU` or the GPU type it asked for, `L40S GPU`), a sparkline
of calls, and how many containers are up right now.

| state | meaning |
| - | - |
| **deployed** | at least one deployment is live; it has a URL |
| **stopped** | it was deployed and every version is stopped |
| **ephemeral** | it ran with `python app.py` and was never deployed; calls still show |

Each card also says **where it came from**, because everything a workspace runs lands here and on the controlplane a
notebook box, a model endpoint and your own code look alike:

| badge | what made it | opens |
| - | - | - |
| **Notebook** | a JupyterLab box started from Notebooks | that notebook |
| **Model endpoint** | vLLM serving a model, deployed from Endpoints | Endpoints |
| **Data Lab** | the import and pre-label pipeline behind Datasets | Datasets |
| **SDK run** | `python app.py` or `levers9 run`, never deployed | — |
| **SDK deploy** | `levers9 deploy` or `.deploy()` | — |

The match comes from the dashboard's own records of what it created, so it is exact rather than guessed from the
name; the app page repeats it with a sentence of explanation.

One list, filtered by state rather than split into tabs: **All apps**, **Running now**, **Deployed**,
**Stopped**. Work here finishes in seconds, so a tab that empties the moment a run ends hides the thing you came
to look at. Sort by most recent, name or activity, and filter further by CPU or GPU. When the workspace is empty the page
shows a **Quickstart guide** with the connection details for this cluster, and a set of featured examples.

## One app

Open an app for its functions, one row per handler, each with its versions, containers, running calls and the
last calls. **Stop** stops every deployment of the app. Each function opens to its own page.

## One function

* **Description**: the first paragraph of the handler's docstring (or the decorator's `description=`) sits
  under the function's name, here and on its card in the app, so a reader knows what `mix` or `evaluate` is
  for without opening the code.
* **One run at a time**: every `python app.py` is its own run, and the page shows one run: the current one by
  default, an earlier one from the **Run** selector. Its calls, containers, logs and the running counts belong
  to that run only, so a cancelled call from an earlier execution never sits next to the one that just started.
  A deployed function has no runs; its page shows the deployment's calls.
* **Calls**: every task of the run, newest first, with status (pending, running, complete, error, timeout, cancelled), when
  it started and how long it took, and which container ran it. Under each call id are the arguments it was
  called with, whole (`('run-7', 'train.jsonl', 3.5)`, or every key of a config dict), which is how two calls of
  the same function are told apart. Open a call to read and copy them. Anything named or shaped like a
  credential is redacted; `show_args=False` on the decorator keeps arguments out. Stop a running call from here.
* **Logs**: one stream for the whole function: every recent call's container and every live container merged,
  each line tagged and coloured by container. Filter by text, by level (errors, warnings, with counts), and by
  container (click a chip to hide or show it); follow-the-tail pauses when you scroll up. A chip marked "not
  captured" ran while the dashboard was not watching that workspace.
* **Failure**: a failed call (error, timeout, cancelled) shows why in the table and in its drawer: the
  controlplane's reason when it has one (could not schedule, cancelled, timed out), otherwise the exception line the
  dashboard captured from the container (`ValueError: ...`), otherwise a note that nothing was captured because
  the dashboard was not watching that workspace while it ran.
* **Task drawer**: click a call. **Logs** is everything the container printed, live while it runs and kept
  afterwards, for your workspace only: the dashboard checks whose container it was, months later too, by asking
  whether your workspace has the function or the call it ran for. **Execution** is a timeline, created → scheduled → started → finished, so you can see cold-start
  time separately from run time.
* **Code**: the file the handler is in, as it was when this run happened. Every `python app.py` uploads the
  folder it was run from, so this is what actually ran, not what the repository holds now: the file list from
  that upload, the source with the handler's own lines highlighted, and the commands that repeat the call,
  starting with the command the run was started with (`python app.py rtx4 --clips 400`). Anything that looks
  like a credential is replaced with `<redacted>` before it is recorded.
* **Deployments**: the versions with their URLs and a start / stop switch. The URL for a function is
  `POST /job/NAME/vN`; the drawer shows a `curl` you can paste.

## Full-page logs

**Logs** in the app header (or "Full view" in a task drawer) opens `/apps/<id>/logs`: every live container and recent call of the app in a rail on the left, grouped by function, and the selected container's output filling the screen on the right, with the same viewer as the drawer: ANSI colours, levels and tracebacks highlighted, per-line timestamps, follow-the-tail that pauses when you scroll up, a filter, copy. The URL carries the container id, so a log view can be shared.

The task drawer itself can be widened by dragging its left edge; the width is remembered.

## Runs

An app's page opens with **Runs**: one row per execution, newest first, with how long ago it was, how many calls
it made across how many functions, the total time, and whether anything failed. Expanding one lists the steps in
order with the wait for a container, the run time, and a link to that step's logs.

This is the answer to work that finishes before you can watch it: the containers are gone, but the run is still
there to read afterwards. Runs are grouped by the id the SDK stamps on every stub an execution creates; calls
from before that, or traffic to a deployed endpoint, are grouped by time instead and labelled as such.

## The pipeline timeline

On the Apps list, an app with several functions shows them as a timeline in the order they first ran, with a node per step and a connector between steps: a spinning node and a flowing connector while a step runs, a lit connector once two consecutive steps completed, red after a failed step, dim where nothing has run yet.

## From the CLI

`levers9 deployment list`, `levers9 task list --filter status=error`, `levers9 container attach ID` show the same
things in a terminal. See the [CLI reference](https://levers9.mintlify.site/guides/cli.md).


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