Use it when your goal in extending the agent is clear and you can limit it to the data and actions it actually needs.
Inspecting Hermes Desktop Dom
Read the live Hermes desktop DOM/CSS over CDP
What does it add to Hermes?
Read the live Hermes desktop DOM/CSS over CDP
Inspecting Hermes Desktop Dom is a skill related to extending the agent. It adds a capability or workflow to Hermes. The publisher description explains the intent, while granted permissions determine what it can actually do.
This plain-language explanation is based on the publisher description. The original text remains visible for verification.
Do not add it merely to experiment when Hermes already has a simpler path, or when you cannot review its source and permissions.
Best for users who want a repeatable way of working inside Hermes.
Start with non-sensitive data and a small task whose result can be verified and reversed.
Read the live Hermes desktop DOM/CSS over CDP
This entry was indexed from Hermes Bundled Skills. Our explanation interprets the type and domain without inventing a capability not present upstream.
The source is official or editorially reviewed, but you still need to review permissions and version compatibility.
Inspect, install, then test.
- 01Open the source
Match the publisher, license, and description to your need. Check the real update history.
- 02Review permissions and secrets
Never paste a secret value into this site. Use environment-variable names and grant the smallest scope.
- 03Copy setup only after review
The controls below copy text. They do not execute commands on your device.
- 04Test with a non-sensitive task
Inspect the visible tools, then exclude write or delete tools you do not need.
Already installed with Hermes.
This skill ships with Hermes and loads when the agent decides it is relevant. There is nothing to install; read the definition below so you know what it will do.
Open the official page ↗Exactly what Hermes loads when this skill runs.
Reproduced from the official documentation. Read it before enabling the skill: this text becomes the agent's instructions.
Read the live Hermes desktop DOM/CSS over CDP.
Skill metadata
A lookup table. Do not read it all; find the row that applies to you.
| Source | Bundled (installed by default) |
| Path | skills/software-development/inspecting-hermes-desktop-dom |
| Version | 1.0.0 |
| Author | Hermes Agent |
| License | MIT |
| Platforms | linux, macos, windows |
| Tags | desktop, electron, cdp, dom, ui-verification, self-inspection |
| Related skills | node-inspect-debugger, systematic-debugging, dogfood |
Reference: full SKILL.md
Explains the idea itself. Read it slowly; the later sections build on it.
Overview
Explains the idea itself. Read it slowly; the later sections build on it.
When you are developing apps/desktop and the user is running that same app
(hgui / npm run dev), you can read the live rendered DOM of the window
they are looking at — computed styles, geometry, which CSS rule actually won,
console output — instead of inferring it from .tsx and being wrong.
Dev-server runs open a Chrome DevTools Protocol port on 127.0.0.1:9222
automatically. The renderer is a Chromium page, so everything DevTools can read,
a script can read.
This does not replace looking at it. CDP answers factual questions ("what is the computed padding", "did this element render", "which selector matches"). It cannot tell you whether the result looks good. Colour balance, spacing feel, and "is this ugly" still need the user's eyes or a screenshot. Answer facts with CDP; hand aesthetics to the user.
When to Use
Explains the idea itself. Read it slowly; the later sections build on it.
- Verifying a UI change actually took effect in the running app
- "Why is this element still X?" — find the winning rule before editing anything
- Locating a stable selector for a component you're about to change
- Checking a design token's computed value on a real node
- Reading renderer console errors the user mentions but can't copy out
Don't use for: perf profiling or heap work (node-inspect-debugger,
debugging-hermes-desktop), or anything where the real question is "does this
look right".
The port
Settings you configure once. Change one at a time so you can see what each does. Set HERMES_DESKTOP_DEV_SERVER, HERMES_DESKTOP_CDP_PORT in your environment, not in the chat.
Open on 127.0.0.1:9222 for any dev-server run. Closed in exactly two cases
(apps/desktop/electron/dev-cdp.ts):
- packaged builds — always, and no environment value overrides it;
- no
HERMES_DESKTOP_DEV_SERVER— an unpackagedelectron .againstdist/is how the packaged app gets smoke tested, so it behaves like one.
HERMES_DESKTOP_CDP_PORT moves the port (=9333) or disables it (=off).
Check before doing anything else:
curl -s --max-time 3 http://127.0.0.1:${HERMES_DESKTOP_CDP_PORT:-9222}/json/versionEmpty → no port. Do not guess another port silently.
Never relaunch the user's app to get a port. That destroys their session and their state. Launch your own isolated instance instead (below).
Reading the DOM
Explains the idea itself. Read it slowly; the later sections build on it.
apps/desktop/scripts/eval.mjs is the one-liner:
cd apps/desktop
node scripts/eval.mjs "document.querySelectorAll('[data-slot]').length"For multi-step work use the shared client — it has target discovery and promise-aware eval:
const cdp = await CDP.connect({ port: 9222, match: '5174' })
const out = await cdp.eval(`JSON.stringify({
radius: getComputedStyle(document.documentElement).getPropertyValue('--radius-scalar').trim(),
composer: !!document.querySelector('[data-slot="composer-rich-input"]')
})`)
cdp.close()SELECTORS in scripts/perf/lib/cdp.mjs holds the stable data-slot hooks
(composer, thread viewport, assistant message, turn pair, profile rail). Prefer
them over inventing a querySelector — they are updated as a unit when
components move.
The question this is best at: which rule won?
Explains the idea itself. Read it slowly; the later sections build on it.
Editing every call site because a style "isn't applying" is the classic waste. Read the real node first:
const el = document.querySelector('[data-slot="aui_assistant-message-root"] a')
JSON.stringify({
ownClasses: el.className,
weight: getComputedStyle(el).fontWeight,
parents: (() => {
const out = []
let n = el
while ((n = n.parentElement) && out.length < 6) out.push(n.className)
return out
})()
})If the node carries no class of its own, the value is inherited — sweeping
call sites will not fix it, and you need the ancestor rule. A plugin stylesheet
(e.g. @tailwindcss/typography's prose a { font-weight: 500 }) routinely beats
a utility class; override on the shared class, not at each usage.
Your own isolated instance
Settings you configure once. Change one at a time so you can see what each does. Set HERMES_HOME, HERMES_DESKTOP_DEV_SERVER in your environment, not in the chat.
When there is no port, or you must not disturb the user's window:
cd apps/desktop
HERMES_HOME=/tmp/cdp-probe-home \
HERMES_DESKTOP_DEV_SERVER=http://127.0.0.1:5174 \
HERMES_DESKTOP_CDP_PORT=9333 \
npx electron . --user-data-dir=/tmp/cdp-probe-userdataThe separate --user-data-dir dodges Electron's single-instance lock, so it
cannot collide with a running hgui; the separate HERMES_HOME keeps it away
from real sessions. Pick a port other than 9222 for the same reason. Run it in
the background and kill it when done.
npm run perf:serve does the same with a temp HERMES_HOME baked in, if you
also want the perf harness.
Pitfalls
Settings you configure once. Change one at a time so you can see what each does. Set ERR_NETWORK_CHANGED, HERMES_HOME in your environment, not in the chat.
- Never kill the user's dev server or app to "free" anything. A mid-serve kill nukes Chromium's socket pool, and the resulting
ERR_NETWORK_CHANGEDgets blamed on whatever you just changed. - A throwaway
HERMES_HOMEhas no backend. The app logsECONNREFUSEDforhermes:apiand may exit on its own. The renderer still mounts and the DOM is readable — read promptly, and don't mistake a self-exited probe for a broken port. Chromium logsDevTools listening on ws://127.0.0.1:<port>/…when it binds; that line is the proof the port opened. - Poll, don't probe once. A just-launched app needs a second or two before the port answers.
- Never dump the whole DOM. The desktop renders hundreds of nodes and
outerHTMLwill bury your context. Project down to a small JSON object inside the evaluated expression. - Pass
matchtoCDP.connect. Without it you may attach to the pet overlay, quick-entry window, or a devtools target instead of the main window. cdp.evalreturns the value; rawRuntime.evaluatedouble-nests it (.result.result.value). Use the wrapper.import.meta.env.DEVistrueundervite devin this repo. The note inapps/desktop/scripts/profile-typing-lag.mdclaiming otherwise is stale.