fxgraph
Use the bundled fxgraph CLI to inspect a running JavaFX application. Treat live verification as
three separate problems: start the actual JavaFX JVM, select the correct target, then inspect or
interact within fxgraph's supported window scope.
Resolve the CLI
Set the skill directory to the absolute directory that contains this SKILL.md. Do not assume the
skill is installed under a particular home-directory layout.
SKILL_DIR="/absolute/path/to/skills/fxgraph"
CLI="$SKILL_DIR/scripts/fxgraph"
test -x "$CLI"
test -f "$SKILL_DIR/scripts/fxgraph-cli.jar"
test -f "$SKILL_DIR/scripts/fxgraph-agent.jar"
On Windows PowerShell, use the sibling scripts/fxgraph.bat and invoke it with & $CLI.
If either JAR is absent in this repository, run ./gradlew :fxgraph-cli:installSkillJars from the
fxgraph repository root. Do not rebuild an installed skill unless its repository is available.
Check capability boundaries first
| Target or action | fxgraph support | Use instead when unsupported |
|---|---|---|
Nodes in a JavaFX Stage scene |
Inspect and interact | — |
Additional windows implemented as Stage |
Inspect with stages and --stageId |
— |
Showing PopupWindow, ContextMenu, MenuButton popup contents, tooltips |
Inspect and interact with the popup's stageId |
Open the popup before inspection |
| Node or individual window scene image | screenshot |
— |
| Node or individual window scene motion (up to 30 seconds) | capture-video |
— |
| One image containing separately composited popups or OS decorations | Not captured by scene snapshots | Native OS/compositor screenshot |
| JavaFX click behavior without moving the system pointer | click-node uses a complete synthetic gesture by default |
Use --mode robot only when native pointer input is required |
| Exact OS-specific mouse and keyboard behavior | Not guaranteed | TestFX or approved native UI automation |
For a popup workflow, open the popup first, then rerun stages. Popup entries expose windowType
and ownerWindowId; the legacy stageId field identifies both Stage and popup windows. Use that ID
with find-nodes, scenegraph, screenshot, or capture-video. A popup is enumerable only while
it is showing. Scene snapshots capture one window at a time, so verify a final image containing both
the owner and its popup with an OS screenshot. Request Accessibility, Screen Recording, GUI, or
sandbox approval only if the chosen native operation is blocked.
Start the actual JavaFX JVM
Prefer the target project's documented, application-specific launch task or generated launcher.
Inspect settings.gradle*, the application module's build.gradle*, launch scripts, and existing
logs before constructing a command.
Do not treat a running Gradle wrapper or daemon as proof that the JavaFX application started. A
root ./gradlew run can remain occupied by another long-lived subproject before the JavaFX task
runs. If discover is empty while Gradle is still running:
- Inspect the captured launch log and the process tree.
- Confirm that a JVM with the configured JavaFX main class actually exists and initialized JavaFX.
- Use the qualified application
runtask or a build-generated launcher such asinstallDist. - If direct
javaexecution is necessary, derive the main class, classpath, module path, and JavaFX modules from the build rather than inventing them. - Retry
discoveronly after the target JVM is alive.
Do not attach to a Gradle daemon, wrapper, build tool, or unrelated server process. If discovery or
attachment is blocked by the execution sandbox or OS permissions, retry the verified launch or
attach command with the required approval; never substitute another PID. The target runtime must
contain the java.instrument module. A future-JDK dynamic-agent warning is informational if the
command otherwise succeeds.
Read troubleshooting.md when startup, discovery, attachment, or popup capture does not behave as expected.
Select the target deliberately
First inspect all candidates:
"$CLI" discover | jq '.[] | {pid, mainClass, vmName, connected}'
Choose PID by the expected main class and, when needed, confirm its Stage titles. Never select
.[0].pid unless the result was first proven to contain exactly one intended application.
PID=12345
"$CLI" "$PID" stages | jq '.[] | {stageId, windowType, title, ownerWindowId, focused, rootNodeId}'
STAGE_ID="123456789"
Choose a Stage by windowType, title, and focus state. Choose a popup by windowType and
ownerWindowId. A focused Stage is a useful signal, not sufficient proof when several applications
or windows exist.
Use the narrow inspection workflow
- Search directly with
find-nodes. - Use a shallow
scenegraphonly for structural orientation or as a fallback. - Read only the properties needed for the assertion.
- Interact, then verify the observable result rather than trusting a success response alone.
# Narrow lookup
"$CLI" "$PID" find-nodes --type Button --text "Submit" --stageId "$STAGE_ID"
# Filtered inspection; node-details does not accept --props
NODE_ID=987654321
"$CLI" "$PID" node-details "$NODE_ID" --filter text,visible,disable
# Interaction and verification
"$CLI" "$PID" click-node "$NODE_ID"
"$CLI" "$PID" node-details "$NODE_ID" --filter text,visible,disable
"$CLI" "$PID" screenshot ./after.png --stageId "$STAGE_ID"
If direct lookup is insufficient:
"$CLI" "$PID" scenegraph --stageId "$STAGE_ID" --depth 3 --bounds
"$CLI" "$PID" scenegraph --stageId "$STAGE_ID" --props --filter text,visible,disable
Use select-node before a risky change when visual confirmation helps. Prefer set-property for
deterministic text entry. click-node sends a complete synthetic gesture by default without moving
the pointer or changing window focus; use --mode robot only when native pointer input is material.
Use activate-node for a deterministic ButtonBase.fire() action without mouse input. type-key
remains synthetic.
Apply command invariants
- All commands already output JSON. Never add
--json. --propsbelongs only toscenegraph; combine it with--filterto limit properties.- Always pass
--filtertonode-detailsunless a complete 60+ property dump is explicitly needed. propertiesis an array of{name, value, type, writable, category}, not a flat object.- Treat IDs as valid only for the current JVM session. After restart, rerun
discover,stages, andfind-nodes; do not reuse PID, window IDs fromstageId, or node IDs. - Inspect JSON error output and exit status before continuing.
- Verify changes through application state, a focused property query, a suitable screenshot, or a combination of them.
- Use
capture-videowhen motion over time is material; usescreenshotfor a single visual state.
Load command references only as needed
- Read inspect-commands.md for exhaustive options and schemas for
discover,stages,find-nodes,scenegraph, andnode-details. - Read interact-commands.md for
set-property,select-node,click-node,activate-node,focus,type-key,screenshot, andcapture-video. - Read troubleshooting.md for decision trees covering empty discovery, attach failures, stale IDs, popup controls, and composite screenshots.