pie-verifier
Autonomously run PIE (Play-In-Editor) sessions, navigate UMG/Slate UI, click elements programmatically, and query world actors to verify changes.
SKILL.mdUnrealEngine/skills/pie-verifier/SKILL.md
GitHubPlay-In-Editor (PIE) Verification SOPs
This skill instructs the agent on how to autonomously test game logic, UI navigation, and gameplay systems using a live Play-In-Editor (PIE) session inside the Unreal Editor.
Available Actions / Tools
The internal C++ MCP server provides the following tools:
start_pie_session: Starts the PIE session. Usestart_mode: "current_camera"(optional) to spawn at the editor camera location.extract_ui_state: Returns a JSON tree of visible UMG widgets (grouped underumg) and raw Slate elements (grouped underslate).trigger_ui_element: Acceptswidget_path(e.g.WBP_MainMenu_C_0.PlayButtonfor UMG, orslate_sbutton_0for Slate) to programmatically click or trigger the element.query_world_state: Accepts a list ofclasses(e.g.,["Character", "BP_TargetActor_C"]),tags(optional), andradius(optional). Returns the coordinates and metadata of matching actors.read_message_log: Captures the output log. Essential for asserting that no "Accessed None" or critical warnings fired.stop_pie_session: Stops the current running PIE session.
Standard Verification Workflow
Follow this loop to verify gameplay changes:
Step 1: Start PIE
Call the start_pie_session tool.
[!NOTE] If PIE is already running, the tool will notify you. Use
read_message_logto ensure no startup asserts occurred.
Step 2: Extract & Interact with UI
If the game starts with a UI menu (e.g., a main menu, inventory, or overlay):
- Call
extract_ui_state. - Inspect the
umgblock for the path of the button you want to click (e.g.,WBP_MainMenu_C_0.StartGameButton). - Call
trigger_ui_elementwith that path. - Call
extract_ui_stateagain if the screen changed to verify the menu closed or a new menu opened.
Step 3: Simulate Gameplay Actions
Use simulate_input to move the character or trigger actions (e.g., press W to move, SpaceBar to jump, or custom keys).
- Since inputs are processed instantly, call
simulate_inputwithaction_type: "down"to hold a key, wait a moment using your harness's native wait mechanism (e.g. Antigravity'sscheduletool, or a short bounded shell wait), and then callaction_type: "up"to release it.
Step 4: Extract World State
Call query_world_state with specific filters to verify that the gameplay action completed successfully:
- To check if the player moved: Query the
playerlocation. - To check if an actor was spawned or destroyed: Pass the class name to
classesand check if it is returned. - To check if an interactable object opened: Query the actor's location/properties.
Step 5: Read Log for Failures
Call read_message_log to check for runtime errors (like Blueprint compiler issues, null pointers, or failed casts) that occurred during play.
Step 6: End PIE
Call stop_pie_session when the verification completes.
Best Practices
- Filter Queries: Always specify
classesortagswhen callingquery_world_stateto keep the context clean and avoid exceeding token limits. - Wait for Loading: Give the engine 1-2 seconds after map loads or starting PIE before expecting widgets to be drawn or actors to fully possess.
- Dynamic Path Lookup: Do not hardcode button paths across different maps. Always call
extract_ui_statefirst to discover the exact widget instance names (e.g., widget instances might end with_C_0,_C_1, etc.). - Progression State Validation: If main menu or game flow buttons are unexpectedly disabled (e.g., Singleplayer button greyed out), verify that required progression registries (like
DA_ProgressionRegistry) have valid starting unlocks (e.g., Capital Ships) registered. - Save-Game Isolation: When testing run-based or roguelite game modes (e.g. Singleplayer Challenges), check for and isolate persistent save games (
Saved/SaveGames/*.sav). Stale save games often trigger modal overwrite confirmation dialogs (UAsyncAction_ShowConfirmation) that intercept automated input. - Hold-to-Activate Inputs: For buttons or input actions that require holding (e.g.
IA_StartRound), usesimulate_inputwithaction_type: "down", wait the required hold duration using the nativescheduletool, and then sendaction_type: "up". Alternatively, check if the screen provides a direct debug bypass method (e.g.,DebugStartRound()).