Automated summary
Explains how to connect to the Decentraland Godot Explorer client's scene-inspector debug-hub to inspect live runtime state (scenes, entities, UI, avatars), stream logs and network traffic, or run GDScript through the eval command.
Strengths
- A single WebSocket channel where the client dials out and retries forever, so it also works on iOS/Android devices that cannot be reached inbound.
- Concrete helper scripts (hub-connect.sh, unified.sh, unified-tail.sh) that automate adb reverse, hub startup and the wait for a device to check in.
- Precisely documents the five trees (scene/entity, ui_scene/ui_entity, avatars/avatar, app_ui, ping/scenes), the shared filters dict and the keyboard-focus tracker.
- The bridge activates at boot, before login, so lobby state is already inspectable.
Limitations
- Tightly coupled to the Decentraland Godot Explorer repo and its Rust CLI (cargo run -- debug-hub); little reuse outside that codebase.
- The eval command runs arbitrary GDScript: hard-disabled in production builds and only appropriate in development environments.
- Requires correct networking (LAN IP, adb reverse, ports 9230/9231) and waits of up to ~35 s, and no authentication of the hub ports is described.
Use it when you need to know what the running Godot client is actually showing, or to execute a GDScript snippet against it, on desktop or on a device.
Avoid it on production builds, on a non-Decentraland project, or when you cannot run the repo's Rust CLI or expose the hub ports on the local network.
Security analysis
CautionThe skill is legitimate developer documentation for a first-party scene-inspector debug channel. Its riskiest element is the `eval` command enabling arbitrary GDScript execution in the running client, but it is explicitly scoped to non-production builds and gated behind a debug default. The scripts it invokes (adb reverse, websocat, a local WebSocket hub) are powerful but used for standard on-device debugging. No destructive, exfiltrating, or obfuscated behavior is present, so it warrants 'caution' rather than 'risky'.
- •Describes an `eval` command that executes arbitrary GDScript against a live client (full code execution on the connected app); mitigated by the stated production hard-disable returning `eval disabled in production builds`, but a production/other build lacking that guard would be exposed.
- •Relies on running helper shell scripts (`scripts/hub-connect.sh`, `scripts/unified.sh`, `scripts/unified-tail.sh`) and `websocat` from the repo; the skill does not inline their contents, so their actual behavior cannot be audited from this file alone.
- •`hub-connect.sh` performs `adb reverse tcp:9231` and starts a WebSocket hub bound for LAN device connections (port 9231/9230) — legitimate for on-device debugging but opens a network listener reachable from the LAN.
- •Instructs running arbitrary `cargo run -- debug-hub` / `cargo run -- run` commands and piping logs through `jq`; all standard developer workflow, no destructive or exfiltration actions.
- •No network exfiltration, credential handling, base64 obfuscation, or safety-disabling content found; no embedded secrets.
- •The `eval` command runs arbitrary GDScript against the live client — effectively a remote code-execution console. It is documented as hard-disabled in production builds, but the skill's own note that the hub's device port (9231) is exposed on the LAN (the iOS plugin bakes ws://<LAN-IP>:9231) means eval could be reachable to untrusted LAN actors unless the consumer port (9230) is strictly loopback-bound. Recommend confirming binding and prod gating before listing.
- •Several helper scripts are executed but not included in the skill content (`scripts/hub-connect.sh`, `scripts/unified.sh`, `scripts/unified-tail.sh`); they perform `adb reverse`, launch/persist a hub, and pipe WebSocket frames via websocat. These are plausible legitimate dev tooling, but their behavior is unverifiable from the provided text.
- •The skill relies on privileged local tooling (cargo run, websocat, adb reverse) and network listeners; all used for legitimate debugging purposes, but they are powerful capabilities that warrant the caution rating rather than safe.
- •No destructive filesystem commands, no secret exfiltration, no obfuscated/base64 payloads, and no attempts to disable safety controls were found.
Examples
Connect to the debug-hub and tell me what state the running client is in: which scenes are loaded, which realm, and where the avatar currently is.Tail the client's log and network streams through the debug-hub while I walk into a new scene, and summarize any errors that appear.Use the debug-hub eval command to run a GDScript snippet that prints the current scene name and the number of loaded scenes in the running client.name: mobile-dev-debug-tool
description: Use when inspecting or reporting the state of the running Decentraland Godot Explorer client — on desktop or on a mobile device (iOS/Android) — over the unified scene-inspector debug-hub (cargo run -- debug-hub; device port 9231, consumer port 9230) that the client dials out to. Covers the SCENE_INSPECTOR_CMD JSON protocol, the five trees (scene/entity, ui_scene/ui_entity, avatars/avatar, app_ui, ping/scenes), the focus keyboard-focus tracker, the log/network streams, the shared filters dict, the websocat helper scripts (scripts/unified.sh, unified-tail.sh), and the wiring across godot/src/tool/debug_server/, scene_inspector_bridge.gd and the Rust SceneManager::debug_* / AvatarScene::debug_* hooks. Also covers the eval command for running arbitrary GDScript against the live client (non-production only). Trigger when the user asks what state the running app/client is in (what scenes/realm are loaded, where the avatar is, what the UI is showing — desktop or on-device/mobile/iOS/Android), asks to connect to or host the debug-hub, or mentions the scene-inspector channel, debug-hub, port 9230/9231, DebugWs, debug_collector, websocat against the client, or running/evaluating GDScript against the running client.
Mobile dev debug tool — scene-inspector debug-hub
A single WebSocket channel exposes live client state (scenes / entities / UI /
avatars / focus), a log/network/lifecycle stream, and an eval command that
runs arbitrary GDScript — reachable on any platform, including iOS/Android
devices that can't be dialed into. The client dials out to a desktop
debug-hub; local tools (AI / websocat) connect to the hub's consumer port.
There is one transport: the scene-inspector CMD protocol (the source-of-truth
contract an external inspector app already parses, so additions stay
backward-compatible). eval is hard-disabled in production builds.
Bring up the hub
cargo run -- debug-hub # device port 9231, consumer port 9230
# launch the client pointed at the hub's device port (LAN IP shown in the banner):
cargo run -- run -- --scene-inspector=ws://127.0.0.1:9231 # desktop
cargo run -- run --target ios -- --scene-inspector=ws://<this-mac>:9231 # device
On iOS the dcl-ios-devtools export plugin auto-bakes the hub address (debug
builds), so even a Godot-editor deploy phones home — just accept the
local-network prompt on first launch. The bridge activates at boot
(global.gd::_activate_scene_inspector_from_config, from _ready + on every
deeplink), so the channel is live from the lobby, before login — no need to
enter a world first.
Answering "what state is the app in?" — ONE step
Run the pre-armed connector in the background, read its output, then query:
scripts/hub-connect.sh # Bash tool: run_in_background: true — read its output
hub-connect.sh does the whole cold-start dance in one shot: wires Android
adb reverse, ensures a hub (reuse or start), waits ≤35 s for the device to dial
in, and prints either === CONNECTED === + a ping snapshot or a NO DEVICE
relaunch hint. If it started the hub it keeps the task alive so the hub persists.
Then query with the id-filtered helpers:
scripts/unified.sh scenes
scripts/unified.sh scene '{"scene_id":0,"filters":{"limit":5}}'
scripts/unified.sh eval 'return {"scene": str(get_tree().current_scene.name), "scenes_loaded": Global.scene_runner.debug_get_loaded_scene_ids().size()}'
Why it just works: the client dials out and retries forever (backoff
1s→…→30 s cap, scene_inspector_websocket.gd), and debug builds default the
target to ws://127.0.0.1:9231 with no arg (global.gd), so a hub started
after the app is picked up within ≤30 s — no app restart needed. Per platform:
- iOS — the
dcl-ios-devtoolsexport plugin bakesws://<LAN-IP>:9231(even a Godot-editor deploy phones home); accept the Local Network prompt once. - Android — NO plugin bakes the arg (the baking plugin is iOS-only, and Android
editor-deploy CLI args don't reach the app). The debug loopback default +
adb reverse tcp:9231(set byhub-connect.sh) carry it instead. A build made before that default won't connect — rebuild+redeploy, or usecargo run -- run --target android. - desktop —
cargo run -- run -- --scene-inspector=ws://127.0.0.1:9231, or an editor F5 also auto-dials loopback.
If hub-connect.sh reports NO DEVICE, the app simply isn't dialing — follow the
hint it prints (usually: relaunch/redeploy the app).
Wiring
- Command backend:
DebugWsautoload →godot/src/tool/debug_server/debug_ws_server.gd(run_command) +debug_collector.gd(data assembly). No longer a server — purely the shared inspection/eval backend + keyboard-focus tracker. - Transport:
godot/src/tool/scene_inspector_bridge.gd(drives CMD ↔ ACK and the streams) +godot/src/logic/scene_inspector_websocket.gd; Rust side inlib/src/tools/scene_inspector/. The hub is thedebug-hubxtask (src/log_server.rs). - Rust
#[func]hooks for state only Rust can reach:SceneManager::debug_*(lib/src/scene_runner/scene_manager.rs) — CRDT enumeration, deserialization, UI control lookup.AvatarScene::debug_*(lib/src/avatars/avatar_scene.rs) — avatar listing, address/alias/entity/local lookup.
Protocol (scene-inspector CMD)
- request:
{"type":"SCENE_INSPECTOR_CMD","cmd":"<verb>","args":{...},"id":"<id>"} - reply:
{"type":"SCENE_INSPECTOR_CMD_ACK","id":"<id>","ok":<bool>,"data":...}(or{"ok":false,"error":"..."}) - streams (push):
{"type":"SCENE_INSPECTOR","payload":{"sessionId":...,"entries":[{type:...}]}}whereentries[].type∈ crdt | op_call_start | op_call_end | scene_lifecycle | perf | log | network | session_start | session_end.
The id is echoed in the ACK — always match replies by it (see the perf-vs-ACK
note below). The helpers (scripts/unified.sh) do this for you.
Five trees, one command surface
| cmd | Tree | Identified by |
|---|---|---|
| scene / entity | 3D entity tree (DclSceneNode → DclNodeEntity3d) | (scene_id, entity_id) |
| ui_scene / ui_entity | per-scene SDK UI (UiNode.base_control) | (scene_id, entity_id) |
| avatars / avatar | global AvatarScene | by ∈ {address,alias,entity,local} |
| app_ui | Explorer's own UI | auto-detected (/root/explorer/UI or /root/Menu) |
| ping / scenes / focus | — | — |
All four data cmds (scene, ui_scene, avatar, app_ui) share a filters dict:
component: [...]— OR-match SDK component names (cheap, no proto decode)property_is: {component, field, contains}— generic substring filter on any (SDK component, field) paircollect_nodes: {<child_name>: [<property>, ...]}— per-child-node property dump viaObject.get(); values pass through_variant_to_jsoninclude_parents,include_children,limit,offset,depth,class_filter,name_contains— traversal/pagination knobs
Querying — unified.sh
scripts/unified.sh <cmd> [args-json] sends one CMD frame to the hub consumer
port (ws://127.0.0.1:9230) and returns its matching ACK. It bakes in
-B 16777216 so websocat doesn't split large replies, and keeps the socket open
until the ACK's id matches (needed for on-device round-trips). Requires
websocat on $PATH (cargo install websocat or your package manager).
# Confirm the round-trip to the connected client
scripts/unified.sh ping
# All loaded scenes
scripts/unified.sh scenes
# All TextShape entities in scene 0 with their Label3D properties
scripts/unified.sh scene '{"scene_id":0,"filters":{
"component":["TextShape"],
"collect_nodes":{"TextShape":["text","font_size","pixel_size","outline_size","modulate"]}
}}'
# Your own avatar — what it's wearing + what's playing
scripts/unified.sh avatar '{"by":"local","filters":{
"collect_nodes":{"AnimationPlayer":["current_animation","autoplay"],"AnimationTree":["active"]}
}}'
# Explorer's own UI hierarchy (lobby in this state, scene UI when loaded)
scripts/unified.sh app_ui '{"filters":{"depth":2}}'
# Keyboard-focus tracker — current owner + ui_root + change history
scripts/unified.sh focus
Eval — running GDScript
scripts/unified.sh eval '<gdscript>' compiles and runs the snippet against the
live client and returns the serialized result — the agent-facing equivalent of a
devtools console. Non-production only: in a production build the cmd replies
{"ok":false,"error":"eval disabled in production builds"}.
code is a GDScript function body. Use return X to send a value back. Three
locals are in scope:
| local | what |
|---|---|
| tree | the SceneTree (tree.root, tree.get_node(...)) |
| global | the Global autoload |
| server | the DebugWsServer command-backend node |
Autoloads (Global, DebugWs, …) and engine singletons (OS, Engine,
Time, …) are reachable directly too. A bare single-line expression is
auto-wrapped in return, so eval '1 + 1' works without the keyword.
The result passes through the same _variant_to_json used elsewhere
(primitives, Vector*, Color, AABB, Array, Dictionary; everything else
— Object/Node/Callable — falls back to str()).
# Bare expression (auto-wrapped)
scripts/unified.sh eval 'Engine.get_frames_per_second()'
# Reach into the tree
scripts/unified.sh eval 'return tree.get_root().get_child_count()'
# Multi-line statement body
scripts/unified.sh eval 'var names = []
for c in tree.get_root().get_children():
names.append(c.name)
return names'
Limitations: synchronous only — await is not supported (it would return a
coroutine signal, not the awaited value). GDScript runtime errors (e.g. a
null access) are logged to the client console and the eval returns null with
ok:true; only compile errors come back as ok:false.
focus — keyboard-focus tracker
focus takes no args and returns the viewport's current keyboard-focus owner
plus a timestamped change history (no filters). Reply data:
{"current": "<path> [<class>]", "ui_root_path": "/root/explorer/UI", "history": [{"t_ms", "frame", "from", "to"}, ...]} (last FOCUS_HISTORY_MAX
= 64 changes; "<none>" means focus was released to null).
DebugWs polls get_viewport().gui_get_focus_owner() every _process frame (in
debug builds) so the history captures transient changes — including
release-to-null, which the engine's gui_focus_changed signal misses.
Use it for "input stops working" bugs: mobile walk/jump are gated by
player.gd → explorer_has_focus() (== ui_root.has_focus()), so movement
silently dies whenever current ≠ ui_root_path. The history shows which
control stole focus and on which frame. (This is how the navbar-toggle
focus-steal bug was found: the gate read true→false when a press landed focus
on the navbar's full-rect Button.)
Streams — unified-tail.sh
scripts/unified-tail.sh # logs only (default)
scripts/unified-tail.sh log,network # logs + HTTP
scripts/unified-tail.sh log,lifecycle # logs + per-tick scene lifecycle
Capture is connection-gated + opt-in. With no consumer connected, the device
captures NOTHING (no buffering) — safe to leave the tool enabled in prod. Classic
streams (crdt/perf) flow once a consumer connects; log/network/lifecycle are
opt-in (the helper subscribes for you). source ∈ rust | godot | native
(Swift/ObjC on iOS).
MCP / AI loop: the hub's consumer port (ws://127.0.0.1:9230) is a stable
local endpoint an MCP server (or the helpers above, called from Bash) can use to
read all logs and issue eval/queries — the same contract the external app uses.
Important notes
- Report state from a request/reply ACK, never from a stray
perfframe. On the hub,perf(andcrdt) are always-on pushes that start the instant a consumer connects — so a naïve read of the socket returns aperfframe, not the answer to your command. Always query with the id-filtered request/reply (unified.sh <cmd>), which matches the ACK by its uniqueid. If a query comes back empty, that's a dropped ACK — do not fall back to inferring app state from aperfpush (it only happens to carryfps/mem/scene_count; it has no realm/avatar/UI, and itsscene_count: 0can mislead you into "everything's fine / in lobby"). On a device the ACK needs a full consumer→hub→device→hub round-trip, so it lands after the first pushedperf: the helper must keep the socket open until the id matches (unified.shdoes this via a trailingsleepthatgrep -m1tears down on match). Closing stdin right after sending — as an ad-hocprintf frame | websocatdoes — drops the ACK on-device. - The local-player avatar appears in
avatarswithis_local: trueand lives onSceneManager.player_avatar_node, separate from theAvatarScene.avatar_godot_sceneHashMap that tracks remote players. - The
entitycmd returnsgodot.present: falsefor CRDT entities the renderer hasn't instantiated yet — that's an instantiation throttle in large scenes, not a bug in the tool. app_uiskips<root>/SceneUIContainer/scenes_uiby default to avoid shadowingui_scene; passinclude_scene_ui: trueto lift the skip.- The inspection cmds are read-only; only
evalcan mutate client state. - Large replies (expanded
scene/app_ui) can be huge — narrowfilters(addcomponent/property_is, dropinclude_children/include_parents, uselimit) if a reply is unwieldy. scenedefaultsinclude_childrenandinclude_parentstofalse. Pass them astrueexplicitly when you want the tree expanded;entitystill inlines parents/direct children by default.
Recipes (use cases)
Setup once (export H=.claude/skills/mobile-dev-debug-tool/scripts):
cargo run -- debug-hub # the hub (terminal 1)
cargo run -- run -- --scene-inspector=ws://127.0.0.1:9231 # desktop client -> hub
# iOS device: cargo run -- run --target ios (export plugin auto-bakes the hub
# address); then log in + enter a world + accept the local-network prompt.
1. Inspect a scene
$H/unified.sh scenes # loaded scenes (id/title/urn/count)
$H/unified.sh scene '{"scene_id":0,"filters":{"limit":5}}' # entities + their components
$H/unified.sh entity '{"scene_id":0,"entity_id":600}' # one entity + parents/children
$H/unified.sh scene '{"scene_id":0,"filters":{"component":["MeshRenderer"]}}' # by component
$H/unified.sh avatars # avatars present
$H/unified.sh avatar '{"by":"local"}' # your avatar (position, animations)
$H/unified.sh app_ui '{"filters":{"depth":2}}' # the explorer's own UI tree
Component histogram across the scene (via eval):
$H/unified.sh eval with a snippet that loops debug_list_entities ×
debug_get_entity_component_names and tallies — see "Tower of Madness" example
in the session notes (Transform/TextShape/GltfContainer counts).
2. See logs
$H/unified-tail.sh log | jq -r 'select(.type=="SCENE_INSPECTOR").payload.entries[]?
| select(.type=="log") | "[\(.source)] \(.msg)"'
$H/unified-tail.sh log,network # + HTTP
Logs are opt-in (the helper subscribes for you) and connection-gated — nothing
flows without it. source ∈ rust | godot | native (Swift/ObjC on iOS).
3. Follow the app lifecycle via logs
Start tailing BEFORE the action, then trigger it (realm change / jump / re-enter world):
$H/unified-tail.sh log | jq -rc 'select(.type=="SCENE_INSPECTOR").payload.entries[]?
| select(.type=="log" or .type=="scene_lifecycle")
| if .type=="log" then "[\(.source)] \(.msg)"
else "LIFECYCLE \(.event) scene=\(.scene_id)" end'
scene_lifecycle events: scene_init, main_crdt_loaded, script_loaded, on_start,
on_update(_end), scene_shutdown. Silence the per-tick on_update firehose with the
set_lifecycle_verbose command (args:{"enabled":false}) so boot/load events stay readable.
4. Instrument a feature you're building (add logs + verify)
The dev loop while working ON this branch:
- Add a log at debug level for your feature:
- Rust:
tracing::debug!("[myfeat] x={:?}", x);— usedebug!, NOTinfo!(info ships to mobile/Sentry-adjacent paths). - GDScript:
print("[myfeat] ...")— captured as source"godot".
- Rust:
- Run with debug logging on for your module:
(device: bakecargo run -- run -- --scene-inspector=ws://127.0.0.1:9231 --rust-log='dclgodot::yourmod=debug,warn'--rust-log=...intoDCL_IOS_GODOT_CMDLINEnext to--scene-inspector=.) - Tail just your tag while you exercise the feature:
$H/unified-tail.sh log | jq -rc 'select(.type=="SCENE_INSPECTOR").payload.entries[]? | select(.type=="log" and (.msg|test("myfeat"))) | "[\(.source)] \(.msg)"' - Poke it live without redeploying —
evalto read state or call your code:($H/unified.sh eval 'return Global.your_singleton.your_state' $H/unified.sh eval 'Global.your_singleton.trigger(); return "ok"'evalmutates — non-prod only. Ideal for "does my new function actually do X?" with no rebuild.)
Caveats: GDScript print is captured but push_warning/push_error are NOT (only
Rust warn/error, via the tracing layer). Mobile's default filter is info, so
debug! lines need --rust-log=...=debug. Everything is connection-gated +
opt-in, so a prod build with the tool present captures nothing until you connect.
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/download' --output '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md.part' && mv '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md.part' '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md' && test -s '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/mobile-dev-debug-tool' && cp -R '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr' '.claude/skills/mobile-dev-debug-tool'Cursor
test -f '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md' && test -s '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/mobile-dev-debug-tool' && cp -R '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr' '.cursor/skills/mobile-dev-debug-tool'Codex
test -f '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md' && test -s '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/mobile-dev-debug-tool' && cp -R '.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr' '.agents/skills/mobile-dev-debug-tool'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr'openskills read 'mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/mobile-debug-tool-scene-inspector-debug-hub-mrzxurfr/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.