Context for developing and debugging Hubitat Elevation apps, drivers, and hub environment — sandbox constraints, lifecycle idioms, capability contracts, plus grounded deploy/log-tail/lint mechanisms.
—
—
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
High
Do not use without reviewing
The hubitat-dev toolset is HTTP/code only. A class of operations has no documented endpoint and
is reachable only through the hub web UI at http://<hub-ip>:8080, driven with the Playwright MCP.
The setup, full workflow, selectors, and per-gotcha detail all live in skills/_reference/playwright-ui.md.
skills/_reference/endpoints.md).skills/device-migration/SKILL.md).label.is-checked CSS class. Read the class, never input.checked — the property is unreliable and may or may not track, depending on element and platform version.browser_click / browser_type. element.click() inside browser_evaluate does not fire jQuery/Vue/MDL handlers.refs are unreliable on Hubitat's MDL <div> controls — a ref resolves to a wrapper and the click hits a container, silently. Tag the real control by walking up from its hidden settings[...] input, then click the tag: skills/_reference/playwright-ui.md gotchas 10–12. Tagging in browser_evaluate is not the banned synthetic click.label.is-checked, MDL <div>, unreliable-ref guidance here applies to them. The device edit page on 2.5.1.135 is PrimeVue (p-inputtext, p-tabview-panel, data-pc-section / data-pc-name); confirm which framework a page uses before assuming a selector strategy.TabView panel renders display:none until its tab is clicked. The Device label input (for POST /device/update) sits in the Device Info panel; Playwright times out filling an invisible element, which reads like a selector bug. Click the tab first, then address it input[inputid="Device label"] (these inputs carry no name or id) (skills/_reference/endpoints.md)..checked or dispatching synthetic events does not persist.settings[<name>] value directly and Done serializes it; the empty→filled validation only gates required inputs (skills/_reference/playwright-ui.md gotcha 14; the required-input validation trap is gotcha 17).submitOnChange gates — the dependent controls do not exist until the picker's Update commits.device-save picker. Newer inline Vue pickers (Room Lighting activation-options switch guards, switchesD/switchesOE) mount inline under the button, not in #deviceListModal (a dead shell): filter with real keystrokes (locator.fill() doesn't trigger the Vue filter) and click the checkbox and its div.mdl-button Update by coordinate — a label-locator click collapses the dropdown (skills/_reference/playwright-ui.md gotcha 26).browser_select_option sets the native select.value and reports success, but the widget never fires submitOnChange and the page never advances — drive the widget (real-click p.CaptionCont to open, then the li), same as RL's enum guards (skills/_reference/playwright-ui.md gotcha 30).class="… device-save" but its tag varies — <div> on one rule, <button> on the next, same hub. Match by class or exact text, never by tag (skills/_reference/playwright-ui.md gotcha 12).configure/json after every change, then re-read the app's live surface when the change is meant to alter behavior.input[name="settings[<name>]"]: "" until the picker's Update commits, a comma-separated id list after. Compare as a set — the order is selection order, not sorted.rules/device-lifecycle.md Audit live consumers separately.statusJson.settings as the configured-input inventory.rules/device-lifecycle.md.mainPage and its sub-pages use different table column layouts — identify a column by its hidden settings[...] input name or by content, never by index across pages.configure/<id>/mainPage is a stub — Cancel / Remove / Enable only, no settings[...]. Enable it first (POST /installedapp/disable {"id":<id>,"disable":false}) or an empty settings set reads as an empty rule (skills/_reference/playwright-ui.md gotcha 31).actType.N/… settings behind — a present settings[N] does not mean action N exists. Verify against the rendered action rows or the "Select Actions to Run" summary (skills/_reference/playwright-ui.md gotcha 33).skills/_reference/playwright-ui.md gotcha 32).browser_snapshot and DOM reads, not browser_take_screenshot.modes: ["0"] means All Modes. It is not mode id 0./modes/json.modeXD.modeXOff.scheduledJobs[].prevRunTime: null records no previous firing for the current schedule. It does not mean the job is disabled.dimLA input; Switch cell → on/off toggles). Avoid "Re-Capture" unless the physical lights already hold the desired state.button[id="settings[runAction]"] ("Run Actions") executes the rule's actions immediately — a live side effect, not navigation. Target it as an attribute selector (the bracketed id is not a CSS id-selector) and read the button before clicking (skills/_reference/playwright-ui.md gotcha 35).removeButton: false (e.g. HubiThings Replica) and cannot be removed from the UI or a synthetic endpoint — record them as remove-not-automatable.