Skip to main content
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:
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. 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: 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.