npx skills add ...
npx skills add forcedotcom/sf-skills --skill experience-lwc-runtime-observe
Use when running Salesforce Lightning Preview for an app or a single LWC component to extract the runtime DOM for inspection. TRIGGER when the user says \"preview an LWC locally\", \"run sf lightning dev\", \"launch Local Dev\", \"inspect a component's shadow DOM at runtime\", \"grab rendered HTML from a live preview\", \"troubleshoot what actually renders versus the template\", \"set up Salesforce Live Preview plugin\", \"lightning preview\", \"local dev server\", or \"extract runtime DOM\". DO NOT TRIGGER when the user is authoring or editing LWC source code (use experience-lwc-generate) or reviewing component code statically without running it.
npx skills add forcedotcom/sf-skills --skill experience-lwc-runtime-observe
Guides the agent through two sequential jobs that typically run together:
Preview is the prerequisite for DOM inspection. Keep them in this order.
sf lightning dev app / sf lightning dev component).sf) installed. Check with sf version.@salesforce/plugin-lightning-dev installed. Check with sf plugins.sf org list shows at least one connected org).Ask the user (or infer from the request) whether the scope is app or component.
Ask the user for (or infer from the request) the org alias the preview
should target. Run the bundled verification script with that alias and
surface any error it emits — do not re-invoke sf version /
sf plugins / sf org display in prose. The script checks CLI
presence, @salesforce/plugin-lightning-dev installation, and that the
specific target alias is authenticated and Connected, and exits nonzero
with an actionable message on failure:
If it reports that the target alias is not authenticated or not
Connected, direct the user to
Enable Local Dev
and have them run sf org login web --alias <orgAlias>, then re-run the
verification script before proceeding.
Note required vs optional flags. If a required flag is ambiguous, ask the user before running.
Prefix every preview command with OPEN_BROWSER=false — the CLI opens a
browser window by default, which we do not want when an agent is driving.
(This env var is undocumented in --help; rely on it unless the user
explicitly asks for a browser window.)
| Scope | Command |
|---|---|
app | OPEN_BROWSER=false sf lightning dev app -o <orgAlias> -n <appName> -t desktop |
component | OPEN_BROWSER=false sf lightning dev component -o <orgAlias> -n <componentName> |
When the preview is up, capture the URL and log it in exactly this format:
If any sub-step fails, stop and surface the error to the user — don't try to paper over auth or plugin-install problems.
Only run this step once Step 1 has produced a live preview URL.
The front-door URL returned by sf org open --url-only --json contains a
short-lived OTP that authenticates the session. Never run sf org open
directly — its output would land in the agent tool-output stream and leak
an auth token into the transcript, violating agent-safety standard S1.
The bundled helper is the only supported way to obtain the URL: it runs
sf org open internally with stdout redirected into a chmod 600 tempfile
and stderr suppressed, so no URL fragment or token substring ever reaches
agent context.
Instead, use the bundled helper script, which writes the URL to a
chmod 600 tempfile and prints only export assignments (no token
material). Capture the helper output first so a nonzero exit status
aborts the caller — eval "$(...)" alone masks failures, letting the
agent proceed with an unset $FRONTDOOR_URL_FILE:
The helper suppresses sf and python3 stderr as well as stdout, so
partial URLs and progress noise never reach the agent transcript.
The browser driver must:
$FRONTDOOR_URL_FILE.cat or otherwise echo the file contents.OTP tokens expire fast. Bring up the browser driver first, then invoke the helper just before navigating — otherwise the token goes stale.
Two deterministic string operations — turning a component name into its
c-<kebab> selector and wrapping the extracted HTML in the exact
DOM_OUTPUT_START / DOM_OUTPUT_END markers — are handled by
<skill_dir>/scripts/extract-dom.sh. Do NOT re-derive the selector or
compose the markers in prose; call the script.
Actual DOM traversal must be run by the browser-automation driver (Playwright / Puppeteer / CDP); the script does not drive the browser.
componentCompute the selector deterministically:
Then, using the driver, pierce the lwr_dev-preview-container shadow
root, locate the first visible element matching $selector, and read its
subtree HTML (via element.shadowRoot.innerHTML). Pipe that HTML into
the wrap step:
appUsing the driver, identify the primary app root (prefer document.body
or the main app container — not document.documentElement), exclude
<head> and non-rendered nodes, and read the subtree HTML. Pipe it into
the wrap step:
Emit the script's stdout unchanged as the DOM output.
Lightning Web Components use Shadow DOM. The template content is not directly queryable on the host element:
| Access pattern | What you get |
|---|---|
element.innerHTML | empty, or only slotted light-DOM content |
element.outerHTML | just the host tag, no children |
element.shadowRoot.innerHTML | the real rendered template content |
If the browser driver's DOM query doesn't pierce shadow roots by default,
walk shadowRoot explicitly. Most modern automation drivers have a
shadow-piercing query helper — use it.
For a worked end-to-end example (preview a component, capture the front-door
URL safely, and extract its DOM), load
examples/component-preview-and-dom.md.
<skill_dir>/scripts/verify-toolchain.sh <orgAlias> exited zero for the target alias.OPEN_BROWSER=false.Lightning Preview running at URL: <URL> format.<skill_dir>/scripts/open-frontdoor.sh (never sf org open directly).shadowRoot traversal (not innerHTML on the host).<skill_dir>/scripts/extract-dom.sh wrap … (script owns the markers).verify-toolchain.sh reports "Target org alias is not authenticated or not Connected" —
run sf org login web --alias <orgAlias> (the alias must match the one
you passed to verify-toolchain.sh and the -o value the preview
command uses).verify-toolchain.sh reports the plugin is missing — install it with
sf plugins install @salesforce/plugin-lightning-dev.OPEN_BROWSER=false.innerHTML on a host. Use
element.shadowRoot.innerHTML instead. Also verify you pierced the
lwr_dev-preview-container shadow root.<skill_dir>/scripts/open-frontdoor.sh and navigate within ~60 seconds.Lightning Preview running at URL: <URL>frontdoor_env="$("<skill_dir>/scripts/open-frontdoor.sh" <orgAlias> <previewUrl>)" || exit 1
eval "$frontdoor_env"selector="$("<skill_dir>/scripts/extract-dom.sh" selector <componentName>)"printf '%s' "$html_subtree" \
| "<skill_dir>/scripts/extract-dom.sh" wrap component <componentName>printf '%s' "$html_subtree" \
| "<skill_dir>/scripts/extract-dom.sh" wrap app