Workflow Recipes
Multi-step JSON-RPC workflow examples demonstrating common editor automation tasks.
Each recipe provides a complete, step-by-step JSON-RPC workflow you can follow or adapt. All requests use the standard JSON-RPC 2.0 format over WebSocket on port 9877.
Table of Contents
Beginner
Intermediate
- Create a Blueprint Actor with Variables and Functions
- Build a Material from Scratch
- Set Up a Level Sequence with Actor Animation
- Mesh Asset Pipeline: Import, Configure LODs, Set Materials
- Texture Import and Configuration
Advanced
- Automated Build Pipeline: Build, Test, Export
- Advanced Blueprint: Interfaces and Debugging
- Source Control Workflow: Check Out, Edit, Check In
- Undo-Safe Mutations: Transactions and Rollback
- Event-Driven Automation: Subscribe and React
- Using RC Passthrough for Niche Operations
- Asset Catalog Sync: Scan, Annotate, and Search Fab Assets
GraphRAG + Editor Control
- GraphRAG-Guided Fog Setup: Research Properties, Then Configure
- API Discovery and Blueprint Wiring: Find Callable Functions, Then Wire Them
1. Scene Setup: Spawn, Transform, and Light a Scene
Spawn geometry and lights into the current level, position everything with transforms, set up the viewport camera, and focus on the hero object.
Prerequisites: A project is loaded in the editor with a level open.
Handlers: editor.actor, editor.viewport
Steps
1. Spawn a floor plane: editor.actor.spawn
{
"jsonrpc": "2.0", "id": 1, "method": "editor.actor.spawn",
"params": { "class": "StaticMeshActor", "location": { "x": 0, "y": 0, "z": 0 } }
} 2. Scale the floor to be large and flat: editor.actor.setTransform
{
"jsonrpc": "2.0", "id": 2, "method": "editor.actor.setTransform",
"params": {
"path": "<floor_path from step 1>",
"scale": { "x": 10, "y": 10, "z": 0.1 }
}
} 3. Spawn the hero object (a cube): editor.actor.spawn
{
"jsonrpc": "2.0", "id": 3, "method": "editor.actor.spawn",
"params": { "class": "StaticMeshActor", "location": { "x": 0, "y": 0, "z": 50 } }
} 4. Spawn a second object offset to the side: editor.actor.spawn
{
"jsonrpc": "2.0", "id": 4, "method": "editor.actor.spawn",
"params": {
"class": "StaticMeshActor",
"location": { "x": 300, "y": 200, "z": 50 },
"rotation": { "pitch": 0, "yaw": 45, "roll": 0 }
}
} 5. Spawn a directional light for the sun: editor.actor.spawn
{
"jsonrpc": "2.0", "id": 5, "method": "editor.actor.spawn",
"params": {
"class": "DirectionalLight",
"rotation": { "pitch": -45, "yaw": -30, "roll": 0 }
}
} 6. Spawn a point light for fill lighting: editor.actor.spawn
{
"jsonrpc": "2.0", "id": 6, "method": "editor.actor.spawn",
"params": { "class": "PointLight", "location": { "x": -200, "y": -200, "z": 300 } }
} 7. Position the viewport camera: editor.viewport.setCamera
{
"jsonrpc": "2.0", "id": 7, "method": "editor.viewport.setCamera",
"params": {
"position": { "x": -500, "y": -400, "z": 350 },
"rotation": { "pitch": -25, "yaw": 40, "roll": 0 }
}
} 8. Focus the camera on the hero object: editor.viewport.focusOnActor
{
"jsonrpc": "2.0", "id": 8, "method": "editor.viewport.focusOnActor",
"params": { "actor_path": "<hero_path from step 3>", "instant": true }
} Notes: Actor paths are assigned by the editor. Store the path from each spawn response. StaticMeshActor spawns with no mesh by default: use editor.actor.setProperty to assign one. For sky, spawn SkyLight and SkyAtmosphere.
2. Batch Requests: Multiple Operations in One Call
Send multiple independent JSON-RPC requests in a single WebSocket message and receive all responses at once.
Prerequisites: A WebSocket connection to AgentUX on port 9877.
Handlers: agentux, editor.state, editor.viewport
Steps
1. Send a batch array of independent requests
[
{ "jsonrpc": "2.0", "id": 1, "method": "agentux.ping" },
{ "jsonrpc": "2.0", "id": 2, "method": "editor.state.getSelection" },
{ "jsonrpc": "2.0", "id": 3, "method": "editor.viewport.getCamera" }
] Response (all results returned in a single message):
[
{ "jsonrpc": "2.0", "id": 1, "result": { "status": "ok", "plugin": "AgentUX", "version": "2.4.0" } },
{ "jsonrpc": "2.0", "id": 2, "result": { "count": 0, "actors": [] } },
{ "jsonrpc": "2.0", "id": 3, "result": { "position": { "x": 0, "y": 0, "z": 200 }, "rotation": { "pitch": -20, "yaw": 0, "roll": 0 } } }
] 2. Batch with mixed success/failure
[
{ "jsonrpc": "2.0", "id": 1, "method": "editor.actor.getTransform", "params": { "path": "/Game/Maps/Level.Level:PersistentLevel.Cube_0" } },
{ "jsonrpc": "2.0", "id": 2, "method": "editor.nonexistent.method" }
] Response: failed requests return error, others still succeed:
[
{ "jsonrpc": "2.0", "id": 1, "result": { "location": { "x": 0, "y": 0, "z": 0 } } },
{ "jsonrpc": "2.0", "id": 2, "error": { "code": -32601, "message": "Method not found: editor.nonexistent.method" } }
] Notes: Batch requests are processed sequentially on the game thread. They reduce network round-trips but do not parallelize execution. Notifications (no id) produce no response entry. Maximum batch size is limited only by WebSocket message size: batches of 10–50 work well.
3. Create a Blueprint Actor with Variables and Functions
Create a Blueprint Actor from scratch, add member variables with categories, create a custom function, wire up BeginPlay to call that function, compile, and verify.
Prerequisites: A project is loaded. The target content directory exists (e.g. /Game/Blueprints).
Handlers: editor.blueprint, editor.graph
Steps
1. Create the Blueprint asset: editor.blueprint.create
{
"jsonrpc": "2.0", "id": 1, "method": "editor.blueprint.create",
"params": { "path": "/Game/Blueprints", "name": "BP_RecipeActor", "parent_class": "Actor" }
} 2. Add a float variable "Health": editor.blueprint.addVariable
{
"jsonrpc": "2.0", "id": 2, "method": "editor.blueprint.addVariable",
"params": {
"asset_path": "/Game/Blueprints/BP_RecipeActor",
"name": "Health", "type": "float", "default_value": "100.0", "category": "Stats"
}
} 3. Add a string variable "DisplayName": editor.blueprint.addVariable
{
"jsonrpc": "2.0", "id": 3, "method": "editor.blueprint.addVariable",
"params": {
"asset_path": "/Game/Blueprints/BP_RecipeActor",
"name": "DisplayName", "type": "string", "default_value": "Hero", "category": "Info"
}
} 4. Add a bool variable "bIsAlive": editor.blueprint.addVariable
{
"jsonrpc": "2.0", "id": 4, "method": "editor.blueprint.addVariable",
"params": {
"asset_path": "/Game/Blueprints/BP_RecipeActor",
"name": "bIsAlive", "type": "bool", "default_value": "true", "category": "Stats"
}
} 5. Create a custom function "InitializeActor": editor.blueprint.addFunction
{
"jsonrpc": "2.0", "id": 5, "method": "editor.blueprint.addFunction",
"params": { "asset_path": "/Game/Blueprints/BP_RecipeActor", "name": "InitializeActor" }
} 6. Add a PrintString node inside InitializeActor: editor.blueprint.addNode
{
"jsonrpc": "2.0", "id": 6, "method": "editor.blueprint.addNode",
"params": {
"asset_path": "/Game/Blueprints/BP_RecipeActor",
"graph_name": "InitializeActor",
"node_type": "CallFunction", "function_name": "PrintString",
"position": { "x": 400, "y": 0 }
}
} 7. Find the existing BeginPlay event: editor.graph.getNodes
{
"jsonrpc": "2.0", "id": 7, "method": "editor.graph.getNodes",
"params": { "asset_path": "/Game/Blueprints/BP_RecipeActor", "graph_name": "EventGraph" }
} Store the id of the "Event BeginPlay" node for wiring in step 10.
8. Compile before calling a custom function: editor.blueprint.compile
{
"jsonrpc": "2.0", "id": 8, "method": "editor.blueprint.compile",
"params": { "asset_path": "/Game/Blueprints/BP_RecipeActor" }
} Custom functions must be compiled before they can be resolved by addNode.
9. Add a CallFunction node for InitializeActor in EventGraph: editor.blueprint.addNode
{
"jsonrpc": "2.0", "id": 9, "method": "editor.blueprint.addNode",
"params": {
"asset_path": "/Game/Blueprints/BP_RecipeActor",
"graph_name": "EventGraph",
"node_type": "CallFunction", "function_name": "InitializeActor",
"position": { "x": 300, "y": 0 }
}
} 10. Wire BeginPlay → InitializeActor: editor.graph.connectPins
{
"jsonrpc": "2.0", "id": 10, "method": "editor.graph.connectPins",
"params": {
"asset_path": "/Game/Blueprints/BP_RecipeActor",
"graph_name": "EventGraph",
"source_node_id": "<BeginPlay node id from step 7>",
"source_pin_name": "then",
"target_node_id": "<InitializeActor node id from step 9>",
"target_pin_name": "execute"
}
} 11. Final compile and verify: editor.blueprint.compile + editor.blueprint.getInfo
{
"jsonrpc": "2.0", "id": 11, "method": "editor.blueprint.compile",
"params": { "asset_path": "/Game/Blueprints/BP_RecipeActor" }
} Notes: Node IDs are GUIDs generated at creation time. New Actor Blueprints include default events (BeginPlay, ActorBeginOverlap, Tick). Custom functions must be compiled before they can be referenced as CallFunction targets.
4. Build a Material from Scratch
Create a PBR material: add a base color texture, roughness scalar, metallic constant, connect them to material properties, compile, and verify.
Prerequisites: A texture asset exists (e.g. /Game/Textures/T_BrickWall_D). Target content directory exists.
Handlers: editor.material
Steps
1. Create the Material asset: editor.material.create
{
"jsonrpc": "2.0", "id": 1, "method": "editor.material.create",
"params": { "path": "/Game/Materials", "name": "M_BrickWall" }
} 2. Add a TextureSample expression for base color: editor.material.addExpression
{
"jsonrpc": "2.0", "id": 2, "method": "editor.material.addExpression",
"params": {
"asset_path": "/Game/Materials/M_BrickWall",
"expression_class": "MaterialExpressionTextureSample",
"position": { "x": -400, "y": -100 }
}
} 3. Add a Constant expression for metallic: editor.material.addExpression
{
"jsonrpc": "2.0", "id": 3, "method": "editor.material.addExpression",
"params": {
"asset_path": "/Game/Materials/M_BrickWall",
"expression_class": "MaterialExpressionConstant",
"position": { "x": -300, "y": 100 }
}
} 4. Add a ScalarParameter for roughness: editor.material.addExpression
{
"jsonrpc": "2.0", "id": 4, "method": "editor.material.addExpression",
"params": {
"asset_path": "/Game/Materials/M_BrickWall",
"expression_class": "MaterialExpressionScalarParameter",
"position": { "x": -300, "y": 200 }
}
} 5. Connect TextureSample RGB → BaseColor: editor.material.connectToProperty
{
"jsonrpc": "2.0", "id": 5, "method": "editor.material.connectToProperty",
"params": {
"asset_path": "/Game/Materials/M_BrickWall",
"from_expression_index": 0, "property": "BaseColor", "from_output_name": "RGB"
}
} 6. Connect Constant → Metallic: editor.material.connectToProperty
{
"jsonrpc": "2.0", "id": 6, "method": "editor.material.connectToProperty",
"params": {
"asset_path": "/Game/Materials/M_BrickWall",
"from_expression_index": 1, "property": "Metallic"
}
} 7. Connect ScalarParameter → Roughness: editor.material.connectToProperty
{
"jsonrpc": "2.0", "id": 7, "method": "editor.material.connectToProperty",
"params": {
"asset_path": "/Game/Materials/M_BrickWall",
"from_expression_index": 2, "property": "Roughness"
}
} 8. Auto-layout and compile: editor.material.layoutExpressions + editor.material.compile
{
"jsonrpc": "2.0", "id": 8, "method": "editor.material.layoutExpressions",
"params": { "asset_path": "/Game/Materials/M_BrickWall" }
} {
"jsonrpc": "2.0", "id": 9, "method": "editor.material.compile",
"params": { "asset_path": "/Game/Materials/M_BrickWall" }
} 9. Verify shader statistics: editor.material.getStatistics
{
"jsonrpc": "2.0", "id": 10, "method": "editor.material.getStatistics",
"params": { "asset_path": "/Game/Materials/M_BrickWall" }
} Notes: Expression indices are assigned sequentially from 0. Using MaterialExpressionScalarParameter instead of MaterialExpressionConstant allows overriding values in Material Instances without recompiling. After layoutExpressions, positions will change. You can add emissive with a Constant3Vector + Multiply chain connected to EmissiveColor.
5. Set Up a Level Sequence with Actor Animation
Spawn an actor, create a Level Sequence, bind the actor as a possessable, add a transform track with a section, set the playback range, and add a marked frame.
Prerequisites: A project with a level open.
Handlers: editor.actor, editor.sequencer
Steps
1. Spawn an actor to animate: editor.actor.spawn
{
"jsonrpc": "2.0", "id": 1, "method": "editor.actor.spawn",
"params": { "class": "StaticMeshActor", "location": { "x": 0, "y": 0, "z": 100 } }
} 2. Create a Level Sequence: editor.sequencer.create
{
"jsonrpc": "2.0", "id": 2, "method": "editor.sequencer.create",
"params": { "path": "/Game/Sequences", "name": "Seq_ActorAnimation" }
} 3. Set display rate and playback range
{
"jsonrpc": "2.0", "id": 3, "method": "editor.sequencer.setDisplayRate",
"params": { "asset_path": "/Game/Sequences/Seq_ActorAnimation", "fps": 30 }
} {
"jsonrpc": "2.0", "id": 4, "method": "editor.sequencer.setPlaybackRange",
"params": { "asset_path": "/Game/Sequences/Seq_ActorAnimation", "start_frame": 0, "end_frame": 150 }
} 4. Add the actor as a possessable binding: editor.sequencer.addPossessable
{
"jsonrpc": "2.0", "id": 5, "method": "editor.sequencer.addPossessable",
"params": {
"asset_path": "/Game/Sequences/Seq_ActorAnimation",
"actor_path": "<actor_path from step 1>"
}
} Store the returned binding_id for subsequent steps.
5. Add a 3D Transform track and section
{
"jsonrpc": "2.0", "id": 6, "method": "editor.sequencer.addTrack",
"params": {
"asset_path": "/Game/Sequences/Seq_ActorAnimation",
"binding_id": "<binding_id from step 4>",
"track_class": "MovieScene3DTransformTrack"
}
} {
"jsonrpc": "2.0", "id": 7, "method": "editor.sequencer.addSection",
"params": {
"asset_path": "/Game/Sequences/Seq_ActorAnimation",
"binding_id": "<binding_id>", "track_index": 0
}
} 6. Set the section range and add a marked frame
{
"jsonrpc": "2.0", "id": 8, "method": "editor.sequencer.setSectionRange",
"params": {
"asset_path": "/Game/Sequences/Seq_ActorAnimation",
"binding_id": "<binding_id>", "track_index": 0, "section_index": 0,
"start_frame": 0, "end_frame": 150
}
} {
"jsonrpc": "2.0", "id": 9, "method": "editor.sequencer.addMarkedFrame",
"params": {
"asset_path": "/Game/Sequences/Seq_ActorAnimation",
"frame": 75, "label": "Midpoint",
"color": { "r": 0.0, "g": 1.0, "b": 0.0, "a": 1.0 }
}
} Notes: New sections default to infinite range: always call setSectionRange. Common track classes: MovieScene3DTransformTrack, MovieSceneFloatTrack, MovieSceneVisibilityTrack, MovieSceneColorTrack. Use addSpawnable instead of addPossessable for sequence-owned actors.
6. Mesh Asset Pipeline: Import, Configure LODs, Set Materials
Import a static mesh, inspect it, generate LODs, assign materials, enable Nanite, and verify.
Prerequisites: An FBX/OBJ mesh file on disk. A material asset for assignment.
Handlers: editor.asset, editor.staticmesh
Steps
1. Import the mesh: editor.asset.import
{
"jsonrpc": "2.0", "id": 1, "method": "editor.asset.import",
"params": { "file_path": "C:/Assets/Props/SM_Pillar.fbx", "destination": "/Game/Meshes" }
} 2. Inspect the mesh: editor.staticmesh.getInfo
{
"jsonrpc": "2.0", "id": 2, "method": "editor.staticmesh.getInfo",
"params": { "asset_path": "/Game/Meshes/SM_Pillar" }
} 3. Set LOD count and generate LODs
{
"jsonrpc": "2.0", "id": 3, "method": "editor.staticmesh.setLODCount",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "count": 3 }
} {
"jsonrpc": "2.0", "id": 4, "method": "editor.staticmesh.generateLOD",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "lod_index": 1, "percent_triangles": 0.5, "max_deviation": 2.0 }
} {
"jsonrpc": "2.0", "id": 5, "method": "editor.staticmesh.generateLOD",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "lod_index": 2, "percent_triangles": 0.25, "max_deviation": 5.0 }
} 4. Set LOD screen size thresholds
{
"jsonrpc": "2.0", "id": 6, "method": "editor.staticmesh.setLODScreenSize",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "lod_index": 1, "screen_size": 0.5 }
} {
"jsonrpc": "2.0", "id": 7, "method": "editor.staticmesh.setLODScreenSize",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "lod_index": 2, "screen_size": 0.25 }
} 5. Assign materials and enable Nanite
{
"jsonrpc": "2.0", "id": 8, "method": "editor.staticmesh.setMaterialSlot",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "slot_index": 0, "material_path": "/Game/Materials/M_Stone" }
} {
"jsonrpc": "2.0", "id": 9, "method": "editor.staticmesh.setNaniteEnabled",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "enabled": true }
} 6. Set collision and verify
{
"jsonrpc": "2.0", "id": 10, "method": "editor.staticmesh.setCollision",
"params": { "asset_path": "/Game/Meshes/SM_Pillar", "complexity": "UseComplexAsSimple" }
} Notes: generateLOD may take a few seconds for high-poly meshes. Nanite is ideal for 100k+ triangle meshes and provides automatic LOD without manual setup. For skeletal mesh inspection, use the editor.skeletalmesh.* namespace.
7. Texture Import and Configuration
Import a texture, inspect properties, and configure compression, LOD group, sRGB, and max resolution.
Prerequisites: A texture file on disk (e.g. C:/Assets/Textures/T_BrickWall_D.png).
Handlers: editor.asset, editor.texture
Steps
1. Import the texture: editor.asset.import
{
"jsonrpc": "2.0", "id": 1, "method": "editor.asset.import",
"params": { "file_path": "C:/Assets/Textures/T_BrickWall_D.png", "destination": "/Game/Textures" }
} 2. Inspect the texture: editor.texture.getInfo
{
"jsonrpc": "2.0", "id": 2, "method": "editor.texture.getInfo",
"params": { "path": "/Game/Textures/T_BrickWall_D" }
} 3. Configure compression, LOD group, sRGB, and max size
{
"jsonrpc": "2.0", "id": 3, "method": "editor.texture.setCompression",
"params": { "path": "/Game/Textures/T_BrickWall_D", "compression": "Default" }
} {
"jsonrpc": "2.0", "id": 4, "method": "editor.texture.setLODGroup",
"params": { "path": "/Game/Textures/T_BrickWall_D", "lod_group": "World" }
} {
"jsonrpc": "2.0", "id": 5, "method": "editor.texture.setSRGB",
"params": { "path": "/Game/Textures/T_BrickWall_D", "srgb": true }
} {
"jsonrpc": "2.0", "id": 6, "method": "editor.texture.setMaxSize",
"params": { "path": "/Game/Textures/T_BrickWall_D", "max_size": 1024 }
} 4. Verify final settings: editor.texture.getSettings
{
"jsonrpc": "2.0", "id": 7, "method": "editor.texture.getSettings",
"params": { "path": "/Game/Textures/T_BrickWall_D" }
} Notes: Compression by type: Default for diffuse, Normalmap for normals (auto-disables sRGB), Masks for packed channels, HDR for environment maps. sRGB should be true for color textures, false for data textures. max_size must be 0 or a power of 2 (32–8192).
8. Automated Build Pipeline: Build, Test, Export
Run a complete editor build pipeline: build lighting, geometry, and navigation, launch PIE to verify, and stop it.
Prerequisites: A project with geometry, lights, and a NavMeshBoundsVolume.
Handlers: editor.build, editor.pie
Steps
1. Build lighting at production quality: editor.build.buildLighting
{
"jsonrpc": "2.0", "id": 1, "method": "editor.build.buildLighting",
"params": { "quality": "production" }
} 2. Build geometry and navigation
{
"jsonrpc": "2.0", "id": 2, "method": "editor.build.buildGeometry",
"params": {}
} {
"jsonrpc": "2.0", "id": 3, "method": "editor.build.buildNavigation",
"params": {}
} 3. Poll build status until complete: editor.build.getBuildStatus
{
"jsonrpc": "2.0", "id": 4, "method": "editor.build.getBuildStatus",
"params": {}
} Poll until is_building is false.
4. Start PIE, verify, and stop
{
"jsonrpc": "2.0", "id": 5, "method": "editor.pie.play",
"params": {}
} {
"jsonrpc": "2.0", "id": 6, "method": "editor.pie.getState",
"params": {}
} {
"jsonrpc": "2.0", "id": 7, "method": "editor.pie.stop",
"params": {}
} Notes: Build order matters: geometry first, then lighting, then navigation. Lighting builds are asynchronous; geometry and navigation are synchronous. For a complete build, also add buildReflectionCaptures, buildTextureStreaming, and buildHLODs. Use "mode": "simulate" in PIE for Simulate-in-Editor.
9. Advanced Blueprint: Interfaces and Debugging
Create a Blueprint Actor, implement a UE interface, set variable defaults, compile, and inspect errors.
Prerequisites: A project is loaded with target content directory.
Handlers: editor.blueprint
Steps
1. Create Blueprint and add variables with defaults
{
"jsonrpc": "2.0", "id": 1, "method": "editor.blueprint.create",
"params": { "path": "/Game/Blueprints", "name": "BP_InterfaceActor", "parent_class": "Actor" }
} {
"jsonrpc": "2.0", "id": 2, "method": "editor.blueprint.addVariable",
"params": { "asset_path": "/Game/Blueprints/BP_InterfaceActor", "name": "Health", "type": "float", "category": "Stats" }
} {
"jsonrpc": "2.0", "id": 3, "method": "editor.blueprint.setVariableDefault",
"params": { "asset_path": "/Game/Blueprints/BP_InterfaceActor", "name": "Health", "value": "100.0" }
} 2. Implement an interface: editor.blueprint.addInterface
{
"jsonrpc": "2.0", "id": 4, "method": "editor.blueprint.addInterface",
"params": {
"asset_path": "/Game/Blueprints/BP_InterfaceActor",
"interface_name": "BlendableInterface"
}
} 3. Verify interfaces and check compile errors
{
"jsonrpc": "2.0", "id": 5, "method": "editor.blueprint.getInterfaces",
"params": { "asset_path": "/Game/Blueprints/BP_InterfaceActor" }
} {
"jsonrpc": "2.0", "id": 6, "method": "editor.blueprint.getCompileErrors",
"params": { "asset_path": "/Game/Blueprints/BP_InterfaceActor" }
} 4. Remove interface (optional): editor.blueprint.removeInterface
{
"jsonrpc": "2.0", "id": 7, "method": "editor.blueprint.removeInterface",
"params": {
"asset_path": "/Game/Blueprints/BP_InterfaceActor",
"interface_name": "BlendableInterface",
"preserve_functions": false
}
} Notes: Interface names can be short (e.g. "BlendableInterface") or full paths. When implemented, interfaces add function graph stubs. getCompileErrors forces recompile: useful for CI/CD. setVariableDefault accepts UE property format: "(X=1,Y=2,Z=3)" for FVector, "(R=255,G=0,B=0,A=255)" for FColor.
10. Source Control Workflow: Check Out, Edit, Check In
Check out files, make edits, and check them back in: the standard team workflow.
Prerequisites: Source control provider connected (Perforce, Git, SVN).
Handlers: editor.sourcecontrol, editor.asset
Steps
1. Check file status: editor.sourcecontrol.getStatus
{
"jsonrpc": "2.0", "id": 1, "method": "editor.sourcecontrol.getStatus",
"params": { "files": ["/Game/Maps/MainLevel", "/Game/Blueprints/BP_Player"] }
} 2. Check out files: editor.sourcecontrol.checkOut
{
"jsonrpc": "2.0", "id": 2, "method": "editor.sourcecontrol.checkOut",
"params": { "files": ["/Game/Maps/MainLevel", "/Game/Blueprints/BP_Player"] }
} 3. Make edits and save
{
"jsonrpc": "2.0", "id": 3, "method": "editor.blueprint.addVariable",
"params": { "asset_path": "/Game/Blueprints/BP_Player", "name": "MaxHealth", "type": "float", "default_value": "100.0" }
} {
"jsonrpc": "2.0", "id": 4, "method": "editor.asset.save",
"params": { "path": "/Game/Blueprints/BP_Player" }
} 4. Check in with description: editor.sourcecontrol.checkIn
{
"jsonrpc": "2.0", "id": 5, "method": "editor.sourcecontrol.checkIn",
"params": {
"files": ["/Game/Blueprints/BP_Player"],
"description": "Added MaxHealth variable to BP_Player"
}
} 5. If something goes wrong, revert: editor.sourcecontrol.revert
{
"jsonrpc": "2.0", "id": 6, "method": "editor.sourcecontrol.revert",
"params": { "files": ["/Game/Maps/MainLevel"] }
} Notes: File paths use UE content paths, not disk paths. Use editor.sourcecontrol.diff to review changes before check-in. Use editor.sourcecontrol.sync to update to latest before starting work.
11. Undo-Safe Mutations: Transactions and Rollback
Perform mutations, inspect the undo stack, then undo/redo: demonstrating how all AgentUX mutations are undo-safe.
Prerequisites: A project with a level open.
Handlers: editor.actor, editor.state
Steps
1. Spawn and move an actor
{
"jsonrpc": "2.0", "id": 1, "method": "editor.actor.spawn",
"params": { "class": "PointLight", "location": { "x": 100, "y": 0, "z": 200 } }
} {
"jsonrpc": "2.0", "id": 2, "method": "editor.actor.setTransform",
"params": { "path": "<path from step 1>", "location": { "x": 500, "y": 300, "z": 200 } }
} 2. Inspect the undo stack: editor.state.getUndoStack
{ "jsonrpc": "2.0", "id": 3, "method": "editor.state.getUndoStack" } Response:
{
"jsonrpc": "2.0", "id": 3,
"result": [
{ "title": "Set Actor Transform", "is_undone": false },
{ "title": "Spawn Actor", "is_undone": false }
]
} 3. Undo, verify, redo
{ "jsonrpc": "2.0", "id": 4, "method": "editor.state.undo" } {
"jsonrpc": "2.0", "id": 5, "method": "editor.actor.getTransform",
"params": { "path": "<path from step 1>" }
} The actor is back at (100, 0, 200).
{ "jsonrpc": "2.0", "id": 6, "method": "editor.state.redo" } Notes: All mutating AgentUX methods wrap operations in FScopedTransaction. The undo stack is shared with manual editor operations. For RC passthrough calls, set "generateTransaction": true to make them undoable.
12. Event-Driven Automation: Subscribe and React
Subscribe to editor events, receive push notifications, and unsubscribe when done.
Prerequisites: A WebSocket connection to AgentUX.
Handlers: agentux.events
Steps
1. List available events: agentux.events.list
{ "jsonrpc": "2.0", "id": 1, "method": "agentux.events.list" } Response:
{
"jsonrpc": "2.0", "id": 1,
"result": {
"available": ["selectionChanged", "assetSaved", "compilationComplete", "levelChanged"],
"subscribed": [], "subscriber_count": 0
}
} 2. Subscribe to events: agentux.events.subscribe
{
"jsonrpc": "2.0", "id": 2, "method": "agentux.events.subscribe",
"params": { "event_types": ["selectionChanged", "assetSaved"] }
} 3. Receive push notifications: server-initiated messages (no id):
{
"jsonrpc": "2.0", "method": "agentux.event",
"params": {
"event_type": "selectionChanged",
"data": { "selected_actors": ["Cube_0", "PointLight_1"], "count": 2 }
}
} 4. Unsubscribe when done: agentux.events.unsubscribe
{
"jsonrpc": "2.0", "id": 3, "method": "agentux.events.unsubscribe",
"params": { "event_types": ["selectionChanged", "assetSaved"] }
} Notes: Events are push notifications: handle incoming messages with no id. Subscriptions are per-connection and cleaned up on disconnect. Rapid changes may be coalesced. Use events for reactive workflows like auto-validation on Blueprint compile.
13. Using RC Passthrough for Niche Operations
Use editor.rc.call, editor.rc.property, and editor.rc.describe to access UE functions and properties not covered by curated handlers.
Prerequisites: Familiarity with UE object paths.
Handlers: editor.rc
Steps
1. Discover available functions: editor.rc.describe
{
"jsonrpc": "2.0", "id": 1, "method": "editor.rc.describe",
"params": { "objectPath": "/Script/EditorScriptingUtilities.Default__EditorLevelLibrary" }
} 2. Call a function: editor.rc.call
{
"jsonrpc": "2.0", "id": 2, "method": "editor.rc.call",
"params": {
"objectPath": "/Script/EditorScriptingUtilities.Default__EditorLevelLibrary",
"functionName": "GetSelectedLevelActors",
"parameters": {}
}
} 3. Read a component property: editor.rc.property
{
"jsonrpc": "2.0", "id": 3, "method": "editor.rc.property",
"params": {
"objectPath": "<level>:PersistentLevel.PointLight_0.LightComponent0",
"propertyName": "Intensity"
}
} 4. Write a component property with undo support: editor.rc.property
{
"jsonrpc": "2.0", "id": 4, "method": "editor.rc.property",
"params": {
"objectPath": "<level>:PersistentLevel.PointLight_0.LightComponent0",
"propertyName": "Intensity",
"value": 10000.0,
"generateTransaction": true
}
} Notes: Always try curated handlers first. Object paths: /Script/<Module>.Default__<ClassName> for statics, <Level>:PersistentLevel.<Actor>.<Component> for instances. Always set generateTransaction: true for mutations. Common subsystems: EditorLevelLibrary (21 fns), EditorAssetLibrary (43 fns), StaticMeshEditorSubsystem (55 fns).
14. Asset Catalog Sync: Scan, Annotate, and Search Fab Assets
Scan Fab marketplace assets, annotate with custom metadata, and use the catalog for AI-driven scene assembly.
Prerequisites: A project with Fab assets under a known path (e.g. /Game/Fab).
Handlers: editor.asset, editor.fab
Steps
1. Scan assets in a folder: editor.asset.scan
{
"jsonrpc": "2.0", "id": 1, "method": "editor.asset.scan",
"params": { "path": "/Game/Fab/Furniture", "class": "StaticMesh", "max_results": 100 }
} 2. Annotate with metadata: editor.asset.setTags
{
"jsonrpc": "2.0", "id": 2, "method": "editor.asset.setTags",
"params": {
"path": "/Game/Fab/Furniture/SM_Desk_Modern_01",
"tags": {
"AgentUX_DisplayName": "Modern Office Desk",
"AgentUX_Description": "Sleek modern desk for office scenes",
"AgentUX_Tags": "furniture,desk,office,modern"
}
}
} 3. Sync Fab library and query by role
{ "jsonrpc": "2.0", "id": 3, "method": "editor.fab.sync", "params": {} } {
"jsonrpc": "2.0", "id": 4, "method": "editor.fab.inventory",
"params": { "role": "vegetation", "imported_only": true, "limit": 50 }
} 4. View role distribution: editor.fab.classify
{ "jsonrpc": "2.0", "id": 5, "method": "editor.fab.classify" } Notes: Use AgentUX_ prefix for custom tags to avoid conflicts. scan returns disk_size and full tags; find is faster for basic lookups. Tags persist in .uasset files and survive migrations. Inventory auto-triggers crossref and classify on first call.
15. GraphRAG-Guided Fog Setup: Research Properties, Then Configure
Use GraphRAG to discover exact property names on an ExponentialHeightFogComponent, then spawn and configure the fog actor with confidence: no guessing.
Prerequisites: AgentUX WebSocket running. GraphRAG MCP server running with Neo4j loaded.
Handlers: editor.actor, editor.rc + GraphRAG MCP tools
Steps
1. Look up the fog component class: search_ue_class (MCP tool)
search_ue_class(pattern="ExponentialHeightFog")
→ UExponentialHeightFogComponent, AExponentialHeightFog 2. Get the component's property list: get_class_details (MCP tool)
get_class_details(class_name="UExponentialHeightFogComponent")
→ FogDensity (float), FogHeightFalloff (float),
bEnableVolumetricFog (bool), FogInscatteringLuminance (FLinearColor), ... 3. Find BlueprintCallable setters: find_api_surface (MCP tool)
find_api_surface(target="UExponentialHeightFogComponent", specifiers=["BlueprintCallable"])
→ SetFogDensity(float), SetFogHeightFalloff(float), SetVolumetricFog(bool), ... 4. Spawn the fog actor: editor.actor.spawn
{
"jsonrpc": "2.0", "id": 1, "method": "editor.actor.spawn",
"params": { "class": "ExponentialHeightFog", "location": { "x": 0, "y": 0, "z": 500 } }
} 5. Configure fog using RC with exact property names from GraphRAG
{
"jsonrpc": "2.0", "id": 2, "method": "editor.rc.call",
"params": {
"objectPath": "<fog_path>.ExponentialHeightFogComponent0",
"functionName": "SetFogDensity",
"parameters": { "NewValue": 0.02 }
}
} {
"jsonrpc": "2.0", "id": 3, "method": "editor.rc.property",
"params": {
"objectPath": "<fog_path>.ExponentialHeightFogComponent0",
"access": "WRITE", "property": "FogHeightFalloff", "value": 0.5
}
} {
"jsonrpc": "2.0", "id": 4, "method": "editor.rc.call",
"params": {
"objectPath": "<fog_path>.ExponentialHeightFogComponent0",
"functionName": "SetVolumetricFog",
"parameters": { "bNewValue": true }
}
} {
"jsonrpc": "2.0", "id": 5, "method": "editor.rc.property",
"params": {
"objectPath": "<fog_path>.ExponentialHeightFogComponent0",
"access": "WRITE", "property": "FogInscatteringLuminance",
"value": "(R=0.8,G=0.9,B=1.0,A=1.0)"
}
} Notes: Steps 1–3 use MCP tools; steps 4–5 use JSON-RPC. Without GraphRAG, you'd guess at property names like FogDensity vs Density vs fogDensity. For FLinearColor struct properties, use UE literal format (R=...,G=...,B=...,A=...). Function calls trigger change notifications needed for rendering updates.
16. API Discovery and Blueprint Wiring: Find Callable Functions, Then Wire Them
Use GraphRAG to discover what functions a CharacterMovementComponent exposes, then create a Blueprint that calls them from BeginPlay.
Prerequisites: AgentUX WebSocket + GraphRAG MCP server running.
Handlers: editor.blueprint + GraphRAG MCP tools
Steps
1. Search for the component class: search_ue_class (MCP)
search_ue_class(pattern="CharacterMovement")
→ UCharacterMovementComponent: Module: Engine 2. Get the class hierarchy: get_class_hierarchy (MCP)
get_class_hierarchy(class_name="UCharacterMovementComponent", direction="up")
→ UCharacterMovementComponent → UPawnMovementComponent → UNavMovementComponent
→ UMovementComponent → UActorComponent 3. Find BlueprintCallable functions: find_api_surface (MCP)
find_api_surface(target="UCharacterMovementComponent", specifiers=["BlueprintCallable"])
→ SetMovementMode(EMovementMode), SetWalkableFloorAngle(float),
SetMaxWalkSpeed(float), GetMaxSpeed() [from UMovementComponent], ... 4. Get function signature: get_function_signature (MCP)
get_function_signature(function_name="SetWalkableFloorAngle", class_name="UCharacterMovementComponent")
→ void SetWalkableFloorAngle(float InWalkableFloorAngle)
Specifiers: BlueprintCallable, Category: "Character Movement: Walking" 5. Create a Blueprint Character with config variables
{
"jsonrpc": "2.0", "id": 1, "method": "editor.blueprint.create",
"params": { "path": "/Game/Blueprints", "name": "BP_CustomCharacter", "parent_class": "Character" }
} {
"jsonrpc": "2.0", "id": 2, "method": "editor.blueprint.addVariable",
"params": {
"asset_path": "/Game/Blueprints/BP_CustomCharacter",
"name": "ConfiguredMaxSpeed", "type": "float", "default_value": "600.0", "category": "Movement Config"
}
} {
"jsonrpc": "2.0", "id": 3, "method": "editor.blueprint.addVariable",
"params": {
"asset_path": "/Game/Blueprints/BP_CustomCharacter",
"name": "ConfiguredFloorAngle", "type": "float", "default_value": "50.0", "category": "Movement Config"
}
} 6. Create a function and wire to BeginPlay
{
"jsonrpc": "2.0", "id": 4, "method": "editor.blueprint.addFunction",
"params": { "asset_path": "/Game/Blueprints/BP_CustomCharacter", "name": "ApplyMovementConfig" }
} {
"jsonrpc": "2.0", "id": 5, "method": "editor.blueprint.addNode",
"params": {
"asset_path": "/Game/Blueprints/BP_CustomCharacter",
"graph": "EventGraph", "node_type": "CallFunction",
"function_name": "ApplyMovementConfig",
"position": { "x": 400, "y": 0 }
}
} {
"jsonrpc": "2.0", "id": 6, "method": "editor.blueprint.connectPins",
"params": {
"asset_path": "/Game/Blueprints/BP_CustomCharacter",
"graph": "EventGraph",
"source_node": "ReceiveBeginPlay", "source_pin": "Then",
"target_node": "CallFunc_ApplyMovementConfig", "target_pin": "execute"
}
} 7. Compile and verify
{
"jsonrpc": "2.0", "id": 7, "method": "editor.blueprint.compile",
"params": { "asset_path": "/Game/Blueprints/BP_CustomCharacter" }
} Notes: Steps 1–4 use GraphRAG MCP tools for API discovery; steps 5–7 use JSON-RPC for Blueprint construction. UCharacterMovementComponent has 100+ properties: GraphRAG eliminates guessing. find_api_surface filters for BlueprintCallable, which is critical since only those can be wired in Blueprint graphs. get_class_hierarchy reveals inherited functions like GetMaxSpeed() from UMovementComponent.