inspecting-hermes-desktop-dom – skill Thiết kế & UI cho agent AI
Đọc DOM/CSS trực tiếp của ứng dụng Hermes desktop qua CDP.
Cài skill inspecting-hermes-desktop-dom bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/inspecting-hermes-desktop-dom-cb2f0.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /inspecting-hermes-desktop-dom – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/inspecting-hermes-desktop-dom-cb2f0.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $inspecting-hermes-desktop-dom – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/inspecting-hermes-desktop-dom-cb2f0.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /inspecting-hermes-desktop-dom – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/inspecting-hermes-desktop-dom-cb2f0.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /inspecting-hermes-desktop-dom – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
Inspecting the live Hermes desktop DOM
Overview
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
- 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
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 .against
dist/ 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
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:
import { CDP, SELECTORS } from './scripts/perf/lib/cdp.mjs'
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?
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
When there is no port, or you must not disturb the user's window:
cd apps/desktop
HERMES_HOME=$HOME/.hermes/cache/scratch/cdp-probe-home \
HERMES_DESKTOP_DEV_SERVER=http://127.0.0.1:5174 \
HERMES_DESKTOP_CDP_PORT=9333 \
npx electron . --user-data-dir=$HOME/.hermes/cache/scratch/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
- 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_CHANGED
gets blamed on whatever you just changed.
- A throwaway
HERMES_HOMEhas no backend. The app logsECONNREFUSEDfor
hermes:api and 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 logs DevTools 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
outerHTML will 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 in
apps/desktop/scripts/profile-typing-lag.md claiming otherwise is stale.
Skill liên quan
- ip-as-logo – Thiết kế logo linh vật IP tối giản, dễ thương, đọc rõ ở kích thước 32px.
- openpiv – Thực hiện phân tích Particle Image Velocimetry (PIV) với OpenPIV. Dùng khi trích xuất…
- design-system – Ghi nhận bản sắc thương hiệu của người dùng chỉ một lần qua trình hướng dẫn 10 câu hỏi…
- optimize-for-gpu – Tăng tốc Python khoa học trên phần cứng NVIDIA bằng GPU và kiểm tra kết quả đúng và…
- postgresql-table-design – Dùng kỹ năng này khi thiết kế hoặc rà soát schema dành riêng cho PostgreSQL. Bao gồm…
- baseline-ui – Nhanh chóng làm sạch code UI bằng cách sửa khoảng cách, phân cấp, typography và các lỗi…
- epic-design – Xây dựng website 2.5D tương tác, điện ảnh, sử dụng kể chuyện theo cuộn trang, parallax…
- beatra-ai-video-studio – Cài đặt và sử dụng gói Beatra AI Video Studio chính thức, ghim theo digest, cho các tác…