Safety model
An Unreal editor is shared, mutable state. An agent can act on a stale read, start Play while something is building, or keep going after a native fault. Hayba checks each write where it happens, in the editor plugin, and refuses with a reason instead of guessing.
Release status
The protections on this page are in the current source as the 0.4.0 release candidate. They are not in the v0.3.0 release, and final release checks are still running. Plan Mode and undo, described on their own page, predate this work.
The checks
Every command passes through one router in the plugin. A refused command does not run, and the reply carries a code the agent can act on.
| Check | What it protects | Typical refusal |
|---|---|---|
| Plan Mode | Writes from an external agent wait for your exact approval. | plan_mode_required, exact_approval_unavailable |
| Leases | One agent cannot quietly write to a resource another agent holds. | lease_conflict, owner_required |
| Asset busy | An asset being built by one agent is not compiled, saved or played by another. | asset_busy |
| Play-In-Editor | Edits that are unsafe during Play are refused while it runs. | pie_active, pie_blocked |
| Editor health | After a contained native fault, later writes stop until restart. | editor_unsafe_restart_required |
| Saves | A read-only file returns an error instead of opening a blocking dialog. | package_read_only |
A refusal is a signal to refresh state or change the plan, not to resend the same write.
editor_get_state reports the current
map, who owns Play-In-Editor, builds in progress, editor health and unsaved packages in one
call.
Leases
Several agents can share one editor: for example a terrain agent, a foliage agent and a reviewer. A lease is a time-limited claim on named resources: the whole editor, a world, a World Partition region, an actor, an asset, or Play-In-Editor. The editor checks leases but never waits on them, so one agent cannot freeze another.
lease_acquireeither grants alease_idor queues the request and says who holds the resource and for how long.- Leases last 120 seconds by default, up to 900, and are renewed with
lease_renew. If an agent disconnects, its leases lapse within about a minute. editor_batchruns several steps under one lease, one step per frame, and waits for the editor to settle between steps.
Set When agents edit the same item, under Settings, Editor safety, to choose how strict this is. It takes effect immediately.
| Setting | Behaviour |
|---|---|
| Enforced for writes (default) | Reads run. A write that collides with another agent's lease is refused. So is a write that names no agent while other agents are connected. |
| Enforced | As above, and a read that names an expired lease is refused too. |
| Advisory | Everything runs; conflicts come back as warnings. |
| Off | No lease checks. |
With a single agent and no other leases, the default refuses nothing. To give each agent a
stable name, set HAYBA_AGENT_ID in its MCP server's environment. Leases coordinate
agents; they are not authentication.
Play-In-Editor
- While Play-In-Editor runs or is starting, only reads and Play observation commands run. Anything else is refused with
pie_active. Nothing ran, so the agent can retry after Play stops. - Only the agent that started a Play session can drive it with input. No agent drives or stops a session you started.
editor_start_piechecks loaded Blueprints first. If one would open a compile-error dialog when Play starts, it answerspie_blockedwith the Blueprints to fix, instead of leaving a dialog that stalls every command behind it.- A running batch pauses during Play and resumes afterwards.
If you press Play while an agent is building assets, Hayba stops it and names the asset. Press
Play again within ten seconds to play anyway. The console variable
hayba.PIEBuildVeto changes this: 0 only notifies, 1 is
the default, 2 always blocks.
After a native fault
The plugin catches native crashes inside its handlers, Python calls and material calls. Catching one does not make the editor safe to keep using: the interpreter, play state or a save may be damaged. So after a caught fault:
- The command that faulted answers
native_fault_contained. - The editor shows a notification that stays until you dismiss it.
- Later commands are refused with
editor_unsafe_restart_required, apart from status checks and some reads. - The Play button is blocked, and any running batch stops.
Only an editor restart clears this. Save what you can, then restart. The goal is that you are warned in time to save, not that a later crash can never happen.
Python
python_run runs a script inside the editor
process. Hayba refuses scripts that write host files, start processes or open network
connections. Each script gets a fresh namespace and a 5 second deadline. A longer deadline,
up to 60 seconds, needs an exclusive lease, because the script holds the editor's game thread
while it runs. python_run is never retried automatically after a lost
connection, so a slow script cannot run twice.
These limits reduce known risks. They are not process isolation: Python still runs inside the editor.
What it does not do
- It does not make arbitrary native code crash-proof, and not every Unreal subsystem can be rolled back.
- Agent identity is self-declared. Leases prevent accidents between cooperating agents, not abuse.
- The plugin listens only on
127.0.0.1. It is not built to be exposed to a network.
Use a scratch project while you evaluate Hayba, keep projects under source control, and stop the agent when its evidence is incomplete.