---
title: "Studio"
description: "The local web UI for starting training runs, watching them stream, chatting with finished models, and publishing them at *.arkor.app URLs."
---

Studio is the local web UI you get when you run `arkor dev`. It is not a separate service to sign into; it boots on your machine, talks to the same Arkor CLI process, and goes away when you stop the dev server.

## What Studio is for

Four jobs:

1. **Start a training run.** A "Run training" button submits the job to the managed backend by spawning `arkor start` under the hood. `arkor start` runs the existing `.arkor/build/index.mjs` artifact (and only auto-builds it when missing); see the dev-loop note below for how Studio keeps that artifact fresh.
2. **See training happen.** A jobs list with live status, a loss chart that updates as the run streams in, and a tail of training events. You can leave it open in a tab while you work on other things.
3. **Try a finished model.** A Playground page lets you pick the base model or the final adapter from any completed job and chat with it. The Playground does not load intermediate checkpoints; for mid-run inference, use [`onCheckpoint`](/docs/framework/concepts/lifecycle) callbacks in your trainer.
4. **Publish a model behind a `*.arkor.app` URL.** An Endpoints page creates a per-deployment subdomain that serves OpenAI-compatible chat completions for a chosen adapter or base model, plus the API keys that authenticate calls to it. The same actions are available programmatically via [`CloudApiClient`](/docs/framework/sdk/deployments). Studio is the interactive surface; the SDK is the lower-level one.

A note on the dev loop: Studio's `/api/manifest` endpoint rebuilds and re-imports your trainer on every request (with a cache-bust query, see `packages/arkor/src/studio/manifest.ts`), but the UI only fetches it when the Run training page mounts. So if you edit `src/arkor/` and stay on the same Run training page, the next click reuses the existing `.arkor/build/index.mjs` and runs your old code. Refresh the page (or run `arkor build` from the terminal) between edits and clicks to pick up the new code reliably.

## Where Studio runs

When you start `arkor dev`, the CLI:

1. Boots a Hono server on `127.0.0.1:4000` (use `-p` to change the port).
2. Serves a Vite + React SPA from the same origin so the UI talks to the CLI through `/api/*` on loopback.
3. Issues a per-launch CSRF token (saved to `~/.arkor/studio-token` with mode `0600`) and requires every request to present it.

The server only binds to loopback and rejects requests with a non-loopback `Host` header. There is no public URL and no remote access path (local requests still need the token), and the token rotates every time you start `arkor dev`.

## How Studio fits with the managed backend

Studio is just a viewer for what your CLI is doing. The CLI talks to the managed backend over authenticated HTTPS; Studio asks the CLI (over loopback) what to render.

```
Studio (browser tab)
   │  /api/* on loopback, CSRF-token gated
   ▼
arkor CLI (your machine)
   │  authenticated HTTPS
   ▼
Arkor managed backend (training, inference)
```

That separation is why Studio works without you logging into anything in the browser: the CLI already has your credentials in `~/.arkor/credentials.json`, and Studio inherits them by virtue of running locally.

If `~/.arkor/credentials.json` is missing, the entry point decides what to do. **`arkor dev`** bootstraps an anonymous session at launch and prints a one-line hint pointing at `arkor login --oauth` so you can upgrade to a real account whenever you want; it never auto-launches the OAuth flow. The one outage case where it does not bootstrap is when `/v1/auth/cli/config` itself is unreachable on first run: the same transport error is rethrown and `arkor dev` exits fast (see [`arkor dev`](/docs/framework/cli/dev) for the exact recovery story). The **Studio server's lazy bootstrap** (when an `/api/*` request arrives before credentials are on disk) does the same anonymous fallback. To use an account session, run `arkor login --oauth` separately before (or after) clicking around in Studio; the credentials file is shared, so Studio picks up the account session on its next request.

## What you actually see

The current views are intentionally small:

- **Jobs.** Status, name, created time, and ID, polled every few seconds.
- **Job detail.** Loss chart, log tail (most recent events), and live status. Streamed via Server-Sent Events so it stays current without manual refresh.
- **Playground.** Adapter selector (base model or the final adapter from any completed job), a chat UI, and a streaming response. Calls flow through the CLI, then to the managed inference endpoint. The Playground only lists jobs that have finished. To run inference against an intermediate checkpoint while a run is still in flight, use [`onCheckpoint`](/docs/framework/concepts/lifecycle) callbacks instead.
- **Endpoints.** A per-deployment `*.arkor.app` URL bound to an adapter or base model, plus the API keys that authenticate it. Slug, target (final adapter / specific checkpoint / base model), auth mode, and key issue / revoke are all in the same view; deeper operations (re-targeting an existing deployment, custom run retention, bulk scripting) stay on the [SDK](/docs/framework/sdk/deployments).

A walkthrough of each view (Run training, Job detail, Playground, Endpoints) lives in the [Studio](/docs/framework/studio/overview) section.

## When not to use Studio

Studio is a development tool. It runs on your machine, only on loopback, and only while `arkor dev` is up. For production usage of a fine-tuned model, publish it as a [deployment](/docs/framework/sdk/deployments) and call the endpoint's OpenAI-compatible API from your application. `infer` is only handed to `onCheckpoint` during a run, and Studio is never something to point users at.
