Multi-Agent Orchestration
Since 1.2.0, ClaudusBridge treats one editor as a shared workbench for a
whole fleet of AI agents. The Orchestration toolset
(ClaudusBridgeEditor.ClaudusBridgeOrchestrationToolset) adds the three things
a fleet needs that plain MCP calls cannot provide: background jobs,
agent identity, and asset locks.
Why it exists
A long tool call — a Niagara compile wait, a big save, a batch migration — executes on the editor's game thread while its HTTP request stays open. Every other agent connected to the same editor stalls behind it, and the client's HTTP timeout (often ~120 s) kills the call even though the editor finishes the work. With two or more agents (verified with 20 concurrent sessions) working on different assets, that serialization is the #1 pain.
The job queue
RunToolAsync(ToolsetName, ToolName, ArgumentsJson, AgentName, Priority)
queues any toolset tool as a background job and returns a jobId
immediately:
{ "method": "tools/call", "params": { "name": "call_tool", "arguments": {
"toolset_name": "ClaudusBridgeEditor.ClaudusBridgeOrchestrationToolset",
"tool_name": "RunToolAsync",
"arguments": {
"ToolsetName": "ClaudusBridgeEditor.ClaudusBridgeNiagaraSystemToolset",
"ToolName": "WaitNiagaraCompile",
"ArgumentsJson": "{\"SystemPath\":\"/Game/FX/NS_MyEffect\"}",
"AgentName": "claude-vfx"
}
} } }
- One job runs at a time (engine mutations are game-thread bound either way); at most one job starts per editor tick, so other agents' fast calls interleave between jobs instead of starving behind a drain loop.
- Queued jobs run priority-first, FIFO within a priority.
- Poll
GetJobStatus(jobId)— it returns the state, elapsed seconds, and yourqueuePosition(−1 when not queued). Poll at 0.5–1 s intervals, not hot loops; useListJobs(AgentName)to batch-check several jobs in one call. - Fetch
GetJobResult(jobId)when the state isSucceeded/Failed. Theresultfield is the raw toolset JSON (typically{"returnValue":"<json string>"}) — unwrapreturnValueand parse, exactly like acall_toolresponse. - Finished jobs stay queryable for ~30 minutes (max 200 retained).
CancelJobworks on queued jobs only; a running engine call is not abortable. A 30-minute watchdog fails a running job whose tool future never completes, so a wedged tool can never block the fleet.- Do not queue interactive/human-gated tools (anything that opens a dialog) — they hold the job slot until the watchdog fails them.
Agent sessions
RegisterAgentSession(AgentName, Purpose) once at session start — pick a short
stable name ("claude-waves", "codex-ui"). ListAgentSessions shows every
registered agent, its purpose, last-seen time, and jobs submitted, so agents
(and you) can see who is working on what. EndAgentSession removes the entry.
Sessions are advisory identity only — they gate nothing by themselves.
Advisory asset locks
Before mutating an asset, acquire a lock:
AcquireAssetLock(AssetPath, AgentName, LeaseSeconds, Note)
- Locks are cooperative (advisory): the protocol is check/acquire before edits. They gate nothing by force.
- Keys are normalized package paths —
/Game/Xand/Game/X.Xare the same lock. - Re-acquiring a lock you hold renews the lease. Another agent's unexpired
lock fails with
{heldBy, note, expiresInSeconds}— wait and retry, or coordinate. - Leases auto-expire (default 300 s), so a crashed agent never wedges the fleet. Keep leases short and scoped to the asset actually being mutated.
ReleaseAssetLock(AssetPath, AgentName, bForce)—bForce=truebreaks a stale lock and reports whose lock was broken.ListAssetLocksshows every active lock with seconds until expiry.
The busy-state dashboard
GetEditorBusyState() returns, in one cheap call: last game-thread frame time,
shader compiles remaining, job-queue depth, the running job, registered agents,
and active locks. Poll it before deciding whether to fire a heavy call directly
or queue it with RunToolAsync.
Recommended fleet protocol
RegisterAgentSessiononce.AcquireAssetLockbefore mutating an asset; release when done.RunToolAsyncfor anything that can take more than ~10 seconds (compile waits, saves, batch edits); poll politely.GetEditorBusyStatebefore heavy direct calls.
The editor also ships this protocol as the ClaudusBridge_MultiAgentOrchestration
Agent Skill, so any agent that connects can discover it via ListSkills.
Fleet-scale HTTP
The engine HTTP server defaults accept one connection per editor frame with
a backlog of 16 — enough for one occasional client, not for a fleet. Since
1.2.0 the bridge raises both (backlog 128, accepts/frame 32) before its
listener starts. User-configured [HTTPServer.Listeners] values in
Engine.ini are respected, and the plugin-written values are removed after
bind so they never persist into the project's saved config. Measured on a
20-agent burst: connection refusals 4/20 → 0, wall time 77.8 s → 11.5 s,
fast-call p50 5.7 s → 334 ms.
If you plan fleets far beyond ~100 concurrent clients, set explicit
DefaultConnectionsBacklogSize / DefaultMaxConnectionsAcceptPerFrame
overrides under [HTTPServer.Listeners] in Engine.ini.
UFUNCTION string parameters remain required in the generated tool schemas
even when they carry C++ defaults — pass every string argument explicitly
(e.g. Note on AcquireAssetLock, AgentName on RunToolAsync).