Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Explains the Starchild iframe-based Browser preview panel, reverse-proxy URL routing, and relative-path asset rules.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
SKILL.md
1---2name: browser-preview3version: 1.1.14description: |5Preview panel and iframe diagnostics: registry, ports, paths, blank screens.67Use when a preview tab is broken or missing (e.g. white screen, tab disappeared, 404 on assets, preview not loading, list running services).89metadata:10starchild:11emoji: "๐"12skillKey: browser-preview1314user-invocable: true15disable-model-invocation: false1617---1819# Browser Preview2021You already know `preview_serve` and `preview_stop`. This skill fills the gap: what happens **after** preview_serve returns a URL โ how the user actually sees it.2223## What is the Preview Panel2425The frontend has a right-side panel with three tabs: **Files**, **Preview**, and **Jobs**. The Preview tab renders preview URLs inside an iframe. When you call `preview_serve`, the frontend automatically opens a Preview tab loading that URL.2627Key facts:28- Each `preview_serve` call creates one Preview tab29- URL format: `https://<host>/preview/{id}/`30- Preview panel has a **โฎ menu** (top-right) showing "RUNNING SERVICES" list31- Preview tab can be **closed by the user** without stopping the backend service32- Backend service stopping โ Preview tab shows an error page3334## โ ๏ธ CRITICAL: Never Tell Users to Access localhost3536**The user's browser CANNOT access `localhost` or `127.0.0.1`.** These addresses point to the server container, not the user's machine. The preview architecture uses a **reverse proxy**:3738```39User's Browser โ https://<host>/preview/{id}/path โ (reverse proxy) โ 127.0.0.1:{port}/path40```4142Rules:43- **NEVER** tell the user to visit `http://localhost:{port}` or `http://127.0.0.1:{port}` โ they cannot reach it44- **ALWAYS** direct users to the preview URL: `/preview/{id}/` (or the full URL `https://<host>/preview/{id}/`)45- `curl http://localhost:{port}` is for **your own server-side diagnostics only** โ never suggest it to the user as a way to "test" the preview46- When a preview is running, tell the user: "Check the Preview panel, or refresh the Preview panel"47- If you need to give the user a URL, use the `url` field returned by `preview_serve` (format: `/preview/{id}/`)4849## โ ๏ธ Static Assets Must Use Relative Paths5051Because previews are served under `/preview/{id}/`, **absolute paths in HTML/JS/CSS will break**. The reverse proxy strips the `/preview/{id}` prefix before forwarding to the backend, but the browser resolves absolute paths from the domain root.5253Example of the problem:54```html55<!-- โ BROKEN: browser requests https://host/static/app.js โ 404 (bypasses preview proxy) -->56<script src="/static/app.js"></script>5758<!-- โ WORKS: browser requests https://host/preview/{id}/static/app.js โ proxied correctly -->59<script src="static/app.js"></script>60<script src="./static/app.js"></script>61```6263Common patterns to fix:64| Broken (absolute) | Fixed (relative) |65|---|---|66| `"/static/app.js"` | `"static/app.js"` or `"./static/app.js"` |67| `"/api/users"` | `"api/users"` or `"./api/users"` |68| `"/images/logo.png"` | `"images/logo.png"` or `"./images/logo.png"` |69| `url('/fonts/x.woff')` | `url('./fonts/x.woff')` |70| `fetch('/data.json')` | `fetch('data.json')` |7172**Check ALL places** where paths appear:731. HTML `src`, `href` attributes742. JavaScript `fetch()`, `XMLHttpRequest`, dynamic imports753. CSS `url()` references764. JavaScript string literals (e.g., `'/static/'` in template strings or concatenation)775. Framework config files (e.g., `publicPath`, `base`, `assetPrefix`)7879โ ๏ธ Be thorough โ it's common to fix CSS `url()` but miss JS string literals like `'/static/'` (with single quotes). Search for ALL occurrences of absolute paths across all file types.8081## โ ๏ธ Do NOT Browse Filesystem to Debug Previews8283**Never** look at workspace directories like `preview/`, `output/`, or random folders to understand preview state. Those are user data, not preview service state.8485The **only** sources of truth:861. Registry file: `/data/previews.json` (running services)872. History file: `/data/preview_history.json` (all past services)883. `preview_serve` / `preview_stop` tools894. Port checks via `curl` (server-side only, for your diagnostics)9091Do NOT use `ls`/`find` on workspace directories to diagnose preview issues. Do NOT call unrelated tools like `list_scheduled_tasks`. Stay focused.9293## Step-by-Step: Diagnosing Preview Issues9495When a user reports any Preview panel problem, follow this exact sequence:9697### Step 1: Read the registry (running services)9899```bash100cat /data/previews.json 2>/dev/null || echo "NO_REGISTRY"101```102103โ ๏ธ Your bash CWD is `/data/workspace/`. The registry is at `/data/previews.json` (absolute path, one level up). Always use the absolute path.104105JSON structure:106```json107{108"previews": [109{"id": "f343befc", "title": "My App", "dir": "/data/workspace/my-project", "command": "npm run dev", "port": 9080, "is_builtin": false}110]111}112```113114### Step 2: Branch based on registry state115116**If registry has entries** โ Go to Step 3 (verify services)117**If registry is empty or missing** โ Go to Step 4 (check history)118119### Step 3: Registry has entries โ verify and fix120121For each preview in the registry, check if the port is responding **server-side** (this is your diagnostic, not for the user):122```bash123curl -s -o /dev/null -w "%{http_code}" http://localhost:{port}124```125126**If port responds (200):**127- The service IS running. Tell the user:128- "You have a running service: {title}"129- "Click the โฎ menu at the top-right of the Preview panel, then click it in the RUNNING SERVICES list to reopen"130- Preview URL: `/preview/{id}/`131- **If user says the โฎ menu is empty or doesn't show the service** โ frontend lost sync. Fix by recreating: `preview_stop(id)` then `preview_serve(dir, title, command)` using the info from the registry. This forces the frontend to re-register the tab.132133**If port does NOT respond:**134- Process crashed but registry entry remains. Recreate:135```136preview_stop(id="{id}")137preview_serve(dir="{dir}", title="{title}", command="{command}")138```139140### Step 4: No running services โ check history first, then scan workspace141142When there are no running services, use a **two-tier lookup** to find projects the user can preview:143144#### Tier 1: Read preview history (preferred โ fast and accurate)145146```bash147cat /data/preview_history.json 2>/dev/null || echo "NO_HISTORY"148```149150JSON structure:151```json152{153"history": [154{155"id": "f343befc",156"title": "Trading System",157"dir": "/data/workspace/my-project",158"command": "python main.py",159"port": 8000,160"is_builtin": false,161"created_at": 1709100000.0,162"last_started_at": 1709200000.0163}164]165}166```167168History entries are **never removed by `preview_stop`** โ they persist across restarts. Entries are automatically pruned only when the project directory no longer exists.169170**If history has entries:**171- List all history entries to the user with title, directory, and last started time172- Ask which one they want to restart173- Call `preview_serve` with the `dir`, `title`, and `command` from the history entry174175**If user says a project is missing from history** โ fall through to Tier 2.176177#### Tier 2: Scan workspace (fallback โ when history is empty or incomplete)178179```bash180find /data/workspace -maxdepth 2 \( -name "package.json" -o -name "index.html" -o -name "*.html" -o -name "app.py" -o -name "main.py" -o -name "vite.config.*" \) -not -path "*/node_modules/*" -not -path "*/skills/*" -not -path "*/memory/*" -not -path "*/prompt/*" -not -path "*/.git/*" 2>/dev/null181```182183Then:1841. List discovered projects with brief descriptions1852. Ask the user which one to preview1863. Call `preview_serve` with the appropriate directory187188**Don't just say "no services running" and stop.** Always check history first, then scan, and offer options.189190## Quick Reference191192| User says | You do |193|-----------|--------|194| "tab disappeared" / "tab ไธ่งไบ" | Step 1 โ 2 โ 3 or 4 |195| "blank page" / "็ฝๅฑ" | Check port (server-side), if dead โ recreate; if alive โ check for absolute path issues |196| "not updating" / "ๅ ๅฎนๆฒกๆดๆฐ" | Suggest refresh button in Preview tab, or recreate preview |197| "port conflict" / "็ซฏๅฃๅฒ็ช" | `preview_stop` old โ `preview_serve` new |198| "can't see service" / "โฎ menu empty" | `preview_stop` + `preview_serve` to force re-register |199| "where's my project" / "what did I build" | Read `/data/preview_history.json` and list entries |200| "resource load failed" / "JS/CSS 404" | Check for absolute paths (`/static/`, `/api/`), fix to relative paths |201202## What You Cannot Do203204- Cannot directly open/close/refresh Preview tabs (frontend UI)205- Cannot force-refresh the iframe206- Cannot read what the iframe displays207208When you can't do something, tell the user the manual action (e.g., "click refresh in Preview tab"). If manual action doesn't work, recreate the preview with `preview_stop` + `preview_serve`.209210## Common Mistakes to Avoid2112121. โ Telling user to "visit http://localhost:18791/" โ user cannot access localhost2132. โ Saying "refresh the page at localhost" โ meaningless to the user2143. โ Only fixing CSS `url()` paths but missing JS string literals with absolute paths2154. โ Forgetting to check ALL file types (HTML, JS, CSS, config) for absolute paths2165. โ Always use `/preview/{id}/` as the user-facing URL2176. โ Always use `curl localhost:{port}` only for your own server-side diagnostics2187. โ After fixing paths, call `preview_stop` + `preview_serve` to restart, then tell user to check Preview panel219