Scripting
The plugin exposes a small scripting API on its editor subsystem, PhEditorSubsystem. Use it from editor Python, Editor Utility Blueprints (category Prophouse | Agent), or from any tool that already drives the editor, such as an editor MCP server running Python for an AI agent. The console commands Ph.Import and Ph.AgentStatus wrap the same calls.
Script imports do not need Accept agent imports. That setting only gates imports queued through the Prophouse MCP. Scripts do need the editor to be signed in and, unless legacy direct transfers are on, the desktop app to be installed.
Get the subsystem
Section titled “Get the subsystem”import unreal
ph = unreal.get_editor_subsystem(unreal.PhEditorSubsystem)Functions
Section titled “Functions”| Python | Blueprint | Returns | Description |
|---|---|---|---|
get_agent_bridge_status() |
Get Agent Bridge Status | PhAgentBridgeStatus |
Whether this editor is ready to import and, if not, what to fix. |
import_entries(entry_ids, target_root) |
Import Entries | PhAgentImportResult |
Imports the given catalog entry ids, with their dependency closure, into this project. Returns immediately. |
get_last_agent_import() |
Get Last Agent Import | PhAgentImportResult |
The latest script or agent import in this editor session. Poll it for progress and results. |
import_entries takes a list of entry ids (integers) and a destination root such as "/Game/Kit". Pass an empty string to use the Default Destination Root setting. Duplicate and non-positive ids are ignored.
The import runs through the normal pipeline, one at a time, and every conflict keeps the local file without a dialog. The call returns with state set to creating, or to rejected with a reason if the import cannot start:
error_code |
Cause |
|---|---|
NOT_SIGNED_IN |
The editor is not signed in to Prophouse. |
VALIDATION |
No positive entry ids were passed. |
BUSY |
Another Prophouse import is running in this editor. Wait for it and try again. |
DESKTOP_AGENT_UNAVAILABLE |
The desktop app is not installed or could not be started. |
PhAgentImportResult
Section titled “PhAgentImportResult”| Field (Python) | Type | Meaning |
|---|---|---|
job_id |
int | The import job’s id (0 before it is created). |
state |
str | none, rejected, creating, waiting, importing, done, failed or cancelled. waiting means the job is queued but held back (for example while the desktop app starts); the editor retries it on its own. |
source |
str | script for import_entries, mcp for imports queued by an agent through the MCP. |
message |
str | A human-readable status line. |
error_code |
str | Error code when state is rejected or failed. |
object_paths |
list of str | Object paths now in the project (placed, or already present and identical), such as /Game/Prophouse/Meshes/SM_Crate.SM_Crate. Includes dependencies such as materials and textures. |
kept_local |
list of str | Object paths where your local edit was kept and the incoming version was not placed. |
failed_items |
list of str | <package>: <error> for each asset that failed to place. |
PhAgentBridgeStatus
Section titled “PhAgentBridgeStatus”| Field (Python) | Type | Meaning |
|---|---|---|
signed_in |
bool | A server URL and token are configured. |
server_url |
str | The Server URL setting. |
project_key |
str | The key imports must target to land in this editor. |
default_root |
str | The Default Destination Root setting. |
accept_agent_imports |
bool | The Accept agent imports setting. |
desktop_agent |
str | live, launchable, unavailable, not_required (legacy direct transfers are on) or unknown. |
connection |
str | unknown, connected, auth_failed or unreachable. |
presence_healthy |
bool | The editor’s last check-in reached the server and was accepted. |
last_heartbeat_error |
str | Why the last check-in failed, if it did. |
seconds_since_heartbeat |
int | Seconds since the last accepted check-in, or -1 if there has been none. |
busy_job_id |
int | The agent or script import running now, or 0. |
pending_agent_jobs |
int | Agent imports the server has queued for this editor that have not started. |
problems |
list of str | Blocking problem codes, empty when ready: NOT_SIGNED_IN, AUTH_FAILED, SERVER_UNREACHABLE, SERVER_TOO_OLD, AGENT_IMPORTS_DISABLED, DESKTOP_AGENT_UNAVAILABLE. |
summary |
str | Ready, or Not ready: followed by what to fix. |
AGENT_IMPORTS_DISABLED only blocks imports queued through the MCP. import_entries works without it.
Check readiness
Section titled “Check readiness”status = ph.get_agent_bridge_status()print(status.summary)for code in status.problems: print("problem:", code)Example: import, then spawn
Section titled “Example: import, then spawn”Imports run asynchronously on the editor’s main thread, so do not wait for them in a loop with time.sleep(): that blocks the editor and the import never advances. Poll from a tick callback instead. This example imports two entries and, once the import is done, spawns every mesh and Blueprint it placed into the current level:
import unreal
ENTRY_IDS = [1234, 5678] # catalog entry idsTARGET_ROOT = "" # "" = the Default Destination Root setting
ph = unreal.get_editor_subsystem(unreal.PhEditorSubsystem)actors = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
result = ph.import_entries(ENTRY_IDS, TARGET_ROOT)if result.state == "rejected": raise RuntimeError(f"{result.error_code}: {result.message}")
SPAWNABLE = (unreal.StaticMesh, unreal.SkeletalMesh, unreal.Blueprint)
def spawn(paths): x = 0.0 for path in paths: asset = unreal.load_asset(path) if not isinstance(asset, SPAWNABLE): continue # skip materials, textures and other dependencies actors.spawn_actor_from_object(asset, unreal.Vector(x, 0.0, 0.0)) x += 300.0
def on_tick(delta_seconds): last = ph.get_last_agent_import() if last.state not in ("done", "failed", "cancelled"): return # creating, waiting or importing unreal.unregister_slate_post_tick_callback(handle) if last.state == "done": spawn(last.object_paths) unreal.log(last.message) else: unreal.log_warning(f"{last.state}: {last.error_code} {last.message}")
handle = unreal.register_slate_post_tick_callback(on_tick)object_paths contains the whole closure, which is why the example filters by class before spawning.
Console commands
Section titled “Console commands”Type these into the editor’s console. Output goes to the Output Log under LogProphouse.
| Command | What it does |
|---|---|
Ph.Import <entryId> [<entryId>...] [Root=/Game/Path] |
Calls import_entries with the given ids and optional destination root, then prints the initial state. |
Ph.AgentStatus |
Prints the readiness summary and status fields, then the last import’s job id, source, state, message and object paths. |
Ph.Import 1234 5678 Root=/Game/KitPh.AgentStatus