From 93e8debb5372523b0189aaf346b0c0fa3f6e9ffc Mon Sep 17 00:00:00 2001 From: Matt Bernstein Date: Thu, 17 Sep 2026 22:47:23 -0400 Subject: [PATCH] docs: FIT-2869 local preview without playground Save (sync-only) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the preview-only thin local playground: two-port localhost cache runtime with writes via interface sync only — matches hs-platform stack layers 1–3 (no Save BFF). Parallel to the with-Save skill PR. Co-authored-by: Cursor --- README.md | 16 +++++- SKILL.md | 33 +++++++++++- references/local-preview.md | 104 ++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 references/local-preview.md diff --git a/README.md b/README.md index b2ec1f1..e3f4b6e 100644 --- a/README.md +++ b/README.md @@ -84,13 +84,24 @@ Or validate a single file: label-studio-sdk interface validate ./Screen.jsx ``` -Preview locally: +Preview locally (Enterprise URL + API key required for first-run asset cache; +live reload then stays on two `127.0.0.1` ports — see `references/local-preview.md`). +The playground is **preview-only** in this skill variant (no in-browser Save): ```bash +export LABEL_STUDIO_URL="https://app.humansignal.com" +export LABEL_STUDIO_API_KEY="YOUR_API_KEY" label-studio-sdk interface preview . ``` -Sync a draft back to Label Studio: +Optional: + +```bash +label-studio-sdk interface preview . --offline # verified cache only +label-studio-sdk interface doctor # cache / auth / setup checks +``` + +After iterating in preview, sync a draft back to Label Studio (this is the write path): ```bash label-studio-sdk interface sync . --message "Describe the change" @@ -111,6 +122,7 @@ references/ authoring-rules.md claude-design-conversion.md examples.md + local-preview.md runtime-contract.md text-spans.md ``` diff --git a/SKILL.md b/SKILL.md index 026ef38..3007127 100644 --- a/SKILL.md +++ b/SKILL.md @@ -84,6 +84,9 @@ Use these references as needed: serialization patterns. - `references/claude-design-conversion.md`: convert Claude Design or React prototypes into the single-file Interface format. +- `references/local-preview.md`: SDK `interface preview` cache, two-port + localhost isolation, offline/auth failure modes, and CLI `sync` for writes + (FIT-2869 preview-only / no playground Save). ## Local Validation @@ -116,12 +119,40 @@ label-studio-sdk interface validate . --json ``` If validation passes and the user wants a visual check, use preview from the -same interface directory: +same interface directory (requires Label Studio Enterprise for first-run asset +download; live reload then stays on localhost): ```bash +export LABEL_STUDIO_URL="https://app.humansignal.com" # or your LSE origin +export LABEL_STUDIO_API_KEY="YOUR_API_KEY" label-studio-sdk interface preview . ``` +Useful variants: + +```bash +label-studio-sdk interface preview Screen.jsx --task task.json +label-studio-sdk interface preview . --no-open +label-studio-sdk interface preview . --offline # needs a prior verified cache +``` + +Preview notes agents must respect: + +- First uncached run authenticates against LSE, downloads version-compatible + playground + sandbox artifacts, verifies them, and stores an origin/protocol- + scoped user cache. Bad/missing tokens fail closed (no anonymous bootstrap). +- Runtime uses **two** `127.0.0.1` listeners (playground host + sandbox) with + capability URLs. Treat printed URLs as workstation-local secrets. +- The API token stays in the CLI process — never in browser JS, HTML, query + params, or storage. The local playground is **preview-only**: there is no + in-browser Save and no Save BFF. Do not tell users to click Save in preview. +- Live reload is localhost SSE only (no Django playground stream, Redis, or + Streamer). `--offline` requires an existing verified cache; protocol mismatch + fails before the browser opens. +- **Writes go through the CLI only:** after iterating in preview, run + `interface sync` (add `--publish` when ready). Use `pull` to refresh a sidecar- + bound interface. See `references/local-preview.md`. + If the SDK CLI is not installed, do not block. Perform static checks: plain JSX only, no `import`/`require`/`export`, no TypeScript syntax, a trailing parenthesized object literal with `default`, stable region IDs, and aligned diff --git a/references/local-preview.md b/references/local-preview.md new file mode 100644 index 0000000..7387b80 --- /dev/null +++ b/references/local-preview.md @@ -0,0 +1,104 @@ +# Local preview (`label-studio-sdk interface preview`) + +Use this reference when helping a user run or debug the SDK local Interfaces +playground (FIT-2869 thin local preview, **preview-only** — no playground Save). +Authoring rules for the JSX module itself stay in `authoring-rules.md` and +`runtime-contract.md`. + +> Variant note: this skill copy matches the hs-platform stack **without** the +> Save BFF layer (stop after runtime). A parallel skill PR documents the world +> **with** playground Save + narrow BFF. + +## What preview does + +1. Resolves `Screen.jsx` (+ optional `task.json` / `sample.json`) from a + directory or explicit paths. +2. Downloads **version-compatible** playground + sandbox static artifacts from + the configured Label Studio Enterprise origin (first run / cache refresh). +3. Verifies fingerprints and stores them in an **origin- and protocol-scoped** + user cache under the platform cache dir + (`label-studio-sdk/interface-preview`). +4. Starts **two** listeners bound only to `127.0.0.1`: + - **Host** — playground UI and localhost SSE for file updates (no Save BFF) + - **Sandbox** — isolated editor-shell iframe +5. Both origins use unguessable **capability** URL prefixes. Print them for the + user but treat them as workstation-local secrets (do not paste into tickets, + chats, or public docs). + +Live reload is **localhost SSE only**. It does not use Django playground +streams, Redis, Streamer, WebSockets, or long-lived Label Studio connections. + +## Auth and credentials + +Set once per shell (or pass `--lse-url` / `--token`): + +```bash +export LABEL_STUDIO_URL="https://app.humansignal.com" +export LABEL_STUDIO_API_KEY="YOUR_API_KEY" +``` + +Rules: + +- The API key stays in the **CLI process**. It is never placed in browser JS, + HTML, query parameters, or local storage. +- First uncached download probes auth (`whoami`) and **fails closed** on + `401`/`403` when no verified cache exists (no anonymous asset bootstrap). +- Later starts may revalidate the manifest; if LSE is unreachable or auth fails + but a verified cache exists, preview can start from cache with a stale-artifact + warning. +- `--offline` skips network entirely and **requires** a verified cache. +- Protocol mismatch between SDK and LSE fails **before** the browser opens. +- View-Only seats cannot mint the PAT needed for first-run bootstrap or `sync`. +- Cookie SSO / OAuth / IAP browser bootstrap is out of scope for this path. + +## No Save in the playground — use `sync` + +In this configuration the local playground is a **viewer/editor with live +reload only**. The Save control is disabled/hidden. Agents must not instruct +users to create or update interfaces from the preview UI. + +To create or update a draft on Label Studio after iterating locally: + +```bash +# From the interface directory (sidecar picks up prior pull/sync ids when present) +label-studio-sdk interface sync . --message "Describe the change" + +# Publish when ready +label-studio-sdk interface sync . --message "Describe the change" --publish +``` + +Typical loop: + +1. `interface preview .` — edit JSX / `task.json`, watch localhost live reload. +2. Keep preview open or stop it; run `interface sync` in the terminal. +3. Open the interface in LSE to review the draft / published version. +4. Optional: `interface pull` before the next session to refresh the sidecar. + +`sync` / `pull` / `start` remain authenticated server operations. Preview never +proxies arbitrary Label Studio APIs from the browser. + +## Proxy / allowlist notes + +Customers who lock down static paths need access to: + +- `/react-app/local-playground/` +- `/react-app/editor-standalone/` + +Or they must populate the preview cache from a reachable instance before going +air-gapped / `--offline`. + +## Agent checklist + +When the user asks to preview locally: + +1. Confirm `label-studio-sdk` is on `PATH` and Node/npm exist (`interface doctor`). +2. Confirm `LABEL_STUDIO_URL` + `LABEL_STUDIO_API_KEY` for first run. +3. Run `interface preview .` from the scaffold directory (or pass file + `--task`). +4. If auth fails with an empty cache, stop — do not invent ORM/API workarounds. +5. If offline/air-gapped, verify a prior successful warm cache or use `--offline` + only after one successful online run. +6. When they need a draft or published version in the product UI, run + `interface sync` (never playground Save). Add `--publish` only when asked. + +Canonical CLI details also live in the SDK's `interface-cli.md` shipped with +`label-studio-sdk`.