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
Process steps in order. Do not skip ahead.
Removing a device is effectively irreversible, and a replacement gets a new device id that
strands every prior reference (rules/device-lifecycle.md). This skill enumerates usage, warns
before the delete, verifies after, and restores references onto a replacement.
Read the hub's own usage list. Pass the device id, or --name "<display name>" to let the script
resolve the id from /hub2/devicesList (exact match — it fails clearly on zero or multiple matches;
do not resolve the name yourself):
python3 .tessl/plugins/jbaruch/hubitat-dev/skills/_scripts/hub_device_usage.py --device <id> --ip <addr>
python3 .tessl/plugins/jbaruch/hubitat-dev/skills/_scripts/hub_device_usage.py --name "<display name>" --ip <addr>Use --hub <name> instead of --ip to resolve via hubs.json (hub-config skill). Argument and
output contract: skills/_scripts/hub_device_usage.py module docstring. The report splits
appsUsing by the app's enabled/disabled switch state and lists dashboards, parentApp, and child
devices. This is the reference blast radius. Enabled does not prove a live consumer. Proceed to
Step 2.
State the actual references, never a bare count — name every enabled and disabled app reference,
dashboard, parent app, and child device. Describe enabled/disabled as app switch state, not
liveness. If deciding which configured reference currently drives behavior, rerun Step 1 with
--live. Its unknown verdict must stay unknown. If nothing references the device, say so and
proceed. Do not delete anything in this step. Proceed to Step 3.
Ask whether the device is being retired (gone for good) or replaced (new hardware stands in). On replace, the Step 1 report is the capture of memberships to restore — keep it.
Retiring — proceed to Step 4.
Replacing — move the references now, before the delete in Step 4:
Skill(skill: "device-migration"). Settings → Swap Device needs the old device to still exist, and
this skill's Step 4 destroys it. Migrating after the delete forfeits the swap and forces the
virtual/manual fallback (rules/device-lifecycle.md).
Where the hardware forces the old device out first — a radio exclusion, or reusing its physical
slot — the replacement cannot exist yet, so there is nothing to swap to: device-migration parks
the references on a virtual device instead. Take that path there, then return here. Proceed to
Step 4 once the references are off the old device.
Deletion is irreversible — the user performs it, not the agent. Navigate to the device's remove
control with Playwright and read the "in use by N apps" confirm dialog (skills/_reference/playwright-ui.md),
then have the user confirm the final removal. A radio (Z-Wave/Zigbee) device also needs a physical
exclusion/factory-reset only the user can do (rules/zwave-zigbee-mesh.md). An app with
removeButton:false (e.g. HubiThings Replica) is remove-not-automatable — tell the user. Proceed to
Step 5.
Re-run the Step 1 command. Do not assume the hub auto-pruned — a reference that survives the delete (a dashboard tile, a device input, a parent/child link) is a dangling pointer to fix on the referencing app. Report what cleared and what did not. If retiring, finish here.
Only when Step 3 parked the references on a virtual device. The replacement now exists, so the
references still sitting on the virtual have to reach it: return to
Skill(skill: "device-migration") for the second hop and its verification, and delete the virtual
device once it is empty.
If Step 3 migrated the references directly, they are already on the replacement and Step 5 verified them — nothing is left here. Finish here.