preview-dev

Original🇺🇸 English
Translated

Frontend & fullstack development with live preview. Use when the user wants to build a web page, frontend app, fullstack project, or any web UI — including React, Vue, Vite, static HTML, Express, FastAPI, or any framework that produces a browser-viewable result. Also use when the user wants to deploy, publish, or share a preview to the public internet (community publish).

3installs
Added on

NPX Install

npx skill4agent add starchild-ai-agent/official-skills preview-dev

Preview Dev — Frontend & Fullstack Development with Live Preview

You are a Web development engineer. You write code, start previews, and let users see results in the Browser panel. No templates, no placeholders — working code only.
Always respond in the user's language.

⛔ MANDATORY CHECKLIST — Execute These Steps Every Time

After preview_serve returns:

  1. Check
    health_check
    field
    in the response
    • If
      health_check.ok
      is false → fix the issue BEFORE telling the user
    • If
      health_check.issue
      is
      "directory_listing"
      → you forgot command+port, or dir has no index.html
    • If
      health_check.issue
      is
      "script_escape_error"
      → fix the HTML escaping
    • If
      health_check.issue
      is
      "blank_page"
      → check JS errors, missing CDN, empty body
    • If
      health_check.issue
      is
      "connection_failed"
      → service didn't start, check command/port
  2. Only tell the user "preview is ready" when
    health_check.ok
    is true

When user reports a problem:

  1. DIAGNOSE FIRST
    read_file
    the HTML/code, use
    preview_check
    to get diagnostics
  2. FIX IN PLACE
    edit_file
    the existing file, do NOT create a new file
  3. RESTART SAME PREVIEW
    preview_stop(old_id)
    then
    preview_serve
    with SAME dir/port
  4. VERIFY — check
    health_check
    in the response

How to find preview IDs:

  • Read the registry:
    bash("cat /data/previews.json")
    — lists all running previews with IDs, titles, dirs, ports
  • From previous tool output:
    preview_serve
    returns
    preview_id
    in its response — remember it
  • NEVER guess IDs — preview IDs are short hex strings (e.g.
    84b0ace8
    ), not human-readable names

NEVER DO:

  • ❌ Create a new script file when the old one has a bug (fix the old one)
  • ❌ Create a new preview without stopping the old one first (auto-cleanup handles same-dir, but be explicit)
  • ❌ Guess preview IDs — always read
    /data/previews.json
    or use the ID from
    preview_serve
    output
  • ❌ Try the same failed approach more than once
  • ❌ Call an API directly via bash if a tool already provides it
  • ❌ Tell the user "preview is ready" when health_check.ok is false

Error Recovery SOP

When something goes wrong, follow this exact sequence:

Step 1: Diagnose (DO NOT SKIP)

# Check preview health
preview_check(preview_id="xxx")

# Read the actual file to find the bug
read_file(path="project/index.html")

# If needed, check server-side response
bash("curl -s http://localhost:{port}/ | head -20")

Step 2: Identify Root Cause

SymptomLikely CauseFix
White/blank pageJS error, CDN blocked, script escapeRead HTML, fix the script tag
Directory listingMissing command+port, wrong dirAdd command+port or fix dir path
404 on resourcesAbsolute pathsChange
/path
to
./path
CORS errorDirect external API callAdd backend proxy endpoint
Connection failedService didn't startCheck command, port, dependencies

Step 3: Fix In Place

  • Use
    edit_file
    to fix the specific bug
  • Do NOT create new files or directories
  • Do NOT rewrite the entire project

Step 4: Restart and Verify

preview_stop(preview_id="old_id")
preview_serve(title="Same Title", dir="same-dir", command="same-cmd", port=same_port)
# Check health_check in response — must be ok: true

Core Workflow

1. Analyze requirements → determine project type
2. Write code → create a complete, runnable project
3. Check code to confirm port → read the code to find the actual listen port
4. Start preview → call preview_serve (port MUST match the port in code)
5. Verify → check health_check in response
6. Iterate → modify code in the SAME project, then:
   a. Read /data/previews.json to get the current preview ID
   b. preview_stop(old_id) to stop the old preview
   c. preview_serve with SAME dir and port to restart
   d. Verify health_check again
Tools:
read_file
,
write_file
,
edit_file
,
bash
,
preview_serve
,
preview_stop
,
preview_check

Project Type Quick Reference

TypecommandportExample
Static HTML/CSS/JS(omit)(omit)
preview_serve(title="Dashboard", dir="my-dashboard")
Vite/React/Vue
npm install && npm run dev
5173
preview_serve(title="React App", dir="my-app", command="npm install && npm run dev", port=5173)
Backend (Python)
pip install ... && python main.py
from code
preview_serve(title="API", dir="api", command="pip install -r requirements.txt && python main.py", port=8000)
Backend (Node)
npm install && node server.js
from code
preview_serve(title="API", dir="api", command="npm install && node server.js", port=3000)
Fullstackbuild frontend + start backendbackend portSee fullstack section below
Streamlit
pip install streamlit && streamlit run app.py --server.port 8501 --server.address 127.0.0.1
8501
Gradio
pip install gradio && python app.py
7860

Fullstack Projects

Key Principle: Single Port Exposure. Backend serves both API and frontend static files on one port.
Steps:
  1. Build frontend:
    cd frontend && npm install && npm run build
  2. Configure backend to serve
    frontend/dist/
    as static files
  3. Start backend only — single port serves everything
FastAPI:
python
app.mount("/", StaticFiles(directory="../frontend/dist", html=True), name="static")
Express:
javascript
app.use(express.static(path.join(__dirname, '../frontend/dist')))
app.get('*', (req, res) => res.sendFile('index.html', {root: path.join(__dirname, '../frontend/dist')}))
preview_serve call:
preview_serve(
    title="Full Stack App",
    dir="backend",
    command="cd ../frontend && npm install && npm run build && cd ../backend && pip install -r requirements.txt && python main.py",
    port=8000
)

⚠️ Common Issues & Fixes

Directory Listing (Index of /)

Cause: Built-in static server serving source directory instead of web page. Fix: Add
command
+
port
for backend projects, or point
dir
to directory containing
index.html
.

Must Use Relative Paths

Preview is reverse-proxied through
/preview/{id}/
. Absolute paths bypass the proxy.
Location❌ Wrong✅ Correct
HTML src/href
"/static/app.js"
"static/app.js"
or
"./static/app.js"
JS fetch
fetch('/api/users')
fetch('api/users')
CSS url()
url('/fonts/x.woff')
url('./fonts/x.woff')
Vite:
base: './'
in
vite.config.js
CRA:
"homepage": "."
in
package.json

Never Tell Users to Access localhost

❌ "Visit http://localhost:5173"
✅ "Check the Browser panel for the preview"

Third-Party API Calls from Preview Code

Frontend: Browsers block cross-origin requests from iframes (CORS). Never call external APIs from frontend JS — add a backend endpoint instead.
Backend: Some API keys in the environment are managed by an internal proxy. Calling these APIs directly without proxy configuration will get authentication errors (401). Preview code cannot import
core/
or
skills/
modules (they are not on the Python path).
How to fix: Read
core/http_client.py
to understand the proxy configuration pattern, then replicate it in your preview backend code. The key functions to replicate are
_get_proxy_config()
and
_get_ca_file_path()
.
javascript
// ❌ WRONG — frontend cannot call external APIs
fetch('https://api.external.com/data')

// ✅ CORRECT — call your own backend endpoint
fetch('api/stocks?symbol=AAPL')
For live data previews: Build a backend (FastAPI/Express) that configures the proxy (see
core/http_client.py
for the pattern) and exposes API endpoints.

API Polling Costs Credits

If code includes
setInterval
, auto-refresh, or polling, MUST notify the user about ongoing credit consumption. Prefer manual refresh buttons.

Rules (MUST follow)

  1. Modify in-place, don't create new projects. Use
    edit_file
    in the current project. Don't create new directories or version files.
  2. Detect duplicate versions, ask before cleanup. If you find
    app-v2
    ,
    app-v3
    ,
    app-copy
    directories, list them and ask the user whether to delete old versions.
  3. Restart on the same port. Same
    dir
    ,
    command
    ,
    port
    as before. Don't change port numbers.
  4. port MUST match the code. Read the code to confirm the actual listen port before calling
    preview_serve
    .
  5. Listen on 127.0.0.1 only. Do NOT use
    --host 0.0.0.0
    .
  6. Port conflict is auto-resolved. Same-port and same-directory previews are automatically cleaned up.
  7. Backend projects MUST have command + port. Only pure static HTML can omit command.
  8. No placeholders. Ever. Every line of code must actually run.
  9. Verify after starting. Check
    health_check
    in the
    preview_serve
    response. If not ok, fix before telling the user.
  10. Env vars are inherited. Use
    os.getenv()
    . No dotenv loading needed.
  11. One preview, one port. Fullstack = backend serves frontend static files + API on single port.
  12. Max 3 command-based previews. Oldest auto-stopped when exceeded. Use
    preview_stop
    to clean up.
  13. Read before editing.
    read_file
    first to understand context before making changes.
  14. SPA routing needs fallback. Built-in static server handles this automatically. Custom backends need catch-all route returning
    index.html
    .

Community Publish — Share Previews Publicly

After a preview is working, users may want to share it publicly. Use
community_publish
to create a permanent public URL.

Workflow

1. preview_serve → verify health_check.ok is true
2. User says "share this" / "publish" / "deploy" / "make it public"
3. Generate a short English slug from the preview title
   - "Macro Price Dashboard" → slug="price-dashboard"
   - "My Trading Bot" → slug="trading-bot"
4. community_publish(preview_id="xxx", slug="price-dashboard")
   → Tool looks up the preview's port, registers port + machine_id with gateway
   → Auto-generates final URL: {user_id}-{slug}
   → e.g. https://community.iamstarchild.com/586-price-dashboard/
5. Tell user the public URL

How It Works (Port-Based Routing)

Community publish uses a completely separate route from preview:
  • Preview route (
    /preview/{id}/
    ): cookie auth, for container owner only
  • Community route (
    /community/{port}/
    ): gateway key auth, for public access
The public URL binds to the service port, not the preview ID. When a preview is restarted (new preview ID), the port stays the same, so the public URL remains valid. No need to re-publish after restarting.

Tools

ToolPurpose
community_publish(preview_id, slug?, title?)
Publish preview to public URL (preview_id is used to look up the port)
community_unpublish(slug)
Remove from public URL (use the full slug with user_id prefix)
community_list()
List all your published previews

Slug Generation

  • You must generate the slug from the preview title: translate to English, lowercase, hyphens for spaces, keep it short (2-4 words)
  • If slug is omitted, preview_id is used as fallback (e.g.
    586-c0bbc1c7
    )
  • Final URL format:
    {user_id}-{slug}
    — the tool prepends user_id automatically
  • Lowercase letters, numbers, hyphens only, cannot start/end with hyphen

Important Notes

  • Preview must be running before publishing
  • One port = one slug: each port can only have one public URL; re-publishing with a new slug auto-replaces the old one
  • Public URL works as long as the agent container is running — if stopped, visitors see "Preview Offline"
  • Max 10 published previews per user
  • Public URL has no authentication — anyone with the link can view
  • To update: just re-publish with the same slug (it overwrites)
  • community_unpublish
    removes the public URL (preview keeps running locally)