Help us improve
Share bugs, ideas, or general feedback.
From html-skills
Set up server mode for html-skills interactive artifacts — starts a per-session receiver in the background on an ephemeral port and arms Monitor on its log so submits become notifications. Idempotent. Skips itself in cloud / web environments where server mode can't work.
npx claudepluginhub f-labs-io/agent-html-skills --plugin html-skillsHow this command is triggered — by the user, by Claude, or both
Slash command
/html-skills:listenThe summary Claude sees in its command listing — used to decide when to auto-load this command
Set up **server mode** for html-skills interactive artifacts — a per-session local receiver + `Monitor` so submits become notifications. Scoped to *this* Claude Code session so parallel sessions don't collide on the same port. Follow these steps in order; do not improvise: 0. **Detect Claude Code on the web and short-circuit.** Cloud sessions sandbox the agent on a different host than the user's browser, with no preview proxy exposed for arbitrary HTML, so server mode can't work. Check: If the output is `WEB`, **do not start the receiver and do not arm Monitor.** Tell the user exact...
/previewLaunches interactive preview for HTML document editing: starts local HTTP server, sets up control panel, opens wrapper in Playwright browser.
/bridgeManages peer-to-peer communication between Claude Code sessions using actions like start, connect, listen, ask, peers, status, stop.
/webuiStarts the Claude Paper web UI server on localhost:5815. Installs Node.js dependencies, builds the production Nuxt.js server if needed, and handles port conflicts with restarts.
/dashboardOpens claude-smart dashboard (http://localhost:3001) in browser, starts backend and dashboard if not running via bash script, shows output verbatim.
/share-pageDeploys an HTML visual explainer page to Vercel and returns a live, claimable URL without requiring an account or API keys.
/forge-dashOpens a local dashboard panel at localhost:4712 for the obsidian-forge skill, with optional port, browser, refresh, and vault path flags.
Share bugs, ideas, or general feedback.
Set up server mode for html-skills interactive artifacts — a per-session local receiver + Monitor so submits become notifications. Scoped to this Claude Code session so parallel sessions don't collide on the same port. Follow these steps in order; do not improvise:
Detect Claude Code on the web and short-circuit. Cloud sessions sandbox the agent on a different host than the user's browser, with no preview proxy exposed for arbitrary HTML, so server mode can't work. Check:
if [ -n "$CLAUDE_CODE_REMOTE_SESSION_ID" ]; then echo "WEB"; fi
If the output is WEB, do not start the receiver and do not arm Monitor. Tell the user exactly:
ⓘ Claude Code web session detected. Server mode can't work here — the sandbox is unreachable from your browser. Interactive html-skills artifacts will use clipboard mode (no setup needed): when you click Submit, the JSON copies to your clipboard and you paste it back to me. To actually use any artifact in this session, open the file in a real browser — easiest is
claude --teleport <session-id>to pull this session local, then open the artifact.
Then stop. Skip steps 1–8.
Resolve per-session paths. Each Claude Code session gets its own port, PID file, log, URL file, and Monitor task ID so two parallel sessions can each run a receiver without colliding:
SID="${CLAUDE_CODE_SESSION_ID:-no-session}"
PIDF=/tmp/html-skills-$SID.pid
LOGF=/tmp/html-skills-$SID.log
URLF=/tmp/html-skills-$SID.url
MIDF=/tmp/html-skills-$SID.monitor-id
echo "SID=$SID PIDF=$PIDF LOGF=$LOGF URLF=$URLF MIDF=$MIDF"
Capture $SID — you'll need to substitute the literal value into the Monitor command: string in step 6 (the Monitor tool runs in a non-shell context and can't expand env vars).
Check if already running for this session. If $PIDF exists, that PID is still alive, and $URLF has a URL, tell the user ✓ html-skills server already running for this session at <url> and stop here. Do not start a second instance:
if [ -f "$PIDF" ] && kill -0 "$(cat "$PIDF")" 2>/dev/null && [ -s "$URLF" ]; then
echo "ALREADY_RUNNING $(cat "$URLF")"
fi
If the output starts with ALREADY_RUNNING, tell the user and stop. Otherwise continue.
Start the receiver in the background on an ephemeral port. HTML_SKILLS_CHANNEL_PORT=0 makes the OS pick an open port — no port-conflict killer needed, no collision with parallel sessions. Redirect both streams to the session log, save its PID:
: > "$LOGF"
HTML_SKILLS_CHANNEL_PORT=0 nohup node "$CLAUDE_PLUGIN_ROOT/channel/server.js" > "$LOGF" 2>&1 </dev/null &
echo $! > "$PIDF"
sleep 0.5
Verify it's alive, parse the chosen port out of the log, and save the URL. If the PID is dead or the log doesn't contain a listening on … line, dump the log to the user as the error and stop:
PID=$(cat "$PIDF")
if ! kill -0 "$PID" 2>/dev/null; then echo "DEAD"; cat "$LOGF"; exit 1; fi
URL=$(grep -oE 'listening on http://127\.0\.0\.1:[0-9]+/' "$LOGF" | tail -1 | sed 's/listening on //')
if [ -z "$URL" ]; then echo "NO_URL_IN_LOG"; cat "$LOGF"; exit 1; fi
echo "$URL" > "$URLF"
echo "URL=$URL"
Capture the URL=… value — that's the URL you'll inject into every interactive artifact you generate this session, and the one you'll quote back to the user in step 8.
Arm a persistent Monitor on the session log, filtered to submit-receiver notifications. Substitute the literal $SID value from step 1 into the command: string (the Monitor tool can't expand $SID itself):
Monitor(
description: "html-skills artifact submissions (session <SID>)",
command: "tail -f /tmp/html-skills-<SID>.log | grep --line-buffered '\"method\":\"notifications/claude/channel\"'",
persistent: true
)
The Monitor tool's response includes a task ID like task <id>. Capture that ID.
Save the Monitor task ID so /html-skills:stop can find it later:
echo "<the-task-id-from-step-5>" > "$MIDF"
Opportunistic cleanup of dead session files. If a previous session crashed without running /html-skills:stop, its PID/log/url files linger. Sweep any whose PID is no longer alive (silent no-op if nothing to clean):
for f in /tmp/html-skills-*.pid; do
[ -f "$f" ] || continue
[ "$f" = "$PIDF" ] && continue
P=$(cat "$f" 2>/dev/null)
if [ -z "$P" ] || ! kill -0 "$P" 2>/dev/null; then
base=${f%.pid}
rm -f "$base.pid" "$base.log" "$base.url" "$base.monitor-id"
fi
done
Confirm to the user with exactly this message, substituting the URL captured in step 4:
✓ html-skills server active for this session at
<URL>. When generating interactive artifacts, injectwindow.__CLAUDE_SUBMIT_URL__ = '<URL>'so submits POST there. I'll be notified the moment one lands. Run/html-skills:stopwhen you're done.