THE UQL FIELD GUIDE

Find the command.
Make it your own.

Start with a task, look up a command, or borrow an example for your next script.

12 how-to guides125 commands49 reference topics

Development reference · r75 — based on the current in-tool documentation. Some features need a particular host or an optional module. Check the help included with your installed version.

How-to guide · Getting startedRun your first UQL scriptConnect Conductor, read one familiar value, and turn that first query into a script you can reuse.

Start with a value you already know how to find in your game. A small first query makes it easy to confirm that UQL is reading the object you intended.

Before you begin: install the UQL Runtime and Editor folders, then open Tools → UQL Conductor. This example needs a GameObject at Level_1/DragonBoss, an attached BossController, and its health member. Replace those names with your own.

  1. Open Files, choose a workspace folder, and press Connect.
  2. Create a source with + Script, or place a .uql file directly in UQLScripts.
  3. Add the script to your selected group and enable its Execute permission.
  4. Press Compile, resolve any diagnostics, then execute Inspect.
  5. Open Output to read the result. Change the game value and execute the block again.
UQLSCRIPT BossTools;

ALIAS $boss = [SCENE:Level_1/DragonBoss].BossController;

BLOCK "Inspect" {
    LOG $boss.health;
}

Saving a source does not compile it, and an ordinary BLOCK does not run merely because compilation succeeded. After a Play Mode or domain transition, compile again before starting another run.

How-to guide · Getting startedGive your game data a readable pathChoose a scene or static root, name frequently used paths, and understand when to use ALIAS, PATH, or VALUE.

A good path makes the rest of your script easier to read. Start at a known object, move to its component, then select the member you need.

  1. Use [SCENE:…] for a loaded GameObject, [STATIC:Namespace.Type] for static members, or a host-registered [ROOT:name].
  2. Continue through an attached component and its fields or properties. Object and member names are case-sensitive.
  3. Give a repeated path an ALIAS. Its binding stays fixed while the value it reads can change.
  4. Use PATH when you need to choose a different path later; use VALUE to store a result at a particular moment.

Declaration excerpt: this needs a unique loaded GameObject named DragonBoss with a BossController.health member. Add these declarations beneath a script header, or enter them once in a fresh terminal session.

ALIAS $boss = [SCENE:DragonBoss].BossController;
ALIAS $health = $boss.health;

For collections, items[0] selects an array/list element; items["Fire"] selects a dictionary key. Dictionary [INDEX:0] means enumeration position, which can change after edits. A hierarchy path does not load a scene, and an ambiguous scene name produces a diagnostic rather than silently choosing an object.

How-to guide · Find and inspectTurn a collection into a useful reportUse SELECT for a focused table of values, and ITERATE when each item needs its own instructions.

When a manager holds hundreds of records, reading the entire object rarely answers your question. SELECT lets you choose useful columns and keep a compact result; ITERATE lets you run a sequence for each item.

  1. Find the collection path and confirm the element members you want to inspect.
  2. Declare an untyped report VALUE, such as VALUE $report = null;.
  3. Choose an item alias, optional index, and named FIELDS. Add WHERE to narrow the rows and LIMIT to bound the result.
  4. Read or record the report. Check its coverage and error information before treating missing rows as proof of absence.

BLOCK excerpt: Records, States, and StatesById must resolve from the host root. Records need Id and Generation members; $report must already exist.

SELECT Records AS $record INDEX $index
FIELDS id = $record.Id, generation = $record.Generation,
       parallelState = States[INDEX:$index], keyedState = StatesById[$record.Id]
INTO $report;

Use EACH for explicit managed parent-to-child collections. Use ITERATE collection AS $item { … } for per-item work. Reports retain selected observations; they do not continuously refresh. Missing keys, changed collections, and query limits remain visible in the result.

How-to guide · Find and inspectFind a value when you do not know its pathSearch a scene or a known object, keep matching paths, and narrow the candidates after a change in the game.

SCAN helps when you know what you are looking for but not where the game stores it. You can search by field name, component type, value, reference, or common missing-object conditions.

  1. Choose the smallest useful starting point: a known manager before the whole scene.
  2. Declare a BUCKET for matching paths and an untyped VALUE for the report.
  3. Set reasonable SCANOPT limits. Keep property traversal off unless you want those getters to run.
  4. Run a selector, inspect the report, and refine the candidates after a controlled gameplay change.

BLOCK excerpt: declare BUCKET $hits; and VALUE $report = null; beforehand. This selector searches loaded scene data for a field named health.

CLEAR $hits;
SCAN FIELD health IN SCENE INTO $hits REPORT $report;
RECORD $report.Text;
REGISTER health_scan;

The report keeps the observations made during discovery; the BUCKET keeps paths you can read again. A later SCAN CHANGED IN $report can narrow those candidates. Check coverage and errors: bounded discovery is not a complete memory search. Collection indices can point at different entries after reordering, so keep identity fields when you need to follow one entity.

How-to guide · Getting startedRead, format, and keep your resultsPick the right output for a quick terminal read, a reusable script, or a report you want to keep.

Use the terminal to explore, then keep the useful query in a BLOCK. The output commands let you decide which information stays on screen and which becomes a saved report.

  1. In the terminal, use READ for a value or object view. In a regular script BLOCK, use LOG or BLUEPRINT.
  2. Add FIELDS when several values need clear labels. Use LINE to end that output line.
  3. Build a report with RECORD, then explicitly commit it with REGISTER.
  4. Open Conductor's Output viewer for LOG text, or the named registry for committed report text.

BLOCK excerpt: provide $oldCount and $newCount VALUEs before running this documented example.

RECORD FIELDS before = $oldCount, after = $newCount, changed = $oldCount != $newCount;
RECORD NEWLINE;
REGISTER test_result;

LOG and RECORD are separate streams. Finishing a BLOCK does not commit pending RECORD text, and an in-memory registry needs a file host to persist to disk. Use CONSOLE LOG only when you want Unity Console output. HELP belongs in the terminal; executable CATALOG commands can run inside a BLOCK.

How-to guide · Verify behaviorCheck what changed after an actionCapture the values that matter, compare them explicitly, and keep a result you can review.

A command finishing tells you that it ran. OBSERVE and CHECK help answer the more useful question: did the game end up in the state you expected?

  1. Choose a small set of addressable values and capture them with OBSERVE FIELDS.
  2. Run your action in the same process, then capture the values again when the result should be available.
  3. Compare named frozen cells with CHECK. Use NEAR and a tolerance for suitable numeric or vector comparisons.
  4. Read and record the result's Outcome and Reason. Add your own IF/STOP behavior if the test should stop.

Self-contained statement excerpt: paste inside a BLOCK or a fresh terminal session. This compares prepared values; replace them with selected game paths for a gameplay test.

VALUE $hp = 10; VALUE $expected = 10; VALUE $snapshot = null; VALUE $result = null;
OBSERVE FIELDS hp = $hp, expected = $expected INTO $snapshot;
CHECK sample: $snapshot["hp"] == $snapshot["expected"] INTO $result;

CHECK returns Pass, Fail, or Inconclusive; it does not automatically fail the process. Missing or truncated evidence cannot silently pass. A PHASE label describes your sampling point but does not schedule it or make several reads an atomic game snapshot.

How-to guide · Verify behaviorFollow a value through a gameplay sequenceKeep a change history for a known path, sample at meaningful points, and export the evidence.

Use TRACE when the sequence matters: a position jumps, health changes twice, or a flag briefly takes an unexpected value. A handle gives the trace a clear name in your script.

  1. Choose a reference-rooted member path for the game value you want to follow.
  2. Create the trace and keep its handle in a VALUE.
  3. Use manual mode and explicit UPDATE instructions when you want to choose the sample points.
  4. Inspect the history or export it with REGISTERTRACE, then stop the trace when the investigation is finished.

Complete script example: the loaded scene must contain a unique GameObject named Character. Execute Begin, move it through your game, then execute PlayerAfterMove.

UQLSCRIPT PositionEvidence;
ALIAS $character = [SCENE:Character];
TRACEOPT manual = true;
VALUE $positionTrace = null;
BLOCK Begin {
    TRACE $character.transform.position INTO $positionTrace;
    UPDATE TRACE $positionTrace PHASE BeforeMovement;
}
BLOCK PlayerAfterMove {
    UPDATE TRACE $positionTrace PHASE AfterMovement;
}

TRACE records sampled changes, so a change that happens and reverses between samples may be missed. The phase name does not create a gameplay hook. Rebinding a PATH or VALUE does not retarget an existing trace; create a new trace for a different target.

How-to guide · Work with game stateInspect a method before making a changeFind the right overload, make a deliberate call or edit, and read back the result.

Once you have found the right target, UQL can help you try a small change without building a custom debugging panel. First confirm the member or method you intend to use.

  1. Read the target and identify the value or behavior you want to change.
  2. Use METHODS to inspect available signatures. NAME and PARAMS filters help select the intended overload without calling it.
  3. Use INVOKE for an explicit method call, or EDIT for a writable path. In Conductor, an EDIT needs the source's Edit grant.
  4. Read the value again, or use OBSERVE/CHECK to verify the effect. Restore temporary changes explicitly when appropriate.

BLOCK excerpt: $controller must already refer to the intended component. This searches its metadata for Move(float, float); it does not move anything.

VALUE $methods = null;
METHODS IN $controller NAME Move PARAMS(float, float) INTO $methods;
LOG $methods.Text;

Method bodies and property setters run real game code, including their side effects. UQL's Edit Log records supported writes; it is separate from Unity Undo and currently has no undo command. Edit Mode writes can mark scenes dirty. Discovery may be limited by visibility settings, budgets, or reflection stripping, so check the report before concluding that a method is absent.

How-to guide · Work with game stateWait for a useful momentWait for readiness, a notification, or elapsed time without losing your process state.

Many debugging steps depend on something happening first: a scene becoming ready, an animation ending, or a game system publishing a notification. WAIT lets a script resume when that condition is met.

  1. Choose WAIT UNTIL for a Boolean condition, WAIT EVENT for the next notification, or a timed FRAME/SECOND wait.
  2. Add a timeout to EVENT or UNTIL so an absent result has a clear ending.
  3. Keep the outcome in a VALUE and compare it with the documented enum.
  4. Record the outcome and choose what to do next. Inspect process diagnostics if the script remains waiting.

BLOCK excerpt: $ready must be a declared Boolean value or path. Place this inside the block that needs to wait.

VALUE $outcome = null;
WAIT UNTIL $ready TIMEOUT 2 SECOND INTO $outcome;

Matched and TimedOut both continue after WAIT; cancellation does not. The process keeps its local state, CALL stack, and RECORD buffer. Compare outcomes with [STATIC:UQL.Runtime.UqlWaitOutcome].TimedOut, not a string. FRAME uses the host's frame clock when available and scheduler steps otherwise. A wait makes the process eligible to resume; it does not guarantee an exact rendering phase or create another thread.

How-to guide · Work with game stateRun a check at a gameplay hookConnect a named BLOCK to a deliberate gameplay event, and choose between CALL, START, and TRIGGER.

A hook gives you a repeatable place to observe gameplay. Name a BLOCK for the event you care about, then publish that event from your game or another UQL block.

  1. Choose a meaningful event name, such as DamageApplied, and add a matching parameterless BLOCK.
  2. Enable Events for the source and compile its Conductor group. A custom C# host must attach its group to the intended hook runtime.
  3. Publish the name at the gameplay point you want to inspect, using the C# hook API or UQL TRIGGER.
  4. Place your reads, OBSERVE, or UPDATE TRACE instructions inside the receiving BLOCK.

Two integration excerpts: the C# call belongs at the intended game-code point; the UQL statement belongs inside a script BLOCK. To execute the receiving BLOCK, register a matching receiver in the same hook runtime. Publishing without a matching receiver is a successful no-op.

UQLHooks.Trigger("DamageApplied");
TRIGGER DamageApplied;

CALL stays in the current process. START queues a separate cooperative process. TRIGGER synchronously notifies matching receivers and existing event waiters. Event names are case-sensitive, and WAIT EVENT does not remember earlier notifications. A hook does not automatically sample TRACE: add UPDATE where the read belongs. Keep hook work bounded so it fits the gameplay point you chose.

How-to guide · Verify behaviorKeep a picture alongside your resultsCapture a camera, an independent scene view, or the final Game View and inspect the resulting PNG.

Sometimes the fastest way to understand a result is to see it. CAPTURE adds an image to your investigation, alongside the values and checks you recorded.

  1. Choose an existing camera, an independent scene viewpoint, or Game View when you need the final composited frame and overlay UI.
  2. Enable the source's Capture permission. Configure dimensions with CAPTUREOPT for camera or scene captures.
  3. Give the PNG a useful name and store the report in a predeclared VALUE.
  4. Check Success, read the returned file path, and open the image to confirm that it shows the intended subject.

BLOCK excerpt: the scene needs a GameObject named Main Camera with a Camera component. Declare VALUE $shot = null; first.

CAPTURE [SCENE:Main Camera].Camera INTO market_view REPORT $shot;
RECORD $shot.Text;
REGISTER camera_capture;

Conductor writes PNGs beneath the host's Captures output folder; reusing a name replaces that image. Camera capture is an additional render and does not include screen-space overlay UI. Game View capture is available from development revision 73, uses the view's own size, and may wait for a frame. A successful file report confirms publication; you still need to judge the image itself.

How-to guide · Agent workflowLet an agent query your local Unity projectConnect the optional local MCP server, discover the host, and review the evidence from a small UQL run.

The optional UQL MCP server exposes the file-channel workflow as tools for an MCP client. It runs locally outside Unity, so an agent can request a query and read its results through the connected Conductor host.

  1. Configure the server's allowed project and channel folder, then connect that workspace in Conductor.
  2. Register the server launch command in your MCP client and reconnect after configuration changes.
  3. Start with uql_hosts to confirm the intended ready host, then uql_help for its current syntax.
  4. Submit a small source through uql_compile or execute a named BLOCK through uql_run, requesting only the grants that task needs.
  5. Review diagnostics, CHECK outcomes, LOG/registry text, and any returned captures. Confirm that temporary grants were restored.

Server launch example: this command assumes the published server exists at this relative path in a source checkout. It is a client process command, not UQL script syntax.

dotnet Tools/UqlMcp/dist/UqlMcp.dll

The server uses stdin/stdout rather than a network port. Development revision 75 adds check-only compilation; an older host may refuse that mode. A completed run is not automatically a passed gameplay check. Available tools and capabilities depend on the installed server and host versions.

Command · DeclarationsUQLSCRIPTNames the script. Required as the first declaration in a regular script; it identifies a source within the group, not a separate namespace.

Names the script. Required as the first declaration in a regular script; it identifies a source within the group, not a separate namespace.

Where to use it

Script header

Example

UQLSCRIPT Combat;
Read the SCRIPT reference →
Command · DeclarationsGROUPProvides a group-name hint. The host-selected group takes precedence in Conductor; this declaration does not select source-file membership.

Provides a group-name hint. The host-selected group takes precedence in Conductor; this declaration does not select source-file membership.

Where to use it

Script header

Example

UQLSCRIPT Combat;
GROUP Gameplay;
Read the SCRIPT reference →
Command · DeclarationsALIASDeclares an immutable path plan. It cannot be reassigned with $a = $b; the game value reached by the path can still change.

Declares an immutable path plan. It cannot be reassigned with $a = $b; the game value reached by the path can still change.

Where to use it

Global / BLOCK scope

Example

ALIAS $boss = [SCENE:DragonBoss].BossController;
ALIAS $health = $boss.health;
Read the PATHS reference →
Command · DeclarationsDEFINECurrently behaves like ALIAS: an immutable path declaration. It is not a separate constant-literal or build-embedded definition system.

Currently behaves like ALIAS: an immutable path declaration. It is not a separate constant-literal or build-embedded definition system.

Where to use it

Global / BLOCK scope

Example

DEFINE $health = [SCENE:DragonBoss].BossController.health;
Read the PATHS reference →
Command · DeclarationsPATHDeclares a path slot that can be rebound at runtime. Assignment changes its path binding, not a VALUE snapshot.

Declares a path slot that can be rebound at runtime. Assignment changes its path binding, not a VALUE snapshot.

Where to use it

Global / BLOCK scope

Example

PATH $target;
BLOCK Choose {
    $target = [SCENE:DragonBoss].BossController.health;
    LOG $target;
}
Read the PATHS reference →
Command · DeclarationsVALUEDeclares a value slot. Use = to assign a new value; RESOLVE stores the value read at that moment.

Declares a value slot. Use = to assign a new value; RESOLVE stores the value read at that moment.

Where to use it

Global / BLOCK scope

Example

VALUE $index = 0;
BLOCK Step { $index = $index + 1; LOG $index; }
Read the PATHS reference →
Command · DeclarationsBUCKETStores captured paths, not object snapshots. Iteration and reads automatically resolve each entry.

Stores captured paths, not object snapshots. Iteration and reads automatically resolve each entry.

Where to use it

Global / BLOCK scope

Example

BUCKET $targets;
BLOCK Collect { ADD [SCENE:DragonBoss] TO $targets; }
Read the BUCKET reference →
Command · FlowBLOCKDeclares a named entry point. CALL runs it in the current process; START queues a separate process. Names must be unique within a group.

Declares a named entry point. CALL runs it in the current process; START queues a separate process. Names must be unique within a group.

Where to use it

Script top level

Example

BLOCK Add($a: int, $b: int) { RETURN $a + $b; }
Read the SCRIPT reference →
Command · FlowAWAKE BLOCKAn authorized file host queues this parameterless block once after successful activation. Compilation alone and terminal submissions do not auto-start it.

An authorized file host queues this parameterless block once after successful activation. Compilation alone and terminal submissions do not auto-start it.

Where to use it

Script top level; Awake permission required

Example

AWAKE BLOCK Init { LOG "Ready"; NEWLINE; }
Read the SCRIPT reference →
Command · FlowCALLCalls a block using the same process and RECORD buffer. Execution resumes in the caller after RETURN; INTO stores a return value in a VALUE slot. CALL also calls a CSHARP function of the group (HELP "CSHARP FUNCTIONS").

Calls a block using the same process and RECORD buffer. Execution resumes in the caller after RETURN; INTO stores a return value in a VALUE slot. CALL also calls a CSHARP function of the group (HELP "CSHARP FUNCTIONS").

Where to use it

Script BLOCK / terminal

Example

BLOCK GetValue { RETURN 12; }
BLOCK Main { VALUE $result = 0; CALL GetValue INTO $result; LOG $result; }
Read the SCRIPT reference →
Command · FlowDEFER CALLRegisters a process-owned cleanup BLOCK with arguments captured now. On completion, failure, STOP or group disposal, registrations run once in reverse order within a separate cumulative instruction budget. CALL shares ownership; START does not. Cleanup cannot WAIT, CAPTURE GAME VIEW, START, TRIGGER, STOP, ABORT or register DEFER.

Registers a process-owned cleanup BLOCK with arguments captured now. On completion, failure, STOP or group disposal, registrations run once in reverse order within a separate cumulative instruction budget. CALL shares ownership; START does not. Cleanup cannot WAIT, CAPTURE GAME VIEW, START, TRIGGER, STOP, ABORT or register DEFER.

Where to use it

Script BLOCK / terminal; cleanup is best effort

Example

BLOCK Release($label: string) { LOG $label; NEWLINE; }
BLOCK Main { DEFER CALL Release("test finished"); WAIT 1 FRAME; }
Read the CLEANUP reference →
Command · FlowSTARTCreates and queues a new process. Unlike CALL, it has a separate RECORD buffer; it does not create a parallel thread. The new process records its parent and this START statement (PROCESSES parent=/via=start/site=); in file-channel run evidence it is a step of the starting request (PROCESS parent=, via=start).

Creates and queues a new process. Unlike CALL, it has a separate RECORD buffer; it does not create a parallel thread. The new process records its parent and this START statement (PROCESSES parent=/via=start/site=); in file-channel run evidence it is a step of the starting request (PROCESS parent=, via=start).

Where to use it

Script BLOCK / terminal

Example

BLOCK Worker { LOG "worker"; }
BLOCK Main { START Worker; }
Read the SCRIPT reference →
Command · FlowIFExecutes a branch when its Boolean condition is true. Supports ELSE IF and ELSE branches. == null and != null treat a destroyed UnityEngine.Object (or the Editor's fake null for a missing component) as null, as path reads do.

Executes a branch when its Boolean condition is true. Supports ELSE IF and ELSE branches. == null and != null treat a destroyed UnityEngine.Object (or the Editor's fake null for a missing component) as null, as path reads do.

Where to use it

Script BLOCK / terminal

Example

IF $health > 0 { LOG "alive"; } ELSE { LOG "dead"; }
Read the reference →
Command · FlowELSERuns when the preceding IF condition is false. ELSE IF introduces another conditional branch.

Runs when the preceding IF condition is false. ELSE IF introduces another conditional branch.

Where to use it

Script BLOCK / terminal

Example

IF $n > 10 { LOG "large"; } ELSE IF $n > 0 { LOG "positive"; } ELSE { LOG "zero or negative"; }
Read the reference →
Command · FlowWHILERepeats while the condition is true. Use WAIT in long-running loops; the instruction budget cannot interrupt user getters or methods.

Repeats while the condition is true. Use WAIT in long-running loops; the instruction budget cannot interrupt user getters or methods.

Where to use it

Script BLOCK / terminal

Example

WHILE $running { LOG $health; WAIT 1 FRAME; }
Read the SCRIPT reference →
Command · FlowITERATEIterates a collection, BUCKET, or inclusive numeric range. INDEX exposes the source or virtual index. Only one range per expression is supported.

Iterates a collection, BUCKET, or inclusive numeric range. INDEX exposes the source or virtual index. Only one range per expression is supported.

Where to use it

Script BLOCK / terminal

Example

ITERATE $enemies[FROM: 2 COUNT: 4] AS $enemy INDEX $i {
    LOG $enemy.health; NEWLINE;
}
ITERATE FROM 0 TO 10 AS $i { LOG $i; NEWLINE; }
Read the QUERY reference →
Command · FlowBREAKExits the innermost loop and releases its iterator resources.

Exits the innermost loop and releases its iterator resources.

Where to use it

Script BLOCK / terminal

Example

ITERATE $enemies AS $enemy { IF $enemy.health <= 0 { BREAK; } }
Read the reference →
Command · FlowCONTINUESkips to the next iteration of the innermost loop.

Skips to the next iteration of the innermost loop.

Where to use it

Script BLOCK / terminal

Example

ITERATE $enemies AS $enemy { IF $enemy.health <= 0 { CONTINUE; } LOG $enemy.health; }
Read the reference →
Command · FlowRETURNExits the current BLOCK. Returns to a CALL caller, or completes the process at its entry block. Does not implicitly REGISTER.

Exits the current BLOCK. Returns to a CALL caller, or completes the process at its entry block. Does not implicitly REGISTER.

Where to use it

Script BLOCK / terminal

Example

RETURN;
// Or return a value:
RETURN 12;
Read the reference →
Command · FlowSTOPStops the current process, including its entire CALL stack. Does not commit pending RECORD text itself. The process records an intended end: stop=statement with the STOP site and the number of RECORD lines still uncommitted when the process finished, which are discarded (PROCESSES, run evidence stopSite=/discardedRecords=). A DEFER cleanup shares the RECORD buffer and can still REGISTER it; lines it registers are committed and not counted.

Stops the current process, including its entire CALL stack. Does not commit pending RECORD text itself. The process records an intended end: stop=statement with the STOP site and the number of RECORD lines still uncommitted when the process finished, which are discarded (PROCESSES, run evidence stopSite=/discardedRecords=). A DEFER cleanup shares the RECORD buffer and can still REGISTER it; lines it registers are committed and not counted.

Where to use it

Script BLOCK / terminal

Example

STOP;
Read the reference →
Command · FlowABORTAborts the current group, a named group, or all groups in the attached hook runtime. Independent hook runtimes are unaffected. Every process it stops records stop=abort with the aborting process and its group (aborted-by= aborted-by-group= / abortedBy= abortedByGroup=; process IDs are local to a group activation) and this ABORT site; run evidence counts it as an intended end (aborted) only when the aborting process is a step of the same run, otherwise as externallyStopped. A stop by the C# UQLHooks.Abort/AbortAll API is recorded as external, a host stop (group stopped, replaced, disposed) as host.

Aborts the current group, a named group, or all groups in the attached hook runtime. Independent hook runtimes are unaffected. Every process it stops records stop=abort with the aborting process and its group (aborted-by= aborted-by-group= / abortedBy= abortedByGroup=; process IDs are local to a group activation) and this ABORT site; run evidence counts it as an intended end (aborted) only when the aborting process is a step of the same run, otherwise as externallyStopped. A stop by the C# UQLHooks.Abort/AbortAll API is recorded as external, a host stop (group stopped, replaced, disposed) as host.

Where to use it

Script BLOCK / terminal

Example

ABORT;
// Alternatives:
ABORT Gameplay;
ABORT ALL;
Read the HOOK reference →
Command · SchedulingWAITWaits for Unity frames (FRAME: actual frames when the host has a frame clock, otherwise scheduler steps), host time (SECOND), or a condition (UNTIL). EVENT/UNTIL optionally accept TIMEOUT and INTO an outcome VALUE. The process and its RECORD buffer survive the wait.

Waits for Unity frames (FRAME: actual frames when the host has a frame clock, otherwise scheduler steps), host time (SECOND), or a condition (UNTIL). EVENT/UNTIL optionally accept TIMEOUT and INTO an outcome VALUE. The process and its RECORD buffer survive the wait.

Where to use it

Script BLOCK / terminal

Example

WAIT 2 FRAME;
WAIT 0.5 SECOND;
VALUE $outcome = null;
WAIT UNTIL $ready TIMEOUT 2 SECOND INTO $outcome;
Read the WAIT reference →
Command · SchedulingWAIT EVENTRegisters a one-shot wait for the next matching hook notification. Matching resumes the same process synchronously; an optional TIMEOUT resumes it when the scheduler processes the deadline.

Registers a one-shot wait for the next matching hook notification. Matching resumes the same process synchronously; an optional TIMEOUT resumes it when the scheduler processes the deadline.

Where to use it

Script BLOCK / terminal; Events permission in Conductor

Example

BLOCK Observe {
    VALUE $outcome = null;
    WAIT EVENT DamageApplied TIMEOUT 60 FRAME INTO $outcome;
    IF $outcome == [STATIC:UQL.Runtime.UqlWaitOutcome].TimedOut {
        LOG "DamageApplied did not arrive before the deadline.";
    }
}
Read the WAIT reference →
Command · SchedulingWAIT UNTILPolls a Boolean expression cooperatively. TIMEOUT is optional; INTO receives Matched or TimedOut. A true condition wins at a poll even when its deadline is due.

Polls a Boolean expression cooperatively. TIMEOUT is optional; INTO receives Matched or TimedOut. A true condition wins at a poll even when its deadline is due.

Where to use it

Script BLOCK / terminal

Example

VALUE $outcome: UQL.Runtime.UqlWaitOutcome;
WAIT UNTIL $ready TIMEOUT 1 SECOND INTO $outcome;
Read the WAIT reference →
Command · SchedulingTRIGGERSynchronously broadcasts a hook identity to matching BLOCKs across attached groups and waiters present at dispatch entry. Reentrancy budgets apply. A BLOCK it starts names this process as parent (via=trigger, hook, site). In file-channel run evidence a same-group receiver is a step of the request; each TRIGGER is accounted once on its publisher (started, resumed, filtered, route failures with the first reason, empty TRIGGERs with the first site), a route that fails to start (parameters, process limit) also gives a DELIVERY row, and receivers in other groups give DELIVERY rows (started, failed, not followed).

Synchronously broadcasts a hook identity to matching BLOCKs across attached groups and waiters present at dispatch entry. Reentrancy budgets apply. A BLOCK it starts names this process as parent (via=trigger, hook, site). In file-channel run evidence a same-group receiver is a step of the request; each TRIGGER is accounted once on its publisher (started, resumed, filtered, route failures with the first reason, empty TRIGGERs with the first site), a route that fails to start (parameters, process limit) also gives a DELIVERY row, and receivers in other groups give DELIVERY rows (started, failed, not followed).

Where to use it

Script BLOCK / terminal

Example

TRIGGER DamageApplied;
Read the HOOK reference →
Command · OutputREADDisplays a value or range results as standalone output using PRINTOPT. Skipped with a diagnostic in the regular script profile.

Displays a value or range results as standalone output using PRINTOPT. Skipped with a diagnostic in the regular script profile.

Where to use it

Terminal only

Example

READ $boss;
READ $enemies[FROM: 0 COUNT: 4].health;
Read the PRINTOPT reference →
Command · OutputLOGAppends a value using PRINTOPT, without an automatic separator or newline. LOG LINE expression; (or LOG NEWLINE expression;) appends then ends the line. Different processes have separate output streams. A System.Type prints its full name and a UqlDiagnostic its source, code and text.

Appends a value using PRINTOPT, without an automatic separator or newline. LOG LINE expression; (or LOG NEWLINE expression;) appends then ends the line. Different processes have separate output streams. A System.Type prints its full name and a UqlDiagnostic its source, code and text.

Where to use it

Script BLOCK / terminal

Example

LOG "Health: "; LOG LINE $boss.health;
Read the PRINTOPT reference →
Command · OutputLOG FIELDSFormats constant labels and values into one output append using PRINTOPT, separated by '; ', without a newline. LOG LINE FIELDS adds an explicit line end. Expressions run once in source order; the formatted output limit truncates with a marker.

Formats constant labels and values into one output append using PRINTOPT, separated by '; ', without a newline. LOG LINE FIELDS adds an explicit line end. Expressions run once in source order; the formatted output limit truncates with a marker.

Where to use it

Script BLOCK / terminal

Example

LOG LINE FIELDS health = $boss.health, "current position" = $boss.transform.position;
Read the FIELDS reference →
Command · EvidenceOBSERVEFreezes named addressable paths in source order into an immutable snapshot VALUE. It records capture ownership, coverage and execution-window provenance; no implicit graph expansion or live target is retained. snapshot.Compare(baseline) explicitly compares frozen selected fields for SELECT; it never rereads or advances the baseline.

Freezes named addressable paths in source order into an immutable snapshot VALUE. It records capture ownership, coverage and execution-window provenance; no implicit graph expansion or live target is retained. snapshot.Compare(baseline) explicitly compares frozen selected fields for SELECT; it never rereads or advances the baseline.

Where to use it

Script BLOCK / terminal; writable VALUE destination required

Example

VALUE $health = 10; VALUE $snapshot = null;
OBSERVE FIELDS hp = $health INTO $snapshot PHASE Before;
Read the OBSERVATIONS reference →
Command · EvidenceCHECKCompares frozen observation cells with each other or immutable literals, or tests STATUS. The right operand may also be derived from one cell and a numeric literal ($snap["b"] + 5), computed from the frozen cell in CHECK's numeric domains; literal-only arithmetic (== 5 + 1) folds at compile time. A bare VALUE on either side is not frozen evidence; capture it with OBSERVE first. Returns Pass, Fail or Inconclusive without failing the process; missing, truncated or wrong-owner evidence cannot silently pass.

Compares frozen observation cells with each other or immutable literals, or tests STATUS. The right operand may also be derived from one cell and a numeric literal ($snap["b"] + 5), computed from the frozen cell in CHECK's numeric domains; literal-only arithmetic (== 5 + 1) folds at compile time. A bare VALUE on either side is not frozen evidence; capture it with OBSERVE first. Returns Pass, Fail or Inconclusive without failing the process; missing, truncated or wrong-owner evidence cannot silently pass.

Where to use it

Script BLOCK / terminal; writable VALUE destination required

Example

VALUE $health = 10; VALUE $expected = 10; VALUE $snapshot = null; VALUE $result = null;
OBSERVE FIELDS hp = $health, expected = $expected INTO $snapshot;
CHECK healthy: $snapshot["hp"] == $snapshot["expected"] INTO $result;
Read the OBSERVATIONS reference →
Command · CollectionsSELECTProjects named paths from a collection or range into a bounded immutable report VALUE. Optional EACH headers explicitly flatten managed parent-to-child collections with shared budgets and detached Origins. Up to four LOOKUP clauses correlate keyed managed stores per row (exact-key single match; Ambiguous/Stale/Undecided stay explicit, never first-wins). WHERE supports scalar/Boolean, pure ordinal text and same-type enum HasAny/HasAll tests. Selecting a whole frozen cell preserves its status, error, original path and reference identity; .Value selects only its payload. Frozen Rows can be narrowed without rescanning their original source.

Projects named paths from a collection or range into a bounded immutable report VALUE. Optional EACH headers explicitly flatten managed parent-to-child collections with shared budgets and detached Origins. Up to four LOOKUP clauses correlate keyed managed stores per row (exact-key single match; Ambiguous/Stale/Undecided stay explicit, never first-wins). WHERE supports scalar/Boolean, pure ordinal text and same-type enum HasAny/HasAll tests. Selecting a whole frozen cell preserves its status, error, original path and reference identity; .Value selects only its payload. Frozen Rows can be narrowed without rescanning their original source.

Where to use it

Script BLOCK / terminal; writable VALUE destination required

Example

VALUE $items = null; VALUE $report = null;
SELECT $items AS $item INDEX $index KEY $key
    FIELDS value = $item, ordinal = $index, key = $key
    WHERE $item != null INTO $report LIMIT 32;
RECORD $report; REGISTER selected;
Read the PROJECTION reference →
Command · OutputCONSOLE LOGExplicitly sends one formatted message to Unity Debug.Log. Does not change ordinary LOG routing or append to RECORD. Avoid high-volume calls; Unity console logging can be expensive.

Explicitly sends one formatted message to Unity Debug.Log. Does not change ordinary LOG routing or append to RECORD. Avoid high-volume calls; Unity console logging can be expensive.

Where to use it

Script BLOCK / terminal; Unity console

Example

CONSOLE LOG $boss.health;
Read the CONSOLE reference →
Command · OutputCONSOLE WARNINGSends one warning to Unity Debug.LogWarning. The expression is optional; an omitted expression emits an empty warning.

Sends one warning to Unity Debug.LogWarning. The expression is optional; an omitted expression emits an empty warning.

Where to use it

Script BLOCK / terminal; Unity console

Example

CONSOLE WARNING "Low health";
Read the CONSOLE reference →
Command · OutputCONSOLE ERRORSends one error message to Unity Debug.LogError; it does not itself fail or stop the UQL process. Unity Editor Error Pause settings can still pause Play Mode.

Sends one error message to Unity Debug.LogError; it does not itself fail or stop the UQL process. Unity Editor Error Pause settings can still pause Play Mode.

Where to use it

Script BLOCK / terminal; Unity console

Example

CONSOLE ERROR "Target missing";
Read the CONSOLE reference →
Command · OutputNEWLINEEnds the LOG line. Bare LOG NEWLINE; and LOG LINE; do the same. As a LOG/RECORD prefix, LINE or NEWLINE appends the following value/FIELDS and then ends that stream's line. Standalone NEWLINE does not affect RECORD.

Ends the LOG line. Bare LOG NEWLINE; and LOG LINE; do the same. As a LOG/RECORD prefix, LINE or NEWLINE appends the following value/FIELDS and then ends that stream's line. Standalone NEWLINE does not affect RECORD.

Where to use it

Script BLOCK / terminal

Example

LOG "first"; NEWLINE;
LOG LINE "second";
RECORD NEWLINE "recorded separately";
Read the reference →
Command · OutputBLUEPRINTProduces a member dump using PRINTOPT. Supports a single path or a range; does not automatically append to RECORD.

Produces a member dump using PRINTOPT. Supports a single path or a range; does not automatically append to RECORD.

Where to use it

Script BLOCK / terminal

Example

BLUEPRINT $boss;
BLUEPRINT $enemies[FROM: 0 COUNT: 2];
Read the PRINTOPT reference →
Command · OptionsPRINTOPTConfigures the group's display profile from literal settings at compile time. The last setting in source order wins. Used by LOG, RECORD, READ, and BLUEPRINT. The defaults of depth/maxchars/maxmembers/maxvalue come from the workspace Limits preset (print.* keys, HELP LIMITS); this group's own keys override them.

Configures the group's display profile from literal settings at compile time. The last setting in source order wins. Used by LOG, RECORD, READ, and BLUEPRINT. The defaults of depth/maxchars/maxmembers/maxvalue come from the workspace Limits preset (print.* keys, HELP LIMITS); this group's own keys override them.

Where to use it

Script top level / terminal declaration

Example

PRINTOPT branchclasses = true, depth = 2, showtypes = true,
    showprops = true, readprops = false, vectors = true;
Read the PRINTOPT reference →
Command · OptionsLIMITOPTOverrides the workspace Limits preset's group limits (BUCKET entries, RECORD/LOG/SELECT/OBSERVE characters, processes, CALL depth, enumeration, registry and output sizes, edit log and dirty marking switches editLog/editDirty) for this group only, from literal integers at compile time. Keys are case-sensitive; an out-of-range value is clamped with a UQL213 warning. Workspace budgets and script option defaults are refused (use the preset or PRINTOPT/SCANOPT/...). When two sources set a key differently, the larger value wins with a UQL213 warning. In the terminal the registry/output keys are skipped (host-sized registry, no output.txt).

Overrides the workspace Limits preset's group limits (BUCKET entries, RECORD/LOG/SELECT/OBSERVE characters, processes, CALL depth, enumeration, registry and output sizes, edit log and dirty marking switches editLog/editDirty) for this group only, from literal integers at compile time. Keys are case-sensitive; an out-of-range value is clamped with a UQL213 warning. Workspace budgets and script option defaults are refused (use the preset or PRINTOPT/SCANOPT/...). When two sources set a key differently, the larger value wins with a UQL213 warning. In the terminal the registry/output keys are skipped (host-sized registry, no output.txt).

Where to use it

Script top level / terminal declaration

Example

LIMITOPT bucketEntries = 500000, recordCharacters = 4194304;
Read the LIMITS reference →
Command · RecordingRECORDAppends text to a process-local buffer. RECORD LINE expression/FIELDS/BLUEPRINT appends then ends its line; NEWLINE is a synonym. Bare RECORD NEWLINE ends the pending line; standalone NEWLINE affects only LOG. CALL and WAIT preserve the buffer; START/new terminal submissions do not inherit it. Completion does not auto-commit.

Appends text to a process-local buffer. RECORD LINE expression/FIELDS/BLUEPRINT appends then ends its line; NEWLINE is a synonym. Bare RECORD NEWLINE ends the pending line; standalone NEWLINE affects only LOG. CALL and WAIT preserve the buffer; START/new terminal submissions do not inherit it. Completion does not auto-commit.

Where to use it

Script BLOCK / terminal

Example

RECORD "Health: "; RECORD LINE $boss.health;
RECORD LINE BLUEPRINT $boss;
REGISTER combat;
Read the RECORD reference →
Command · RecordingRECORD FIELDSAppends labeled values using PRINTOPT, separated by '; ', without a newline. The FIELDS append is atomic against buffer quota failures; game-side expression effects are not rolled back. RECORD LINE FIELDS then separately appends a line end; it is not one atomic append.

Appends labeled values using PRINTOPT, separated by '; ', without a newline. The FIELDS append is atomic against buffer quota failures; game-side expression effects are not rolled back. RECORD LINE FIELDS then separately appends a line end; it is not one atomic append.

Where to use it

Script BLOCK / terminal

Example

RECORD LINE FIELDS health = $boss.health, "current position" = $boss.transform.position;
REGISTER combat;
Read the FIELDS reference →
Command · RecordingREGISTERAppends the process RECORD buffer to a named registry and clears the buffer on success. Conductor periodically appends new batches to the persistent file archive; recompiling or reopening does not erase it.

Appends the process RECORD buffer to a named registry and clears the buffer on success. Conductor periodically appends new batches to the persistent file archive; recompiling or reopening does not erase it.

Where to use it

Script BLOCK / terminal

Example

RECORD "sample";
REGISTER combat;
// Submit both commands in the same terminal input.
Read the RECORD reference →
Command · RecordingCLEAR RECORDDiscards only the current process's uncommitted RECORD buffer; does not clear registry contents.

Discards only the current process's uncommitted RECORD buffer; does not clear registry contents.

Where to use it

Script BLOCK / terminal

Example

CLEAR RECORD;
Read the RECORD reference →
Command · RecordingCLEAR REGISTERClears a named registry in the current group and queues truncation of its Conductor archive, even if the archive is not loaded in memory. Does not clear the process RECORD buffer. Groups sharing this name share the disk archive.

Clears a named registry in the current group and queues truncation of its Conductor archive, even if the archive is not loaded in memory. Does not clear the process RECORD buffer. Groups sharing this name share the disk archive.

Where to use it

Script BLOCK / terminal; provider must support clearing

Example

CLEAR REGISTER combat;
Read the RECORD reference →
Command · RecordingCLEARREGISTEREquivalent to CLEAR REGISTER; the spaced spelling is recommended.

Equivalent to CLEAR REGISTER; the spaced spelling is recommended.

Where to use it

Script BLOCK / terminal; provider must support clearing

Example

CLEARREGISTER combat;
Read the RECORD reference →
Command · RecordingSHOWREGISTERDisplays lines stored in registry memory; does not read arbitrary files from disk.

Displays lines stored in registry memory; does not read arbitrary files from disk.

Where to use it

Terminal host

Example

SHOWREGISTER combat;
Read the RECORD reference →
Command · RecordingREGISTERTRACEAppends retained history, or an ordered incremental batch SINCE a typed cursor. Cursor advances only after the registry accepts the batch; explicit GAP markers report retention loss/clears. Does not stop or clear the TRACE.

Appends retained history, or an ordered incremental batch SINCE a typed cursor. Cursor advances only after the registry accepts the batch; explicit GAP markers report retention loss/clears. Does not stop or clear the TRACE.

Where to use it

Script BLOCK / terminal

Example

REGISTERTRACE 1, combat;
// For a prepared handle and writable cursor VALUE:
REGISTERTRACE $trace, combat SINCE $cursor INTO $cursor LIMIT 64;
Read the TRACE reference →
Command · RecordingEXPORTREGISTERExports registry contents to a safe file name inside the host-approved output directory. Does not grant arbitrary file-path access.

Exports registry contents to a safe file name inside the host-approved output directory. Does not grant arbitrary file-path access.

Where to use it

Terminal: ExportDirectory required; Conductor: group output area

Example

EXPORTREGISTER combat, "combat.txt";
Read the RECORD reference →
Command · CollectionsADDCaptures a single path or a range into a BUCKET. Range indices are fixed at capture time; reordering the collection can change their targets.

Captures a single path or a range into a BUCKET. Range indices are fixed at capture time; reordering the collection can change their targets.

Where to use it

Script BLOCK / terminal

Example

ADD $enemies[FROM: 0 COUNT: 4].health TO $targets;
Read the BUCKET reference →
Command · CollectionsREMOVERemoves a captured path entry from a BUCKET by index. Does not destroy the game object.

Removes a captured path entry from a BUCKET by index. Does not destroy the game object.

Where to use it

Script BLOCK / terminal

Example

REMOVE 0 FROM $targets;
Read the BUCKET reference →
Command · CollectionsCLEARRemoves all BUCKET entries. CLEAR RECORD and CLEAR HISTORY are separate forms.

Removes all BUCKET entries. CLEAR RECORD and CLEAR HISTORY are separate forms.

Where to use it

Script BLOCK / terminal

Example

CLEAR $targets;
Read the BUCKET reference →
Command · CollectionsRESOLVEReads a captured path's current value into VALUE. Does not copy a live path; a later TRACE observes that VALUE slot.

Reads a captured path's current value into VALUE. Does not copy a live path; a later TRACE observes that VALUE slot.

Where to use it

Script BLOCK / terminal

Example

VALUE $snapshot = null;
RESOLVE $targets[0] INTO $snapshot;
// To track the live path: TRACE $targets[0];
Read the BUCKET reference →
Command · PathsROOTRegisters a discovered reference under a session identity. Binds a PATH or exports ROOT path text into VALUE; not a universal persistent identity for value types or field locations.

Registers a discovered reference under a session identity. Binds a PATH or exports ROOT path text into VALUE; not a universal persistent identity for value types or field locations.

Where to use it

Script BLOCK / terminal

Example

VALUE $go = null; VALUE $text = "";
PATH $exact;
FIND "DragonBoss" IN SCENE INTO $go;
ROOT $go INTO $exact;
ROOT $go INTO $text;
Read the ROOT reference →
Command · SceneFINDEvaluates a string expression and stores the first exact-name match from loaded scenes in VALUE, or null if missing. Quote literal names; bare identifiers are paths. Discovery order does not guarantee a persistent choice among duplicate names. FIND INSTANCEID <id> INTO $value finds the live Unity object with that 64-bit session id instead, or null (HELP INSTANCEID).

Evaluates a string expression and stores the first exact-name match from loaded scenes in VALUE, or null if missing. Quote literal names; bare identifiers are paths. Discovery order does not guarantee a persistent choice among duplicate names. FIND INSTANCEID <id> INTO $value finds the live Unity object with that 64-bit session id instead, or null (HELP INSTANCEID).

Where to use it

Script BLOCK / terminal

Example

VALUE $go = null; VALUE $name = "MonoManagers";
FIND $name IN SCENE INTO $go;
// A literal also works: FIND "MonoManagers" IN SCENE INTO $go;
// By session id ($id from $x[INSTANCEID] or a report): FIND INSTANCEID $id INTO $go;
Read the SCENE reference →
Command · SceneCOLLECTAppends matching scene objects, scene roots, children, or components to a BUCKET. COMPONENTS optionally filters by OF Type. Captured inputs work directly; CHILDS RECURSIVE walks descendants.

Appends matching scene objects, scene roots, children, or components to a BUCKET. COMPONENTS optionally filters by OF Type. Captured inputs work directly; CHILDS RECURSIVE walks descendants.

Where to use it

Script BLOCK / terminal

Example

BUCKET $matches; COLLECT "Enemy" IN SCENE INTO $matches;
BUCKET $roots; COLLECT ROOTS IN SCENE INTO $roots;
BUCKET $children; COLLECT CHILDS RECURSIVE $go INTO $children;
BUCKET $parts; COLLECT COMPONENTS $go INTO $parts;
BUCKET $cameras; COLLECT COMPONENTS $go OF UnityEngine.Camera INTO $cameras;
Read the SCENE reference →
Command · MutationEDITWrites a value or reference through a path. Supports constructors, tuples, and enum names. |= adds bits; &= ~ clears bits. Use a decimal point.

Writes a value or reference through a path. Supports constructors, tuples, and enum names. |= adds bits; &= ~ clears bits. Use a decimal point.

Where to use it

Script BLOCK / terminal

Example

EDIT $position = p(1.5, 2, 3);
EDIT $flags |= Visible, Active;
EDIT $flags &= ~Visible;
EDIT $reference = $other;
Read the EDIT reference →
Command · MutationUNSAFE EDITWrites an authorized native collection element. Requires native write permission and valid access conditions; does not synchronize jobs or disposal.

Writes an authorized native collection element. Requires native write permission and valid access conditions; does not synchronize jobs or disposal.

Where to use it

Script BLOCK / terminal

Example

ENABLE UNSAFE WRITE;
BLOCK Change { UNSAFE EDIT $native[0] = 12; }
Read the NATIVE reference →
Command · MutationINVOKEEvaluates a method expression without printing its return value. Immediate calls support existing value constructors, arithmetic, nested calls and result suffixes. Trailing C# optional parameters with concrete defaults may be omitted; viable exact-count overloads take priority. Relevant methods/types must be preserved for IL2CPP; live path declarations still require addressable path syntax. A method call is never a bare statement: write INVOKE $x.M(...); or INVOKE [STATIC:Type].M(...); (assign a result with $v = $x.M(...);, write through a path with EDIT).

Evaluates a method expression without printing its return value. Immediate calls support existing value constructors, arithmetic, nested calls and result suffixes. Trailing C# optional parameters with concrete defaults may be omitted; viable exact-count overloads take priority. Relevant methods/types must be preserved for IL2CPP; live path declarations still require addressable path syntax. A method call is never a bare statement: write INVOKE $x.M(...); or INVOKE [STATIC:Type].M(...); (assign a result with $v = $x.M(...);, write through a path with EDIT).

Where to use it

Script BLOCK / terminal

Example

INVOKE $boss.TakeDamage(5);
INVOKE $terrain.IsTillable(v3i(-3, -1, 0));
INVOKE $boss.TakeDamage($baseDamage + 2);
Read the PATHS reference →
Command · DiscoveryMETHODSFinds method signatures without invoking them. Optional NAME, COUNT and exact PARAMS filters produce a bounded immutable report in VALUE; PRINTOPT controls discovery and display.

Finds method signatures without invoking them. Optional NAME, COUNT and exact PARAMS filters produce a bounded immutable report in VALUE; PRINTOPT controls discovery and display.

Where to use it

Script BLOCK / terminal

Example

VALUE $methods = null;
METHODS IN $character NAME Move PARAMS(float, float) INTO $methods;
RECORD $methods.Text; REGISTER method_search;
Read the METHODS reference →
Command · DiscoveryCODESearches versioned C# sources for lexical reference, declaration, write, call or event-operation candidates. Optional CONTEXT and FILE filters narrow discovery; results are not semantic symbol bindings.

Searches versioned C# sources for lexical reference, declaration, write, call or event-operation candidates. Optional CONTEXT and FILE filters narrow discovery; results are not semantic symbol bindings.

Where to use it

Script BLOCK / terminal; Editor default sources, explicit provider in players

Example

VALUE $report = null;
CODE CALLS Move COUNT 2 CONTEXT PlayerController INTO $report;
RECORD $report.Text; REGISTER movement_calls;
Read the CODE reference →
Reference topic · Language referenceCODEBODYReads a matched lexical member or exact line range from the source revision captured by CODE. Changed/missing sources return explicit diagnostics.

Reads a matched lexical member or exact line range from the source revision captured by CODE. Changed/missing sources return explicit diagnostics.

Where to use it

Reference topic; report methods, not a standalone command

Example

READ $report.ReadBody(0).Text;
READ $report.ReadLines(0, 20, 35).Text;

Detailed reference

From the in-tool help for CODE.

CODE DETECTIVE / READ-ONLY SOURCE DISCOVERY
VALUE $report = null;
CODE CALLS Move CONTEXT PlayerController INTO $report;
CODE CALLS Move COUNT 2 CONTEXT PlayerController FILE Controller INTO $report;
CODE WRITES health CONTEXT BossController INTO $report;
CODE DECLARATIONS Move COUNT 2 CONTEXT PlayerController INTO $report;
CODE REFERENCES Rigidbody2D INTO $report;
CODE SUBSCRIPTIONS OnHit INTO $report;
CODE UNSUBSCRIPTIONS OnHit INTO $report;
CODE EMISSIONS OnHit COUNT 0 INTO $report;
CODE REFERENCES PlayerController IN PROJECT INTO $report;
LOG $report.Summary;
READ $report.Hits[0].File;
RECORD $report.Text; REGISTER code_report;
CODE REFRESH;

Use LOG $report.Text or RECORD $report.Text for the CODE search text. LOG/RECORD $report
uses object display under PRINTOPT and is not shorthand for its Text property.
The structured Hits/counters remain available through ordinary paths.

Bounded source extraction from an existing hit:
READ $report.ReadBody(0).Text;
READ $report.ReadLines(0, 20, 35).Text;
ReadBody selects the exact matched declaration or innermost enclosing caller member.
It does not follow a call to its callee. ReadLines uses inclusive one-based line numbers.
Both re-read the original provider on the owning thread and validate source version,
length and content fingerprint. A changed/missing source produces an unavailable report;
run CODE again. The report weakly references its provider and does not own old source text.
Malformed/ambiguous lexical body selection gives a diagnostic; raw line reads may remain
available. Fields: Available, Complete, SourceChanged, TextTruncated, Content, Text,
Diagnostic, File, SourceVersion, Kind, EnclosingMember and source line range.
Host UqlCodeBodyOptions bounds input characters, output characters and output lines.

Grammar: CODE selector name [COUNT n] [CONTEXT type] [FILE filter] [IN PROJECT] INTO $value;
Selectors: REFERENCES, DECLARATIONS, WRITES, CALLS, SUBSCRIPTIONS, UNSUBSCRIPTIONS, EMISSIONS.
Simple names need no quotes; use quotes for filters containing spaces/slashes or nested '+'
type names. Names/context/filters are literals; COUNT is literal 0..64, supported only by
CALLS/DECLARATIONS/EMISSIONS. Names match case sensitively unless ignorecase=true.
FILE is a case-insensitive relative-path substring, not a directory permission or regex.
IN PROJECT is optional and does not alter the host's configured source roots.
INTO requires an untyped writable VALUE; completion replaces its previous snapshot.
Ordinary scripts put executable CODE commands in BLOCKs; terminal commands may be top-level.

CODEOPT packages=false, ignorecase=false, contextscope=false, contextlines=1,
        maxfiles=4096, maxresults=1000, maxfilecharacters=1048576,
        maxcharacters=262144, maxsourcecharacters=16777216;
contextlines supports 0..8 lines on each side of a hit. Invalid options leave the previous
value intact and produce their own diagnostic, not errors for subsequent valid settings.
In a Conductor workspace the defaults of contextlines and the max* budgets come from the Limits
preset (code.* keys, HELP LIMITS); this group's own CODEOPT keys override them.
Options are group-level literal declarations, not per-read string interpretation.
CONTEXT with contextscope=false is the UDB-style file hint: basename or code identifiers
mention the short type name. Comments/string payloads do not qualify the file. This can
include unrelated same-name uses and can exclude genuine calls through interfaces,
inherited types, var or cross-file aliases. It is neither receiver proof nor exhaustive.
contextscope=true instead selects hits lexically enclosed by that type (qualified names
supported); it does NOT find all external callers. Omit CONTEXT for broad discovery.

Reports: Text, Summary, Source, Resolution, Available, Cancelled, Truncated, TextTruncated,
Matches, FilesVisited, FilesRead, CacheHits, Errors, StartedUtc, FinishedUtc, Hits, Diagnostics.
CoverageComplete and CoverageTruncated describe the requested lexical search, independently
of TextTruncated. Legacy Truncated remains coverage-or-text. Selection and Scope describe
the query; FilesFiltered and FilesOutsideContext disclose configured exclusions, while
DiagnosticsTruncated indicates errors not included in the bounded diagnostic list.
SourceCharacters, MaxFiles, MaxResults, MaxFileCharacters, MaxSourceCharacters, MaxCharacters,
MinimumReadCharacterBudget and MaximumReadCharacterBudget describe effective limits.
FileLimitReached, ResultLimitReached and SourceCharacterLimitReached name stopping caps.
Increase CODEOPT maxfiles/maxresults/maxfilecharacters/maxsourcecharacters for wider search;
maxcharacters widens presentation only, not discovery. Zero lexical hits are not proof of absence.
Resolution is always LexicalCandidates, NOT semantic bindings. Each hit has File, Line,
Column, SourceVersion, Kind, EnclosingType, EnclosingMember, ArgumentCount and Snippet. EnclosingMember
is a recognized method/local-function scope (empty when unknown), not a bound method symbol. Arity is syntactic;
generics/comparisons can be ambiguous. -1 means no recognized call/declaration parameter list.
Writes include initializers, assignment operators, increments, ref/out exposure and some
indexed element changes. Ref/out is possible mutation, not proof of an executed write.
Subscriptions/unsubscriptions select +=/-= candidates, which can also be numeric operators.
Emissions select direct calls or .Invoke/?.Invoke candidates, not confirmed event bindings.
CALLS excludes recognized declarations/attribute applications but can include constructors.

This is a bounded C# lexer/heuristic classifier, not a Roslyn compiler/call graph. It skips
comments, character/regular/verbatim/raw strings (including interpolation expressions),
and directive lines. Both preprocessor branches are considered; active assembly defines,
overload resolution, using-alias/type inference, escaped Unicode identifiers, reflection calls and generated code absent
from supplied sources are not resolved. No source/game code is compiled or executed.
Scope/declaration recognition is approximate. Malformed delimiters or metadata limits
produce truncated diagnostics. Zero results are never proof of absence.

Editor default reads project Assets/*.cs recursively. packages=true also permits physical
Packages and Library/PackageCache; external/linked package roots are not followed. No
AssetDatabase.Refresh, UI-repaint scan, source/config write or process launch occurs.
Players have no default provider: Available=false plus diagnostics, not an execution crash.
Hosts may set group.CodeSources (IUqlCodeSourceProvider). This is not a complete sandbox.

Queries yield token/file steps to the VM budget. STOP/ABORT/error disposes enumeration;
cancelled/unfinished queries do not replace VALUE. LastCodeReport exposes partial cancellation
to C# hosts. Source acquisition/tokenization and directory metadata calls remain synchronous
cold operations: avoid frame-critical hooks; no hard-time/zero-GC/atomic-snapshot guarantee.
Hits/reports hold immutable strings/numbers, not MonoScript, Type bindings or game objects.

Cache: per group, at most 32 documents / 2 Mi source characters plus token/scope metadata;
unchanged path/version/length reuses parsing. Accepted terminal replacement transfers the
cache; group disposal releases it. CODE REFRESH forces rereads; prior reports stay unchanged.
The filesystem version is mtime + byte length, not a content hash. Same-stamp/same-size
edits need REFRESH. Individual read version checks reject changes during disk reads.
Files may still represent different times: the report is not an atomic project snapshot.
Tokenization caps each file at 262144 tokens and 4096 type/method ranges each; directory enumeration
caps at 16384 directories. Errors counts all issues; Diagnostics retains at most 100.
Truncated is also true on source/provider errors, including an oversized or unreadable file.
The filesystem read diagnostic includes its effective character budget and CODEOPT names.
Check Available, Errors, Truncated and Cancelled before interpreting coverage. TextTruncated
limits only report text; Hits still contains collected results. Large Text may exceed the
process RECORD buffer: reduce CODEOPT limits/contextlines or use LOG instead.
Reference topic · Language referenceASSETSRead-only Editor asset GUID/local-file/session identity lookup through UqlAssetIdentities. Players without a provider return Unavailable; AssetUsages maps a published SCAN report to frozen usage/item identities.

Read-only Editor asset GUID/local-file/session identity lookup through UqlAssetIdentities. Players without a provider return Unavailable; AssetUsages maps a published SCAN report to frozen usage/item identities.

Where to use it

Reference topic; public method expressions

Example

LOG [STATIC:UQL.Runtime.UqlAssetIdentities].ByObject($sprite).Text;

Detailed reference

From the in-tool help for ASSETS.

READ-ONLY EDITOR ASSET IDENTITIES
LOG [STATIC:UQL.Runtime.UqlAssetIdentities].ByGuid("74c253e3f16be4776bb2d88e01f77c8a").Text;
LOG [STATIC:UQL.Runtime.UqlAssetIdentities].ByGuidLocal("74c253e3f16be4776bb2d88e01f77c8a", "12345").Text;
LOG [STATIC:UQL.Runtime.UqlAssetIdentities].ByObject($sprite).Text;
ByGlobalId accepts a serialized Unity GlobalObjectId string. The Editor service installs
the provider; players without an explicit provider return Status=Unavailable. Explicit
queries do not import/Refresh/mutate assets or enumerate the whole project.
Snapshot fields: Status, Guid, LocalFileId, GlobalObjectId, AssetPath, AssetType (main asset),
ObjectType, SessionInstanceId (Int64, HELP INSTANCEID), HasSessionObject, LocalFileIdVerified, Error, Text.
A GUID/local ID lookup establishes the asset path/main type only. It does not verify that
the requested subobject exists. ByObject can verify a live object's local ID; the returned
snapshot retains no Unity object. Instance IDs and [ROOT:...] are session identities;
GUID/local-file/GlobalObjectId identities are different from portable game save IDs.
Editor lookup runs on the main thread. Requery after asset moves/deletion when needed.

SELECTED ASSET USAGES (published SCAN report -> frozen usage/item relations)
BUCKET $owners; BUCKET $refs; VALUE $ownerReport = null; VALUE $refReport = null; VALUE $relations = null;
SCAN COMPONENT UnityEngine.SpriteRenderer IN SCENE INTO $owners REPORT $ownerReport;
SCAN PROPERTY sprite IN $ownerReport INTO $refs REPORT $refReport;
$relations = $refReport.AssetUsages("sprite");
LOG $relations.Summary; LOG $relations.Items[0].UsageIndexes.Count;
AssetUsages(role = "", maxUsages = 256, maxItems = 256, maxMetadataCharacters = 0,
            maxTextCharacters = 16384) is an ordinary method expression, not a keyword. The defaults stop
at 256 usages / items and 16384 text characters, so a large report ends early (StopReason says which
limit stopped it): pass larger values, e.g. AssetUsages("sprite", 4096, 4096, 0, 262144).
Limits: maxUsages/maxItems 1..4096, maxMetadataCharacters 1..4194304 or 0 (since revision 54
the default: the producing group's assetMetadataCharacters, Limits preset / LIMITOPT, default
1048576, about 1300 sprite usages at about 770 characters each; HELP LIMITS), maxTextCharacters
256..1048576; role is explicit selection metadata (<=128 characters). A metadata stop names
the limit in StopReason: '(assetMetadataCharacters=N; raise it with LIMITOPT or the Limits
preset), or pass maxMetadataCharacters (at most 4194304)', or the argument when one was passed.

Input and re-reads: AssetUsages re-reads each frozen row Path in the report's PRODUCING
group (generated session ROOT or STATIC paths only; no name/scene fallback; method or
invocation paths are refused). It samples the CURRENT value; a successful lookup does not
prove the same object was there when SCAN ran, and ordinal paths can retarget. BUCKETs are
not inputs: CLEAR/append does not change membership. DisplayValue is never identity.
Usage Read outcomes: Value, Null, Destroyed, NonUnityValue, MissingRoot, Refused, ReadError.
Classification is separate: PersistentAsset, SceneReference, Transient, Unknown, taken
from the member object's own persistence (EditorUtility.IsPersistent via the host context
provider) and its actual scene; never from the row's root. A .unity backing path or a
FoundObject status is not persistence; missing/failed context evidence is Unknown.
Items (KeyKind GuidLocalFileId) exist only for persistent objects with a verified
FoundObject identity of the same session object/type, a valid 32-hex GUID and a canonical
nonzero signed local-file ID. They deduplicate by (GUID, local ID), not by path or type;
different Sprites in one texture are different items. UsageIndexes lists every referring
usage; AssetPathVaried flags a path change during one read. Invalid identities never merge.
Coverage and budgets: UpstreamCoverageComplete is copied from the source; resolving every
path does not repair incomplete discovery. UsageCoverageComplete (the Usages flag) needs
Completion=Complete, upstream coverage and ResolutionComplete. CoverageComplete (the Items
flag) also needs ClassificationComplete (no Unknown/provider error), no Destroyed reference
and UnkeyedPersistentUsages=0, so provider gaps never publish a complete empty item set.
Usage, item, metadata and text limits are independent. A budget stop publishes
Completion=Partial with consistent links (StopReason explains it; a metadata stop may count
one read row in Attempted that is not retained); identifiers are never clipped.
Invalid input, wrong thread, a disposed/aborted/replaced group, cancellation or fatal
errors throw (InvalidInput/Unavailable/Refused/Cancelled/Error) and leave the previous
VALUE unchanged. Provider call counters include the work of such an unretained row.
Lifetime and threading: hosts must install a reader. The file workspace installs one per
activation after VALUE initializers run (only those see Unavailable; AWAKE blocks start
after installation and can call it); players and
other hosts without one get Unavailable. The call runs synchronously on the group's owner
thread; getters and providers are not preempted, and the result is not frame-perfect or
an atomic snapshot (Mode samples Play/Edit once). ROOT strings in the report are session
provenance, not a portable save ID. The report retains no Unity object, group, resolver
or provider. After a terminal resubmission or recompile, re-run SCAN ... IN $old REPORT $new.
Owner enrichment registers the row owner's GameObject as a session ROOT (OwnerGameObjectRoot).
Prefab stage (revision 54): an owner in a scene without a path asks the host once whether it
is in a preview stage. In a prefab stage OwnerInPreviewStage is true and OwnerStageAssetPath
names the prefab asset the stage edits (OwnerScenePath stays empty: a preview scene has no
path), and the usage text line shows 'owner-stage=preview prefab=Assets/.../X.prefab'. A
failed lookup keeps OwnerOutcome Enriched, says 'preview-stage lookup failed: ...' in
OwnerError and counts as an owner error.
C# hosts: new UqlAssetRelationReader(group, hostId, sessionId, activationId)
    .TryRead(report, options, out var relations, out var error);
Reference topic · Language referenceENVIRONMENTExplicit selective project/quality/graphics/pipeline/scenes/camera snapshot through UqlEnvironment.Read. Frozen fields and per-field availability; no automatic settings/asset scan or renderer creation.

Explicit selective project/quality/graphics/pipeline/scenes/camera snapshot through UqlEnvironment.Read. Frozen fields and per-field availability; no automatic settings/asset scan or renderer creation.

Where to use it

Reference topic; public method expression, Editor provider; other hosts without provider return Unavailable

Example

VALUE $env=null;
$env=[STATIC:UQL.Runtime.UqlEnvironment].Read("project,quality,pipeline");
RECORD $env.Text; REGISTER environment;

Detailed reference

From the in-tool help for ENVIRONMENT.

SELECTIVE ENVIRONMENT SNAPSHOT (PUBLIC METHOD API, NOT A STATEMENT KEYWORD)
VALUE $env=null;
$env=[STATIC:UQL.Runtime.UqlEnvironment].Read("project,quality,pipeline");
RECORD $env.Text; REGISTER environment;
READ $env.Get("pipeline.effective.kind").Value;   // keys exist only in a report that selected their section
$env=[STATIC:UQL.Runtime.UqlEnvironment].Read("graphics,scenes");
VALUE $view=null; $view=[STATIC:UQL.Runtime.UqlEnvironment].Read("camera", $camera);

Read(sections = "project,quality,pipeline", camera = null, maxFields = 256,
     maxCharacters = 32768). Sections: project, quality, graphics, pipeline, scenes,
camera; comma-separated, case-insensitive, duplicates coalesced. all requests all
six sections but does not choose a camera. Camera requires an explicit live Camera
or GameObject with an existing Camera; no main-camera fallback or added component.
A destroyed reference is camera.target [Unavailable] 'The referenced UnityEngine.Camera was
destroyed (or its native object unloaded). ...' (revision 54); find the camera again.
Only selected sections invoke provider reads. No implicit poll, import, writes or
whole asset/ProjectSettings dump. Default Editor provider runs on its owning main
thread. Other hosts may install an explicit provider; without one Status=Unavailable.

Status is Complete, Partial, Unavailable or InvalidInput. Fields contain immutable
Name, Value (invariant text), Status (Available/Unavailable/Error), Error. Get(name)
returns a field or null when absent; absent is not a successful empty value.
Context has HostId, SessionId, ProjectPath, UnityVersion, Mode, nullable Frame and
Error and Truncated. Host/session can be empty without a connected Conductor. Edit frame is
unknown. StartedUtc/CompletedUtc bound sequential sampling, not an atomic/frame-
perfect snapshot or a loaded-source attestation; use HOOK/OBSERVE for that purpose.

Pipeline default, quality-override and effective are distinct asset identities;
no asset means Built-in or no override according to that field's role, not a getter
failure. Configured build graphics APIs and active graphics device are distinct.
Quality reads show configuration, not proof an SRP uses every setting, and never
change the current level. Renderer/stack getters that can
construct renderers, package-private layouts and arbitrary setting getters are
deliberately excluded; package version is optional per-field evidence.

CoverageComplete covers only this selected known-field schema. Truncated signals
field/value/context budget loss; TextTruncated is presentation-only and retained
Fields remain available. Limits: maxFields1..4096, maxCharacters1024..1048576;
each value4096 and error1024 characters. Provider/field errors preserve other
selected results. Reports retain no Unity objects or mutable game graph.
Ids are Int64 UqlUnityIds values (HELP INSTANCEID): scenes.active-handle, scenes.sceneN.handle
and camera.instance-id. project.unity-id-source names the identity API this build reads
(InstanceID / int below Unity 6000.6, EntityId / SceneHandle from 6000.6) and
project.unity-id-verified the Unity versions it was verified against.
This API does not add an ENVIRONMENT opcode or affect normal ALIAS reads.
Command · DiscoveryEDITOR UNDOLOGRead-only bounded Unity Undo/Redo history into a VALUE: record names, the Undo History window steps and the cursor. Count optional (default 50, clamped 0..1000; a clamp is stated: RequestedCount, AppliedCount, a 'Count: requested N, applied M' Text line); names cut at 200 characters.

Read-only bounded Unity Undo/Redo history into a VALUE: record names, the Undo History window steps and the cursor. Count optional (default 50, clamped 0..1000; a clamp is stated: RequestedCount, AppliedCount, a 'Count: requested N, applied M' Text line); names cut at 200 characters.

Where to use it

Script BLOCK / terminal; Execute grant only; Editor provider (UQL Editor service); players and other hosts store Status Unavailable and continue

Example

VALUE $h = null;
EDITOR UNDOLOG 20 INTO $h;
LOG $h.Text;
Read the EDITOR reference →
Reference topic · Language referenceEDITORNamed, documented read-only Editor state commands: EDITOR <member> [count] INTO $value. Members: UNDOLOG, EDITLOG. Results are immutable reports with Status, Success, Error and Text.

Named, documented read-only Editor state commands: EDITOR <member> [count] INTO $value. Members: UNDOLOG, EDITLOG. Results are immutable reports with Status, Success, Error and Text.

Where to use it

Reference topic; command family, Editor providers

Example

VALUE $h = null;
EDITOR UNDOLOG INTO $h;

Detailed reference

From the in-tool help for EDITOR.

EDITOR READS (NAMED, READ-ONLY EDITOR STATE)
VALUE $h = null;
EDITOR UNDOLOG INTO $h;        // default 50 entries
EDITOR UNDOLOG 20 INTO $h;     // count: integer expression, clamped 0..1000 (a clamp is stated)
LOG $h.Text;                   // Undo History window view, newest first; > now marks the cursor
IF $h.Success { LOG $h.CurrentGroupName; }

Syntax: EDITOR <member> [count] INTO $value; inside a BLOCK or in the terminal. The destination is
a writable VALUE (untyped, or of the member's report type). Members: UNDOLOG, EDITLOG (UQL's own edit
history, HELP EDITLOG: Runtime-owned, no Editor provider, works in players too). An unknown member,
a missing INTO or a typed non-integer count is a source-located compile error; an untyped VALUE
that holds a non-integer at run time stores Status Error. The count bounds the Undo/Redo record
lists and the text view on each side of the cursor. A count outside 0..1000 is clamped, never
silently: RequestedCount is what the script asked for, AppliedCount what the read used, CountClamped
says they differ, and Text then has a 'Count: requested 5000, applied 1000' line.
UNDOLOG reports (UQL.Runtime.UqlUndoHistoryReport): Member, Status (Complete, Partial, Error,
Unavailable), Success, Error, CurrentGroup, CurrentGroupName, Undo (record names, oldest first;
the last is the next Undo), Redo (next Redo first), UndoCount, RedoCount, Truncated, Groups (the
Undo History window steps, oldest first; at most 1000, a longer history keeps the window around the
cursor), GroupCursor (index of the current step in Groups; later entries are redo steps; -1 when
none), GroupsStart (index of Groups[0] in the full history), GroupsTruncated, GroupCount (all
steps), GroupsError, RequestedCount, AppliedCount, CountClamped, Source, Text.
Read-only: it never performs, reverts, collapses, clears or records undo, and it is separate from
UQL-owned edit history. It reads Unity's internal Undo.GetRecords/GetUndoList on the Editor main
thread; when they are missing the report says so (Error or Partial) instead of guessing.
Without an Editor provider (players, other hosts) the read stores Status Unavailable and the
process continues: check $h.Success or $h.Status. Permission: Execute only, like SCAN and METHODS.
The legacy expression [STATIC:UQL.Editor.UqlUndoHistory].Read(20) returns the same report.
Adds no instruction to ordinary path/ALIAS reads and no per-read check. A new member is a catalog
entry in UqlEditorReads, an Editor registration and a HELP card; no new grammar.
Command · GameSCENE OPENOpens a scene as the only loaded scene and waits until it is loaded and active. Target: a path, a scene name, ACTIVE (reload), BUILD n, a handle or a Scene value. In Edit Mode it is refused while a scene it would close has unsaved changes, unless SAVE CHANGES (saves them first; needs the Edit grant) or DISCARD CHANGES (drops them and lists them; needs the Edit grant) is stated; a Prefab stage with unsaved changes always refuses. It is also refused while the UQL host object (a runtime terminal's GameObject) lives in any loaded scene, because OPEN closes every loaded scene and recreates a reopened one; a host in DontDestroyOnLoad is exempt. TIMEOUT n FRAME|SECOND bounds the wait, NOWAIT returns at once (allowed in DEFER cleanup), REPORT $r stores the UqlSceneReport. Failure logs the full report and fails the process unless REPORT is used.

Opens a scene as the only loaded scene and waits until it is loaded and active. Target: a path, a scene name, ACTIVE (reload), BUILD n, a handle or a Scene value. In Edit Mode it is refused while a scene it would close has unsaved changes, unless SAVE CHANGES (saves them first; needs the Edit grant) or DISCARD CHANGES (drops them and lists them; needs the Edit grant) is stated; a Prefab stage with unsaved changes always refuses. It is also refused while the UQL host object (a runtime terminal's GameObject) lives in any loaded scene, because OPEN closes every loaded scene and recreates a reopened one; a host in DontDestroyOnLoad is exempt. TIMEOUT n FRAME|SECOND bounds the wait, NOWAIT returns at once (allowed in DEFER cleanup), REPORT $r stores the UqlSceneReport. Failure logs the full report and fails the process unless REPORT is used.

Where to use it

Script BLOCK / terminal; Execute grant; Edit grant with SAVE CHANGES / DISCARD CHANGES; Edit Mode needs the UQL Editor service; Edit Mode: the Editor switch 'Allow interruptions' (UQL406); SAVE CHANGES / DISCARD CHANGES with dirty scenes: the Editor switch 'Allow saving / discarding changes' (UQL407, off by default)

Example

SCENE OPEN "Assets/Scenes/Level2.unity";
SCENE OPEN "Level2" SAVE CHANGES;
SCENE OPEN ACTIVE DISCARD CHANGES REPORT $r;
Read the SCENE reference →
Command · GameSCENE LOADLoads a scene additively and waits until it is loaded. A scene that is already loaded is a reported no-change. Same targets, TIMEOUT, NOWAIT and REPORT as SCENE OPEN. Play Mode loads enabled Build Settings scenes with SceneManager and any other scene asset with EditorSceneManager.LoadSceneAsyncInPlayMode (the report's Route says a player cannot load it); players load enabled Build Settings scenes only.

Loads a scene additively and waits until it is loaded. A scene that is already loaded is a reported no-change. Same targets, TIMEOUT, NOWAIT and REPORT as SCENE OPEN. Play Mode loads enabled Build Settings scenes with SceneManager and any other scene asset with EditorSceneManager.LoadSceneAsyncInPlayMode (the report's Route says a player cannot load it); players load enabled Build Settings scenes only.

Where to use it

Script BLOCK / terminal; Execute grant; Edit Mode needs the UQL Editor service; Edit Mode: the Editor switch 'Allow interruptions' (UQL406)

Example

SCENE LOAD "Arena_Lighting" TIMEOUT 600 FRAME;
SCENE LOAD BUILD 3 REPORT $r;
Read the SCENE reference →
Command · GameSCENE UNLOADUnloads a loaded scene and waits until it is gone. Refused for the last loaded scene, for the UQL host's own scene and, in Edit Mode, for a scene with unsaved changes unless SAVE CHANGES or DISCARD CHANGES is stated (Edit grant). Unloading a scene that is not loaded is a reported no-change. TIMEOUT, NOWAIT and REPORT as SCENE OPEN.

Unloads a loaded scene and waits until it is gone. Refused for the last loaded scene, for the UQL host's own scene and, in Edit Mode, for a scene with unsaved changes unless SAVE CHANGES or DISCARD CHANGES is stated (Edit grant). Unloading a scene that is not loaded is a reported no-change. TIMEOUT, NOWAIT and REPORT as SCENE OPEN.

Where to use it

Script BLOCK / terminal; Execute grant; Edit grant with SAVE CHANGES / DISCARD CHANGES; Edit Mode: the Editor switch 'Allow interruptions' (UQL406); SAVE CHANGES / DISCARD CHANGES with dirty scenes: the Editor switch 'Allow saving / discarding changes' (UQL407, off by default)

Example

SCENE UNLOAD "Arena_Lighting";
SCENE UNLOAD "ProbeScene" DISCARD CHANGES NOWAIT;
Read the SCENE reference →
Command · GameSCENE SETACTIVEMakes a loaded scene the active scene (the one new objects join) and waits for the result. The active scene again is a reported no-change. No TIMEOUT: the progress rule applies. NOWAIT and REPORT as SCENE OPEN.

Makes a loaded scene the active scene (the one new objects join) and waits for the result. The active scene again is a reported no-change. No TIMEOUT: the progress rule applies. NOWAIT and REPORT as SCENE OPEN.

Where to use it

Script BLOCK / terminal; Execute grant; Edit Mode: the Editor switch 'Allow interruptions' (UQL406)

Example

SCENE SETACTIVE "Arena_Lighting";
Read the SCENE reference →
Command · GameSCENE SAVESaves a loaded scene, or every dirty loaded scene (ALL), through EditorSceneManager.SaveScene; never through a modal helper. AS "Assets/....unity" is Save As (relative path under Assets/, existing folder, not an existing file, not Packages/). An AS clause is never ignored: an empty or blank AS path is refused, it does not fall back to a plain SAVE. A clean scene is a reported no-change; an untitled scene needs AS; SAVE ALL refuses before saving anything when a dirty scene is untitled. The file must be open for edit (version control): otherwise it is refused before any write. Edit Mode only; needs the Edit grant and, at run time, the user's Editor switch 'Allow saving / discarding changes' (UQL407, off by default; HELP CONSENT): while it is off a dirty target, ALL with dirty scenes and AS are refused and the scenes stay dirty.

Saves a loaded scene, or every dirty loaded scene (ALL), through EditorSceneManager.SaveScene; never through a modal helper. AS "Assets/....unity" is Save As (relative path under Assets/, existing folder, not an existing file, not Packages/). An AS clause is never ignored: an empty or blank AS path is refused, it does not fall back to a plain SAVE. A clean scene is a reported no-change; an untitled scene needs AS; SAVE ALL refuses before saving anything when a dirty scene is untitled. The file must be open for edit (version control): otherwise it is refused before any write. Edit Mode only; needs the Edit grant and, at run time, the user's Editor switch 'Allow saving / discarding changes' (UQL407, off by default; HELP CONSENT): while it is off a dirty target, ALL with dirty scenes and AS are refused and the scenes stay dirty.

Where to use it

Script BLOCK / terminal; Edit grant; the Editor switch 'Allow saving / discarding changes' (UQL407, off by default); Editor Edit Mode only (Play Mode refuses, players report Unavailable)

Example

SCENE SAVE ACTIVE;
SCENE SAVE ALL;
SCENE SAVE $untitled AS "Assets/Scenes/Generated.unity";
Read the SCENE reference →
Command · DiscoverySCENE LISTReads the scene state into a VALUE (UqlSceneListReport): loaded scenes with handle, path, dirty and root count, the active scene, Build Settings (index or -1 when disabled), a Prefab stage and whether it has unsaved changes, the pending operation, queued requests and still-running Unity operations (orphans). Works in every mode.

Reads the scene state into a VALUE (UqlSceneListReport): loaded scenes with handle, path, dirty and root count, the active scene, Build Settings (index or -1 when disabled), a Prefab stage and whether it has unsaved changes, the pending operation, queued requests and still-running Unity operations (orphans). Works in every mode.

Where to use it

Script BLOCK / terminal; Execute grant

Example

VALUE $s = null;
SCENE LIST INTO $s;
LOG $s.Text;
Read the SCENE reference →
Command · DeclarationsPATCHDeclares an immutable PATCH descriptor: one concrete method body, a point in it and the HOOK BLOCK the point publishes when a real game call reaches it (the original method then continues). Nothing physical happens when it is declared or compiled; APPLY PATCH installs it through the optional executor (the UQL IL Patch addon). Target: TYPE(Ns.Type).Method, with (TYPE(T1), ...) to select an overload; the method must be declared on that type and have an IL body (generic, ref / out / pointer, abstract and accessor targets are refused in this version). Point: AT ENTRY (the default), AT EXIT, AT LINE n [COLUMN c] [SOURCE "path"]; the executor states which points it serves (a refused point is a compile error). CONTEXT lets the hook BLOCK read PATCHCONTEXT. The hook BLOCK is a BLOCK of the same group without parameters. Without an executor every PATCH statement is the compile error UQL460; the declaration needs the Events grant.

Declares an immutable PATCH descriptor: one concrete method body, a point in it and the HOOK BLOCK the point publishes when a real game call reaches it (the original method then continues). Nothing physical happens when it is declared or compiled; APPLY PATCH installs it through the optional executor (the UQL IL Patch addon). Target: TYPE(Ns.Type).Method, with (TYPE(T1), ...) to select an overload; the method must be declared on that type and have an IL body (generic, ref / out / pointer, abstract and accessor targets are refused in this version). Point: AT ENTRY (the default), AT EXIT, AT LINE n [COLUMN c] [SOURCE "path"]; the executor states which points it serves (a refused point is a compile error). CONTEXT lets the hook BLOCK read PATCHCONTEXT. The hook BLOCK is a BLOCK of the same group without parameters. Without an executor every PATCH statement is the compile error UQL460; the declaration needs the Events grant.

Where to use it

Global / BLOCK scope; optional UQL IL Patch module; Events grant

Requires the relevant optional module. Check the module requirements in your installed version.

Example

PATCH $damage = TYPE(Game.Health).ApplyDamage(TYPE(System.Int32), TYPE(System.Boolean)) AT LINE 84 HOOK DamagePoint CONTEXT;
BLOCK DamagePoint { RECORD FIELDS damage=PATCHCONTEXT.damage; RECORD NEWLINE; REGISTER Hits; }
Read the PATCHING reference →
Command · GameAPPLY PATCHAsks the executor to install the point; the request never blocks the Editor. WAIT yields this process until the request succeeds, fails, is cancelled or expires (it is not a wait for a hit and never pauses the game); without WAIT the process continues and PATCHINFO shows the outcome later. APPLY of an installed point of the same declaration confirms its state (it does not re-enable a disabled point: ENABLE does). Another declaration of the same method, a changed point, HOOK or capture set, and a lease kept after a failed cleanup are refused. One LOG line on success; a failure logs the full text and fails the process. STOP, ABORT or the group's release cancels a waiting request; every APPLY leaves one PATCH run-evidence row (orphan=yes when the executor may still carry a cancelled request out).

Asks the executor to install the point; the request never blocks the Editor. WAIT yields this process until the request succeeds, fails, is cancelled or expires (it is not a wait for a hit and never pauses the game); without WAIT the process continues and PATCHINFO shows the outcome later. APPLY of an installed point of the same declaration confirms its state (it does not re-enable a disabled point: ENABLE does). Another declaration of the same method, a changed point, HOOK or capture set, and a lease kept after a failed cleanup are refused. One LOG line on success; a failure logs the full text and fails the process. STOP, ABORT or the group's release cancels a waiting request; every APPLY leaves one PATCH run-evidence row (orphan=yes when the executor may still carry a cancelled request out).

Where to use it

Script BLOCK / terminal; Events grant; the WAIT form is refused in DEFER cleanup

Requires the relevant optional module. Check the module requirements in your installed version.

Example

APPLY PATCH $damage WAIT;
PATCHINFO $damage;
Read the PATCHING reference →
Command · GameREMOVE PATCHDisables the point at once, then asks the executor to remove this declaration's interception at a safe boundary. WAIT as APPLY PATCH. A failed cleanup keeps a disabled, retained lease (PATCHINFO: retained after a failed cleanup) that blocks APPLY and ENABLE; REMOVE again to retry. Removal restores no-hook execution; it does not promise that runtime or JIT metadata is reverted.

Disables the point at once, then asks the executor to remove this declaration's interception at a safe boundary. WAIT as APPLY PATCH. A failed cleanup keeps a disabled, retained lease (PATCHINFO: retained after a failed cleanup) that blocks APPLY and ENABLE; REMOVE again to retry. Removal restores no-hook execution; it does not promise that runtime or JIT metadata is reverted.

Where to use it

Script BLOCK / terminal; Events grant; the WAIT form is refused in DEFER cleanup

Requires the relevant optional module. Check the module requirements in your installed version.

Example

REMOVE PATCH $damage WAIT;
Read the PATCHING reference →
Command · GameDISABLE PATCHStops future delivery of an installed point at once and keeps it installed (the lease). No WAIT form. Refused when this declaration has no installed point on the group's hook hub.

Stops future delivery of an installed point at once and keeps it installed (the lease). No WAIT form. Refused when this declaration has no installed point on the group's hook hub.

Where to use it

Script BLOCK / terminal; Events grant

Requires the relevant optional module. Check the module requirements in your installed version.

Example

DISABLE PATCH $damage;
Read the PATCHING reference →
Command · GameENABLE PATCHResumes delivery of an installed, disabled point at once; it never reinstalls (APPLY PATCH does). Refused for a lease retained after a failed cleanup and when nothing is installed.

Resumes delivery of an installed, disabled point at once; it never reinstalls (APPLY PATCH does). Refused for a lease retained after a failed cleanup and when nothing is installed.

Where to use it

Script BLOCK / terminal; Events grant

Requires the relevant optional module. Check the module requirements in your installed version.

Example

ENABLE PATCH $damage;
Read the PATCHING reference →
Command · DiscoveryPATCHINFOReads a PATCH's state: the declaration; this group's last APPLY / REMOVE (receipt, state, detail, error, orphan); the executor's point facts (validated, MVID, metadata token, source line, IL offset, installed, enabled); the lease (id, owner, retained after a failed cleanup, removal confirmed, last setup and cleanup errors); hit counters (hits, dispatch attempts, delivered, no receiver, refused, reentry refusals, dispatch failures). A counter the executor does not measure is -1 and printed unknown, never 0. Without INTO it logs the text; INTO stores a UqlPatchInfoReport. A successful APPLY, an installed point or a hit count does not prove that a BLOCK ran.

Reads a PATCH's state: the declaration; this group's last APPLY / REMOVE (receipt, state, detail, error, orphan); the executor's point facts (validated, MVID, metadata token, source line, IL offset, installed, enabled); the lease (id, owner, retained after a failed cleanup, removal confirmed, last setup and cleanup errors); hit counters (hits, dispatch attempts, delivered, no receiver, refused, reentry refusals, dispatch failures). A counter the executor does not measure is -1 and printed unknown, never 0. Without INTO it logs the text; INTO stores a UqlPatchInfoReport. A successful APPLY, an installed point or a hit count does not prove that a BLOCK ran.

Where to use it

Script BLOCK / terminal; Execute grant only; with no executor, or another one than at compile time, Status Unavailable and the process continues

Requires the relevant optional module. Check the module requirements in your installed version.

Example

VALUE $info = null;
PATCHINFO $damage INTO $info;
LOG $info.Text;
Read the PATCHING reference →
Command · GamePATCHCONTEXTInside a hook BLOCK named by a PATCH ... CONTEXT: the patched call that is publishing right now. THIS is the receiver (not for a static method), ARGn and the parameter names are the current argument values, POINT is the PATCH symbol's name. Typed from the declaration, so PATCHCONTEXT.THIS.health binds against the declaring type. Only what the BLOCK reads is captured, and the executor refuses a shape it cannot capture at compile time. Readable only while the call runs, in the hook BLOCK itself: after a WAIT there is no call (a WAIT EVENT that a later call of the point resumes reads that new call), nor in a BLOCK started by CALL, START or TRIGGER; copy what you need into VALUEs first. THIS, POINT and ARGn are keywords; when the method has a parameter of such a name, PATCHCONTEXT.point (any spelling but capitals) reads the parameter. The call of another declaration (another group's BLOCK with the same name) or a point installed with another capture set is refused, never read.

Inside a hook BLOCK named by a PATCH ... CONTEXT: the patched call that is publishing right now. THIS is the receiver (not for a static method), ARGn and the parameter names are the current argument values, POINT is the PATCH symbol's name. Typed from the declaration, so PATCHCONTEXT.THIS.health binds against the declaring type. Only what the BLOCK reads is captured, and the executor refuses a shape it cannot capture at compile time. Readable only while the call runs, in the hook BLOCK itself: after a WAIT there is no call (a WAIT EVENT that a later call of the point resumes reads that new call), nor in a BLOCK started by CALL, START or TRIGGER; copy what you need into VALUEs first. THIS, POINT and ARGn are keywords; when the method has a parameter of such a name, PATCHCONTEXT.point (any spelling but capitals) reads the parameter. The call of another declaration (another group's BLOCK with the same name) or a point installed with another capture set is refused, never read.

Where to use it

Hook BLOCK of a PATCH ... CONTEXT declaration; synchronous only

Requires the relevant optional module. Check the module requirements in your installed version.

Example

BLOCK DamagePoint {
    VALUE $who = PATCHCONTEXT.THIS;
    VALUE $amount: int = PATCHCONTEXT.damage;
    RECORD FIELDS point=PATCHCONTEXT.POINT, amount=$amount; RECORD NEWLINE; REGISTER Hits;
}
Read the PATCHING reference →
Command · DiscoveryKB NOTEWrites one note of your own asset knowledge to the host's knowledge store (Workspace/Knowledge/<host-id>/assets.kb): what you found out about an asset, so a later session finds it instead of re-reading code, ScriptableObjects and prefabs. Subject: an asset object (its GUID and local file id; a sub-asset such as a Sprite has its own), a 32-hex GUID, "guid:lfid", an asset path "Assets/...", an alias of an earlier note or the name of a noted asset. TEXT is required; FIELDS key = value (text, numbers, bools, enum names), TAGS and ALIAS (handles for KB FIND) are optional; REPLACES <noteId> hides the old note from KB FIND (the history keeps it). Each note records its provenance (group, request, process, revision); it is a claim, not a fact the store checks. In the Editor it also stores the fingerprint of the subject's asset file (dependency hash and main asset type), so KB FIND can tell when the asset changed since (Stale). One LOG line on success; a refusal logs the reason and fails the process; with REPORT $r a UqlKbNoteReceipt is stored and the process continues. Hosts without a channel workspace keep the notes in memory (Status Memory).

Writes one note of your own asset knowledge to the host's knowledge store (Workspace/Knowledge/<host-id>/assets.kb): what you found out about an asset, so a later session finds it instead of re-reading code, ScriptableObjects and prefabs. Subject: an asset object (its GUID and local file id; a sub-asset such as a Sprite has its own), a 32-hex GUID, "guid:lfid", an asset path "Assets/...", an alias of an earlier note or the name of a noted asset. TEXT is required; FIELDS key = value (text, numbers, bools, enum names), TAGS and ALIAS (handles for KB FIND) are optional; REPLACES <noteId> hides the old note from KB FIND (the history keeps it). Each note records its provenance (group, request, process, revision); it is a claim, not a fact the store checks. In the Editor it also stores the fingerprint of the subject's asset file (dependency hash and main asset type), so KB FIND can tell when the asset changed since (Stale). One LOG line on success; a refusal logs the reason and fails the process; with REPORT $r a UqlKbNoteReceipt is stored and the process continues. Hosts without a channel workspace keep the notes in memory (Status Memory).

Where to use it

Script BLOCK / terminal; Execute grant only (writes only the knowledge store, never game or project state)

Example

VALUE $r = null;
KB NOTE "Assets/Art/Items.png" TEXT "Sprite sheet of every item icon; cut into 64 sprites." FIELDS cells = 64 TAGS "item", "atlas" ALIAS "atlas:items" REPORT $r;
LOG $r.Text;
Read the KB reference →
Command · DiscoveryKB FINDReads notes of the knowledge store into a UqlKbReport, newest first. Conditions combine with AND: a subject or handle (an asset object or "guid:lfid" finds that object's notes and its whole asset's, a GUID every note of the asset file, an asset path the notes written with that path and the asset's GUID, any other text an alias or the recorded name), TAG t, FIELD k = v, TEXT CONTAINS s; matching ignores case. COUNT n (default 50, 0..1000) and FROM k (skip the k newest) bound the matching notes; Total counts them all. Forgotten and replaced notes are left out unless HISTORY is given (then flagged). RELATED [DEPTH n] also returns the notes of the related subjects: a texture's sprites, a sprite's texture, the assets the file uses directly and the assets that use it ("user of Items.png", from the Editor's reverse dependency index), each note with Via ("sprite of Items.png"); DEPTH 2 or 3 (default 1) walks on from the subjects the previous hop reached, Via then being the chain ("user of Items.png <- dependency of Hero.prefab"); at most 256 related subjects in the whole walk (a cut is stated). The reverse index is built on demand, a few milliseconds per Editor update: until it is ready RelationsStatus is Partial with the progress (run KB FIND again later). Every returned note is checked against its asset file: Stale (StaleReason: content changed, moved, missing asset, type changed; still returned, marked [stale: ...]), Fresh, or Unknown (no fingerprint or no asset identity). The report has Notes, Text, Filter, Relations, ReverseIndex and Status (Complete, Memory or Error); a failed FIND is stored, logged and warned, and the process continues.

Reads notes of the knowledge store into a UqlKbReport, newest first. Conditions combine with AND: a subject or handle (an asset object or "guid:lfid" finds that object's notes and its whole asset's, a GUID every note of the asset file, an asset path the notes written with that path and the asset's GUID, any other text an alias or the recorded name), TAG t, FIELD k = v, TEXT CONTAINS s; matching ignores case. COUNT n (default 50, 0..1000) and FROM k (skip the k newest) bound the matching notes; Total counts them all. Forgotten and replaced notes are left out unless HISTORY is given (then flagged). RELATED [DEPTH n] also returns the notes of the related subjects: a texture's sprites, a sprite's texture, the assets the file uses directly and the assets that use it ("user of Items.png", from the Editor's reverse dependency index), each note with Via ("sprite of Items.png"); DEPTH 2 or 3 (default 1) walks on from the subjects the previous hop reached, Via then being the chain ("user of Items.png <- dependency of Hero.prefab"); at most 256 related subjects in the whole walk (a cut is stated). The reverse index is built on demand, a few milliseconds per Editor update: until it is ready RelationsStatus is Partial with the progress (run KB FIND again later). Every returned note is checked against its asset file: Stale (StaleReason: content changed, moved, missing asset, type changed; still returned, marked [stale: ...]), Fresh, or Unknown (no fingerprint or no asset identity). The report has Notes, Text, Filter, Relations, ReverseIndex and Status (Complete, Memory or Error); a failed FIND is stored, logged and warned, and the process continues.

Where to use it

Script BLOCK / terminal; Execute grant only

Example

VALUE $k = null;
KB FIND "item:sword_03" INTO $k;
LOG $k.Text;
KB FIND TAG "weapon" FIELD tier = 2 COUNT 20 INTO $k;
KB FIND "atlas:items" RELATED INTO $k;
KB FIND "atlas:items" RELATED DEPTH 2 INTO $k;
Read the KB reference →
Command · DiscoveryKB FORGETAppends a tombstone for one note of the knowledge store: KB FIND leaves it out from then on (HISTORY still lists it as Forgotten, with the reason). Forgetting a forgotten note changes nothing (Status NoChange). One LOG line on success; an unknown note id logs the reason and fails the process.

Appends a tombstone for one note of the knowledge store: KB FIND leaves it out from then on (HISTORY still lists it as Forgotten, with the reason). Forgetting a forgotten note changes nothing (Status NoChange). One LOG line on success; an unknown note id logs the reason and fails the process.

Where to use it

Script BLOCK / terminal; Execute grant only

Example

VALUE $k = null;
KB FIND "item:sword_03" INTO $k;
IF $k.Total > 0 { KB FORGET $k.Notes[0].Id REASON "the item was removed from the game"; }
Read the KB reference →
Command · DiscoveryKB COMPACTRewrites the host's knowledge store without its forgotten and replaced notes: the NOTE lines of current notes are kept unchanged (ids, provenance, unknown keys); their tombstones, the OPEN housekeeping lines and broken lines are dropped, and lines still pending in memory are written with it. The new file is written as assets.kb.new and replaces assets.kb atomically; the previous file stays as assets.kb.1 (one generation). HISTORY no longer lists the dropped notes. One LOG line with the counts (kept, dropped, bytes before and after); with REPORT $r a UqlKbCompactReceipt (Status Compacted, Memory, NoChange or Error; Kept, Forgotten, Replaced, OtherLines, LinesBefore, LinesAfter, BytesBefore, BytesAfter, File, Backup) is stored and the process continues. NoChange when there is nothing to drop. A store that another writer changed during the rewrite, or a replace that fails, leaves assets.kb as it was (Error). A memory-only store (terminal, players) drops them in memory (Status Memory).

Rewrites the host's knowledge store without its forgotten and replaced notes: the NOTE lines of current notes are kept unchanged (ids, provenance, unknown keys); their tombstones, the OPEN housekeeping lines and broken lines are dropped, and lines still pending in memory are written with it. The new file is written as assets.kb.new and replaces assets.kb atomically; the previous file stays as assets.kb.1 (one generation). HISTORY no longer lists the dropped notes. One LOG line with the counts (kept, dropped, bytes before and after); with REPORT $r a UqlKbCompactReceipt (Status Compacted, Memory, NoChange or Error; Kept, Forgotten, Replaced, OtherLines, LinesBefore, LinesAfter, BytesBefore, BytesAfter, File, Backup) is stored and the process continues. NoChange when there is nothing to drop. A store that another writer changed during the rewrite, or a replace that fails, leaves assets.kb as it was (Error). A memory-only store (terminal, players) drops them in memory (Status Memory).

Where to use it

Script BLOCK / terminal; Execute grant only (rewrites only the knowledge store)

Example

VALUE $c = null;
KB COMPACT REPORT $c;
LOG $c.Text;
Read the KB reference →
Command · DeclarationsCSHARPDeclares a named C# function at script level, next to the BLOCKs: CSHARP Name(<C# parameters>) [RETURNS <C# type>] { <C# method body> }. The parameter list, the return type and the body are C# text, copied verbatim into one generated C# unit per group; when the group is compiled, the optional Editor-only module "UQL CSharp Load" compiles and loads that unit (without it a compile with a CSHARP declaration fails with one UQL490). A BLOCK of any source of the group calls it with CALL Name(args) [INTO $v]; and in no other way (not in expressions, SCAN/SELECT WHERE, CHECK, HOOK or PATCH targets, START or DEFER CALL). Arguments convert with the INVOKE rules and are checked against the compiled C# parameter types before activation; INTO needs a writable VALUE and a return value (without RETURNS, or with RETURNS void, the function returns nothing). C# errors are compile errors of the group at their .uql position (UQL492; warnings UQL493), and the compile result gets a CSharp: line with the assembly budget (csharpAssemblies). Needs the csharp grant (not part of execute or All). The body runs synchronously on the Editor main thread with no time limit; its scene changes are not in UQL's edit log and do not mark scenes dirty.

Declares a named C# function at script level, next to the BLOCKs: CSHARP Name(<C# parameters>) [RETURNS <C# type>] { <C# method body> }. The parameter list, the return type and the body are C# text, copied verbatim into one generated C# unit per group; when the group is compiled, the optional Editor-only module "UQL CSharp Load" compiles and loads that unit (without it a compile with a CSHARP declaration fails with one UQL490). A BLOCK of any source of the group calls it with CALL Name(args) [INTO $v]; and in no other way (not in expressions, SCAN/SELECT WHERE, CHECK, HOOK or PATCH targets, START or DEFER CALL). Arguments convert with the INVOKE rules and are checked against the compiled C# parameter types before activation; INTO needs a writable VALUE and a return value (without RETURNS, or with RETURNS void, the function returns nothing). C# errors are compile errors of the group at their .uql position (UQL492; warnings UQL493), and the compile result gets a CSharp: line with the assembly budget (csharpAssemblies). Needs the csharp grant (not part of execute or All). The body runs synchronously on the Editor main thread with no time limit; its scene changes are not in UQL's edit log and do not mark scenes dirty.

Where to use it

Script level (file-channel group; optional Editor module); csharp grant

Requires the relevant optional module. Check the module requirements in your installed version.

Example

UQLSCRIPT EnemyProbe;
CSHARP USING "System.Text";
CSHARP CountActive(string tag) RETURNS int {
    int n = 0;
    foreach (var go in GameObject.FindGameObjectsWithTag(tag))
        if (go.activeInHierarchy) n++;
    return n;
}
CSHARP Describe(Transform t, float scale) RETURNS string {
    var text = new StringBuilder();
    text.Append(t.name).Append(" @ ").Append((t.position * scale).ToString("F2"));
    return text.ToString();          // a "}" inside a string or a comment } does not end the body
}
ALIAS $player = [SCENE:Player];
BLOCK Main {
    VALUE $active = 0;
    CALL CountActive("Enemy") INTO $active;
    VALUE $text = "";
    CALL Describe($player.transform, 0.5) INTO $text;   // 0.5 is a double; it converts to float because it fits
    LOG LINE $active; LOG LINE $text;
}
Read the CSHARP FUNCTIONS reference →
Command · DeclarationsCSHARP USINGScript level: adds one C# using directive to the group's generated C# unit, written without 'using' and ';': CSHARP USING "System.Text"; (also "static UnityEngine.Mathf" or an alias "V3 = UnityEngine.Vector3"). Double or single quotes; the text must not be empty, must not contain ; { } a quote, a backslash, a line break, // or /*, and must not start with using (UQL491). Any source of the group may add lines: the group uses their union, and exact duplicates and the default usings (System, System.Collections.Generic, System.Linq, UnityEngine) are dropped. UnityEditor is not a default. A C# error in the directive is reported at the string's characters. Needs the csharp grant; a group with USING lines but no CSHARP function compiles no C#. CSHARP followed by USING never starts a function.

Script level: adds one C# using directive to the group's generated C# unit, written without 'using' and ';': CSHARP USING "System.Text"; (also "static UnityEngine.Mathf" or an alias "V3 = UnityEngine.Vector3"). Double or single quotes; the text must not be empty, must not contain ; { } a quote, a backslash, a line break, // or /*, and must not start with using (UQL491). Any source of the group may add lines: the group uses their union, and exact duplicates and the default usings (System, System.Collections.Generic, System.Linq, UnityEngine) are dropped. UnityEditor is not a default. A C# error in the directive is reported at the string's characters. Needs the csharp grant; a group with USING lines but no CSHARP function compiles no C#. CSHARP followed by USING never starts a function.

Where to use it

Script level (file-channel group; optional Editor module); csharp grant

Requires the relevant optional module. Check the module requirements in your installed version.

Example

CSHARP USING "System.Text";
CSHARP USING "UnityEditor";
CSHARP USING "V3 = UnityEngine.Vector3";
Read the CSHARP FUNCTIONS reference →
Command · OutputCAPTURERenders an explicit Camera/GameObject or independent SCENE view once and atomically publishes a PNG. Optional REPORT stores immutable file/view/time/frame metadata in a VALUE. A full Captures folder rotates: the oldest UQL captures are removed first and reported (captureArchiveFiles/captureArchiveMegabytes, HELP LIMITS). A camera render never contains screen-space overlay UI: for the screen as the player sees it use CAPTURE GAME VIEW.

Renders an explicit Camera/GameObject or independent SCENE view once and atomically publishes a PNG. Optional REPORT stores immutable file/view/time/frame metadata in a VALUE. A full Captures folder rotates: the oldest UQL captures are removed first and reported (captureArchiveFiles/captureArchiveMegabytes, HELP LIMITS). A camera render never contains screen-space overlay UI: for the screen as the player sees it use CAPTURE GAME VIEW.

Where to use it

Script BLOCK / terminal; Capture permission in Conductor

Example

VALUE $shot = null;
CAPTURE [SCENE:Main Camera].Camera INTO market_view REPORT $shot;
RECORD $shot.Text; REGISTER camera_capture;
Read the CAPTURE reference →
Command · OutputCAPTURE SCENERenders an owned temporary disabled camera from explicit world position and Euler rotation or LOOKAT target, without moving the game camera. Built-in and compatible URP Base camera support.

Renders an owned temporary disabled camera from explicit world position and Euler rotation or LOOKAT target, without moving the game camera. Built-in and compatible URP Base camera support.

Where to use it

Script BLOCK / terminal; Capture permission

Example

CAPTUREOPT width=512,height=512,ppu=32;
CAMERAOPT orthographic=true,orthographicsize=4;
VALUE $shot=null;
CAPTURE SCENE FROM p(0,0,-10) LOOKAT p(0,0,0) INTO map_view REPORT $shot;
Read the CAPTURE reference →
Command · OutputCAPTURE GAME VIEWWaits for the Game View's next composited frame (every camera, post-processing, screen-space overlay UI, OnGUI) through Unity's end-of-frame screenshot and publishes Captures/<name>.png. Asynchronous (1-2 frames in Play); Edit Mode in the Editor. A hidden Game tab is shown and put back while the user's Editor switch 'Allow interruptions' is on (the default), else refused (UQL406). Captures requested in the same frame share one rendered frame, one PNG each. Without REPORT a success prints one LOG line; a failure always logs the full report text and the process continues. The PNG has the Game view's own render size: CAPTUREOPT/CAMERAOPT do not apply (warning UQL484).

Waits for the Game View's next composited frame (every camera, post-processing, screen-space overlay UI, OnGUI) through Unity's end-of-frame screenshot and publishes Captures/<name>.png. Asynchronous (1-2 frames in Play); Edit Mode in the Editor. A hidden Game tab is shown and put back while the user's Editor switch 'Allow interruptions' is on (the default), else refused (UQL406). Captures requested in the same frame share one rendered frame, one PNG each. Without REPORT a success prints one LOG line; a failure always logs the full report text and the process continues. The PNG has the Game view's own render size: CAPTUREOPT/CAMERAOPT do not apply (warning UQL484).

Where to use it

Script BLOCK / terminal; Capture permission; not in initializers or cleanup

Example

VALUE $hud = null;
CAPTURE GAME VIEW INTO hud_check REPORT $hud;
LOG $hud.Success;
Read the CAPTURE reference →
Command · OptionsCAPTUREOPTPrepares literal output width/height/PPU. Missing dimensions derive from the borrowed camera ratio or scene16:9; explicit dimensions set the ratio. Camera overrides belong in CAMERAOPT. The width/height defaults come from the workspace Limits preset (capture.* keys, HELP LIMITS); this group's own keys override them.

Prepares literal output width/height/PPU. Missing dimensions derive from the borrowed camera ratio or scene16:9; explicit dimensions set the ratio. Camera overrides belong in CAMERAOPT. The width/height defaults come from the workspace Limits preset (capture.* keys, HELP LIMITS); this group's own keys override them.

Where to use it

Script top level / terminal

Example

CAPTUREOPT width = 1024, height = 0, ppu = 0;
Read the CAPTURE reference →
Command · OptionsCAMERAOPTPrepares explicit temporary camera overrides for both CAPTURE forms. Unspecified/null values inherit borrowed state or owned-view defaults. URP renderer and postprocessing are optional; no aspect option.

Prepares explicit temporary camera overrides for both CAPTURE forms. Unspecified/null values inherit borrowed state or owned-view defaults. URP renderer and postprocessing are optional; no aspect option.

Where to use it

Script top level / terminal

Example

CAMERAOPT orthographic=false,fieldofview=60,nearclip=0.1,farclip=1000,
          cullingmask=-1,transparent=false;
Read the CAPTURE reference →
Command · OptionsCODEOPTPrepares group-wide source query filters, snippets and budgets. contextscope=false uses a UDB-style file hint; true restricts matches to enclosing type declarations. The defaults of contextlines and the max* budgets come from the workspace Limits preset (code.* keys, HELP LIMITS); this group's own keys override them.

Prepares group-wide source query filters, snippets and budgets. contextscope=false uses a UDB-style file hint; true restricts matches to enclosing type declarations. The defaults of contextlines and the max* budgets come from the workspace Limits preset (code.* keys, HELP LIMITS); this group's own keys override them.

Where to use it

Script top level / terminal declaration

Example

CODEOPT packages = false, ignorecase = false, contextscope = false,
        contextlines = 2, maxfiles = 4096, maxresults = 1000;
Read the CODE reference →
Command · DiscoveryCODE REFRESHInvalidates this group's lexical source cache. Does not refresh Unity assets, compile C# or change prior immutable reports.

Invalidates this group's lexical source cache. Does not refresh Unity assets, compile C# or change prior immutable reports.

Where to use it

Script BLOCK / terminal

Example

CODE REFRESH;
Read the CODE reference →
Command · OptionsENABLE UNSAFEEnables native READ or WRITE permission as a group declaration. READ also enables queries and observation; WRITE is separate. The caller is responsible for a safe lifetime.

Enables native READ or WRITE permission as a group declaration. READ also enables queries and observation; WRITE is separate. The caller is responsible for a safe lifetime.

Where to use it

Script top level / terminal declaration

Example

ENABLE UNSAFE READ;
ENABLE UNSAFE WRITE;
Read the NATIVE reference →
Command · OptionsDISABLE UNSAFEDisables the group's native READ or WRITE permission. This is a declaration, not an executable toggle inside a BLOCK.

Disables the group's native READ or WRITE permission. This is a declaration, not an executable toggle inside a BLOCK.

Where to use it

Script top level / terminal declaration

Example

DISABLE UNSAFE READ;
DISABLE UNSAFE WRITE;
Read the NATIVE reference →
Command · ObservationINSPECTCreates a live display that updates in place instead of appending output on every sample. Use a separate TRACE when history is needed.

Creates a live display that updates in place instead of appending output on every sample. Use a separate TRACE when history is needed.

Where to use it

Terminal only

Example

INSPECT $boss;
INSPECT $enemies[FROM: 0 COUNT: 4].health;
Read the LIVE reference →
Command · ObservationUNINSPECTRemoves a LIVE view by ID.

Removes a LIVE view by ID.

Where to use it

Terminal host

Example

UNINSPECT 1;
Read the LIVE reference →
Command · ObservationLIVECLEARRemoves all LIVE views; TRACE records are separate.

Removes all LIVE views; TRACE records are separate.

Where to use it

Terminal host

Example

LIVECLEAR;
Read the LIVE reference →
Command · ObservationLIVEPAUSEPauses terminal LIVE sampling without pausing the game or TRACE processes.

Pauses terminal LIVE sampling without pausing the game or TRACE processes.

Where to use it

Terminal host

Example

LIVEPAUSE;
Read the LIVE reference →
Command · ObservationLIVERESUMEResumes terminal LIVE sampling.

Resumes terminal LIVE sampling.

Where to use it

Terminal host

Example

LIVERESUME;
Read the LIVE reference →
Command · TracingTRACEStarts independent per-member tracking with a copied TRACEOPT profile. Optional INTO stores a target-free typed handle in a writable VALUE; handles identify the owned trace, not a recycled numeric ID.

Starts independent per-member tracking with a copied TRACEOPT profile. Optional INTO stores a target-free typed handle in a writable VALUE; handles identify the owned trace, not a recycled numeric ID.

Where to use it

Script BLOCK / terminal

Example

VALUE $trace = null;
TRACE $boss INTO $trace;
TRACE $enemies[FROM: 0 COUNT: 4].health;
Read the TRACE reference →
Command · TracingTRACEOPTConfigures the sampling/display profile for new TRACE records. manual=true disables periodic sampling. Existing records require TRACEAPPLY. The defaults of depth/capacity/maxmembers/maxvalue come from the workspace Limits preset (trace.* keys, HELP LIMITS); this group's own keys override them.

Configures the sampling/display profile for new TRACE records. manual=true disables periodic sampling. Existing records require TRACEAPPLY. The defaults of depth/capacity/maxmembers/maxvalue come from the workspace Limits preset (trace.* keys, HELP LIMITS); this group's own keys override them.

Where to use it

Script top level / terminal declaration

Example

TRACEOPT manual = true, capacity = 64, depth = 2;
BLOCK Sample { UPDATE TRACES; }
Read the TRACE reference →
Command · TracingTRACEAPPLYApplies the current TRACEOPT profile to one TRACE or all active TRACE records.

Applies the current TRACEOPT profile to one TRACE or all active TRACE records.

Where to use it

Script BLOCK / terminal

Example

TRACEAPPLY 1;
TRACEAPPLY ALL;
Read the TRACE reference →
Command · TracingUPDATE TRACESSamples active TRACE paths at this instruction; optional literal PHASE labels the sample. Actual source/HOOK provenance is separate. Hooks do not sample automatically.

Samples active TRACE paths at this instruction; optional literal PHASE labels the sample. Actual source/HOOK provenance is separate. Hooks do not sample automatically.

Where to use it

Script BLOCK / terminal

Example

BLOCK DamageApplied { UPDATE TRACES PHASE AfterDamage; }
Read the TRACE reference →
Command · TracingUPDATE TRACESamples a validated selection of typed handles and/or positive #IDs. Duplicate targets read once; invalid/stale selectors fail before any selected getter. Optional PHASE labels author intent.

Samples a validated selection of typed handles and/or positive #IDs. Duplicate targets read once; invalid/stale selectors fail before any selected getter. Optional PHASE labels author intent.

Where to use it

Script BLOCK / terminal

Example

UPDATE TRACE $trace, #3 PHASE AfterAction;
Read the TRACE reference →
Command · TracingSTOPTRACEPermanently stops sampling while keeping history available. Create a new TRACE to restart tracking.

Permanently stops sampling while keeping history available. Create a new TRACE to restart tracking.

Where to use it

Script BLOCK / terminal

Example

STOPTRACE 1;
Read the TRACE reference →
Command · TracingTRACEPAUSEPauses the selected TRACE while preserving its history.

Pauses the selected TRACE while preserving its history.

Where to use it

Script BLOCK / terminal

Example

TRACEPAUSE 1;
Read the TRACE reference →
Command · TracingTRACERESUMEResumes a paused TRACE. Does not restart a record ended by STOPTRACE.

Resumes a paused TRACE. Does not restart a record ended by STOPTRACE.

Where to use it

Script BLOCK / terminal

Example

TRACERESUME 1;
Read the TRACE reference →
Command · TracingUNTRACERemoves a TRACE record and its history.

Removes a TRACE record and its history.

Where to use it

Script BLOCK / terminal

Example

UNTRACE 1;
Read the TRACE reference →
Command · TracingHISTORYDisplays TRACE history, not terminal command-input history.

Displays TRACE history, not terminal command-input history.

Where to use it

Script BLOCK / terminal

Example

HISTORY 1;
Read the TRACE reference →
Command · TracingCLEAR HISTORYClears the selected TRACE's history while retaining its tracking record. CLEARHISTORY is also supported.

Clears the selected TRACE's history while retaining its tracking record. CLEARHISTORY is also supported.

Where to use it

Script BLOCK / terminal

Example

CLEAR HISTORY 1;
// Equivalent: CLEARHISTORY 1;
Read the TRACE reference →
Command · TracingCLEARHISTORYEquivalent to CLEAR HISTORY: clears the selected TRACE's history.

Equivalent to CLEAR HISTORY: clears the selected TRACE's history.

Where to use it

Script BLOCK / terminal

Example

CLEARHISTORY 1;
Read the TRACE reference →
Command · DiscoveryCATALOGWithout a selector, lists group symbols and execution state. CAPABILITIES lists shared built-in documentation, current scalar context and limits; ACCEPTANCE lists qualified recorded test scopes, not current-binary attestation.

Without a selector, lists group symbols and execution state. CAPABILITIES lists shared built-in documentation, current scalar context and limits; ACCEPTANCE lists qualified recorded test scopes, not current-binary attestation.

Where to use it

Script BLOCK / terminal; explicit metadata requests only

Example

CATALOG;
CATALOG CAPABILITIES;
CATALOG ACCEPTANCE;
Read the CATALOG reference →
Command · DiscoverySYMBOLSLists group-wide declarations without reading game values.

Lists group-wide declarations without reading game values.

Where to use it

Script BLOCK / terminal

Example

SYMBOLS;
Read the CATALOG reference →
Command · DiscoverySCRIPTSLists the scripts in the compiled group.

Lists the scripts in the compiled group.

Where to use it

Script BLOCK / terminal

Example

SCRIPTS;
Read the CATALOG reference →
Command · DiscoveryBLOCKSLists BLOCK names and parameter information.

Lists BLOCK names and parameter information.

Where to use it

Script BLOCK / terminal

Example

BLOCKS;
Read the CATALOG reference →
Command · DiscoveryREGISTERSLists registry names. Use SHOWREGISTER to read their contents.

Lists registry names. Use SHOWREGISTER to read their contents.

Where to use it

Script BLOCK / terminal

Example

REGISTERS;
Read the CATALOG reference →
Command · DiscoveryTRACESLists TRACE IDs and their current states.

Lists TRACE IDs and their current states.

Where to use it

Script BLOCK / terminal

Example

TRACES;
Read the CATALOG reference →
Command · DiscoveryPROCESSESLists stable activation-local process IDs, source versions/locations, state and wait/deadline details. Completed snapshots are included only when the host opts into bounded history. Each line also shows the lineage (parent=, via=start/trigger/hook, site=, hook=), non-zero step counters (calls, writes, cleanup-writes, methods, commands, logs, warnings, triggers, started, resumed, filtered, route-failures, empty-triggers), the stop cause of a stopped process (stop=statement/abort/external/host) and, for a failed file-channel step, its failure context (failure=, op=, expression=, values=).

Lists stable activation-local process IDs, source versions/locations, state and wait/deadline details. Completed snapshots are included only when the host opts into bounded history. Each line also shows the lineage (parent=, via=start/trigger/hook, site=, hook=), non-zero step counters (calls, writes, cleanup-writes, methods, commands, logs, warnings, triggers, started, resumed, filtered, route-failures, empty-triggers), the stop cause of a stopped process (stop=statement/abort/external/host) and, for a failed file-channel step, its failure context (failure=, op=, expression=, values=).

Where to use it

Script BLOCK / terminal

Example

PROCESSES;
Read the CATALOG reference →
Command · GamePAUSESets Time.timeScale to zero. Does not pause the Editor.

Sets Time.timeScale to zero. Does not pause the Editor.

Where to use it

Script BLOCK / terminal

Example

PAUSE;
Read the GAME reference →
Command · GamePLAYRestores the positive timeScale saved before PAUSE.

Restores the positive timeScale saved before PAUSE.

Where to use it

Script BLOCK / terminal

Example

PLAY;
Read the GAME reference →
Command · GameTIMESCALEAssigns a finite, non-negative timeScale value, affecting Unity's global game time.

Assigns a finite, non-negative timeScale value, affecting Unity's global game time.

Where to use it

Script BLOCK / terminal

Example

TIMESCALE = 2;
Read the GAME reference →
Command · GamePAUSEMODEPauses Editor Play Mode.

Pauses Editor Play Mode.

Where to use it

Editor host; in Play Mode the Editor switch 'Allow interruptions' (UQL406); players report unsupported and continue

Example

PAUSEMODE;
Read the GAME reference →
Command · GamePLAYMODEResumes paused Editor Play Mode; does not start a new Play session.

Resumes paused Editor Play Mode; does not start a new Play session.

Where to use it

Editor host; in Play Mode the Editor switch 'Allow interruptions' (UQL406); players report unsupported and continue

Example

PLAYMODE;
Read the GAME reference →
Command · GameSTARTPLAYQueues entry into Editor Play Mode after the current host Tick returns. Reloading can interrupt waiting processes.

Queues entry into Editor Play Mode after the current host Tick returns. Reloading can interrupt waiting processes.

Where to use it

Editor host; the Editor switch 'Allow interruptions' (UQL406); players report unsupported and continue

Example

STARTPLAY;
Read the GAME reference →
Command · GameSTOPPLAYQueues exit from Editor Play Mode after the current host Tick returns. Reloading can interrupt waiting processes.

Queues exit from Editor Play Mode after the current host Tick returns. Reloading can interrupt waiting processes.

Where to use it

Editor host; the Editor switch 'Allow interruptions' (UQL406); players report unsupported and continue

Example

STOPPLAY;
Read the GAME reference →
Command · HelpHELPDisplays the shared documentation. Accepts a command or topic name; quote multiword names.

Displays the shared documentation. Accepts a command or topic name; quote multiword names.

Where to use it

Terminal host

Example

HELP;
HELP COMMANDS;
HELP RECORD;
HELP "WAIT EVENT";
Read the reference →
Command · HelpCLEAROUTPUTClears terminal output lines without clearing registries, TRACE records, or declarations. The terminal keeps its newest UqlTerminalOptions.OutputCapacity lines (default 512); past that its oldest row is one '<output: N earlier line(s) dropped; ...>' marker (also in CopyOutput, DroppedLines counts them), so clear before a long output such as HELP of a large topic.

Clears terminal output lines without clearing registries, TRACE records, or declarations. The terminal keeps its newest UqlTerminalOptions.OutputCapacity lines (default 512); past that its oldest row is one '<output: N earlier line(s) dropped; ...>' marker (also in CopyOutput, DroppedLines counts them), so clear before a long output such as HELP of a large topic.

Where to use it

Terminal host

Example

CLEAROUTPUT;
Read the reference →
Command · SceneSCANDiscovers live paths in scenes, a resolved root, explicit loaded catalogs, a published SCAN report's selected paths, or the captured entries of a BUCKET. A report source re-reads live values without rediscovering its catalog and preserves upstream gaps. A BUCKET source copies its entries at command start and walks each entry as its own source (SourceIndex/SourcePath = bucket index and captured path; unavailable entries are counted, never skipped). ROOTS is root-only; LOADED AS/WHERE filters root metadata, MATCH AS/WHERE filters already-read hits with scalar/enum predicates or explicit Value.SameReference identity. CHANGED/UNCHANGED/INCREASED/DECREASED IN $report narrow a prior report by re-reading each row once and comparing it with the row's frozen Observed baseline. REPORT keeps frozen evidence, never the live graph.

Discovers live paths in scenes, a resolved root, explicit loaded catalogs, a published SCAN report's selected paths, or the captured entries of a BUCKET. A report source re-reads live values without rediscovering its catalog and preserves upstream gaps. A BUCKET source copies its entries at command start and walks each entry as its own source (SourceIndex/SourcePath = bucket index and captured path; unavailable entries are counted, never skipped). ROOTS is root-only; LOADED AS/WHERE filters root metadata, MATCH AS/WHERE filters already-read hits with scalar/enum predicates or explicit Value.SameReference identity. CHANGED/UNCHANGED/INCREASED/DECREASED IN $report narrow a prior report by re-reading each row once and comparing it with the row's frozen Observed baseline. REPORT keeps frozen evidence, never the live graph.

Where to use it

Script BLOCK / terminal

Example

BUCKET $hits; VALUE $report = null;
SCAN FIELD health IN SCENE INTO $hits REPORT $report;
RECORD $report.Text; REGISTER health_scan;
BUCKET $dead; SCAN VALUE 0 IN $hits INTO $dead;  // BUCKET source: each captured health path re-read as its own source
Read the SCANNING reference →
Command · SceneSPATIALProduces frozen scene geometry, or refines a previous SPATIAL report without rereading Unity. Chain type/region and ACTIVE/LAYER/ENABLED/TRIGGER selection before NEAR/RADIUS/NEAREST in XY/XZ/XYZ, then project collider bounds/rects with SELECT. Original geometry evidence and incomplete source coverage survive refinement.

Produces frozen scene geometry, or refines a previous SPATIAL report without rereading Unity. Chain type/region and ACTIVE/LAYER/ENABLED/TRIGGER selection before NEAR/RADIUS/NEAREST in XY/XZ/XYZ, then project collider bounds/rects with SELECT. Original geometry evidence and incomplete source coverage survive refinement.

Where to use it

Script BLOCK / terminal

Example

VALUE $space = null;
SPATIAL IN SCENE CENTER v3(0, 0, 0) SIZE v3(20, 20, 4) INTO $space;
RECORD $space.Text; REGISTER nearby_geometry;
Read the SPATIAL reference →
Command · OptionsSPATIALOPTPrepares the group's literal spatial-query profile. Tile cells require tiles=true, an explicit world region and a rectangular Grid; object/component/cell/text budgets are independent. The defaults of the max* budgets come from the workspace Limits preset (spatial.* keys, HELP LIMITS); this group's own keys override them.

Prepares the group's literal spatial-query profile. Tile cells require tiles=true, an explicit world region and a rectangular Grid; object/component/cell/text budgets are independent. The defaults of the max* budgets come from the workspace Limits preset (spatial.* keys, HELP LIMITS); this group's own keys override them.

Where to use it

Script top level / terminal declaration

Example

SPATIALOPT maxvisited = 50000, maxobjects = 512, maxcomponents = 4096,
           maxcells = 1024, maxtext = 262144, children = true, inactive = true, tiles = false, preview = false;
Read the SPATIAL reference →
Command · DeclarationsSCANOPTSets the group's cold discovery profile. Literal settings at script level; normal path reads are unaffected. The defaults of depth/maxnodes/maxresults come from the workspace Limits preset (scan.* keys, HELP LIMITS); this group's own keys override them.

Sets the group's cold discovery profile. Literal settings at script level; normal path reads are unaffected. The defaults of depth/maxnodes/maxresults come from the workspace Limits preset (scan.* keys, HELP LIMITS); this group's own keys override them.

Where to use it

Script top level / terminal

Example

SCANOPT depth = 4, maxnodes = 50000, maxresults = 1000,
        collections = true, properties = false, privatefields = true,
        children = true, contains = false, ignorecase = false,
        includehidden = false, includepreview = false, assetpaths = false;
Read the SCANNING reference →
Reference topic · Language referenceSCANNINGBounded reverse-reference, member, value, component and missing-asset discovery with SCAN.

Bounded reverse-reference, member, value, component and missing-asset discovery with SCAN.

Where to use it

Reference topic; not a command

Example

HELP SCAN;

Detailed reference

From the in-tool help for SCANNING.

SCAN / COLD DISCOVERY
BUCKET $hits; VALUE $report = null;
SCAN FIELD health IN SCENE INTO $hits REPORT $report;
SCAN NAME Enemy IN SCENE INTO $hits;
SCAN COMPONENT UnityEngine.Camera IN SCENE INTO $hits;
SCAN TYPE float IN $manager INTO $hits;
SCAN VALUE 12 IN $manager INTO $hits;
SCAN GREATER 10 IN $manager INTO $hits;
SCAN LESS 0 IN $manager INTO $hits;
SCAN REFERENCE $sprite IN SCENE INTO $hits;
SCAN PROPERTY Health IN $manager INTO $hits;
SCAN OBJECTS IN SCENE INTO $hits;
SCAN NULL IN $manager INTO $hits;
SCAN DESTROYED IN SCENE INTO $hits;
SCAN DISABLED IN SCENE INTO $hits;
SCAN MISSING SCRIPT IN SCENE INTO $hits;
SCAN MISSING MATERIAL IN SCENE INTO $hits;
SCAN MISSING SPRITE IN SCENE INTO $hits;
SCAN MISSING MESH IN SCENE INTO $hits;
SCAN MISSING AUDIOCLIP IN SCENE INTO $hits;
SCAN ROOTS IN LOADED SCRIPTABLEOBJECTS INTO $hits REPORT $report;
SCAN ROOTS IN LOADED OBJECTS OF UnityEngine.Camera CONTEXT Scene INTO $hits REPORT $report;
SCAN ROOTS IN LOADED SCRIPTABLEOBJECTS CONTEXT Editor INTO $hits REPORT $report;
SCAN ROOTS IN LOADED SCRIPTABLEOBJECTS AS $root
    WHERE $root.Context == "Editor" && $root.IsPersistent == false
    INTO $hits REPORT $report;
SCAN FIELD WorkspaceRoot IN LOADED SCRIPTABLEOBJECTS INTO $hits REPORT $report;
SCAN TYPE System.Int32 IN $manager MATCH AS $hit
    WHERE $hit.MemberKind == "FIELD" && $hit.MemberName.StartsWith("health")
    INTO $hits REPORT $report;
SCAN CHANGED IN $report INTO $changed REPORT $next;

IN accepts SCENE, a live reference expression, [STATIC:Type], LOADED OBJECTS or
LOADED SCRIPTABLEOBJECTS. LOADED may be followed by OF a compile-time UnityEngine.Object
subtype (a ScriptableObject subtype for SCRIPTABLEOBJECTS); derived types match.
After optional OF, CONTEXT Scene|LoadedAsset|Editor|Unknown narrows only candidate
roots before opening members. The value is one case-insensitive compile-time literal,
optionally quoted. Different-context descendants of accepted roots remain reachable.
Editor means proven EditorWindow/UnityEditor.Editor, not all hidden configuration
objects; those may correctly be Unknown. LoadedAsset requires persistence evidence.
Without a context provider, Editor/LoadedAsset queries fail before catalog acquisition
with a short process diagnostic, preserving the old BUCKET/report destination.
Scene/Unknown remain usable. Context errors still count as read gaps, not harmless
policy exclusions. CONTEXT is command-local, not a SCANOPT or WHERE predicate.
After optional OF/CONTEXT, AS $root WHERE predicate filters loaded source roots
before traversal. $root is frozen scalar metadata, NOT the game object: RootName,
RootTypeName, RootInstanceId, HideFlags, Context, SceneName, ScenePath, SceneHandle,
SceneLoaded, IsPersistent, IsPreview, AssetPath, ContextError and EditorHost.
RootInstanceId and SceneHandle are Int64 Unity session ids (HELP INSTANCEID).
No Root/Path/member/value fields are available before traversal. Metadata strings
are the stored bounded snapshots, not full live-name/asset-path comparisons.
The predicate supports literals, metadata members, bare outer VALUE/parameter
symbols, scalar comparisons/arithmetic and symbolic && / || / ! (short-circuit).
Outer VALUE operands are sampled once at SCAN start; subsequent writes do not
change that running query. Live paths, ALIAS/PATH/BUCKET operands, captured path
wrappers, general methods, constructors, selectors and arbitrary getters are not predicates.
Nullable metadata needs explicit null/true/false tests; guard nullable arithmetic.
Equality between object references is identity, never user Equals. String equality
is case-sensitive. OF checks assignability; RootTypeName equality checks exact text.
Query ==, !=, <, <=, >, >= compare integral/decimal pairs exactly when UInt64 or
decimal is involved. UInt64/decimal with float/double is rejected, not rounded;
prepare a common numeric domain outside the predicate if needed. This changes no
metadata allowance, general expression comparisons, arithmetic/unary operations or
existing supported integer/float/double behavior. SELECT WHERE shares this rule.
Pure text tests use these exact one-argument spellings in this WHERE scope:
  $root.RootName.StartsWith("Enemy")
  $root.RootTypeName.Contains($needle)
  $root.RootName.EndsWith("_Data")
They compile to direct ordinal, case-sensitive text comparisons, not reflection
or gameplay method calls. Receivers/needles use the same pure operands above, with
safe concatenation of two strings permitted (no number or object joins here, unlike an
ordinary expression's '+': HELP VALUES). Other methods, overloads, coercion/ToString and
StringComparison arguments are rejected. Outside SCAN WHERE, normal method/path
expression rules are unchanged; no global intrinsic or new VM instruction exists.
Both operands must be nonnull strings of at most 4096 UTF-16 characters; an empty
needle matches a valid receiver. Guard nullable text explicitly with != null &&.
Null/wrong-type/oversized runtime operands are predicate errors, never false;
unreached Boolean branches are not evaluated. Oversized text literals are compile
diagnostics. Needles are never silently clipped; metadata text is already bounded.
String concatenation is bounded at 4096 characters; plans have 256 nodes/depth below 64.
An oversized operand or concatenation error names its actual length, for example
'... at most 4096 UTF-16 characters per operand (this operand has 18233).'
False predicates are policy exclusions; predicate failures count as read gaps and
lower coverage (NOT cannot turn an error into a match). Each bounded predicate is
evaluated synchronously for a candidate, not interrupted halfway by VM scheduling.
The initial AS $root WHERE scope remains LOADED source metadata only. Preparing
invalid VALUE operands fails before catalog acquisition and preserves the previous
BUCKET/report.

After the source/root filter, optional TRAVERSE AS $node WHERE predicate controls
whether an already-read nonterminal node is expanded. It accepts the same bounded
metadata as MATCH (Path/Root/MemberName/MemberKind/DeclaredTypeName/RuntimeTypeName
and root metadata), but never Value, Depth, SameReference or gameplay paths/calls.
Use it before MATCH/INTO; all clause metadata names must be distinct:
  SCAN TYPE System.Object IN $manager
      TRAVERSE AS $node WHERE $node.MemberName != "largeCache"
          && !$node.RuntimeTypeName.StartsWith("ThirdParty.")
      MATCH AS $hit WHERE $hit.MemberKind == "FIELD"
      INTO $hits REPORT $report;
The current node is selected/MATCH-tested before the guard. False keeps its match
but leaves its interior unopened: PolicyPruned is selected-policy exclusion, not
a read gap. Guard errors close that branch and lower coverage. True never bypasses
native/depth/cycle guards or SCANOPT opt-ins. ROOTS, scalar/null/dead nodes and
direct-scope leaves are already terminal and do not evaluate TRAVERSE. Incoming
getters and root/context metadata were already read; this is not a getter sandbox.
Other selector/collection/native/depth/cycle expansion checks follow the guard;
a guard may therefore run even when a later check would leave that node unopened.
PolicyPruned counts guard denials, not avoided getter/enumerator calls. SCENE and
LOADED catalog roots are independent: pruning one path is not a global blacklist
of that object when it is also selected through another source/path.
CoverageComplete describes only the selected policy, not absence in pruned branches.
Outer raw VALUE inputs are sampled once at command start; normal paths/instructions
are unchanged. Depth is intentionally not a predicate operand: legacy recursive
GameObject->Component traversal is not a uniform edge-distance metric.

After the source/root/TRAVERSE clauses and before INTO, MATCH AS $hit WHERE predicate filters
the match selector's candidate paths. It supports every current source, not only
LOADED; the synthetic $hit symbol exists only inside that predicate, not as a
VALUE, path or exported alias. Supported metadata is Path, Root, MemberName,
MemberKind, DeclaredTypeName, RuntimeTypeName and the root metadata listed above.
Index and DisplayValue are deliberately unavailable. Root and hit names
must be distinct, and each predicate may read only its own synthetic metadata.
The same pure literal/VALUE/scalar/Boolean/text rules and operand limits apply.
For example:
  SCAN TYPE System.Int32 IN $manager MATCH AS $hit
      WHERE $hit.MemberKind == "FIELD" && $hit.MemberName.StartsWith("health")
      INTO $hits REPORT $report;
  SCAN FIELD WorkspaceRoot IN LOADED SCRIPTABLEOBJECTS AS $root
      WHERE $root.Context == "Editor"
      MATCH AS $hit WHERE $hit.DeclaredTypeName == "System.String"
      INTO $hits REPORT $report;
MATCH runs after the field/property/element value has already been read, before
display formatting, capture and publication. It does NOT prevent getter reads or
prune ancestors: a rejected parent can still contain an accepted descendant.
MaxNodes charges rejected candidates too; MaxResults counts accepted paths only.
False is an exclusion; a reached predicate error is an explicit coverage gap,
not false (including under !). Outer VALUE inputs are sampled once at command
start, and all predicate sessions release their inputs on finish/cancel/error.
Within MATCH only, the exact $hit.Value operand accesses the already-read candidate
without another path/getter read. It permits actual CLR null, string, Boolean,
character, the eight primitive integral types, float/double/decimal and actual enums.
Other references, captured paths, types, native values, common/custom structs,
DateTime/Guid/TimeSpan/IntPtr and destroyed Unity wrappers are unsupported: a reached
Value operand produces a predicate error, not false or a Unity-null coercion.
Use RuntimeTypeName rather than DeclaredTypeName to guard polymorphic fields:
  SCAN TYPE System.Object IN $manager MATCH AS $hit
      WHERE $hit.RuntimeTypeName == "System.Int32" && $hit.Value > 0
      INTO $hits REPORT $report;
  SCAN TYPE System.String IN $manager MATCH AS $hit
      WHERE $hit.Value != null && $hit.Value.Contains("quest")
      INTO $hits REPORT $report;
Metadata/Boolean short-circuiting can skip unsupported Value reads. Candidate values
are observed when traversal reads each hit; outer VALUE inputs still sample once
at command start. These are different sampling points, not an atomic graph snapshot.
Value exists only in this predicate (MATCH Value stays transient): it is not kept as a
live value in ScanRow/REPORT, exposed in root WHERE or exported as a path/slot. An
accepted row separately carries Observed, a bounded frozen scalar cell (see CANDIDATE
REFINEMENT below); it is never the candidate object. Further .Value members, indices, coercions or
gameplay methods are rejected; only pure one-argument text predicates above,
raw enum HasAny/HasAll and the explicit SameReference operation below are calls.
Strings are compared as actual untruncated values; text operations
retain the nonnull/4096-character operand limits. Raw enum equality retains its
type-aware enum semantics, without numeric/descriptor conversion. The exact UInt64/decimal comparison rule above applies;
arithmetic/unary and existing integral/float/double behavior are unchanged (this
is not new decimal arithmetic or a universal mixed-domain exactness guarantee).
For explicit reference identity, use the separate MATCH-only operation:
  VALUE $target = null; // assign the wanted reference before SCAN
  SCAN TYPE System.Object IN $manager MATCH AS $hit
      WHERE $hit.Value.SameReference($target)
      INTO $hits REPORT $report;
SameReference accepts the exact $hit.Value receiver and one raw outer VALUE target
or literal null. It compares the already-read candidate using CLR ReferenceEquals,
not a reflected gameplay method, Equals override or Unity's destroyed-object ==.
Non-null value-type candidates are false exclusions, not read errors. A destroyed
Unity wrapper is a reference: identical destroyed wrappers match; real null does
not match one. String VALUE targets use reference identity, not content equality.
Targets sample once at command start. Non-null boxed value-type targets, paths and
BUCKETs are rejected before traversal/publication even in a short-circuited branch;
known invalid target types diagnose at compile time. ALIAS/PATH/getter/metadata
arguments and further selectors are not accepted; prepare a raw VALUE first.
($hit.Value).SameReference($target), !, && and || retain the same pure semantics.
Only this explicit operation permits reference candidates; ordinary scalar .Value
comparisons retain their allowlist. Targets/candidates are not retained in report
rows, and session targets are released on finish/cancel/failure. Existing
SCAN REFERENCE remains available for a single identity selector. Neither form
prunes branches or makes cooperative sampling atomic/frame-perfect.
Generalized traversal pruning, custom struct equality and query joins remain
outside this slice.
SCAN WHERE/MATCH lowers exactly one-argument HasAny(mask)/HasAll(mask) to pure
enum membership nodes, not reflection or Enum.HasFlag/gameplay dispatch:
  VALUE $mask = [STATIC:UnityEngine.HideFlags].HideInHierarchy;
  SCAN TYPE UnityEngine.HideFlags IN $manager MATCH AS $hit
      WHERE $hit.Value != null && $hit.Value.HasAny($mask)
      INTO $hits REPORT $report;
Prepare masks as raw enum VALUEs or BLOCK parameters before the command. Receiver
and mask must be nonnull actual enums of the SAME concrete enum type; integer/text
masks, frozen descriptors/cells, references and custom conversions are rejected.
Known invalid types or mismatched concrete enum declarations produce compile
diagnostics; reached dynamic null/wrong-type/mismatch is a predicate error, not
false (including under !). &&/|| metadata guards may skip unsupported branches.
All eight enum underlying widths are exact, including signed negatives and UInt64.
HasAny means at least one common bit; HasAll means every mask bit. Zero mask gives
false/true respectively; [Flags] is not required. !HasAny tests no common bits.
No bitwise expression grammar or global intrinsic is added. SELECT retains its
separate actual/frozen-descriptor membership contract. Outer enum VALUE operands
still sample once at command entry; MATCH reads its already-observed candidate,
not another getter. Reports retain no candidate or mask object. These nodes use
the existing 256-node/depth budgets and predicate coverage/cancellation contracts.
Root WHERE can use prepared raw enum VALUEs but does not expose the root object
or .Value: its HideFlags metadata remains a string, not an enum operand. Use MATCH
to test enum fields. Ordinary path execution/16-byte instructions are unchanged.
SCAN can also consume a published, non-cancelled SCAN report directly:
  BUCKET $details; VALUE $detailReport = null;
  SCAN FIELD health IN $report MATCH AS $hit WHERE $hit.Value > 0
      INTO $details REPORT $detailReport;
This takes ONLY the prior report's frozen Path membership, re-reads each path
using the current execution group's session ROOT registry, then scans from that
original anchored location. It does not enumerate the report's CLR fields, repeat
the scene/loaded catalog search, or read the original result BUCKET. SELECT
$report.Rows remains frozen-evidence filtering; SCAN IN $report is live re-evaluation.
Partial published reports are valid sources, but their inherited coverage gap
survives even an empty downstream result. Pending/cancelled/unpublished reports
are rejected before candidate reads and preserve the previous destination/report.
Root evidence and membership are frozen from the prior scan; values/member runtime
types and command timestamps are new observations. SourceIndex/SourcePath on each
derived row identify its immediate input row, not a stable entity or dictionary key.
Duplicate membership is preserved. Depth starts at each selected path, so explicit
scalar/null/struct member paths work without registering boxed values as ROOTs.
Standalone SCAN scalar-root restrictions are unchanged. ROOTS still excludes
real null/destroyed values; NULL/DESTROYED may select successfully read such fields.
A selected [INDEX] element is typed by its runtime type (System.Object when null), as
the walk types collection elements, so TYPE re-selects the same element rows.
The source report carries no live resolver/owner references. Foreign/expired ROOTs,
invalid paths, forbidden method-bearing captures and failed reads are explicit
errors/unavailable candidates, never scene/name fallback or false exclusions.
Existing getters on selected paths remain explicit synchronous reads; native
paths use current explicit grants and guards, while broad native layout traversal
remains skipped. Reports do not grant access or guarantee lifetime/safety.
Node/result limits apply across every path and descendant; failure/STOP releases
path plans/frames and preserves atomic BUCKET publication. BUCKET results append;
using the source report's VALUE as REPORT destination is safe because replacement
occurs only after successful publication. Collection [INDEX:n] paths can retarget
after reordering. No join, generation identity, deduplication or pruning is implied.
BUCKET ENTRY SOURCES - SCAN ... IN $bucket walks the captured entries (revision 49):
  COLLECT COMPONENTS $go INTO $parts;
  SCAN FIELD health IN $parts INTO $hits REPORT $healthReport;
  SCAN VALUE 0 IN $hits INTO $dead REPORT $deadReport;   // re-reads each captured field
The BUCKET's entry membership is copied at command start: later ADD/REMOVE/CLEAR, or
this scan's own results appended to the same BUCKET, do not change this scan. Each
entry is resolved once and walked as its own source, depth starting at the entry
(depth 0 = the entry node itself). An entry captured as a generated session ROOT or
[STATIC:T] path with only [FIELD]/[PROPERTY]/[INDEX] steps (SCAN, COLLECT and
PathParents output) is re-read in place like a report row: struct and scalar entries
work and result paths start with the entry's own path. Any other entry (a script
capture such as ADD $player.Target TO $b) resolves through its capture; a live
reference is then walked as its own generated ROOT (results start with that ROOT),
while a value-type or string entry needs an anchored path and is unavailable.
Rows carry SourceIndex = the bucket index and SourcePath = the entry's captured path
text. An anchored entry that reads null or a destroyed object is the entry node itself,
as for a report row: NULL/DESTROYED match there, ROOTS excludes it and it has no
interior, so the BUCKET and report routes agree and coverage stays complete. A bare
ROOT entry (COLLECT output) whose object is gone fails to resolve, also when it was
destroyed between its read and its walk; an entry with steps destroyed then is walked
as a destroyed entry node. Unanchored null/destroyed/value-type/string, method-bearing
and failed entries count in UnavailableCandidates with one reason line each in
Exclusions (at most 32; Text lists them); failed reads and refusals (including a
destroyed or expired ROOT) also count in Errors with an ERROR line, so
CoverageComplete is false.
The bucket object itself is never registered or walked; ROOTS IN $bucket selects each
live entry and duplicate entries are walked once per entry. An anchored entry node is
named by its path's last selector (FIELD/PROPERTY name; an [INDEX] keeps its
collection's name), which TRAVERSE and MATCH see, and an [INDEX] entry is typed by its
runtime type (System.Object when null), as the walk types collection elements. An
unanchored entry walked as its own ROOT is an unnamed root node (MemberName/MemberKind
empty). UNITYPROPERTY/UNITYELEMENT labels are not recovered from path text, so
MISSING MATERIAL/SPRITE/MESH/AUDIOCLIP do not match at the entry node itself (scan its
owner instead). Ordinal [INDEX:n] entries can retarget after reordering.
HasBucketSource, SourceCandidates (entry count), CandidatesVisited and EligibleRoots
describe the source; no upstream coverage is carried.
CANDIDATE REFINEMENT - narrow a candidate set by an unknown value's change:
  SCAN TYPE System.Int32 IN $player MATCH AS $h WHERE $h.MemberKind != ""
      INTO $hits REPORT $g0;                       // candidates with frozen baselines
  // ...change the game (pick up an item, take damage)...
  SCAN CHANGED IN $g0 INTO $changed REPORT $g1;    // unknown value: which ones moved?
  SCAN UNCHANGED IN $g1 INTO $stable REPORT $g2;   // after a no-op: drop the noise
  SCAN DECREASED IN $g2 INTO $down REPORT $g3;     // direction check
CHANGED, UNCHANGED, INCREASED and DECREASED take no operand and accept only IN $report:
a published, non-cancelled SCAN report. Another, pending or cancelled source fails
before any read and the previous BUCKET/REPORT stay. SCENE, LOADED and TRAVERSE are
compile errors (UQL450); MATCH AS $hit WHERE and REPORT work as usual.
Baselines: every accepted SCAN row (any selector, after MATCH and the result cap)
carries Observed, a bounded frozen cell for null, primitives, bool, char, enums, the
OBSERVE Unity numeric structs (Vector2/3/4, Vector2Int/3Int, Quaternion, Color, Color32,
Rect, RectInt, Bounds, BoundsInt, Matrix4x4, LayerMask) and strings up to 256 characters
(longer: Status Truncated). References, STATIC scopes and other structs (Unity.Mathematics,
DateTime/Guid/TimeSpan, custom) get Observed = null: no identity token, no allocation.
MATCH Value stays transient; Observed is a separate frozen cell, never the live object.
Comparison: each source row's own Path is re-read once (no traversal; depth, direct and
children are ignored; one maxnodes unit per row), frozen with the same bound and compared
with that row's Observed baseline by the OBSERVE comparison rules: equality for
CHANGED/UNCHANGED, numeric order for INCREASED/DECREASED. A selected row keeps Path, Root,
SourceIndex/SourcePath and gets Previous = the source row's baseline cell (the same
instance) and Observed = the fresh cell. MATCH then sees the fresh value as $hit.Value.
Outcomes: a conclusive non-match -> ComparisonExcluded. INCREASED/DECREASED on a
conclusive pair without numeric order (text, bool, enum, struct, null) -> excluded and
counted in ComparisonNotOrderable, not a coverage gap. A missing baseline (reference,
unsupported or legacy row, a PathParents parent), a Truncated/Unsupported/Destroyed cell,
NaN/Infinity or a mixed exact/floating domain -> ComparisonInconclusive plus an ERROR line
(Errors, CoverageComplete false). A failed re-read -> UnavailableCandidates, never UNCHANGED.
A null -> reference transition answers CHANGED: the fresh value is frozen with an
observation token, so that row's Observed holds a reference-token cell.
Generations: the REPORT is the next baseline generation; the source report never changes.
Reusing the same VALUE (SCAN CHANGED IN $g INTO $hits REPORT $g;) gives a rolling baseline
that is replaced only after successful publication; STOP/failure keeps the previous report
and BUCKET. Reusing an older report branches from that generation. SourceStartedUtc,
SourceFinishedUtc, SourceStartFrame and SourceEndFrame record the baseline window next to
StartedUtc..EndFrame; the cooperative re-read is not an atomic snapshot.
Identity is the frozen route (session ROOT plus member path), not an entity: [INDEX:n]
can retarget after reordering, so re-validate with MATCH on an id field when it matters.
SCAN skips native containers (NativeArray/NativeList), so their elements are never
candidates (a non-goal); scan managed System.Int32/System.Single fields instead.
TRACE records the history of known paths (512 members, display text, no BUCKET);
refinement narrows a candidate set and returns live BUCKET paths. SCAN VALUE/GREATER/LESS
IN $report remains the way to narrow by a known value.
PATH PARENTS - open the record that holds a hit:
Known collection: use SELECT; it reads typed columns in one pass, for example
  SELECT $inventory.Entries AS $e INDEX $i FIELDS item = $e.Item
      WHERE $e.StackSize == 1 INTO $rows;
Unknown location: SCAN, then $report.PathParents(levels), then SCAN ... IN the parents:
  SCAN VALUE 1 IN $inventory MATCH AS $h WHERE $h.MemberName == "StackSize"
      INTO $hits REPORT $found;
  $parents = $found.PathParents(1);   // ...[FIELD:"Entries"][INDEX:2]
  SCAN FIELD Item IN $parents INTO $items REPORT $itemReport;
PathParents(levels = 1, at most 64) is a pure method of a published, non-cancelled
report. It removes the last levels [FIELD]/[PROPERTY]/[INDEX] selector steps of each
anchored row Path: N selector steps up the path, not a Transform/GameObject owner. It
reads no value and calls no Unity API. Identical parent paths merge ordinally; the first
contributor wins and SourceIndex/SourcePath name it (merged rows = SourceCandidates -
Matches - ParentlessRows). A row with fewer steps, another selector or no generated
ROOT/STATIC anchor counts in ParentlessRows and UnavailableCandidates (CoverageComplete
false); it is never clamped to the root. Stripping one [INDEX] keeps the collection's
MemberName and UNITYPROPERTY/UNITYELEMENT kind. Other lifts label a Unity-safe property
PROPERTY and its elements INDEX, so MISSING MATERIAL/SPRITE/MESH/AUDIOCLIP do not match
at such a parent or its direct elements although coverage reads complete:
run the MISSING scan from the owner, or lift exactly one [INDEX]. A generic or array
[STATIC:"T"] anchor (its quoted name contains ']') lifts like any STATIC anchor.
Root evidence, upstream coverage, the producing group and the source's UTC/frames are
copied; DisplayValue/types are empty.
Reference searches: add $h.MemberKind != "" to MATCH. A target walked as its own ROOT
(the component itself, zero selectors) is otherwise a parentless self-hit:
  SCAN TYPE System.Object IN SCENE MATCH AS $h
      WHERE $h.MemberKind != "" && $h.Value.SameReference($enemy)
      INTO $hits REPORT $refs;
Overlapping (nested) parents and retargeted [INDEX:n] parents are not collapsed or
re-validated: re-validate with MATCH on an id field. SCAN skips native containers
(NativeArray/NativeList), so their records never reach PathParents. The next SCAN
returns one row per selected field, not a record table. Invalid levels or a pending
report throw: the process faults, the rest of the BLOCK does not run and the destination
VALUE keeps its previous value.
ROOTS selects only each supplied root/candidate without opening members. OBJECTS
keeps its GameObject-only match meaning. Loaded catalogs contain objects already in
memory, not every project asset; they do not import/load assets or refresh Unity.
A value-type root
is rejected; nested structs are supported. COMPONENT/TYPE names are compile-time
type names (quoted names also work). FIELD/PROPERTY/NAME accept bare names, strings,
or dynamic text expressions. Name matching is exact and case-sensitive by default.
TYPE tests assignability against the visited declared field/property type; collection
elements use their runtime type. COMPONENT tests the live component's runtime type.
VALUE uses scalar/enum/common-value equality; GREATER/LESS compare numeric values.
Floating-point operands use double comparison without an epsilon; NaN never matches.
Other numeric operands compare as decimal. Tuple/custom struct fields are traversed,
not compared with arbitrary user-defined Equals implementations.
REFERENCE compares managed reference identity, not Equals. NULL excludes destroyed
Unity objects; DESTROYED finds their remaining field/collection references.

SCANOPT depth=3, direct=false, maxnodes=50000, maxresults=1000, collections=true,
        properties=false, privatefields=true, children=true,
        contains=false, ignorecase=false,
        includehidden=false, includepreview=false, assetpaths=false;
Depth is 0..32; maxnodes 1..1000000; maxresults 1..10000. Last option wins across
sources in compilation order (a UQL213 warning names both values when they differ).
Terminal settings persist across submissions. In a Conductor workspace the defaults of
depth/maxnodes/maxresults come from the Limits preset (scan.* keys, HELP LIMITS).
Depth=0 tests only the supplied root(s), before any field/property, component,
collection-item or child expansion. IN SCENE tests each scene GameObject itself at
depth=0; it does not inspect its components. Use depth=1 or greater for contents.
For example, SCAN FIELD health IN $manager needs depth>=1 even for a direct field.
Set direct=true to inspect each selected source plus at most one outgoing edge:
its immediate fields/properties, collection values, components or child objects.
Direct members still run MATCH, but their interiors are deliberately not opened.
GameObject -> Component is one edge in this mode: use the component as an explicit
source to inspect its fields. SCENE still supplies every scene GameObject as a
source; direct does not narrow that catalog. Report-source rows each begin a new
relative scope without losing their original paths or upstream coverage.
Depth=0 and ROOTS remain narrower root-only queries. direct=false preserves the
existing recursive depth convention. Policy leaves are not depth/native/cycle
gaps; CoverageComplete describes the declared scope, never global absence.
  SCANOPT direct=true, properties=false;
  SCAN FIELD health IN $manager INTO $hits REPORT $report;
Nested fields/getters/enumerators are not entered, but root getter/enumerator
failures and native-source refusal retain their existing error/coverage rules.
Properties opt-in runs user getters; property-name scans also need this opt-in.
Static fields may run type initializers. Hidden base members with the same name are
represented only by the most-derived field/property to keep paths unambiguous.
The three new options apply only to explicit LOADED candidate selection. Nonzero
HideFlags candidates are excluded by default; includehidden=true includes them.
This filters candidate roots, not every reference reached through their fields.
includepreview controls known Editor preview-scene candidates. assetpaths enables
optional Editor persistent-asset path lookup; it never loads an asset. Hidden flags,
type namespaces and a nonempty asset path do not by themselves prove ownership.
Runtime uses scene evidence first, then an optional Editor context provider, otherwise
Unknown. EditorHost describes the host, not an object's owner. No permission changes
or automatic access grant are caused by discovery.
Known engine asset getters are separately allowed: sharedMaterials, sprite, sharedMesh,
clip, shader/mainTexture and UI Image/RawImage references. Renderer.material and
MeshFilter.mesh are never used to avoid instantiating copies. Engine-private fields
and arbitrary engine properties are not scanned. Missing asset means null/destroyed
in these slots, not proof of a broken serialized GUID. MISSING SCRIPT returns the owner
GameObject per missing component slot. Empty material arrays have no missing slots.

Each scan appends to the bucket. CLEAR $hits; before scanning to replace results.
Results stay live paths, not object/value snapshots. Duplicate incoming paths are kept;
cycles stop only on the current ancestry. Dictionary scans select values by INDEX,
not keys. Collection reordering can change targets. Component roots use exact session
identity even when names/types repeat. Roots expire after destroy/session reset.

REPORT / OPTIONAL SCAN METADATA (also available through HELP REPORT)
Neither REPORT nor $report.Text is required. REPORT is a suffix of SCAN, not a
standalone command, RECORD buffer, or registry. INTO $hits remains required.

Without a report variable:
  BUCKET $hits;
  SCAN FIELD health IN SCENE INTO $hits;
  ITERATE $hits AS $hit { LOG LINE $hit; }

With metadata (declare VALUE at script level, put executable lines inside a BLOCK;
in the terminal these lines may run directly):
  VALUE $report = null;
  SCAN FIELD health IN SCENE INTO $hits REPORT $report;
  LOG LINE $report.Summary;
  LOG LINE $report.Matches;
  IF ($report.Truncated) { LOG LINE "Partial scan: check limits."; }
  LOG LINE FIELDS startFrame = $report.StartFrame, endFrame = $report.EndFrame;
READ is terminal-only: in a script BLOCK a READ line is skipped with UQL201, so these
recipes use LOG LINE; in the terminal READ $report.StartFrame; displays the same value.

The destination must be an untyped writable VALUE, such as VALUE $report = null.
The variable name is your choice. These are read-only report properties:
  Text         (string): detailed dump: owner labels, session paths, observed values,
                         errors, options and start/end timing. Not a live view.
  Summary      (string): compact counters and completion/publication flags.
  Selection / Target / Scope (string): bounded labels for requested query/root/scope.
  Rows         (immutable list): frozen hit metadata (no live object) and upstream query coverage.
                 Path is the matched live path; Root is its session ROOT prefix;
                 RootName/RootTypeName/RootInstanceId/HideFlags identify the root;
                 Context, SceneName/ScenePath, AssetPath, EditorHost describe known
                 evidence; MemberName/MemberKind, DeclaredTypeName/RuntimeTypeName
                 and DisplayValue describe the match. These are not refreshed values.
                 RootInstanceId/SceneHandle are nullable Int64 Unity session ids (HELP INSTANCEID).
                 Extra root evidence: SceneHandle/SceneLoaded, IsPersistent/IsPreview
                 (nullable), ContextError. Index is the result's ordinal.
                 DisplayValue keeps 256 characters, root/scene/asset metadata 4096 (errors
                 1024); a longer text ends with '… (+N chars; M total)', never silently.
                 SourceIndex (nullable int) / SourcePath (string): immediate report-source
                 row ordinal/path, or the BUCKET entry index and its captured path text;
                 absent/empty for other sources; no entity identity.
                 Observed (UqlObservationCell or null): the accepted hit's bounded frozen
                 scalar value (strings 256 characters, longer Truncated); null for references
                 and other structs. On a comparison row: the fresh re-read cell.
                 Previous (UqlObservationCell or null): comparison rows only, the source
                 row's Observed baseline. Read .Value/.Status/.TypeName; neither is live.
  HasReportSource (bool): frozen SCAN report paths were used as the source.
  HasBucketSource (bool): a BUCKET's captured entries were the source (membership copied
                 at command start, each entry walked as its own source; see HELP SCANNING).
  UpstreamCoverageComplete / UpstreamCoverageSummary: copied prior coverage and
                 bounded summary. Exhausting selected paths cannot repair an earlier gap.
  PathParentLevels / ParentlessRows (int): 0 on ordinary reports. On a report made by
                 $parents = $report.PathParents(levels): the selector steps stripped per
                 row, and source rows without a liftable parent (also counted in
                 UnavailableCandidates, so CoverageComplete is false). See HELP SCANNING.
  ComparisonExcluded / ComparisonInconclusive / ComparisonNotOrderable (int): CHANGED,
                 UNCHANGED, INCREASED, DECREASED only (0 otherwise): conclusive non-matches,
                 undecided pairs (also in Errors, with an ERROR line) and the excluded pairs
                 without numeric order (part of ComparisonExcluded, not a coverage gap).
  SourceStartedUtc / SourceFinishedUtc (string), SourceStartFrame / SourceEndFrame (int):
                 a report source's own sampling window (the baseline window for comparison
                 selectors); empty/0 when the source is not a SCAN report.
  LoadedSource / SourceType (string): explicit loaded catalog and optional OF type.
  SourceContext (string): canonical requested context, or empty for no qualifier.
  SourceCandidates / CandidatesVisited / EligibleRoots (int): eager catalog size,
                 frozen report path count or copied BUCKET entry count,
                 charged candidate examinations, and roots whose traversal began.
  HiddenExcluded / PreviewExcluded / TypeExcluded (int): source policy exclusions.
  ContextExcluded (int): otherwise eligible roots rejected by the requested context.
  HasRootPredicate (bool): a source metadata WHERE plan was compiled.
  RootPredicateText (string): bounded predicate source (4096 characters; a longer source
                 ends with '… (+N chars; M total)'), for diagnostic intent.
  PredicateEvaluations / PredicateExcluded / PredicateErrors (int): evaluated roots,
                 false-policy exclusions and failures (also included in Errors).
  HasMatchPredicate / MatchPredicateText: compiled hit-metadata filter and bounded
                 predicate source (4096 characters, same cut marker).
  MatchPredicateEvaluations / MatchPredicateExcluded / MatchPredicateErrors (int):
                 selector hits examined, false exclusions and failures (also Errors).
                 These counters are independent of source-root predicate counters.
                 An accepted hit that triggers MaxResults overflow is evaluated but
                 not retained in Matches; use ResultLimitReached, not a partition sum.
  HasTraversalPredicate / TraversalPredicateText: compiled metadata-only branch
                 guard and its bounded predicate source (4096 characters, same cut marker).
  TraversalPredicateEvaluations / PolicyPruned / TraversalPredicateErrors (int):
                 nonterminal nodes examined, false interior exclusions and failures
                 (also Errors). Current hits survive false guards; only guard errors
                 lower coverage. Other terminal/safety/SCANOPT stops remain separate.
  UnavailableCandidates / ContextErrors / PreviewUnknown (int): destroyed/failed
                 candidate reads (BUCKET sources: null, destroyed, unanchored value-type,
                 method-bearing or failed entries), context errors and unknown preview evidence.
  ContextProviderAvailable / SourceComplete (bool): classification capability and
                 source exhaustion; SourceComplete alone is not complete coverage.
  IncludeHidden / IncludePreview / AssetPaths (bool): captured loaded source options.
  Exclusions   (immutable string list): at most 32 explanatory exclusion examples.
  Matches      (int): number of paths selected by THIS scan, not total bucket Count.
  Visited      (int): visited nodes/charged read attempts, not scene object count.
  Errors       (int): caught member/enumerator read failures; coverage may be partial.
  NativeSkipped(int): native collection nodes left unopened.
  ByRefLikeSkipped (int): property getters returning a byref-like type (Span<T>, ReadOnlySpan<T>,
                 other ref structs) skipped by metadata, never invoked (Summary adds
                 byref-like-skipped=N, Text names up to 8). UQL cannot box, read or capture such
                 a value at all, so they are neither Errors nor a CoverageComplete gap.
  DepthStops   (int): nodes whose expansion stopped at the configured depth.
  Cycles       (int): branches stopped because they revisit the current ancestry.
  Truncated    (bool): node/result budget stopped the scan; partial results may publish.
  CoverageTruncated (bool): same node/result cap loss; not presentation clipping.
  CoverageComplete (bool): published, uncancelled, exhausted source without caps/read
                           errors/native skips, unavailable candidates or depth stops,
                           and complete upstream coverage for report sources.
                           This is configured-query coverage,
                           not proof that the entire Unity scene was inspected.
  TextTruncated(bool): detailed rows hit the presentation limit; results are separate.
  DisplayValuesTruncated (int): rows whose DisplayValue was cut at 256 characters (Summary
                 adds display-values-truncated=N when it is not 0). Paths are never cut.
  NodeLimitReached / ResultLimitReached (bool): identifies the stopping cap.
  MaxNodes / MaxResults / Depth (int): effective SCANOPT traversal/result/depth limits.
  Direct (bool): frozen explicit source + one-edge scope; depth=0/ROOTS can be narrower.
  MaxDetailCharacters (int): detail threshold (262144); header/last row can exceed it.
  MaxErrorDetails (int): maximum stored error detail rows (32).
  Published    (bool): result batch committed to the bucket, including an empty batch.
  Cancelled    (bool): unfinished scan disposed, including failure cleanup.
  StartedUtc / FinishedUtc (string): ISO 8601 UTC timestamps.
  StartFrame / EndFrame (int): Unity frame counters at scan start/end, not tick counts.

$hits stores live paths that can be read again. $report stores plain strings, numbers,
booleans and frozen scalar cells from that scan, with no retained game-object graph. It does not refresh
when the game changes. A later completed SCAN with the same REPORT destination replaces
that variable; it does not append to the previous report. BUCKET results DO append.
The REPORT variable is assigned only after successful scan completion/publication.
While running, or after failure/STOP, it keeps its previous value (possibly null).
C# hosts can inspect group.LastScanReport after completion or cancellation; constructor
failures before a scan starts do not produce a new report. Published does not mean
complete coverage: also check Errors, Truncated, NativeSkipped and DepthStops.
$relations = $report.AssetUsages("sprite") maps a published report's frozen paths to current
usage/item asset identities in its producing group; see HELP ASSETS.
$parents = $report.PathParents(1) derives a new report whose rows are each path minus its last
selector step (the containing record), for SCAN ... IN $parents; see HELP SCANNING.

Choose the output you need:
  LOG $report.Summary;                    // concise host output
  LOG LINE $report.Matches;               // one scalar value (READ in the terminal)
  LOG $report.Text;                       // detailed host output, no registry write
  RECORD $report.Text; REGISTER scan_log; // archive using the existing registry host
Keep RECORD and REGISTER in the same process (same terminal submission, or CALL chain).
LOG $report is NOT shorthand for LOG $report.Text; object display follows PRINTOPT.
Text is capped near 256 Ki characters with a marker. RECORD has its own independent buffer
(recordCharacters: 1048576 characters by default, the in-game terminal 131072; LIMITOPT raises it),
and the LOG value bound (logCharacters, 131072) is separate again: any of them can be the
smaller one, and a RECORD past its buffer fails rather than truncating. For large reports use
lower maxresults, a larger recordCharacters or host output. Omitting REPORT does
not disable internal report generation. Without REPORT the summary is logged;
errors/native skips/truncation also log a summary even when REPORT is present.
Inspect the report before treating zero matches as absence: depth, disabled properties,
excluded native internals, collections=false and metadata stripping restrict coverage.

Scan steps consume VM instruction budget and can span scheduler ticks. STOP/ABORT/error
dispose active enumerators; uncommitted results are discarded. Capacity/path-compile
failure leaves the destination bucket unchanged. Node/result limits publish the bounded
partial batch with Truncated=true. Scene enumeration, reflection metadata preparation,
individual getters/MoveNext and final path compilation are synchronous cold operations;
the budget is not a hard millisecond deadline. Do not perform broad scans in frame-critical
hooks. A scan is not a frame-perfect atomic snapshot: it records its start/end frames.
Resources.FindObjectsOfTypeAll supplies an eager Unity reference array. Its initial
allocation/acquisition is synchronous, uninterruptible and NOT capped by maxnodes.
Loaded candidate examinations and subsequent traversal share the node and scheduler
budgets; rejected candidate examinations also consume budget. Source/exclusion counters
and bounded examples explain the declared policy and any unfinished catalog. On
completion, cancellation or failure the operation releases the catalog/references.
Rows carry copied coverage into SELECT; complete means within the declared policy,
not all hidden objects, unloaded assets or an atomic all-memory snapshot.

Project selected metadata without reparsing Text:
  SELECT $report.Rows AS $r
      FIELDS path=$r.Path, name=$r.RootName, type=$r.RootTypeName,
             context=$r.Context, flags=$r.HideFlags INTO $selected;
  RECORD $selected; REGISTER loaded_discovery;
The captured BUCKET remains the direct way to read matching live values again:
  ITERATE $hits AS $hit { LOG LINE $hit; }    // READ $hit; in the terminal

Native collections are reported and skipped, even when native access is enabled; existing
explicit native reads are unchanged. This version does not scan unloaded assets/prefabs
or perform method searches. Use TRACE for the history of known paths and SCAN CHANGED/
UNCHANGED/INCREASED/DECREASED IN $report to narrow candidates (CANDIDATE REFINEMENT
above). UDB is not required.
IL2CPP requires preservation of game members and reflected engine asset properties.
Reference topic · Language referenceREPORTOptional SCAN result metadata. Text is only one property; use counters, status and timing independently. Not a standalone command or a registry write.

Optional SCAN result metadata. Text is only one property; use counters, status and timing independently. Not a standalone command or a registry write.

Where to use it

SCAN suffix: REPORT $value; see the field reference below

Example

BUCKET $hits; VALUE $report = null;
SCAN FIELD health IN SCENE INTO $hits REPORT $report;
LOG $report.Summary;
LOG $report.Matches;
IF ($report.Truncated) { LOG "Partial scan: check limits."; }
RECORD $report.Text; REGISTER health_scan;
Read the SCANNING reference →
Reference topic · Language referencePATHSRoots, ALIAS/PATH, dynamic selectors, and dictionary key/index syntax.

Roots, ALIAS/PATH, dynamic selectors, and dictionary key/index syntax.

Where to use it

Reference topic; not a command

Example

HELP PATHS;

Detailed reference

From the in-tool help for PATHS.

PATHS / SYMBOLS
ALIAS $boss = [SCENE:Level_1/DragonBoss].BossController;
ALIAS $hp = $boss.Health;       // immutable path definition, live reads
DEFINE $fixed = $boss.Health;   // currently identical to ALIAS
PATH $target = $boss;           // mutable path binding
$target = OtherBoss;            // relative to the host root
VALUE $i = 0;                   // mutable value, not a path string
VALUE $member = "Health";
READ $boss[FIELD:$member];      // explicit dynamic member name
READ $boss.Enemies[$i].Health;  // dynamic collection index

Dictionary: dict[29] is KEY 29, not ordinal 29.
dict[INDEX:0] selects by enumeration position; ordering may change.
dict["mail@123"] is a literal string key (no UDB hash-marker interpretation).
Use [FIELD:name] / [PROPERTY:name] when the member kind needs to be explicit.
READ $go.PlayerController.Health; // short component class name, first attached match
READ $go[COMPONENT:HappyHarvest.PlayerController].Health; // qualified selection
READ $component[AS:HappyHarvest.PlayerController].Health; // validate actual type
READ $component[CAST:HappyHarvest.PlayerController].Health; // AS synonym
Short component selectors match the attached component's Type.Name; duplicate names
across namespaces select the first attached live match. Missing-script slots are skipped.
COMPONENT also accepts a Component receiver and selects on its owning GameObject.
AS/CAST validate a reference; they do not retrieve another component. Use a qualified
type name or a registered type alias for casts and TYPE literals. Short component
selection does not globally import short type names or cache scene object references.
A GameObject's own members are read by plain name (ordinal, camelCase): name, tag, layer,
activeSelf, activeInHierarchy, isStatic, scene, sceneCullingMask, hideFlags, gameObject,
and transform. They bind as members with their real types (.layer is int); every other
dotted name on a GameObject selects a component (type names: .Rigidbody, .Transform).
READ $go.layer; EDIT $go.layer = 3; EDIT $go.tag = "Enemy"; // own members
INVOKE $go.SetActive(false);   // activeSelf/activeInHierarchy are read-only
READ $go[COMPONENT:tag].Value; // a component class named like a member
EDIT never assigns a component itself (EDIT $go[COMPONENT:tag] = ...; is refused with the
selector named): edit one of its members, EDIT $go[COMPONENT:tag].Value = 1;.
GameObject has no enabled: read .activeSelf, call SetActive, or use .<Component>.enabled.
A lowercase name outside that list on a typed GameObject (SCENE root, typed ALIAS) is
a compile warning (UQL221), once per name per statement (a range query or a terminal LIVE
view does not repeat it); other GameObject members: [PROPERTY:"x"].
READ $boss[NAME];              // Unity object name; never inferred as a component
READ $boss[TYPE];              // System.Type; use [TYPE].FullName for qualified names
READ $boss[TYPENAME];          // short Type.Name (namespace omitted)
READ $boss[INSTANCEID];        // Int64 Unity session id (HELP INSTANCEID); null for managed objects
Metadata selectors are operand-free and read-only. NAME returns UnityEngine.Object.name,
or Type.Name for a System.Type/static scope; ordinary managed objects return null.
TYPE/TYPENAME use the actual runtime type, or the represented type for Type/static scope.
They do not call arbitrary Name getters or ToString. Null/destroyed receivers retain
normal path failure behavior; these operators are not null-safe navigation.
[NAME] does not change dictionary [NAME:operand] key-name selection.
INSTANCEID reads the 64-bit Unity session id of an Object (a Scene handle for a Scene; EntityId/
SceneHandle values on Unity 6000.6+) as long?; FIND INSTANCEID $id INTO $v; resolves it back.
String data does not become executable path text by itself.
$alias = $other; is rejected; use ALIAS $new = $other; or a PATH declaration.
READ snapshots only the output. A VALUE assigned from a path stores that read result.
Root/type/field names in examples must match your game; SCENE needs a resolver.
Ordinary selectors use path operands; range FROM/TO/COUNT also accept arithmetic.
ALIAS/PATH denote a single target: ranges belong to commands, not declarations.

IMMEDIATE SCRIPT METHOD EXPRESSIONS
VALUE $cellResult = $terrain.IsTillable(v3i(-3, -1, 0));
LOG $boss.CalculateDamage($baseDamage + 2);
VALUE $typeName = TYPE(System.String).Name; // metadata lookup, not a cast
VALUE $health = $boss.GetChild($index + 1).Health;
INVOKE $boss.TakeDamage($boss.CalculateDamage($baseDamage + 2));
READ/LOG/RECORD/VALUE/INVOKE can evaluate expression-bearing calls and then select
members or indices from the returned value. The receiver is evaluated before arguments;
a null/destroyed receiver fails without evaluating those arguments. Arguments evaluate
once, left to right. Existing short-circuit Boolean behavior is preserved.

Persistent ALIAS/PATH/TRACE/BUCKET and EDIT targets cannot store a temporary lowered
expression chain. Prepare arguments as VALUE symbols, then use the existing path form:
VALUE $cell = v3i(-3, -1, 0);
ALIAS $isTillable = $terrain.IsTillable($cell);
This restriction applies to complex expression-bearing calls, not existing literal/
symbol-argument method paths. A VALUE storing a call result is a value/reference snapshot,
not a live path to that call. Re-evaluate explicitly when a fresh result is required.
Parsing/binding happens at compile time; execution uses the flat 16-byte VM instructions.
Ordinary valid path expressions keep the existing path runner. See HELP VALUES for
tuple/overload/numeric limits and the separate trusted-host CompileExpression API.
Reference topic · Language referenceNAME[NAME] reads a Unity object name or represented type name without component inference. Ordinary managed objects have no implicit name and return null.

[NAME] reads a Unity object name or represented type name without component inference. Ordinary managed objects have no implicit name and return null.

Where to use it

Read-only path operator; distinct from dictionary [NAME:operand]

Example

READ $target[NAME];
Read the PATHS reference →
Reference topic · Language referenceTYPE[TYPE] returns System.Type for the actual object, or the represented type of a static scope/Type value.

[TYPE] returns System.Type for the actual object, or the represented type of a static scope/Type value.

Where to use it

Read-only path operator; null/destroyed receivers fail normally

Example

READ $target[TYPE].FullName;
Read the PATHS reference →
Reference topic · Language referenceTYPENAME[TYPENAME] returns short Type.Name, without the namespace. Use [TYPE].FullName for qualified names.

[TYPENAME] returns short Type.Name, without the namespace. Use [TYPE].FullName for qualified names.

Where to use it

Read-only path operator; works on captured BUCKET entries

Example

READ $target[TYPENAME];
Read the PATHS reference →
Reference topic · Language referenceINSTANCEID[INSTANCEID] reads the 64-bit Unity session id (Int64; never a hash) of a UnityEngine.Object, the handle of a Scene and, on Unity 6000.6+, the raw value of an EntityId or SceneHandle; other managed objects give null. FIND INSTANCEID <id> INTO $value resolves an id back to the live object (null when gone). Report *InstanceId/CameraId/*SceneHandle fields carry the same Int64. Verified: 2022.3, 6000.0 and 6000.6.0a3 verified by API compile; 6000.1 - 6000.5 unverified (not supported until an installed Editor of that band passes).

[INSTANCEID] reads the 64-bit Unity session id (Int64; never a hash) of a UnityEngine.Object, the handle of a Scene and, on Unity 6000.6+, the raw value of an EntityId or SceneHandle; other managed objects give null. FIND INSTANCEID <id> INTO $value resolves an id back to the live object (null when gone). Report *InstanceId/CameraId/*SceneHandle fields carry the same Int64. Verified: 2022.3, 6000.0 and 6000.6.0a3 verified by API compile; 6000.1 - 6000.5 unverified (not supported until an installed Editor of that band passes).

Where to use it

Read-only path operator and FIND form; Unity 2022.3 - 6000.6 (6000.1 - 6000.5 unverified)

Example

VALUE $go = null; VALUE $id = null; VALUE $back = null;
FIND "Player" IN SCENE INTO $go;
$id = $go[INSTANCEID];              // Int64 session id; null for an ordinary managed object
FIND INSTANCEID $id INTO $back;     // the live object again, or null when it is gone

Unity version details

The identity API differs by Unity version. Open the version that matches your project.

Unity 6000.6 and newer
INSTANCEID - UNITY SESSION IDS (64-bit, every supported Unity version)
VALUE $enemy = null; VALUE $space = null; VALUE $rows = null; VALUE $cid = null;
VALUE $r = null; VALUE $again = null; VALUE $back = null; BUCKET $hits;
READ $enemy[INSTANCEID];                                   // Int64, or null for an ordinary managed object
SELECT $space.Rows AS $o FIELDS id = $o.InstanceId, parent = $o.ParentInstanceId INTO $rows;
$cid = $enemy[INSTANCEID];
SCAN ROOTS IN LOADED OBJECTS OF UnityEngine.Collider AS $m WHERE $m.RootInstanceId == $cid INTO $hits REPORT $r;
SPATIAL IN SCENE($space.SelectedSceneHandle) INTO $again;  // a 64-bit handle is accepted
FIND INSTANCEID $cid INTO $back;                           // the live object again, or null when it is gone
$back = [STATIC:UQL.Runtime.UqlUnityIds].Require($cid);    // the object, or a failure with the reason and NEXT

[INSTANCEID] is an operand-free, read-only path metadata selector like [NAME], [TYPE] and [TYPENAME].
A UnityEngine.Object gives its id; a Scene gives its handle (an invalid default Scene gives null); on
Unity 6000.6+ an EntityId or SceneHandle value gives its raw value (None gives null). Any other managed
object, a System.Type value included, gives null. A null or destroyed receiver fails with the usual
path diagnostics. A static scope has no id: [STATIC:T][INSTANCEID] is a compile error, and a static
scope held in a VALUE fails at run time with the same text. [INSTANCEID:x] is an unknown selector;
$dict["INSTANCEID"] still selects a dictionary key. Works on captured BUCKET entries and in
FIELDS/WHERE/ON; the result type is long? (Int64 or null).

Value: one Int64 on every Unity version, never a hash: the instance id below Unity 6000.6 (negative
for runtime-created objects), the full raw EntityId from 6000.6 (about 18 digits). The kind travels
in the name: object ids are the *InstanceId and CameraId fields (SCAN RootInstanceId; SPATIAL
InstanceId, ParentInstanceId, TilemapInstanceId, ObjectInstanceId; AssetUsages InstanceId and
RootInstanceId; asset identity SessionInstanceId; CAPTURE CameraId; ENVIRONMENT camera.instance-id;
observation UnityInstanceId), scene handles the *SceneHandle fields (SCAN SceneHandle; SPATIAL
SelectedSceneHandle and SceneHandle; AssetUsages RootSceneHandle and ValueSceneHandle; ENVIRONMENT
scenes.active-handle and scenes.sceneN.handle). Display text prints a Unity object as #<id> and a
managed object as #m<n> (INSPECT/BLUEPRINT refids, TRACE), so the two never read as the same
reference; ROOT keys and TRACE child paths print the same Int64.
A session identity: stable for an object's lifetime within one Editor or player session, also
across a C# refresh (domain reload); not across sessions and not a save id (like ROOT).
Reopening or reloading a scene creates new objects with new ids: an old id then finds nothing.
Whether a Play Mode round trip keeps the ids of a scene's objects depends on the Unity version and
the Enter Play Mode options (Unity 2022.3 with the default options was observed to keep them across
Play and back); do not rely on either outcome: after a transition find the object again by path or
name, and treat a null from FIND INSTANCEID as "gone". Persistent assets normally keep their ids
across scene changes.

Reverse lookup: FIND INSTANCEID <id> INTO $value stores the live object, or null when nothing
has that id (unknown, destroyed, another session; a null id also gives null). The id is any
integral number (Int32, Int64, UInt64; on Unity 6000.6+ also an EntityId, where EntityId.None
finds nothing and gives null); another type fails with the value it got.
[STATIC:UQL.Runtime.UqlUnityIds].Find(id) is the same lookup for a long id; Require(id) fails
instead of returning null:
  UqlUnityIds.Require(<id>): no live Unity object has id <id> in this Editor session. Ids survive
  a C# refresh but change when a scene is reloaded or reopened (also when Play Mode reloads it).
  NEXT: find the object again (FIND, SCAN, SPATIAL) and use its new id.
Find/Require take a long: a literal, an [INSTANCEID] result, a report field (Int64) and an
Int32 VALUE (widened since revision 54, HELP VALUES) bind. A UInt64 or an EntityId does not
(C# has no implicit UInt64 -> Int64): use FIND INSTANCEID for those. On Unity 6000.6+ an int
id kept by game code (GetInstanceID era, the low 32 bits) still binds but never matches: Find
gives null and Require fails. Use ROOT or a path for repeated access.

Comparisons and joins: query comparisons accept Int64/UInt64 exactly and LOOKUP normalizes
integral keys to Int64, so an int id stored by game code still joins a report id below Unity
6000.6. Unity 6 struct ids (EntityId or SceneHandle fields, RaycastHit.colliderEntityId) are not
keys: convert them first, for example $hit.colliderEntityId[INSTANCEID].
SPATIAL IN SCENE(handle) accepts Int32, Int64 and UInt64 (and a SceneHandle on 6000.6+) and
compares with the full handle; handle 0 is the invalid scene. An unknown handle fails with the
loaded scenes and their handles. SPATIAL ties sort by instance id, then source ordinal; with
6000.6 raw ids runtime-created objects sort after loaded ones (the reverse of 2022.3).
Unity 6000.6+: a reflected $x.GetInstanceID() still runs but returns only the low 32 bits of the
EntityId, which never equal UQL ids, so the compiler warns (UQL217) on a GetInstanceID or
GetEntityId method step. Use $x[INSTANCEID].
Migration: report ids are Int64 on every Unity version, so passing one to a Unity int parameter
fails (UQL never narrows integer method arguments). Use FIND INSTANCEID or UqlUnityIds.Find/Require instead
of Resources.InstanceIDToObject, ROOT/paths for repeated access, and
[STATIC:System.Convert].ToInt32(...) for another int parameter below Unity 6000.6.
Planned work must not use the Unity int id APIs that 6000.6 marks obsolete-as-error
(Selection.instanceIDs/activeInstanceID, EditorUtility.InstanceIDToObject,
RaycastHit.colliderInstanceID, AssetDatabase.GetAssetPath(int), ...): use the Object forms.

Verified Unity versions: 2022.3, 6000.0 and 6000.6.0a3 verified by API compile; 6000.1 - 6000.5 unverified (not supported until an installed Editor of that band passes). This build reads
EntityId / SceneHandle ([STATIC:UQL.Runtime.UqlUnityIds].Source / SceneSource; InstanceID / int below
Unity 6000.6, EntityId / SceneHandle from 6000.6). ENVIRONMENT project.unity-id-source and
project.unity-id-verified show the same. Unity versions after 6000.6 (CoreCLR) are later work.
Earlier Unity versions
INSTANCEID - UNITY SESSION IDS (64-bit, every supported Unity version)
VALUE $enemy = null; VALUE $space = null; VALUE $rows = null; VALUE $cid = null;
VALUE $r = null; VALUE $again = null; VALUE $back = null; BUCKET $hits;
READ $enemy[INSTANCEID];                                   // Int64, or null for an ordinary managed object
SELECT $space.Rows AS $o FIELDS id = $o.InstanceId, parent = $o.ParentInstanceId INTO $rows;
$cid = $enemy[INSTANCEID];
SCAN ROOTS IN LOADED OBJECTS OF UnityEngine.Collider AS $m WHERE $m.RootInstanceId == $cid INTO $hits REPORT $r;
SPATIAL IN SCENE($space.SelectedSceneHandle) INTO $again;  // a 64-bit handle is accepted
FIND INSTANCEID $cid INTO $back;                           // the live object again, or null when it is gone
$back = [STATIC:UQL.Runtime.UqlUnityIds].Require($cid);    // the object, or a failure with the reason and NEXT

[INSTANCEID] is an operand-free, read-only path metadata selector like [NAME], [TYPE] and [TYPENAME].
A UnityEngine.Object gives its id; a Scene gives its handle (an invalid default Scene gives null); on
Unity 6000.6+ an EntityId or SceneHandle value gives its raw value (None gives null). Any other managed
object, a System.Type value included, gives null. A null or destroyed receiver fails with the usual
path diagnostics. A static scope has no id: [STATIC:T][INSTANCEID] is a compile error, and a static
scope held in a VALUE fails at run time with the same text. [INSTANCEID:x] is an unknown selector;
$dict["INSTANCEID"] still selects a dictionary key. Works on captured BUCKET entries and in
FIELDS/WHERE/ON; the result type is long? (Int64 or null).

Value: one Int64 on every Unity version, never a hash: the instance id below Unity 6000.6 (negative
for runtime-created objects), the full raw EntityId from 6000.6 (about 18 digits). The kind travels
in the name: object ids are the *InstanceId and CameraId fields (SCAN RootInstanceId; SPATIAL
InstanceId, ParentInstanceId, TilemapInstanceId, ObjectInstanceId; AssetUsages InstanceId and
RootInstanceId; asset identity SessionInstanceId; CAPTURE CameraId; ENVIRONMENT camera.instance-id;
observation UnityInstanceId), scene handles the *SceneHandle fields (SCAN SceneHandle; SPATIAL
SelectedSceneHandle and SceneHandle; AssetUsages RootSceneHandle and ValueSceneHandle; ENVIRONMENT
scenes.active-handle and scenes.sceneN.handle). Display text prints a Unity object as #<id> and a
managed object as #m<n> (INSPECT/BLUEPRINT refids, TRACE), so the two never read as the same
reference; ROOT keys and TRACE child paths print the same Int64.
A session identity: stable for an object's lifetime within one Editor or player session, also
across a C# refresh (domain reload); not across sessions and not a save id (like ROOT).
Reopening or reloading a scene creates new objects with new ids: an old id then finds nothing.
Whether a Play Mode round trip keeps the ids of a scene's objects depends on the Unity version and
the Enter Play Mode options (Unity 2022.3 with the default options was observed to keep them across
Play and back); do not rely on either outcome: after a transition find the object again by path or
name, and treat a null from FIND INSTANCEID as "gone". Persistent assets normally keep their ids
across scene changes.

Reverse lookup: FIND INSTANCEID <id> INTO $value stores the live object, or null when nothing
has that id (unknown, destroyed, another session; a null id also gives null). The id is any
integral number (Int32, Int64, UInt64; on Unity 6000.6+ also an EntityId, where EntityId.None
finds nothing and gives null); another type fails with the value it got.
[STATIC:UQL.Runtime.UqlUnityIds].Find(id) is the same lookup for a long id; Require(id) fails
instead of returning null:
  UqlUnityIds.Require(<id>): no live Unity object has id <id> in this Editor session. Ids survive
  a C# refresh but change when a scene is reloaded or reopened (also when Play Mode reloads it).
  NEXT: find the object again (FIND, SCAN, SPATIAL) and use its new id.
Find/Require take a long: a literal, an [INSTANCEID] result, a report field (Int64) and an
Int32 VALUE (widened since revision 54, HELP VALUES) bind. A UInt64 or an EntityId does not
(C# has no implicit UInt64 -> Int64): use FIND INSTANCEID for those. On Unity 6000.6+ an int
id kept by game code (GetInstanceID era, the low 32 bits) still binds but never matches: Find
gives null and Require fails. Use ROOT or a path for repeated access.

Comparisons and joins: query comparisons accept Int64/UInt64 exactly and LOOKUP normalizes
integral keys to Int64, so an int id stored by game code still joins a report id below Unity
6000.6. Unity 6 struct ids (EntityId or SceneHandle fields, RaycastHit.colliderEntityId) are not
keys: convert them first, for example $hit.colliderEntityId[INSTANCEID].
SPATIAL IN SCENE(handle) accepts Int32, Int64 and UInt64 (and a SceneHandle on 6000.6+) and
compares with the full handle; handle 0 is the invalid scene. An unknown handle fails with the
loaded scenes and their handles. SPATIAL ties sort by instance id, then source ordinal; with
6000.6 raw ids runtime-created objects sort after loaded ones (the reverse of 2022.3).
Unity 6000.6+: a reflected $x.GetInstanceID() still runs but returns only the low 32 bits of the
EntityId, which never equal UQL ids, so the compiler warns (UQL217) on a GetInstanceID or
GetEntityId method step. Use $x[INSTANCEID].
Migration: report ids are Int64 on every Unity version, so passing one to a Unity int parameter
fails (UQL never narrows integer method arguments). Use FIND INSTANCEID or UqlUnityIds.Find/Require instead
of Resources.InstanceIDToObject, ROOT/paths for repeated access, and
[STATIC:System.Convert].ToInt32(...) for another int parameter below Unity 6000.6.
Planned work must not use the Unity int id APIs that 6000.6 marks obsolete-as-error
(Selection.instanceIDs/activeInstanceID, EditorUtility.InstanceIDToObject,
RaycastHit.colliderInstanceID, AssetDatabase.GetAssetPath(int), ...): use the Object forms.

Verified Unity versions: 2022.3, 6000.0 and 6000.6.0a3 verified by API compile; 6000.1 - 6000.5 unverified (not supported until an installed Editor of that band passes). This build reads
InstanceID / int ([STATIC:UQL.Runtime.UqlUnityIds].Source / SceneSource; InstanceID / int below
Unity 6000.6, EntityId / SceneHandle from 6000.6). ENVIRONMENT project.unity-id-source and
project.unity-id-verified show the same. Unity versions after 6000.6 (CoreCLR) are later work.
Reference topic · Language referenceSTATICStatic type scopes: reading, blueprint output, and TRACE.

Static type scopes: reading, blueprint output, and TRACE.

Where to use it

Reference topic; not a command

Example

HELP STATIC;

Detailed reference

From the in-tool help for STATIC.

STATIC SCOPES
ALIAS $stats = [STATIC:Game.SessionStats];
PATH $target = [STATIC:Game.SessionStats];
READ $target; BLUEPRINT $stats; TRACE $target;
READ $target.Score; EDIT $target.Score = 12;
$target = [STATIC:Game.OtherStats];
PRINTOPT inheritance = true, interfaces = true, attributes = true;

A bare STATIC is an explicit type scope, not an instance and not System.Type.
Only static members are listed/traced; no constructor is used to fabricate an instance.
Static field reads can trigger the type initializer. Properties still need readprops:
PRINTOPT showprops = true, readprops = true;
TRACEOPT properties = true, readprops = true; TRACEAPPLY ALL;
Automatic property reads can run game code. Getter failures stay on the affected member.
TRACE captures the current PATH definition; later rebinding does not retarget old traces.
Use an untyped PATH for scopes. A PATH typed as an instance type cannot return that type's
static scope. A scope cannot be assigned to a game object; EDIT a static member instead.
Referenced types/members must survive IL2CPP stripping, just as for other reflection paths.
Reference topic · Language referenceHOOKSynchronous hook notifications, BLOCK entry points, and WAIT EVENT lifetime.

Synchronous hook notifications, BLOCK entry points, and WAIT EVENT lifetime.

Where to use it

Reference topic; not a command

Example

HELP HOOK;

Detailed reference

From the in-tool help for HOOK.

HOOK / EVENT (single-thread, synchronous)
BLOCK DamageApplied { WAIT EVENT DamageApplied; LOG "next damage"; }
TRIGGER DamageApplied; // broadcasts to same-named BLOCKs and existing WAITs
First trigger starts the BLOCK and leaves a WAIT. The next trigger resumes that WAIT
and also starts a new BLOCK process. New waits never consume the old publication.
Every attached, active execution group participates. BLOCK names are unique per group.
String identities are case-sensitive. Unknown identities are successful no-ops.

C#: UQLHooks.Attach(group); // once for a C#-created group; terminal attaches automatically
UQLHooks.Trigger("DamageApplied");
UQLHooks.TryGetHandle("DamageApplied", out var hit); UQLHooks.Trigger(hit);
UQLHooks.StartBlocks(hit);    // only start matching BLOCKs, synchronously
UQLHooks.SignalWaiters(hit);  // only resume existing WAITs, synchronously
Same APIs accept strings. Handles belong to the hub, not a compiled BLOCK index.
Parameterized BLOCKs take a payload (below) or CALL/START arguments; a payloadless hook reports a diagnostic.

PAYLOADS: UQLHooks.Trigger("PfDelivered", jobId, npcId);  // up to two int or long values
UQLHooks.TriggerObject("Spawned", gameObject);          // or one object reference
BLOCK PfDelivered($job: int, $npc: int) { ... }          // the first K parameters take the first K values
The same forms exist on a hub (hub.Trigger(name or handle, a[, b]), hub.TriggerObject(...)). A hook
BLOCK binds K <= payload count values (prefix binding); a parameterless BLOCK ignores the payload.
Integers convert like CALL arguments: range-checked for int/short/byte/uint/enum parameters (an enum
by its underlying type), widened for long/double, kept as int/long when untyped. An object must be an
instance of the parameter type (TriggerObject never converts). Overloads: byte/short/int bind to int,
uint to long; cast an enum or ulong; there is no object Trigger overload, so nothing boxes by accident.
Bind errors (more parameters than values, an out-of-range integer, an object of another type, null for
a value type, an integer for a string/reference parameter) fail that BLOCK only: other receivers still
run and the call returns false. The first error of each kind per receiver and group activation is
reported in full (HOOK, payload, BLOCK header with its location, group, reason, remedy) through
hub.Diagnostic and the group's ProcessFailed (the file host shows it as the group's error); repeats
return false with the same cached LastError and are only counted.

UqlHookPoint (hot game call sites, UQLHooks.Default only):
static readonly UqlHookPoint mindTick = new UqlHookPoint("MINDTICK"); // a field; touches no hub
mindTick.Trigger(npcId, (int)callSite);  // also Trigger(), Trigger(long[, long]), TriggerObject(o)
The point binds its identity on the hub's thread on the first call that could deliver (no lookup per
call), rebinds after UQLHooks.Reset / Play start (a stored handle goes stale there) and never creates
the hub. While the identity is not armed (no route and no queued waiter) a call is one field load and
one branch: it returns true with no thread, reentry or limits check, no LastError write and no
allocation, on any thread. A point not bound yet (only ever called on a worker thread) or still bound
to a reset hub asks a per-name armed flag the hub's thread keeps: not armed is the same idle true,
nothing counted. Once armed, a call on another thread returns false, is not delivered and is counted
in DroppedWrongThread; a call from C# code that UQL is running (INVOKE, getter, method, command
handler) does the same and counts DroppedReentry only when something live could take it (a route of a
live, not aborted group or a queued waiter); otherwise it is the idle true as well (both counters per
hook name, cumulative since the first point with the name was created). The hub's
LastError and the outer dispatch result stay untouched; point.LastError holds the refusal. A reentry
drop is reported in full once per activation of the running group, at the running instruction (group,
BLOCK). Reentry and wrong thread are retried on the next call; only the identity limit (MaxIdentities)
is a cached refusal, until the hub or the limit changes. HasReceivers may stay true briefly after the
last receiver left, never false while one exists. Existing string/handle forms keep their contract
(entry checks, LastError reset, limits check). A publication nothing could take (not armed, or every
receiver filtered) returns true without a dispatch frame or evidence publication ID; CollectStatistics
counts armed publications only. Always-on receiver counters (armed path only, reset per group
activation): hub.TryGetSnapshot(name, out s) -> s.Armed, s.Receivers[i].Seen / Filtered / Started /
BindErrors / FilterErrors / FirstError, and s.PointsConstructed / PointDroppedReentry /
PointDroppedWrongThread. WHEN receiver filters, UQL TRIGGER payloads and args= evidence stamps are
later HOOK-CONTEXT slices; until then the payload reaches BLOCK parameters only.

Terminal model.Hooks/session.Hooks defaults to UQLHooks.Default. Successful submissions
replace only that terminal's routes. Terminal reset/dispose does not reset the shared hub.
Unnamed simultaneous terminals get distinct group names; inspect Group.Name to target one.
UQLHooks.Reset (application owner only) stops/detaches all default-hub groups, clears hub
settings/listeners and invalidates handles. Unity play-session startup does this too.
Reattach/reload groups and reacquire handles after a global reset. The terminal UI starts
a fresh session; old declarations do not cross that boundary.
For isolation, create new UqlHookRuntime(), Attach groups, or pass hooks: to the terminal
session/model constructor. Its owner disposes that hub. Static calls do not reach it.

CALL: same process/call stack. START: new process queued for a later scheduler turn.
Nested UQL TRIGGER is synchronous and shares the outer instruction budget across groups.
Host callback reentry is rejected; do not call Trigger from a getter/host callback.
Prepare TryGetHandle in C# setup or a later main-thread callback outside UQL execution.
A method invoked by UQL cannot bind handles while the VM is running; check the Boolean
result before caching a handle. The first external Update can perform deferred setup.
MaxInstructions / MaxDispatchDepth are hub limits; MaxCallDepth / MaxProcesses are group limits.
On synchronous budget exhaustion unfinished participants and reserved waiters fail;
unstarted BLOCK recipients are skipped with a diagnostic, not deferred to a later frame.
STOP cancels one process; ABORT; disables its group; ABORT Name; / ABORT ALL; target this hub.
UQLHooks.Reactivate("Name") explicitly enables a stopped group; state/history remain.
Hook publication does not advance time or frames. With a host frame clock, WAIT n FRAME (n >= 1) resumes no earlier than the actual
frame sampled at the WAIT instruction + n (so a hook-issued wait cannot resume inside its own frame); otherwise it counts scheduler ticks.
WAIT SECOND resumes on an eligible scheduler turn. Unity Conductor and the built-in
terminal sample an unscaled clock at the WAIT instruction, not at the beginning of a
potentially expensive tick. Standalone hosts can set group.WaitClock in the same time
domain as Tick(timeSeconds); null retains deterministic caller-supplied tick time.
WAIT EVENT name TIMEOUT 2 SECOND INTO $outcome; can stop waiting indefinitely.
The next hook claim versus Tick timeout processing decides Matched/TimedOut; a hook does
not compare its publication time to the timeout clock. TIMEOUT 0 never registers an event
waiter. Stopped/failed waiters are Cancelled in snapshots and do not run a continuation.
See HELP WAIT for outcome VALUE types, condition tie handling and process diagnostics.
Cold host diagnostics: hub.TryGetSnapshot("DamageApplied", out var snapshot) reports
ReceiverBlocks and WaiterCount without registering an unknown identity. Unknown names
return false. Use the owning, idle hub; this is not a publication-time callback API.
ReceiverBlocks lists registered routes, including aborted groups whose routes remain
registered for Reactivate. It is not a count of currently eligible/successful executions.
hub.CollectStatistics defaults to false. Enable it explicitly to count Publications,
SelectedWaiters and StartedBlocks. Counters advance only while enabled, and toggling it
does not reset earlier counts. They are hub-lifetime counts, not frame/time measurements
or proof that every selected BLOCK completed. Snapshots allocate only on explicit request.
HOOK is not a native lifetime permission or an automatic TRACE sampling command.
Reference topic · Language referenceSCRIPTScripts, scopes, processes, CALL/START, and WAIT semantics.

Scripts, scopes, processes, CALL/START, and WAIT semantics.

Where to use it

Reference topic; not a command

Example

HELP SCRIPT;

Detailed reference

From the in-tool help for SCRIPT.

SCRIPT / EXECUTION
BLOCK Show { LOG LINE Boss.Health; }
CALL Show;           // same process, separate local call frame
START Show;          // independent cooperative process, not an OS thread
BLOCK Sum($a: int, $b: int) { RETURN $a + $b; }
VALUE $answer = 0;
CALL Sum(2, 3) INTO $answer;

IF $answer > 0 { LOG $answer; } ELSE { LOG 0; }
VALUE $i = 0;
WHILE $i < 3 { LOG $i; $i = $i + 1; }
ITERATE Enemies AS $enemy INDEX $index { LOG $enemy.Health; }
ITERATE Enemies[FROM: 2 TO: 6] AS $enemy INDEX $index { LOG $enemy.Health; LOG LINE; }
ITERATE FROM 0 TO 10 AS $index { LOG $index; LOG LINE; }
BREAK; / CONTINUE; only inside loops. RETURN ends the current BLOCK; STOP the process.
WAIT 2 FRAME;  WAIT 0.5 SECOND;  WAIT UNTIL Ready;
WAIT EVENT "ready";  TRIGGER "ready";
VALUE $outcome = null;
WAIT UNTIL $ready TIMEOUT 2 SECOND INTO $outcome;
WAIT EVENT Ready TIMEOUT 60 FRAME INTO $outcome;
BLOCK ready { LOG "hook received"; } // same-name hook entry, no ON EVENT
ABORT; / ABORT GroupName; / ABORT ALL; // disable group(s) in this hook runtime

Terminal commands outside BLOCK enter a temporary entry block (WAIT included).
Top-level ALIAS/DEFINE/PATH/VALUE/BUCKET are session globals.
BLOCK locals are not globals. Initializers run once, not on every submission.
A local declaration that hides a symbol of another kind (VALUE $b in a BLOCK next to a
group BUCKET $b) compiles with warning UQL220 naming both declarations; inside that scope
$b is the local one. Same-kind locals, BLOCK parameters and ITERATE items shadow silently.
Duplicate symbol: $b names the earlier declaration (already declared at File(line,col)).
SCAN INTO, COLLECT INTO and ADD/REMOVE/CLEAR targets that are not a BUCKET say what the name is:
not declared, another kind (declared at File(line,col)), or a symbol hiding a BUCKET of that name.
A retained BLOCK is recompiled with later submissions, but not automatically called.
Regular scripts start UQLSCRIPT Name; optionally GROUP GroupName; and put commands in BLOCKs.
AWAKE BLOCK Init { ... } marks a no-argument entry for the optional file workspace host.
Scheduler budgets: each tick runs a bounded number of instructions per process. Play Mode ticks (a Unity frame each)
allow 1000 per process and 10000 in total; ticks without a game frame (Editor Edit Mode, about 10 per second while the Editor
is unfocused) allow 20000 per process and 100000 in total (UqlFileWorkspace.EditModeProcessBudget/EditModeInstructionBudget).
In the Conductor these four budgets are workspace limits preset keys (playTickInstructions, playProcessInstructions,
editTickInstructions, editProcessInstructions; HELP LIMITS) and apply as soon as the Config is applied.
In Edit Mode there is no game frame, so WAIT n FRAME counts scheduler ticks and takes seconds. In Play Mode (host frame clock) it counts actual frames. Keep loops small; prefer one query to many reads.
That host queues it once per successful activation. Compilation alone never executes it.
The terminal does not auto-start AWAKE entries; START/CALL still work normally.
All sources compiled together share globals and unique BLOCK names. No Script::Block namespace.
CALL/START remain group-local. See HELP HOOK for cross-group synchronous broadcasts.
CSHARP Name(<C# parameters>) [RETURNS <C# type>] { ... } declares a C# function at script level, in the BLOCK name space;
CALL Name(args) INTO $v; calls it (optional Editor module, csharp grant; HELP "CSHARP FUNCTIONS").
READ/INSPECT are terminal-only: outside that profile they are skipped with a diagnostic
(UQL201) whose NEXT is LOG LINE <expr>; (BLUEPRINT <expr>; for an object dump; for a range
query BLUEPRINT <query>; or ITERATE <query> AS $e { LOG LINE $e; }).
BLUEPRINT/LOG/EDIT and recording/bucket commands also work in regular scripts.
Tick counts scheduler advances, not Unity frame numbers; WAIT FRAME uses actual frames only when the host binds a frame clock (HELP WAIT).
The scheduler is single-threaded. User getters/methods cannot be preempted by its budget.
PROCESSES; shows stable activation-local IDs, source/version and current wait details.
TIMEOUT/INTO are supported on WAIT EVENT and WAIT UNTIL, not ordinary timed waits.
See HELP WAIT for matching, cancellation, deadline races and bounded snapshot history.

CONDUCTOR FILE CHANNEL (optional host, not UQL syntax)
Workspace > Accept config updates permits stable, validated external Conductor.xml changes
without reconnecting. It defaults off. Permissions/membership changes affect relevant
groups; malformed Config leaves old settings active and pauses new compile requests.
The selected host's config.txt is session-tagged: watching/disabled on connection,
pending after the first changed observation, accepted after a committed update, or
rejected on validation/read failure. A poll that cannot open Conductor.xml because
another process holds it (sharing/lock violation, e.g. an atomic replacement) or
because its name is briefly missing (the same replacement: Config is missing or
FileNotFound) is not a rejection: nothing is reported, requests wait and the next
poll reads again; only 20 consecutive such polls are reported, once (config.txt and
host Last error). The connect-time load retries these within the interactive window (about 250 ms) and never
loads defaults over a Config that existed during that window; a Config still held then fails the connect
with a typed busy error (UqlConfigBusyException: nothing loaded, connect again). A missing Config while
Config/ holds a .uql-*.previous or .uql-<32 hex>.tmp file of an interrupted save is a recovery error that
names those files, not a new all-default workspace.
Returning to accepted bytes restores watching
without inventing an acceptance event. Unchanged feedback is not rewritten; its UTC
is the last state change, not a heartbeat. Read fresh host.txt and compare Session.
Every committed update reports pending, then accepted with a new UTC. After editing
Config, read your grant back and wait for an accepted report of the current Session
newer than your write before compiling; a fixed sleep is not proof. Host Config saves
never replace an external Config written during the save: those bytes are restored,
the host save is discarded and the external Config is adopted; unchanged settings are
not rewritten. A save that another process blocks (a held Conductor.xml) is not a conflict: it is
retried within the interactive window and then refused as busy (nothing was saved; the connection is
kept). A restore of external bytes that cannot finish stays pending, guarded on every attempt (it is
dropped, and the backup kept as a recovery file, when Conductor.xml or the backup changed meanwhile), and
is recorded in Config/.uql-restore-pending: until it is done the host adopts no Config and refuses
compiles (config.txt 'blocked: ...', host.txt Request wait:), and the next Load finishes it first. The
refused save is never adopted. A save whose replaced Config cannot be read back is refused as busy and
undone the same way (the Config before it is put back). A disconnect gives a pending restore one more
attempt and writes its record if it was missing; one left without a record is reported (Last error,
journal) with the file to copy back.
Config has no fixed group/source count (the former 128/256 caps were removed). The host
reads Config up to UqlConductorConfig.MaxConfigCharacters (1048576, thousands of
registrations); a save that would exceed it is refused, nothing is written and the host keeps its connection. Unused
groups and closed sources stay registered until deleted.
Config <Limits .../> under the root holds the workspace limits preset (BUCKET entries, RECORD/LOG/SELECT/OBSERVE
characters, registry/output.txt sizes, process limits, scheduler/hook budgets, the io*/progress* host I/O
budgets). Every group takes it at its next compile; budgets apply at once. host.txt lists Limits: and
Limits warning N: lines. See HELP LIMITS.
The preset also holds the script option defaults (print.maxchars, scan.maxnodes, ...). One group overrides it for
itself with LIMITOPT (group limits) or its own PRINTOPT/SCANOPT/... key; its status Limits: line names each origin.
Quick start: <Limits preset="large-data" /> starts from a named preset (default, agent, large-data, play-safe,
low-memory; HELP LIMITS QUICK PRESETS); attributes next to it change single values. host.txt Limits preset: line.
Output directory relocation requires reconnect.
Sources: UQLScripts/; permissions and memberships: Config/Conductor.xml.
Default displays the manually enabled execution group. All reports are group-scoped.
Editor hosts use a stable project-path-derived host ID, retained across reload/workspace
switch; the connection session changes. One owner may claim each host channel.
Each Editor has one local connection; projects can share sources/Config, not mailboxes.
Compile results: CompileDiagnostic/<host-id>/<group-name--id>.txt.
Check results (UQL-REQUEST 2 with the sixth line CHECK, revision 75): CompileDiagnostic/<host-id>/Checks/<group-name--id>.txt.
Logs/archives: Outputs/Hosts/<host-id>/Logs/ and Registeries/.
Use the Request path shown in Workspace: Workspace/Hosts/<host-id>/CompileRequest/request.txt.
The old root mailbox is NOT consumed by addressed Editor hosts; old files are retained.
UQL-REQUEST 2 uses five lines: header / request ID / group / host ID / session ID.
An optional sixth line CHECK compiles the group without activating it (revision 75; such a host writes
Compile modes: activate check into host.txt); a sixth line ACTIVATE equals the five lines. Any other
sixth line is rejected before the host/session check and not consumed: it is rejected again until the
slot is replaced (use a fresh ID). channel.txt Request rejected: and host.txt Last error: then say
  Unknown compile mode '<text>' on line 6: expected CHECK or ACTIVATE.
where <text> is the line as read, cut to 64 characters (then ...), with control and line-separator
characters as ?; the report names no request ID. Seven or more lines, like any other malformed
request, get 'Expected UQL-REQUEST 1 / request ID / group, or UQL-REQUEST 2 / request ID / group /
host ID / session ID [/ CHECK or ACTIVATE].' A host before revision 75 has no Compile modes: line and
rejects six lines with its older text, never compiling them.
Read the current host.txt; mismatched host or stale session is refused. Version 1 remains
valid at a specific host mailbox (no session check), using the following three lines:
UQL-REQUEST 1
unique-request-001
Default
Use a fresh request ID. Sources must already be saved. The third line selects a Config
group; Default selects the manual group unless a named group already uses that name.
<UQL:manual> explicitly selects the manual group in that case.
Wait for the same ID in that host's latest.txt before replacing the mailbox. Read its
Result file for compile success, not completion of processes. Its Status/ reports
the active runtime; a failed compile can leave an older version running.
latest.txt Activation: names the group's CURRENT activation: after a failed compile that is
the older version still running (or none), not this attempt. Decide success from the Result
file's Status: active|failed (it also states Activation: none and Previous version running:).
With diagnostics it states Diagnostic counts: errors=<n> warnings=<n> skipped=<n> before the
lines; errors block the compile, warnings do not (LIMITOPT notes, compile warnings), and
skipped counts the warnings whose statement was left out (a terminal-only READ in a BLOCK).
When the UQL compile of a group with CSHARP functions succeeded, the C# step runs and the Result
adds one CSharp: line before Diagnostic counts: (the C# unit and the assembly budget, or why the
C# step failed; HELP "CSHARP FUNCTIONS").
A retained older version only continues what already runs (WAITs resume, DEFER cleanups run);
once its source changed it is stale, and a new START against it is refused with 'Source is
stale; compile before Execute.' until a compile succeeds.
A CHECK compile runs the same source selection, grants, UQL compile and C# compile (nothing loaded)
as an activating one but activates nothing: no hooks, initializers or AWAKE BLOCKs. It needs the same
grants (execute on every source; csharp, awake, edit, capture or events for the commands that need
them; UQL403 otherwise). Its Result, CompileDiagnostic/<host-id>/Checks/<group-name--id>.txt, says
Status: compiled (not activated) or failed, then Mode: check, with Activation: none; Previous version
running: yes means the group's active version keeps running. Its latest.txt adds Mode: check after
Group key: and says Activation: none and Runtime status: none even while the group is active (read
the group's Status file for the active version); its channel.txt report adds Mode: check after
Status:. A check never replaces the active version, its Status file or the group's Result file
(activating records have no Mode: line). A different text written into the group's source before
the check (a client staging the edit) still marks the active version stale like any edit (Source
stale: yes; START refused until it is activated again), and closing a grant the active version
needs stops it.
A request the host reads inside your atomic replace (a sharing violation, or its name briefly
missing) is not observed that poll: no rejection, it is read again at the next poll (host.txt
Request wait: names a mailbox it could not read past ioSlowMilliseconds; past ioRetrySeconds Last
error reports it, never a rejection receipt). A compile request whose Config or sources another process
holds waits unconsumed the same way; a Config that turns busy after the request was consumed fails that
compile explicitly ('Config busy; nothing was compiled; the previous version keeps running; resend with
a new ID'). UQL-REQUEST 1 runs only after the host wrote its bookmark (last-request.txt) in the same
poll; while that write fails transiently the request waits unconsumed, and a permanent failure (or one
past ioRetrySeconds) answers channel.txt 'Request: <id>' with 'bookmark cannot be written; not executed;
use UQL-REQUEST 2' (a resend of that ID is answered as already handled, never executed). Prefer UQL-REQUEST 2.
The host replaces latest.txt, operation.txt, host.txt and Status files atomically. Poll them with
short reads or Delete sharing (.NET FileShare.ReadWrite|FileShare.Delete): a reader holding a file with
the default FileShare.Read can block a replace, and so can an antivirus or indexer scan. A transient
failure (a sharing/lock violation, a replace that could not remove or move a file, a mapped section)
is retried for ioSyncMilliseconds; then the publication stays pending and later host ticks retry it
(HELP LIMITS), and the file keeps its previous content meanwhile. Receipts are must-deliver and ordered
per request: the CompileDiagnostic file before latest.txt, operation.txt before its channel.txt copy.
While the receipt of a consumed request is pending, the host consumes no new mailbox request (host.txt
Request processing: suspended; Request wait: names the receipt). A publication fails only when its error
is permanent or past ioRetrySeconds after at least 6 attempts (host.txt I/O failed:, Last error, the
journal, run evidence Failed); consumption then resumes, and a later success withdraws the report.
A failed replace that left the file missing is completed with a move,
and a temporary .uql-*.tmp file is never deleted while its target is missing (the error names it).
Check channel.txt and the CompileDiagnostic file for the same request ID before assuming a
request was lost.
host.txt advertises Run index: Workspace/Hosts/<host-id>/runs.txt. Compile/START results
point to Runs/<session>/<request>.txt when retained. Request acceptance, compilation,
activation, process completion, CHECK outcomes, capture readiness and file publication
remain separate facts. Completed is NOT a passed test. Old sessions are not current.
The bounded index owns only scalar/text metadata; shared artifact paths can be superseded
and registry paths remain mutable archives. It does not archive immutable output bytes.
Publication evidence records required/published revisions, errors and SupersededBy.
A revision a newer publication replaced while it was still unwritten (a recompile while the group's
Status file or output.txt was held, a newer Editor/API compile receipt) ends Unavailable with
SupersededBy naming the newer request: it is never left Pending. A run evidence file dropped
unpublished (an evicted run, or the host's pending cap) is counted in runs.txt Unpublished dropped runs;
a retained run's file is queued again once the cap has room.
It does not hash output bytes or preserve historical contents of shared paths. Published
means a successful host-observed write, not unchanged contents at a later read. Validate
request/session/activation and process state before interpreting output. Registry archives
append until explicitly cleared; capture names and other shared paths may be overwritten.
Legacy publicationHashes/maxPublicationHashBytes Config attributes are ignored and omitted
on the next save. Normal ALIAS reads and 16-byte instructions are unchanged.
Request journal timestamps use local [yyyy-MM-dd HH:mm:ss.fff UTC+HH:mm] (signed offset). Every
requests.log entry starts with one; the only line without it is the '[journal] N earlier entries
...' first line (revision 52, see the request journal below), which is not an entry.
Workspace/Hosts/<host-id>/host.txt identifies the host session with a throttled UTC heartbeat.
State distinguishes connected, compiling, reloading, updating and play-transition.
These are HOST lifecycle states, not UQL compile results. Request processing is suspended
during transitions; Request channel still describes the configured permission. Reload
and play-transition advertise Reconnect expected. Compilation start/finish and reload
callbacks publish changes before Editor updates stop. The file is last-reported evidence,
not a live probe: validate UTC, session and project identity. A stale compiling/reloading
file is not proof that compilation is still running, and connected does not mean that
request acceptance is enabled. Explicit disconnect or quit reports disconnected.
A full Editor restart reconnects only with the opt-in Connect at Editor start toggle
(per project, EditorPrefs UQL.Conductor.AutoConnect.<host-id>, off by default); the quit
reason then ends with "; connect at Editor start is on". Otherwise press Connect again.
Last disconnect is a bounded, single-line reason in the current session (or none).
It records the requested shutdown before disposal; State is authoritative about
whether closing completed. Busy callbacks or failed final flushes may leave the
host connected/retryable. Reload and Play transitions retain their lifecycle state.
The requests.log journal records the reason once per distinct normalized value
when request logging is enabled. A new session starts with none; its journal may
retain the previous session's reason. Validate session/UTC rather than treating a
disconnect request as completed disposal or an automatic restart.
Last error: is one bounded, single-line diagnostic, labelled workspace and/or service,
or none (current session). Each source is capped at 1024 UTF-16 characters; a longer
message ends with an explicit "... <truncated: shown of total characters>" marker. Controls
and line separators replaced by spaces. Changes publish immediately while the session
is owned; identical displayed errors do not add writes. This does not clear the error
on every healthy tick: only existing successful operations or explicit host clearing
do so, and clearing one source leaves the other intact. A new session starts with none.
host.txt is a deferred publication: a held file is retried on later ticks and ends at the newest
state, and while it is only pending nothing sets Last error. A permanent status-file failure cannot
report itself in that file; it is reported in Last error and withdrawn after a later successful write.
A failed file is retried every ioRetryMaxMilliseconds with its newest content and reported once (the
journal's io failed line), again only when its error changes, so a ReadOnly host.txt or a full disk
does not flood requests.log. Dispose, FlushRegisters and TryPublishRunEvidence, and publications while
the host is not connected, retry each file for about 62 ms within ioFinalFlushMilliseconds in total.
A manual Dispose (Disconnect) refuses only while must-deliver data is pending within its budget:
receipts, the request bookmark and append batches (registry archives, output.txt, edits.txt); its error names
them. Snapshots (host.txt, Status files, config.txt, requests.log, run evidence) and failed items never
block it: they are named in the journal, so a ReadOnly Status file cannot lock you out of Disconnect.
A refused Dispose keeps any only copy as a recovery file. A reload, Play transition, quit or forced
disconnect closes with CloseForTransition (revision 53), which never refuses: after a flush within
ioFinalFlushMilliseconds (the bookmark, the journal with its disconnect marker, receipts and host.txt
first) it spills what is still pending to Workspace/Hosts/<host-id>/Pending/<utc>-<seq>.txt (one new
file each: the bookmark, receipts, the final Status files with their Stop reason: line, registry and
output append batches with their expected byte length, the unwritten edit-log lines (kind edits), run
evidence and the unwritten journal lines; not host.txt or runs.txt). The next session of the same host ID
replays them in its constructor, before its first mailbox poll: it moves each file into Pending/Replaying/
first, writes receipts only from its immediate predecessor (the Session of host.txt before it connected;
they keep their old Session line), applies append batches only by length (an already applied batch is not
written again; another length is reported and the file kept for manual recovery; edits.txt, an append-only
log, instead takes the batch at its end after a NOTE line, and its replay never holds requests), merges the journal lines after
the earlier ones, and writes the spilled evidence, whose still Pending publications read 'spilled at
close; replayed by session <id>'. Until that is done host.txt shows Request processing: suspended
and Request wait: spill replay pending. A spill file that is not this host's, names a target outside
its channel or output folders, or is damaged is refused, reported and left in place. What could be
neither published nor spilled is named in the close summary and, by the Editor, in the next session's
Last disconnect: line (previous session lost N publication(s): ...).
Heartbeat: counts this session's 5 s heartbeats; it advances while the host is compiling, updating,
reloading or in a Play transition too (the host's Pump keeps host.txt fresh). I/O: is ok, or the slow publications (a call, a
publication or a deferral past ioSlowMilliseconds; also synchronous calls: the UQL-REQUEST 1 bookmark
write, CAPTURE and EXPORTREGISTER writes, mailbox, receipt, Config and source reads) and the lost ones
(dropped unpublished run evidence).
I/O pending: names the oldest pending publication (budget time, error class) and the requests whose
receipts are pending; I/O failed: names failed publications; Request wait: names the receipt the next
mailbox request waits for (or a spill replay, a Config restore or a deferred request). Config wait: names
a Conductor.xml that the external-update poll could not read for ioSlowMilliseconds or longer (held by
another process, or its name briefly missing inside a replace), how long and the error: meanwhile no
Config update is adopted and no mailbox request is consumed; it reads none once the Config is readable
(revision 53; 20 such polls in a row are also reported in Last error). Request IDs: remembered=N limit=N evicted=N is this session's duplicate
guard (requestIds, Limits preset, default 4096, range 1024..16384, revision 52): a resent remembered ID
is answered 'Already handled request: <id>'; past the limit the oldest IDs (and their rejection
reasons) are evicted and counted, the first eviction of a session adds one 'request-ID guard: ...'
journal line, and a resent evicted ID would run again, so use a fresh ID for every request. A
lowered value trims at the next request. The connect sweep deletes only exact .uql-<32 hex>.tmp
names older than one hour in this host's own directories where temporary files are created (not their history: run evidence
only of sessions written in the last 48 hours). An Editor
reconnect failure without an owned workspace remains in the UI, not an unowned old file.
Last error is last-reported evidence, not a liveness check or proof of current failure.
A 'Config update rejected: ...' Last error ends (revision 55) at the poll that accepts a repaired
Config or finds the accepted Config on disk again; requests.log keeps one 'config rejection ended'
line. A poll that observes new bytes only once (Config update: pending) keeps it.
It names the project folder/full path, configured product, Unity version, host kind and
Editor process ID where available; actual play/background/focus/frame state is separate.
Metadata is cached per connection, not resolved during instructions. An open owner.lock
holds the channel claim; a crashed process releases its OS handle. A remaining file alone
does not prove a live owner. Legacy low-level hosts without a host ID remain unclaimed.
Workspace shows local identity and a bounded compile/execution journal: sources, group,
AWAKE/Execute queueing, results and runtime transitions. Log compile requests toggles
new records, not execution. Config stores requestLogging. Request journal (revision 52):
requests.log keeps the newest journalEntries entries within journalCharacters characters, its first
line included (Limits preset workspace values, LIMITOPT refuses them; defaults 1024 / 524288, maximum
524288 since revision 54, below the MCP server's 1048576 read limit; HELP LIMITS). A changed value trims at the next entry; raising it
does not bring back rotated entries. One entry is at most 32768 characters; a longer one keeps its
start and ends with '… (+N chars; M total)'. Once entries have rotated out, the first line is
'[journal] N earlier entries were rotated out of this host's journal; it keeps the newest ...': not an
entry and without a timestamp (skip it when parsing), N counted across sessions (a reconnect continues
the loaded count). Both journal loads (at connect, and at a later poll for a journal held at connect)
read up to 1048576 characters (the revision 52-53 maximum) whatever the current value, so a journal written
under a larger value still loads, trimmed; a longer or damaged file is preserved and new records stay memory-only. Entries
rotated out before any write covered them are counted in one '... evicted from the ring
(journalEntries=N, journalCharacters=N) before requests.log could be written; they were never
published' line. A compile result line can rotate out: its absence in requests.log does not mean the
request never ran (raise journalEntries for deeper history). Disabled logging preserves old records:
it adds no entry, a lowered value trims nothing and requests.log is not rewritten. The last handled
file request is bookmarked per host, not in shared Config. Config edits still conflict-check.
A new session consumes the mailbox request an earlier session handled or answered (its
bookmark, or latest.txt/operation.txt naming that ID) without a new receipt or Last error;
an unanswered request addressed to another session is still rejected visibly. An earlier
receipt that exists but cannot be read defers the request; past ioRetrySeconds it is consumed
without execution and channel.txt names it ('not executed by this session; earlier receipt ...
unreadable'); the unreadable receipt itself is never written. A UQL-REQUEST 1 that an earlier
session's latest.txt or channel.txt names is consumed quietly too (a lost bookmark cannot make it
run twice), also while the other receipt cannot be read. When neither names it and one cannot be read,
it waits; past ioRetrySeconds it is rejected ('not executed; use UQL-REQUEST 2'). That rejection goes
into channel.txt only when channel.txt is readable and does not name it; when channel.txt itself is
unreadable it is written once channel.txt can be read (dropped when an earlier answer is found there or a
newer receipt replaced it), and the bookmark names the request, so no later session executes it.
The bookmark is read at connect without rewriting it; a bookmark that stays unreadable
fails the connect (typed transient) rather than risk running a request twice.
Old-session or stale status files are not proof of a running process. channel.txt records
handled/rejected requests; it starts with one 'Session: <id>' line (since revision 54 also for a
UQL-RUN operation report, whose own text already begins with it). No AssetDatabase refresh is required for UQL compilation.
The channel polls one bounded file, not a request directory. It is a single-writer
mailbox, not a durable queue.

EDITOR C# REFRESH (separate control channel; not a UQL command)
After updating Unity .cs files, Workspace > Refresh C# explicitly requests asset refresh
and asynchronous script compilation in stable Edit Mode. Accept file requests must
be enabled. It never stops Play Mode automatically or reactivates UQL groups.
While the user's Editor switch 'Allow interruptions' is off (HELP CONSENT) a mailbox request is
rejected before anything is issued (Error: 'C# refresh refused (UQL406): ...'); the Refresh C#
button itself is never refused.
External request: Workspace/Hosts/<host-id>/EditorRequest/request.txt, five lines:
UQL-EDITOR 1
unique-csharp-request-001
<current-host-id>
<current-session-id>
REFRESH_SCRIPTS
Read the matching EditorRequest/result.txt; accepted is only acknowledgment.
Compilation errors, missing lifecycle callbacks and observed reload/reconnection are
separate states. Even reloaded is NOT proof of exact source/binary freshness. Unity
may skip unchanged scripts; modal/OS blocking can defer Editor processing. This
mechanism neither launches Unity nor forces its focus. After reload, reread host.txt
and compile desired UQL groups with a fresh session/request ID before testing.
Each refresh state is also a REFRESH line in sessions.log, the session log (HELP SESSIONS).
Reference topic · Language referenceLIVEINSPECT display, lifetime, and refresh behavior.

INSPECT display, lifetime, and refresh behavior.

Where to use it

Reference topic; not a command

Example

HELP LIVE;

Detailed reference

From the in-tool help for LIVE.

LIVE / BLUEPRINT
INSPECT $boss;        // add a persistent view of this path, not a log stream
INSPECT $boss.Health; // scalar view
BLUEPRINT $boss;      // one-shot textual blueprint to output, no subscription

Open the LIVE tab. Select a view; Remove releases it. Clear LIVE removes all views.
UNINSPECT 1;          // remove the view with id 1
LIVECLEAR;  LIVEPAUSE;  LIVERESUME;
Settings: type names (health = 12; / int health = 12;), values, fields,
properties, method signatures, private/static members, modifiers, paths and nesting.
Default: fields + values, including private game fields; no property values or methods.
Enabling Properties lists members; Property names and Property get/set signatures are
independent display options. Reading property values is a SEPARATE opt-in.
Methods are never called by member enumeration; only their signatures are displayed.

Top-level INSPECT follows live global VALUE/PATH changes across session rebuilds.
INSPECT inside BLOCK/IF/loop captures the lexical context at registration (like BUCKET).
Captured bindings do not track later slot assignments; target field contents remain live.
Repeated top-level INSPECT of the same text replaces the view, keeping its id.
BLOCK captures create separate views. Default limit: 8; remove unused views.
Refresh is scheduled (default 0.25s, maximum 2 views per Tick), never during repaint.
Hidden window pauses LIVE reads, not scripts or TRACE processes.
Pause LIVE stops LIVE sampling only. Errors replace that view's text and retry
at the next interval. No repeated error lines are appended to output.
An explicit path can itself contain getters/methods: INSPECT repeats them!
Prefer field-only paths for side-effect-free observation. No automatic deep collection walk.
Reference topic · Language referenceUITerminal window, input, and session management.

Terminal window, input, and session management.

Where to use it

Reference topic; not a command

Example

HELP UI;

Detailed reference

From the in-tool help for UI.

TERMINAL UI
Ctrl+Enter: run. Enter: newline. Alt+Up/Down: input history. Run button also submits.
The input area wraps text and grows its vertical scroll range with the document.
Text +/- changes content and input font size. Settings controls width/height/input height.
Full toggles available-screen sizing. Drag the title to move the normal window.
Output, Explorer, LIVE, History and Settings share the bottom terminal input.
Successful submissions clear input. Explorer and History have draggable splitters.
Copy copies displayed History/LIVE text in those tabs; otherwise it copies output.
Explorer has Copy path. Collection pages have <32 / 32>, an index field and Go;
Enter in the index field jumps to that exact zero-based real/virtual index.
Transform rows have Children / GameObject branch buttons, not collection paging.
Their + button opens safe position/rotation/scale properties and optional component members.
Explicitly opening Transform reads its standard engine projection even with readprops=false;
extra reflected properties still obey readprops. Position mode never replaces the reference.
Only an opened Children branch pages through GetChild; closed branches are not read.
History Keep up follows new events; scrolling up disables it until explicitly resumed.
Compact + Tail parts (1..32) show the last N path steps in History without FIELD/PROPERTY
prefixes. These labels are visual only. Copy full path retains the executable path.
Settings has separate left-alignment and 0..100 padding controls for Explorer members,
GameObject selection and History members (defaults: left aligned, 36 pixels).
Ctrl/Cmd+Enter submission failures retain the original input and release keyboard focus.
Settings exposes blueprint options, live refresh and native read/query/observation/write
permissions. Native changes apply to the existing terminal session and captured query
policy without recompiling; ENABLE/DISABLE UNSAFE READ/WRITE declarations update the
same session profile. Existing read/write guards still apply. UNSAFE EDIT remains
required for native writes. Explorer opens native pages with read/query/observation permission.
Copied native rows are read-only; copy their source path for UNSAFE EDIT. No reads run in OnGUI.
Stop cancels scripts, not LIVE subscriptions. Pause LIVE stops observation reads.
Clear Output does not clear LIVE, aliases or registers.
Reset cancels scripts and removes definitions/LIVE/TRACE views; it does NOT undo game edits.
Close hides the window; script processes still Tick while the component is enabled.
Re-open using the configured hotkey or the host Show() method.
Output/history/source stores are bounded; use explicit RECORD for reports you need to retain.
Reference topic · Language referenceSAFETYGetter side effects, budgets, IL2CPP metadata, and release-build usage.

Getter side effects, budgets, IL2CPP metadata, and release-build usage.

Where to use it

Reference topic; not a command

Example

HELP SAFETY;

Detailed reference

From the in-tool help for SAFETY.

SAFETY / BUILD NOTES
This is a trusted developer tool, NOT an untrusted-script sandbox or authorization layer.
READ/INSPECT paths can call user getters/methods. EDIT changes live game state.
Property-values and static-member inspection are opt-in: getters/type initializers can run.
Blueprints never invoke listed methods or custom ToString. Closed collection views do
not enumerate; explicitly opening managed collections/pages does execute enumerators.
Native collection internals/raw pointers/fixed buffers are not explored by blueprint rendering.
Null/destroyed receivers produce a bounded view error; one member error does not hide others.
No perfect timing guarantee: a single user getter/host command may block the main thread.
Private member metadata and closed generic APIs must survive IL2CPP stripping.
Use correct link.xml/preserve rules for your game. A registered type name alone is not preservation.
Release players require explicit terminal opt-in. Do not expose this interface to an untrusted network.
Compiler diagnostics carry script/line/column; invalid submissions keep the current session.
Output is bounded and may be truncated. Blueprint text is descriptive, not loadable UQL code.
Reference topic · Language referenceQUERYInclusive ranges, COUNT, virtual indices, and scan budgets.

Inclusive ranges, COUNT, virtual indices, and scan budgets.

Where to use it

Reference topic; not a command

Example

HELP QUERY;

Detailed reference

From the in-tool help for QUERY.

MANAGED RANGE QUERIES
READ Enemies[FROM: 0 TO: 10];           // TO inclusive: at most 11 entries
READ Enemies[FROM: 0 COUNT: 4].Health; // select, then read one path per entry
VALUE $start = 0; VALUE $count = 4;
INSPECT Enemies[FROM: $start COUNT: $count].Health;
TRACE Enemies[FROM: $start COUNT: $count].Health;
BLUEPRINT Enemies[FROM: 0 COUNT: 4];
ITERATE FROM 0 TO 10 AS $i { LOG $i; LOG LINE; }
ITERATE Enemies[FROM: 2 TO: 6] AS $e INDEX $i { LOG $e.Health; LOG LINE; }
BUCKET $targets; ADD Enemies[FROM: 0 COUNT: 4].Health TO $targets;

One range per path/source expression, not one range for the whole nested SELECT.
A root source and EACH child source may each have one range; see HELP PROJECTION.
ALIAS/PATH remain single-target definitions.
Bounds evaluate once at command entry, or once per LIVE sample. TO clamps at collection
end; COUNT 0 / reversed ranges are empty. Negative collection starts/counts and Int32
overflow fail with a diagnostic. Numeric ITERATE increments by one; reversed is empty.
INDEX is the original real/virtual index. Dictionary ranges return VALUES; display rows
also show keys. Ordinary dictionary ITERATE still returns its original entries.
Indexable lists jump to FROM. Other enumerables use one iterator, stopping at TO.
Skipped elements consume ITERATE instruction budget. BREAK/STOP/error dispose iterators.
One-shot queries use MaxEnumerationCount (default 100000); output limits mark incomplete
results. User getters/enumerators are synchronous and cannot be forcibly interrupted.
Native ranges/ITERATE require NativeAccess.AllowQueries (Settings or ENABLE UNSAFE READ).
See HELP NATIVE.
Reordering a collection changes what a captured ordinal addresses; BUCKET is not a snapshot.
Reference topic · Language referencePROJECTIONSELECT row/column projection, scalar and pure text WHERE filters, frozen report chaining, partial coverage and cooperative execution budgets.

SELECT row/column projection, scalar and pure text WHERE filters, frozen report chaining, partial coverage and cooperative execution budgets.

Where to use it

Reference topic; not a command

Example

HELP SELECT;

Detailed reference

From the in-tool help for EACH.

SELECT — selected collection columns, not a live object graph
VALUE $report = null;
SELECT $enemies[FROM: 0 COUNT: 16] AS $enemy INDEX $index KEY $key
    FIELDS name = $enemy[NAME], health = $enemy.health, position = $enemy.transform.position
    WHERE $enemy != null && $enemy.health > 0 INTO $report LIMIT 32;
RECORD $report; REGISTER alive_enemies;

Shape: SELECT collection-or-range AS $item [INDEX $index] [KEY $key]
    [EACH $previousItem.childCollection AS $child [INDEX $childIndex] [KEY $childKey] ...]
    [LOOKUP storePath AS $peer [INDEX $peerIndex] [KEY $peerKey] ON peer == probe [&& ...] ...]
    FIELDS label = path [, label = path ...] [WHERE scalar-predicate]
    INTO $writableValue [LIMIT literal-integer];
INDEX and KEY may appear in either order in every SELECT/EACH header; each may appear only once.
Each requires a bare $name (not a member/index path). Repeated modifiers or missing aliases are compile errors.
One range per individual source path and an optional suffix use existing inclusive TO / COUNT rules.
The root and each EACH child source may have separate ranges; this is not a one-range
limit for the whole nested SELECT or an implicit Cartesian join.
Collection/bounds are read once at entry, and each selected row target once.
Columns run in source order. INDEX is the source ordinal; KEY is the dictionary key
(null for ordinary lists). BUCKET paths resolve once before WHERE/columns.
Item/index/key are query-local, not visible to subsequent BLOCK statements.

Labels must be unique and 1..256 characters; columns must be addressable paths,
not arbitrary expressions. WHERE supports scalar/Boolean operators, literals and
paths, with short-circuit AND/OR. Exactly StartsWith/Contains/EndsWith with one
argument are pure text predicates, not reflected method calls. They require actual
non-null strings, compare ordinal case-sensitive text and bound each operand to
4096 UTF-16 code units. Empty needles match a valid non-null string. Null/type/length
failures become FilterError rows, not false; guard null explicitly if desired.
Parenthesized receivers and string concatenation are supported without ToString
coercion (two strings only; an ordinary expression's '+' joins like C#, HELP VALUES). WHERE is bounded to 256 operand nodes and depth below 64.
SELECT also lowers one-argument HasAny(mask)/HasAll(mask) to pure enum membership:
WHERE $r["flags"].Value.HasAny($mask). Prepare $mask as an enum VALUE before SELECT.
Both operands must be actual enums or frozen enum descriptors with the same
assembly-qualified enum identity; mixed live/frozen operands are supported.
No automatic cell .Value, integer/string mask, custom conversion or game method
dispatch occurs. Null/mismatched types produce FilterError; known invalid types
are compile diagnostics. Zero enum mask: HasAny=false, HasAll=true. Non-[Flags]
enums can explicitly use these bitset operations; signed and UInt64 bits stay exact.
Use !HasAny for no matching bits, || for any alternative, && for all alternatives.
Example: VALUE $mask = [STATIC:UnityEngine.HideFlags].HideInHierarchy;
SELECT $objects AS $o FIELDS flags=$o.hideFlags
    WHERE $o.hideFlags.HasAll($mask) INTO $hidden;
Member getters remain trusted reads; the predicate does not invoke Enum.HasFlag.
These pure membership calls belong to query scopes, not general VALUE/IF intrinsics.
SCAN WHERE/MATCH also supports HasAny/HasAll, but only actual same-type enum
operands, not these frozen descriptors; see HELP SCAN for its sampling rules.
Other explicit methods/constructors, including method-backed aliases/captured
paths, are not query capabilities: prepare values first.
Property getters and enumerators remain trusted game code, not a security sandbox.
Reference equality is identity, not a gameplay Equals override. Select scalar struct
members for comparisons. Sorting, grouping and general multi-range joins are not added.

Managed nested selection (at most eight source levels, root plus seven EACH headers):
SELECT $managers[FROM: 0 COUNT: 4] AS $manager INDEX $owner
EACH $manager.Groups AS $group KEY $groupKey
EACH $group.Records[FROM: 0 COUNT: 16] AS $record INDEX $recordIndex
FIELDS owner=$owner, group=$groupKey, index=$recordIndex,
       id=$record.Id, generation=$record.Generation, health=$record.Health
INTO $report LIMIT 128;
Each EACH source must start at the immediately preceding item alias. Independent
sources and sibling Cartesian products are rejected; this is not JOIN or recursion.
Each source may have one range and suffix. Child bounds/source are read once per
parent opening; root preparation still precedes Pending publication, even if its
source/bounds read the destination's previous VALUE. Aliases are lexical/query-local,
unique across headers; current/future headers are not visible to earlier sources.
FIELDS/WHERE can read all active parents. Struct records need no reference roots:
select their scalar fields, not an arbitrary whole-struct deep snapshot.
Explicit FIELDS peer=$states[INDEX:$recordIndex], data=$byId[$record.Id] correlate
existing single-target paths. Unequal arrays/missing keys remain Missing cells;
ID/generation correspondence is explicit, never inferred from index/name equality.
The new multi-source branch rejects native sources BEFORE opening any cursor,
including native roots and open unsafe grants. Existing single-source native SELECT
is unchanged. There is no new automatic native traversal or developer provider.
Empty child collections emit no row. Null/missing/faulting child sources emit an
error row (index=-1 when no child ordinal exists), keep their parent route and
continue safe sibling branches. Those reports are Partial, not absence evidence.
Root failure stops the query. Shared referents keep separate routes; explicitly
bounded ancestry reuse is allowed without global reference deduplication.

Nested rows expose Origins: Level (zero-based), ParentLevel (-1 for root), Source
(template), ItemName (without $), Index, Key, Target, DeclaredType and RuntimeType.
DeclaredType is the source collection's known element/value type; RuntimeType is
the selected target's actual type, including an optional range suffix. Each origin
has frozen key/target evidence; unsupported whole-struct target metadata does not
invalidate successfully selected scalar fields. Origins retain no game references.
Source templates plus indices/keys identify sampled routes, NOT stable entity IDs
or guaranteed replayable UQL. Reordering/reused generations require explicit guards.
The compact route in .Text complements the full structured Origins API.

Keyed LOOKUP (DOD entity correlation; at most four per SELECT, after the SELECT/EACH headers):
SELECT $entities AS $e
    LOOKUP $records AS $r INDEX $ri ON $r.Entity == $e.Id && $r.Generation == $e.Generation
    LOOKUP $handles AS $h KEY $hk ON $hk == $e.Handle
    FIELDS id = $e.Id, hp = $r.Hp, owner = $h.Owner WHERE $ri >= 0 INTO $report LIMIT 64;
Grammar: LOOKUP storePath AS $p [INDEX $pi] [KEY $pk] ON peer == probe [&& peer == probe]{0,3},
either operand order. The peer side uses only $p/$pi/$pk with literal selectors; the probe side is a
row alias path, an outer VALUE path or an int/string/bool/char literal (no LOOKUP alias, method or
arithmetic). The store path is bound before SELECT and read once at entry, like the source/bounds.
Stores: 1-D zero-based arrays, IList, generic IList/IReadOnlyList (indexer + Count), IDictionary and
generic dictionaries, and frozen report Rows. Native containers (rejected before any access, even
with unsafe grants), HashSet/IEnumerable-only collections, strings and multi-dimensional arrays are
root failures: the SELECT ends Partial with zero rows and StopReason names the LOOKUP.
Build: each LOOKUP indexes its whole store before the first row, one element per VM step, through
the SELECT's shared scan counter (enumerationCount); a managed primary cursor opens after the builds,
so no source enumerator is held across them (a native primary source is snapshotted at entry, as
without LOOKUP, and never dereferenced later). Store/entry/enumerator failures and budget overruns
are root failures. Per entry: a null element or null key part counts as NullKeys; a missing member/
key/index or a non-key value counts as NotIndexed (it can never equal a valid probe, so a
heterogeneous store stays Decisive); a getter exception or read error counts as KeyErrors and makes
the index non-Decisive, as does incomplete upstream coverage of frozen Rows. The index is also
non-Decisive when no entry proves the ON shape (NotIndexed entries and not one indexed or null-keyed
entry: a misspelled peer member or a wrong key type is not a compile error) and when the store Count
changed during the build (StoreChangedDuringBuild: an insertion or removal can move an entry past
the build cursor). NotDecisiveReason says why.
Key equality is the hashable restriction of SELECT WHERE ==: exact integers of any width by value
(an int probe matches a long key), bool, char, ordinal string, same-type live enum and object
reference identity. Null and destroyed objects never match. An integral float/double entry key
below 2^53 in magnitude, or an integral decimal entry key, is indexed as that exact integer (WHERE
2 == 2.0 is true; a UInt64 probe, which WHERE refuses to compare with float/double, matches it by
exact value); a non-integral, NaN or infinite one is NotIndexed (it equals no probe), and a
float/double entry key at or beyond 2^53 is a KeyErrors entry (WHERE compares it through double
rounding). float/double/decimal probes, other structs, frozen descriptors and cells are not keys
(probe: KeyError; entry: NotIndexed): use a frozen cell's .Value. LOOKUP's own index never calls
gameplay Equals/GetHashCode; a dictionary re-read uses the dictionary's own comparer, like a
$map[key] peer path.
Probe: one VM step per LOOKUP right after each row's target read. Outcomes:
  Matched   exactly one entry; it is re-read (list ordinal or original dictionary key) and its
            peer parts are re-verified.
  NoMatch   no entry on a Decisive index, or a null probe part (null never matches).
  Ambiguous two or more entries share the key; never first-wins (add a generation part).
  Stale     the store Count changed since the build, or the re-read entry no longer matches.
  KeyError  a probe part failed to read or is not a key type.
  Undecided Matched or NoMatch on a non-Decisive index: neither is proven.
Ambiguous/Stale/KeyError/Undecided rows get Status LookupError (LookupErrors counts them); their
fields read with $p = null (ordinary Missing cells). A WHERE that names no LOOKUP alias ($p/$pi/$pk
of any LOOKUP) still judges such a row: false drops it as Filtered, so an excluded entity's bad key
never makes the result incomplete, and an error makes it a FilterError row. A WHERE that names one
cannot judge it, so the row is retained with WHERE skipped. Matched/NoMatch rows bind $p (or null),
$pi (ordinal or -1) and $pk (dictionary key or null) and run WHERE unchanged, so WHERE $pi < 0
keeps exactly the unmatched rows (plus any retained LookupError rows). A field rooted at a NoMatch
LOOKUP's item or KEY alias is LEFT JOIN null: Status Null, PathErrorCode KeyNotFound, Error
"LOOKUP $r: no match for (3, 1)", not an error here or after a whole-cell reprojection. A
FilterError of a WHERE that reads a LOOKUP alias, on a NoMatch row, says to guard with $pi >= 0.
TargetError rows are not probed. Uniqueness holds as of the build: an in-place key edit on a
different entry after the build, or a Count-preserving replacement during it, is not detected.
Evidence: Row.Lookups (Name, Status, Index, Key cell, Candidates, bounded Probe text, Error, IsError;
no per-row Source). Report.Lookups holds one UqlProjectionLookupSummary per LOOKUP: Name, Source,
Scanned, Entries, NullKeys, NotIndexed, FirstNotIndexed, KeyErrors, FirstKeyError, DuplicateKeys,
Built, UpstreamCoverageComplete, StoreChangedDuringBuild, NotDecisiveReason, Decisive, MatchedRows,
NoMatchRows, AmbiguousRows, StaleRows, KeyErrorRows, UndecidedRows and Text (outcome counts include
probed rows that WHERE dropped). Errors includes the retained rows' LookupErrors; CoverageComplete
also requires every LOOKUP to be Decisive. Without LOOKUP, Summary and Text are unchanged.
Cost: a LOOKUP reads its whole store (O(m) scan budget) even with ON $pk == $e.Id; the existing peer
path $byId[$e.Id] stays the O(1) route when absence really is an error (Missing). Duplicate ids in
one collection: SELECT $items AS $e LOOKUP $items AS $o ON $o.Id == $e.Id ... marks them Ambiguous.
LOOKUP is a keyed single-match correlation, not a JOIN: a row never fans out.

Default rows=128; LIMIT 1..4096 replaces that. group.MaxProjectionRows (default 4096, the
LIMIT ceiling) caps both; a host that lowers it gets the reduction stated in StopReason,
e.g. "SELECT row limit reached (LIMIT 1000 reduced to the host row cap 128 (MaxProjectionRows))".
Hosts may set MaxProjectionFields (128), MaxProjectionCharacters (aggregate retained
characters, default 1048576, at most 4194304) and MaxProjectionCellCharacters (4096);
AccessOptions.MaxEnumerationCount limits scanning. In the Conductor these come from the
Limits preset keys selectCharacters, selectCellCharacters and enumerationCount (HELP LIMITS).
Each VM step advances one source element (including skips) or reads one column.
With EACH, opening/closing a level is also a cooperative VM step. One shared scan
limit includes parent elements, child elements, prefix skips and nonindexed EOF
attempts; it never resets per parent. Origins use the shared character budget.
Work may yield across scheduler steps: this is NOT an atomic frame snapshot.
Use an appropriate HOOK/host budget when exact-point execution is required.
After the row cap, unknown-length sources are not probed again; coverage is partial.
Native SELECT uses existing query permission (ENABLE UNSAFE READ). Native adapters
may eagerly snapshot; NativeScanCost/NativeSourceCount disclose that cost.

LOG/RECORD $report prints its bounded table; .Text is optional.
$report.Rows[0]["health"].Value and .CellsByName["health"].Value read a frozen column.
Report properties: Source, Activation, Completion, SourceComplete, CoverageComplete,
UpstreamCoverageComplete, UpstreamCoverageSummary,
DataTruncated, TextTruncated, Scanned, Visited, Returned, Filtered, TargetErrors,
FilterErrors, CellErrors, SourceErrors, LookupErrors, Errors, NativeScanCost, NativeSourceCount,
MaxRows, MaxFields, MaxCharacters, MaxCellCharacters, MaxScanned, StopReason,
Columns, Rows, Lookups, Summary, Text. Rows contain Index, Key, Target, Root, Status,
FilterError, Cells, CellsByName, Origins (empty on single-source rows) and Lookups
(empty without LOOKUP).
Key/Target/Cells are frozen UqlObservationCell values.
Missing/getter/filter/source errors stay explicit, not silently false.
CellErrors counts retained failed/truncated selected cells, including unread
placeholders sealed on cancellation or aggregate exhaustion, once per column.
Unvisited rows are not fabricated; target/filter/source errors have separate counters.
SourceComplete means requested-source exhaustion, not successful values.
CoverageComplete additionally requires Complete, no data truncation, no errors and
UpstreamCoverageComplete. Snapshot row collections that implement IUqlQuerySourceCoverage
carry their producer's coverage into SELECT, including filtered/empty results; finite
enumeration alone cannot restore whole-scene coverage. Ordinary collections have no
upstream claim and default to true; SourceComplete still describes local exhaustion.
To narrow frozen discovery results without repeating discovery:
VALUE $names = null; VALUE $narrow = null; VALUE $needle = "Controller";
SELECT $scan.Rows AS $r
    FIELDS name = $r.RootTypeName, root = $r.Root, ordinal = $r.Index
    WHERE $r.RootTypeName.Contains($needle) INTO $names;
SELECT $names.Rows AS $r
    FIELDS name = $r["name"].Value, root = $r["root"].Value
    WHERE $r["name"].Value.StartsWith("Game.") INTO $narrow;
These filters inspect retained strings, which may already be clipped; they do not
follow stored ROOT/path text into game objects. Projection of .Value copies the
retained payload, not the source cell's Status/Error or original row identity.
To preserve complete cell evidence, select the cell instead of its .Value:
SELECT $names.Rows AS $r FIELDS name = $r["name"], root = $r["root"]
    WHERE $r["name"].Value.Contains($needle) INTO $narrow;
Only selected fields use this transfer. The new column Name is the selected label;
Path, TypeName, Status, Error, PathErrorCode, Step, ReferenceId and the immutable
payload retain their original meaning. Numeric/enum/reference descriptor atoms
stay frozen, not tokens for their wrapper objects. No original cell/report or
game graph is retained. Smaller output budgets may clip strings/errors; Value
string clipping becomes Truncated, existing error statuses never become Value,
and DataTruncated discloses any new clipping. Source cells are not modified.
Row Index/Root/Key/Target/Status/FilterError are not implicitly replaced by upstream
row metadata: select those explicitly when needed. Whole-cell transfer does not
copy a snapshot's CaptureId/Activation/timing or grant CHECK snapshot ownership.
Ordinary OBSERVE, target/key freezing and raw .Value behavior are unchanged.
Upstream incomplete coverage still propagates, even if the filtered output is empty.
Live collection paths may read trusted getters; no frozen-read claim applies to them.
Unlike SCAN's once-at-entry outer VALUE sampling, SELECT filter VALUEs keep their
existing per-row evaluation and may change between cooperative scheduler steps.
SELECT/SCAN WHERE comparisons ==, !=, <, <=, >, >= accept integral/decimal pairs
exactly when UInt64 or decimal is involved; no lossy double promotion occurs.
Example: WHERE $r["flags"].Value.Bits != 0. The descriptor itself is not a number.
Frozen enum descriptors print their member name(s) (.Name, captured when frozen, e.g. "Complete"
or "A, B"); undefined values print Type(0xBits). Name is text only; comparisons use type and Bits.
Mixing UInt64/decimal with float/double is rejected; prepare an explicit common
domain before the query. Known types produce compile diagnostics, reached dynamic
types produce FilterError/read gaps; short circuit still applies. Existing supported
integer/float/double combinations retain VM behavior. Arithmetic/unary operations,
enum/descriptor conversion and general IF/VALUE expression comparisons are unchanged.
TextTruncated concerns rendered text; frozen data has separate coverage indicators.
STOP/failure/disposal publish Cancelled for an unfinished owned destination.
The pending-report identity prevents an older operation overwriting another writer.
Reports retain immutable scalars/metadata, not gameplay graphs, enumerators or frames.
Root text is session-specific and uses the existing weak root registry.
Reference topic · Language referenceCLEANUPProcess-owned DEFER CALL, cancellation, bounded cleanup, secondary errors and temporary test resources.

Process-owned DEFER CALL, cancellation, bounded cleanup, secondary errors and temporary test resources.

Where to use it

Reference topic; not a command

Example

HELP CLEANUP;

Detailed reference

From the in-tool help for CLEANUP.

DEFER CALL / PROCESS CLEANUP
DEFER CALL Release($resource); captures the argument values when the instruction executes.
It does not execute Release immediately and cannot use INTO. Owned arguments remain
reachable until this process finishes; no released local frame or borrowed buffer is retained.
CALL registrations belong to the same process. START creates its own cleanup owner.
There is no DEFER { ... } body form: put the statements in BLOCK Cleanup { ... } and write
DEFER CALL Cleanup(args); (DEFER { is one diagnostic and its braces are skipped). DEFER without
CALL (DEFER Cleanup(); DEFER LOG 1;) is one diagnostic too; the rest of that statement is skipped.

Completion, command failure, STOP, ABORT, replacement and group disposal drain registrations
in reverse order before output End, terminal history and file-channel terminal evidence.
A wait (including a timeout that resumes the process) does not itself run cleanup.
An entry is removed before execution and never retried; errors do not block earlier entries,
except that exhaustion of the shared cleanup budget skips the remaining entries explicitly.

Cleanup uses fresh frames and the SAME process ID, output and RECORD buffer. It cannot WAIT,
CAPTURE GAME VIEW, START, TRIGGER, STOP, ABORT or DEFER; reachable CALL blocks are checked at compile time and
the VM also rejects these operations. Bounded CALL, conditions, EDIT, INVOKE, LOG, RECORD
and REGISTER can be used. Normal permission rules still apply to all cleanup source.

Group limits: MaxCleanupRegistrations = 32 (1..1024), CleanupInstructionBudget = 256
(1..65536), MaxCleanupCallDepth = 16 (1..256). Configure them on an idle owning-thread host.
The cleanup budget is an ADDITIONAL bounded allowance, not the regular scheduling budget.
It cannot interrupt a blocking user method/getter or recover from a Unity/OS crash.

Process diagnostics: CleanupAttempted, CleanupCompleted, CleanupFailed, CleanupSkipped,
CleanupInstructions and CleanupDiagnostics; snapshots carry text-only CleanupErrors.
CleanupDiagnosticsOmitted reports dropped diagnostics beyond the process cap (1025).
Individual process diagnostic messages are clipped at 4096 characters with an explicit marker.
File-run evidence keeps up to 16 errors at 2048 characters each within its global metadata
budget; CleanupErrorsOmitted and incomplete metadata coverage disclose further omissions.
The original error, return value and terminal source location are retained. A failed cleanup
turns an otherwise Completed process into Failed; an already Stopped process stays Stopped.
Keep developer-side idempotent End and cooperative deadman cleanup as a second safeguard.
Optional C# bridge template: Templates/Testing/UqlTestInputBridge.cs, not a core provider.
Reference topic · Language referenceNATIVENative queries, permissions, and UNSAFE EDIT boundaries.

Native queries, permissions, and UNSAFE EDIT boundaries.

Where to use it

Reference topic; not a command

Example

HELP NATIVE;

Detailed reference

From the in-tool help for NATIVE.

NATIVE COLLECTION ACCESS (owner-controlled lifetime)
ENABLE UNSAFE READ;  // script-level; enables selection, queries and range LIVE/TRACE
ENABLE UNSAFE WRITE; // script-level; grants writes, UNSAFE EDIT still required
READ NativeArray[0];
READ NativeMap[KEY:29];       // exact key; INDEX is enumeration position
READ NativeMultiMap[KEY:29]; // managed list of the values for this key
READ NativeArray[FROM: 0 COUNT: 8];
ITERATE NativeSet AS $item { LOG $item; NEWLINE; }
UNSAFE EDIT NativeArray[0] = 12;
UNSAFE EDIT NativeMap[KEY:29].Health = 80;

DISABLE UNSAFE READ;
DISABLE UNSAFE WRITE;
These are compile-time group declarations like PRINTOPT, not executable on/off scopes.
Place at script top level, outside BLOCK/IF/ITERATE. Last READ/WRITE declaration in source
input order wins for the WHOLE group, regardless of its position relative to commands.
Do NOT put ENABLE and DISABLE around commands to form a runtime region: the final value
applies before execution starts. BLOCK-local declarations log a diagnostic and are skipped.
READ controls AllowReads + AllowQueries + AllowObservation together; WRITE controls only
AllowWrites. Disabling READ also prevents writes that require a validation read.
Ordinary groups receive their own declared permission profile. Terminal submissions and
Settings update one live session profile, including already captured query watches.
No permission declaration opcode or new per-read setting parsing is introduced.

Host: PathExecutionOptions.NativeAccess = new UqlNativeAccessPolicy {
    AllowQueries = true, AllowWrites = true, AllowObservation = false };
AllowReads defaults true, retaining explicit native selection behavior. Other grants
default false. Settings > Native access updates the current terminal session, including
already captured query policies; no recompilation required. Host component checkboxes
set initial defaults. Scripts may declare ENABLE/DISABLE UNSAFE READ/WRITE too.
No embedded-script permission ceiling or extra security framework is implemented here.
UNSAFE is acknowledgement, not a grant. Read/write guards remain effective.
Plain EDIT rejects native element writes, including dynamically resolved targets.
Writes: existing NativeArray/Slice/List indices, NativeHashMap/ParallelHashMap keys.
Nested struct edits copy back to the native element. No insertion, resize, queue/set
mutation, multimap record replacement, ReadOnly or ParallelWriter writes.

New queries/ITERATE copy selected data into a bounded managed snapshot at command entry.
No native enumerator survives WAIT/yield/BREAK. Range maps yield values + source INDEX;
plain map ITERATE yields copied Key/Value entries. These copies are not writable paths.
Use an explicit source index/key to write. BUCKET ADD captures paths, not object snapshots.
Snapshot limit is MaxEnumerationCount; skipped enumeration consumes the limit too.
NativeQueue uses a temporary whole-queue copy; the entire Count must fit the limit.
Queue temporaries and enumerators are released in finally, never the original container.
Native range INSPECT/TRACE additionally requires AllowObservation. Each sample makes a
fresh snapshot. Explorer explicitly opens 32-item pages with the same three read permissions;
indexable sources jump directly, enumerators stop at the page end, queues copy within budget.
Closed native rows never call Count/IsCreated/enumeration. Opened rows show known Count.
Page copies and their fields are read-only in Explorer; copy the source path for UNSAFE EDIT.
Whole native containers remain opaque in automatic text blueprints and whole-container TRACE.
Existing explicit single-element paths retain their native read guard behavior.

HOOK is optional and grants no native permission. You must arrange job synchronization,
storage lifetime and compatible thread access. IsCreated is not a stale-copy guarantee.
No automatic JobHandle.Complete, pointer access, safety bypass or crash recovery.
UNSAFE does NOT turn off type/bounds/existing-key/Unity checks. Release Unity checks may
be absent; concurrent dispose/resize/write can still crash or corrupt memory.
Reflection requires preserved concrete generic methods/types in IL2CPP. Missing/ref-only
APIs produce diagnostics. Native selection APIs are not a sandbox for arbitrary methods:
explicit game method calls/getters/host commands can have their own side effects.
Reference topic · Language referenceVALUESUnity value constructors, immediate method expressions, trusted-host prepared expressions, TYPE metadata, enums, tuples, and numeric culture.

Unity value constructors, immediate method expressions, trusted-host prepared expressions, TYPE metadata, enums, tuples, and numeric culture.

Where to use it

Reference topic; not a command

Example

HELP VALUES;

Detailed reference

From the in-tool help for VALUES.

TYPED VALUE CONSTRUCTORS
EDIT $position = p(99, 99, 99);   // p is an alias for v3; it does not select a Transform
EDIT $position = v3($x, $y + 1, 0);
EDIT $position = (99.5, 88, 88); // contextual Vector3, same syntax in inspector
v2(x,y); v3(x,y,z); v4(x,y,z,w); v2i(x,y); v3i(x,y,z)
quat(x,y,z,w); euler(x,y,z)     // Euler degrees -> Quaternion; quat is not normalized
color(r,g,b[,a]); color32(r,g,b[,a]) // alpha defaults 1 / 255; color32 uses 0..255 ints
rect(x,y,width,height); bounds(v3(center...),v3(size...))
recti(x,y,width,height); boundsi(v3i(position...),v3i(size...)); mask(bits)
Use constructors in expressions, VALUE, EDIT, READ/LOG, BLOCK arguments, or immediate
method-call arguments, not alone as commands. Constructor arguments are normal
expressions; values must be finite.
VALUE $valid = $terrain.IsTillable(v3i(-3, -1, 0));
INVOKE $boss.TakeDamage($baseDamage + 2);
VALUE $health = $boss.GetChild($index + 1).Health;
VALUE $metadata = TYPE(System.String); // literal type name -> System.Type
VALUE $name = TYPE(System.String).Name;
TYPE(...) takes a literal qualified/registered type name; it is not a dynamic cast or
a constructor. Ordinary reference [AS:Type]/[CAST:Type] selectors remain available.
EDIT $stats = tuple(100, "alive", p(1,2,3));
The existing target supplies the exact ValueTuple type. Items convert before assignment.
Parenthesized comma expressions also create contextual literals: (100, "alive", (1,2,3)).
The target may be a supported Unity struct OR ValueTuple. (x+1) is still grouping.
Long tuples use flat arguments (Rest handled internally); nested tuples use tuple(...) or (...).
Unity.Mathematics float/double/int/uint/bool vectors (2..4) and quaternion also accept
contextual components, without a hard package dependency. Their fields must be preserved.
Mathf is a static helper, not an editable value type. Its numeric results are scalar values.
Always use decimal '.', never decimal ',' or thousands separators. Integers must be exact.
A tuple stored in an untyped VALUE remains a contextual literal until a typed assignment.
Immediate tuple(...) method arguments convert against a supported closed ValueTuple
parameter. Known item shapes help overload binding; unknown shapes are handled
conservatively, and ambiguous candidates produce diagnostics rather than a guessed match.
Numeric literal method arguments retain existing checked literal conversion. Arithmetic
arguments instead use their actual/promoted expression type; they do not gain implicit
literal narrowing merely because the resulting number happens to fit. When no overload
takes the arguments as they are (revision 54), binding then tries C#'s implicit numeric
widenings (int -> long/float/double/decimal, long -> float/double, float -> double, char ->
int, ...), and after that a double value for a float parameter: C# needs a cast there; UQL
converts when the value fits the float range (rounded to the nearest float) and otherwise
fails naming the argument ('Argument 2: the double value 1E+300 does not fit the float
parameter'). Bind time only; every call that bound before keeps its target.
OVERLOADS AND WIDENING: 'as they are' includes boxing to object and a numeric literal's checked
conversion, and that pass decides first (an ambiguity there ends the search). So, unlike C#,
an int VALUE binds M(object) when it exists beside M(long) and M(double), and an int literal
with only M(long) and M(double) is an Ambiguous overload (C# picks M(long) in both cases).
C#'s better conversion target decides only between widenings: an int VALUE with M(long) and
M(double) (no M(object)) binds M(long); signed before unsigned. An argument typed int? at bind
time never widens to a non-nullable long (int? -> long? does; a late-bound int? that holds a
number is an int at run time and widens, a null never binds a long). An enum never widens.
Other narrowings (long -> int, double -> int, decimal -> float) are not added: use
[STATIC:System.Convert].ToInt32(x) or a typed VALUE. A failed bind ends with the first
argument that does not fit each nearest overload, counted from 1 over the supplied arguments:
'Argument mismatch: Queue(Single x, Single y): argument 2 is System.String, parameter 'y'
takes System.Single'. General C# numeric casts are not added. C# in parameters bind directly by their element type (the runtime passes the
method a copy of the value, never a reference to a VALUE or the source); when two
overloads of one class differ only in by-value versus in passing,
the by-value one is chosen, as in C#. Like C#, an in overload whose element type matches
exactly now beats a sibling that needs a conversion (object, an interface, Nullable, long
for an int literal), and an in method declared in a base class never displaces an
applicable method of a more derived class (C#'s most-derived rule). Unlike C#, a base
class's by-value method still competes with a derived class's methods by conversion
(unchanged): with Base.M(int) and Derived.M(in int), M(5) binds Base.M(int) where C#
picks the derived one. Crossing modes (M(in int, int) + M(int, in int)) stay ambiguous. An instance call on
a struct receiver (FixedList, UnsafeList, any struct) runs on a copy of the receiver, as
for every method: a mutating call changes only that copy (a growing UnsafeList<T>.Add can
even free the buffer the source still points to). Arbitrary constructors, out/ref arguments
(including interop [In] ref and C# 12 ref readonly) and generic-only methods are not
bound directly; call them through reflection (HELP "REFLECTION CALLS"), no C# bridge.
A receiver whose declared type is an interface (a static property or a typed VALUE of an interface type) can call
System.Object's instance methods GetType, ToString, Equals and GetHashCode, as in C#; a method the interface
redeclares wins. [TYPE] still reads the actual type of any receiver.
Trailing C# optional parameters may be omitted only when their preserved metadata
provides a usable concrete default. Defaults are prepared once at binding (or a new
runtime-type binding), not discovered during each invocation. Supplying null is an
explicit argument, not an omission. default(struct) is zero-initialized without calling
a user constructor. Missing.Value/DBNull or [Optional] without a concrete default
requires an explicit argument; required omissions name the missing parameter.
A viable exact-count overload takes priority over every default-filled overload.
Within either tier, supplied argument conversion/specificity decides as before;
equal candidates remain ambiguous. Fewer omitted defaults are NOT a tiebreaker.
Only trailing omissions are supported: no named arguments or skipped middle arguments
(out/ref and generic-only methods: HELP "REFLECTION CALLS"). An omitted trailing C# params array is
passed as an empty array of its element type, as in C# (so OpenProject(path) binds); it ranks
below default-filled optional overloads, as C# prefers the normal form. Since revision 54
an expanded params list is packed like C# when no normal form applies: the arguments from
the params position on go into a new array of its element type per call (an array argument
still binds the normal form). A C vararg (__arglist) method is never a candidate (reflection
cannot call it). BLOCK parameter rules
are unchanged. The same binding applies to clean paths and immediate expressions.
VALUE $messages = [STATIC:UQL.Runtime.UqlConsoleLog].Read($mark, 50);
// Read(afterSequence = 0, max = 100, minimumSeverity = 0): final severity defaults to 0.
TEXT FROM VALUES: in scripts, the terminal and the host CompileExpression API, '+' with a string on
either side joins like C# string concatenation (revision 71):
- null becomes empty text;
- numbers, decimal, bool, char and enum values use the invariant culture (1.5 stays 1.5 in any Editor
  culture, bool is True/False; float digits follow the runtime): the one deviation from C#;
- any other value (a class or struct, a gameplay object, a UnityEngine.Object, a collection, a Type)
  joins as its own ToString(), which can run game code; a null ToString() result joins as empty text;
- a destroyed UnityEngine.Object joins as LOG LINE prints it (null), so one object never reads
  differently in LOG and in a join (LOG of a live object still prints UQL's display, not ToString());
- a ToString() that throws fails the process with the exception's text, like a failing getter or call;
- a BUCKET entry (a captured path) is not a value: RESOLVE $e INTO $v; first (refused with that hint).
At compile time string + any known type is a string; '+' is UQL212 only when the other side is not a
value (a void call result, a [STATIC:] scope, a captured path). The other operators are unchanged. SCAN WHERE, SELECT WHERE and range bounds keep joining two strings only, with their caps
(HELP SCANNING): build such text in a VALUE first. For several values String.Format or String.Concat take any number of arguments:
VALUE $line = null;
$line = "hp = " + $hp + " (" + $alive + ")";
$line = "target: " + $go;        // the object's ToString(), as in C#
$line = [STATIC:System.String].Format("{0} = {1} ({2}, {3})", $name, $value, $min, $max);
$line = [STATIC:System.String].Concat($name, " = ", $value);
Format uses the current culture (a tr-TR Editor prints 1.5 as 1,5): pass [STATIC:System.Globalization.CultureInfo].InvariantCulture
as the first argument for culture-independent numbers:
$line = [STATIC:System.String].Format([STATIC:System.Globalization.CultureInfo].InvariantCulture, "{0}", $value);
FLAGS ENUM ARGUMENTS: expressions have no bitwise '|'. Parse a comma list of names (C#'s [Flags]
text form) once into a VALUE and pass it; Enum.Parse(TYPE(T), text, true) ignores case:
VALUE $flags = null; VALUE $field = null;
$flags = [STATIC:System.Enum].Parse(TYPE(System.Reflection.BindingFlags), "Instance, Public, NonPublic");
$field = TYPE(System.String).GetProperty("Length", $flags);   // a PropertyInfo; null when there is none
An enum member of a game object is changed with EDIT $x.Flags |= A, B; (HELP EDIT).
Invocation uses frame-owned scratch, not a shared mutable cached argument array;
reflection/boxing and first scratch allocation do not promise zero GC.
No runtime MakeGenericType, Emit or new AOT specialization. Reflection metadata of the
target ValueTuple/fields must still be preserved for IL2CPP, like other reflection paths.
These constructors create values; surrounding immediate script expressions may invoke
methods. Compile-time parsing/binding and flat VM execution do not promise zero GC;
boxing, constructors, reflection calls and requested output may allocate.

TRUSTED-HOST COMPILE-ONCE EXPRESSIONS (C# API, not a UQL keyword)
var compiled = group.CompileExpression("$boss.health > $threshold",
    new UqlExpressionOptions {
        Imports = new[] { "boss" },
        Parameters = new[] { new UqlExpressionParameter("threshold", typeof(float)) },
        SourceName = "health-probe.expr"
    });
if (compiled.Success) {
    using (var plan = compiled.Plan) {
        if (plan.TryEvaluate(out var result, 50f)) Console.WriteLine(result.Value);
        // Reuse the same plan with another typed argument; no recompilation:
        if (plan.TryEvaluate(out var next, 75f)) Console.WriteLine(next.Value);
    }
}

The group must already be initialized, active and idle on its owning thread for both
compile and evaluation. This API does not initialize/recompile/replace the group, replay
declarations, attach hooks, start processes or automatically print/record its result.
Compilation returns Success/Plan/Diagnostics. Evaluation returns Success/Value/Error,
ValueType and Instructions. A default result is not success. Handle both failure paths.
Only explicitly imported group globals are available as $symbols; BLOCK locals cannot
be imported. ALIAS/PATH/VALUE/BUCKET bindings stay live in that original activation.
Parameter values must be assignable to their declared types before gameplay reads run;
there is no implicit numeric argument coercion (float parameters need float values).
Names may include '$'; duplicates and import/parameter name collisions are diagnostics.

The disposable plan weakly binds its original group and cannot migrate to a new group
or replacement activation. Expired/disposed/aborted owners and callback/concurrent reentry
are rejected. Returned references belong to the caller, not to a deep object snapshot.
Temporary roots/parameters/register references are released after each evaluation.
The plan does not cache the owner's State/Root/frame. Inherited developer-registered
reader delegates/metadata may themselves capture objects; the host owns those provider
and closure lifetimes. Weak group binding is not a blanket no-object-retention guarantee
for custom providers.
Fresh access/call frames allocate; this API is compile-once, not zero-GC.

Options: MaxSourceLength defaults 65536; MaxInstructions defaults 10000. SourceName
identifies diagnostics. Optional Permissions checks Execute for that host source at
compile time; original script permissions are unchanged. Explicit imports/this policy
are NOT a sandbox: implicit roots, getters and invoked methods can expose/change game
state. Only trusted/authorized hosts should provide expressions. Policy revocation after
compilation does not automatically invalidate a plan; dispose it when host access changes.
Only one expression is accepted: no statement fragment, EVAL keyword, assignments,
WAIT/LOG/EDIT commands or general C# evaluator. Existing constructor/signature limits
still apply. User methods/getters cannot be interrupted by the expression instruction limit.
Reference topic · Language referenceREFLECTION CALLSOut/ref arguments, generic-only methods and arbitrary constructors through ordinary method expressions on System.Reflection objects (MakeByRefType + MethodInfo.Invoke, MakeGenericMethod, Activator.CreateInstance): no C# bridge, refresh or domain reload. C# in parameters need no recipe (HELP VALUES). A failed bind names the by-ref parameter or generic definition and points here.

Out/ref arguments, generic-only methods and arbitrary constructors through ordinary method expressions on System.Reflection objects (MakeByRefType + MethodInfo.Invoke, MakeGenericMethod, Activator.CreateInstance): no C# bridge, refresh or domain reload. C# in parameters need no recipe (HELP VALUES). A failed bind names the by-ref parameter or generic definition and points here.

Where to use it

Reference topic; ordinary method expressions, no new grammar

Example

HELP "REFLECTION CALLS";

Detailed reference

From the in-tool help for REFLECTION CALLS.

REFLECTION CALLS (out/ref arguments, generic-only methods, constructors)
Method expressions bind by-value and C# in parameters of non-generic methods directly.
C# in parameters need no recipe (HELP VALUES). Three call shapes are not bound directly,
yet need no C# bridge, refresh or domain reload: call them through ordinary method
expressions on System.Reflection objects. Live-verified in the Unity Editor (Runtime
revision 44); the offline tests run the same lines on .NET.
- out/ref: build the parameter Type[] with TYPE(E).MakeByRefType() in each by-ref slot
  (also in the in slots of such a method), select the overload with
  TYPE(T).GetMethod(name, $types), then $m.Invoke(target, $args) (null target for a
  static method). Invoke writes out/ref results back into the object[]: read $args[i]
  afterwards. For ref/in slots, store the input in $args[i] before the call.
- generic-only methods: TYPE(T).GetMethod(name).MakeGenericMethod($typeArguments), then
  Invoke. When the name is overloaded GetMethod(name) is ambiguous: pick the definition
  from TYPE(T).GetMethods() by Name, IsGenericMethodDefinition and GetParameters().Length.
- constructors: [STATIC:System.Activator].CreateInstance(TYPE(T), $args). Reflection
  applies only widening primitive conversions (an int fits a long, float or double
  parameter) and never narrows: an unsuffixed fractional literal such as 1.5 is a double
  and fails for a float parameter ("Constructor on type ... not found"). Write 1.5f or
  [STATIC:System.Convert].ToSingle(x). Unity value constructors (p/v3, color, ...; HELP
  VALUES) stay the short form for the supported Unity values.
- arrays: [STATIC:System.Array].CreateInstance(TYPE(E), n), then INVOKE $a.SetValue(x, i);
  (a method call is never a bare statement).
A failed bind whose only fitting candidates take out/ref parameters (interop [In] ref and
C# 12 ref readonly included) or are generic definitions says so, for example "Not directly callable: TryParse(String s, out Int32
result) has out parameter 2 'result'", and points here. Candidates that reflection
cannot invoke either (a byref-like Span parameter or return, a ref return) are not listed.
BindingFlags for GetMethod/GetField/GetProperty: $flags = [STATIC:System.Enum].Parse(
TYPE(System.Reflection.BindingFlags), "Instance, Public, NonPublic"); (a comma list; HELP VALUES).
Keep the C# bridge (UQL-AGENT-GUIDE.md section 2) for what UQL cannot express: delegates,
interface implementations and callbacks, byref-like (Span) or ref-return signatures,
named arguments and long multi-step workflows (expanded params lists bind directly since
revision 54).
Unity ids: UQL report ids and [INSTANCEID] are Int64 on every Unity version, and a call never
narrows an integer argument (long -> int), so an id does not bind to a Unity int parameter such as
Resources.InstanceIDToObject(int). Use FIND INSTANCEID $id INTO $o; or
[STATIC:UQL.Runtime.UqlUnityIds].Require($id) (HELP INSTANCEID), ROOT/paths for repeated access,
and [STATIC:System.Convert].ToInt32(x) for another int parameter below Unity 6000.6.
Calls run with their usual side effects. IL2CPP players: reflection metadata must survive
stripping, and MakeGenericMethod over value-type arguments may need an existing AOT
instantiation; the recipe is verified in the Editor only. The generic example below uses
an Editor-only type; leave it out of player scripts.

UQLSCRIPT ReflectionCalls;
VALUE $types = null; VALUE $m = null; VALUE $args = null; VALUE $ok = null; VALUE $found = null;
VALUE $cam = null; VALUE $go = null; VALUE $source = null; VALUE $sb = null; VALUE $vec = null;
BLOCK Main {
    // out: Int32.TryParse(string, out int)
    $types = [STATIC:System.Array].CreateInstance(TYPE(System.Type), 2);
    INVOKE $types.SetValue(TYPE(System.String), 0);
    INVOKE $types.SetValue(TYPE(System.Int32).MakeByRefType(), 1);   // the by-ref slot
    $m = TYPE(System.Int32).GetMethod("TryParse", $types);
    $args = [STATIC:System.Array].CreateInstance(TYPE(System.Object), 2);
    INVOKE $args.SetValue("42", 0);
    $ok = $m.Invoke(null, $args);                                     // static: null target
    LOG LINE FIELDS ok = $ok, result = $args[1];                      // True, 42 (written back)
    // out on a Unity API: Component.TryGetComponent(Type, out Component)
    $cam = [STATIC:UnityEngine.Camera].main;
    $types = [STATIC:System.Array].CreateInstance(TYPE(System.Type), 2);
    INVOKE $types.SetValue(TYPE(System.Type), 0);
    INVOKE $types.SetValue(TYPE(UnityEngine.Component).MakeByRefType(), 1);
    $m = TYPE(UnityEngine.Component).GetMethod("TryGetComponent", $types);
    $args = [STATIC:System.Array].CreateInstance(TYPE(System.Object), 2);
    INVOKE $args.SetValue(TYPE(UnityEngine.Transform), 0);
    $found = $m.Invoke($cam, $args);                                  // instance: the receiver
    LOG LINE FIELDS found = $found, component = $args[1];
    // generic-only (Editor): PrefabUtility.GetCorrespondingObjectFromSource<GameObject>(GameObject)
    FIND "Character" IN SCENE INTO $go;
    $types = [STATIC:System.Array].CreateInstance(TYPE(System.Type), 1);
    INVOKE $types.SetValue(TYPE(UnityEngine.GameObject), 0);
    $m = TYPE(UnityEditor.PrefabUtility).GetMethod("GetCorrespondingObjectFromSource").MakeGenericMethod($types);
    $args = [STATIC:System.Array].CreateInstance(TYPE(System.Object), 1);
    INVOKE $args.SetValue($go, 0);
    $source = $m.Invoke(null, $args);
    LOG LINE FIELDS source = $source;
    // constructors: new StringBuilder("abc"), new Vector3(1, 2, 3)
    $args = [STATIC:System.Array].CreateInstance(TYPE(System.Object), 1);
    INVOKE $args.SetValue("abc", 0);
    $sb = [STATIC:System.Activator].CreateInstance(TYPE(System.Text.StringBuilder), $args);
    $args = [STATIC:System.Array].CreateInstance(TYPE(System.Object), 3);
    INVOKE $args.SetValue([STATIC:System.Convert].ToSingle(1), 0);    // float (1 widens too; 1.5 would not)
    INVOKE $args.SetValue([STATIC:System.Convert].ToSingle(2), 1);
    INVOKE $args.SetValue([STATIC:System.Convert].ToSingle(3), 2);
    $vec = [STATIC:System.Activator].CreateInstance(TYPE(UnityEngine.Vector3), $args);
    LOG LINE FIELDS sb = $sb.ToString(), vec = $vec;
}
Reference topic · Language referenceOBSERVATIONSNamed before/after evidence, explicit typed checks, coverage/lifecycle states and host-clock/HOOK provenance. Not an automatic sampler or object-graph snapshot.

Named before/after evidence, explicit typed checks, coverage/lifecycle states and host-clock/HOOK provenance. Not an automatic sampler or object-graph snapshot.

Where to use it

Reference topic; not a command

Example

HELP OBSERVATIONS;

Detailed reference

From the in-tool help for OBSERVATIONS.

NAMED BEFORE/AFTER EVIDENCE
VALUE $before = null; VALUE $after = null; VALUE $check = null;
BLOCK Test {
    OBSERVE FIELDS hp = $boss.health, position = $boss.transform.position
        INTO $before PHASE Before;
    CALL PerformAction;
    OBSERVE FIELDS hp = $boss.health, position = $boss.transform.position
        INTO $after PHASE After;
    CHECK health_changed: $after["hp"] != $before["hp"] INTO $check;
    RECORD FIELDS check = $check.Outcome, reason = $check.Reason;
    RECORD NEWLINE; REGISTER action_test;
}
The surrounding script supplies $boss and PerformAction. CALL keeps the same process.
CHECK continues normally; use existing IF/STOP explicitly to stop on Fail/Inconclusive.
Neither command automatically prints, registers, pauses or aborts a test.

OBSERVE FIELDS label = path [, label = path ...] INTO $snapshot [PHASE name];
CHECK name: $snapshot["label"] operator operand INTO $result;
CHECK lifecycle: $snapshot["target"] STATUS Destroyed INTO $result;
Labels, phase and check names are identifiers or quoted constant strings. Empty or
duplicate observation labels are errors. INTO is mandatory: use an untyped VALUE,
or a VALUE accepting UQL.Runtime.UqlObservationSnapshot / UqlCheckResult respectively.
ALIAS/PATH/BUCKET are not result destinations. No EVAL/ASSERT expression dialect; the one
derived right operand below is the only arithmetic CHECK computes.

OBSERVE selects one addressable path per label. Local VALUEs, collection elements,
explicit Count/Length and selected getters use the existing path layer. Query ranges,
literals, arithmetic/comparisons and explicit method expressions are rejected (UQL440,
one diagnostic per field, naming the label): compute the value first and observe it:
VALUE $ok = $x == null; then OBSERVE FIELDS ok = $ok INTO $snap;. A literal needs no
capture (CHECK compares it directly). Each selection runs once in source order.
Known method paths hidden by ALIAS/DEFINE are rejected at compilation. A PATH rebound
to a method is Unsupported for that field without invoking the method. Known captured
BUCKET method paths are likewise guarded before bare or suffix resolution. Bare BUCKET
entries / IUqlPathReference capabilities resolve before freezing; failures stay local,
and reference chains/cycles have a bound. Developer-provided readers can run custom
code, so this feature does not revoke the host's trusted reader/delegate capabilities.
PRINTOPT never adds hidden getters, Transform reads or automatic enumeration here.
An explicitly selected getter may have side effects; there is no sandbox or rollback.

Frozen snapshot cells are also readable in ordinary paths: $snapshot["hp"],
$snapshot[0], $snapshot[INDEX:0] and $snapshot[$selector]. Use .Value for the frozen
scalar/atom; no gameplay getter is rerun. Missing labels return null, invalid ordinals
produce a path diagnostic. Cells are read-only.

CHECK name: comes first. The left operand is a named frozen cell, WITHOUT a .Value
suffix; it never computes (CHECK n: $o["a"] + 1 == ... is one diagnostic whose NEXT
moves the arithmetic to the right). The right operand is another frozen cell, an
immutable scalar literal/supported closed constructor, or ONE cell with ONE operator
(+ - * /) and a numeric literal: CHECK grew: $after["hp"] == $before["hp"] + 5 INTO $r;
The derived value is computed from the frozen cell when CHECK runs (no live read) and
keeps CHECK's numeric domains: an integer cell with an integer literal stays exact in the
C# result type (int, uint, long, ulong or decimal; integer division truncates). The literal
is a C# constant: a non-negative one keeps a uint or ulong cell unsigned (a uint cell 3
with - 5 is Inconclusive "UInt32 overflow", not -2); a negative literal widens a uint cell to long.
Float or double with a floating literal stays floating. A mixed exact/floating pair, a non-numeric,
null or unavailable cell, division by zero and overflow make the CHECK Inconclusive with a
reason; a non-Pass result names the operand in Values: right $before["hp"] + 5 = 12
(System.Int32). Literal-only arithmetic (== 5 + 1, == -(2 * 3), also ABS 0.05 * 2.0) folds at
compile time by the same rules; a mixed, overflowing or zero-dividing literal expression is
UQL441. Not a gameplay path, an arbitrary call, cell + cell or a second operator: compute
those into a VALUE, OBSERVE it and CHECK its cell. A CHECK mistake is one diagnostic at the
bad token (no cascade). Operators: == != < <= > >=
NEAR. STATUS accepts Value, Null, Destroyed, Missing, ReadError, Unsupported, Truncated.
The result has Label, Outcome (Pass/Fail/Inconclusive), Reason, source/provenance and
left/right CaptureId. process.LastCheck retains its latest immutable result.

A bare VALUE is also a live path here: CHECK sample: $snapshot["hp"] == $expected
is rejected. Capture both values explicitly, then compare their frozen cells:
VALUE $hp = 10; VALUE $expected = 10; VALUE $snapshot = null; VALUE $result = null;
OBSERVE FIELDS hp = $hp, expected = $expected INTO $snapshot;
CHECK sample: $snapshot["hp"] == $snapshot["expected"] INTO $result;
The same cell syntax applies to NEAR; preparing a VALUE alone does not freeze it.

Known null supports equality with null or STATUS Null. Destroyed Unity wrappers are
distinct: ordinary comparisons are Inconclusive; STATUS Destroyed may pass. Missing,
ReadError and Unsupported are not null/zero/default values. A failed selected getter
is recorded on its cell; later selected reads and script commands still run.

Snapshots expose Completion (Pending/Complete/Cancelled/Conflict), CoverageComplete,
SameWindow, CaptureId, Activation, ProcessId, Phase, Start/End, ordered Cells, CellsByName
and a read-only string indexer. Cells expose Name, Path, TypeName, Status, Value,
ReferenceId, Error, PathErrorCode and Step. Values are frozen primitives or dedicated
immutable enum/reference/numeric atoms, never raw target graphs or boxed game structs.
Approved Unity numeric shapes include vectors, Quaternion, Color, Rect, Bounds,
Matrix4x4, integer variants and LayerMask. Unknown structs need selected scalar members.
References become weak session identity tokens, NOT addresses, retained objects or
persistent ROOT paths. A caller may retain evidence after group disposal; bound history.

Exact integers/decimal compare without narrowing long/ulong through double. Finite
float/double form a separate domain; mixed exact/floating comparisons are Inconclusive.
A float cell against an integer literal ($snap["ms"] > 0) is such a mixed comparison: write a
floating literal ($snap["ms"] > 0.0); the Inconclusive reason names it (revision 54:
'NEXT: write the literal 0 as the floating literal 0.0 ...').
Non-finite input is Inconclusive. Enums require matching types for equality. Numeric
structs require the same frozen type/shape; equality/NEAR are componentwise, not vector
ordering or Quaternion-angle calculations. Strings compare ordinally.
NEAR optionally accepts finite nonnegative literal ABS and REL (both default zero):
abs(a-b) <= ABS + REL * max(abs(a),abs(b)), componentwise for numeric structs.
Nonzero floating tolerances on exact integer/decimal values are unsupported; zero
tolerance permits exact equality. General path/numeric conversion rules are unchanged.

Capture executes charged Begin, one Read per field, then End instructions. Begin
publishes immutable Pending; a private frame-owned builder performs the selected reads.
Cooperative budget yields can split a capture. Complete with SameWindow=false is not
single-point evidence and CHECK returns Inconclusive, even within one Unity frame.
Known game frames, clock domains and HOOK publication contexts must agree at both
capture ends as well. Advancing time within a consistent frame/window is allowed;
unknown frame/time is explicitly unknown, never evidence of game-frame atomicity.
No capture guarantees atomicity; a blocking getter cannot be preempted by VM budgets.
STOP/abort/disposal/hook failure finalize the owned attempt as Cancelled. Cancellation
does not sample a host clock during cleanup. Another writer replacing the destination
causes Conflict; the old attempt must not overwrite the newer result. LastObservation
retains the process's latest immutable attempt, including Pending/Cancelled/Conflict.

Default limits: 128 fields, 4096 selected string/diagnostic characters, 65536 total
observation characters (16384 before revision 43; Conductor preset keys observeStringCharacters /
observeCharacters, HELP LIMITS). Hosts can constrain MaxObservationFields,
MaxObservationStringCharacters and MaxObservationCharacters. Budget/string clipping
records Truncated and makes CoverageComplete=false. A failed field's reason (Error of a
Missing/ReadError/Unsupported cell) keeps at least 1024 characters within the string limit,
also when the total is nearly spent, and a cut reason ends with '… (+N chars; M total)';
its status is unchanged and frozen values never get that marker (revision 52). Ordinary value checks then return
Inconclusive, even for an earlier intact-looking cell. STATUS may intentionally test
Truncated. Covered getter/missing/unsupported errors are not blanket coverage gaps;
they affect their own cells, not unrelated good fields. Pending/Cancelled/Conflict,
missing labels, different activations/processes and multi-window captures cannot pass.
Both comparison dependencies are preflighted; no short-circuit hides unavailable data.
CALL shares evidence ownership; START creates another process. Cross-process evidence
comparison is deliberately not implicit. Prefer local snapshot VALUEs for independent tests.

FROZEN BASELINE COMPARISON (public API, no new command)
VALUE $health = 10; VALUE $before = null; VALUE $after = null;
VALUE $delta = null; VALUE $changes = null;
OBSERVE FIELDS hp = $health INTO $before;
$health = 12;
OBSERVE FIELDS hp = $health INTO $after;
$delta = $after.Compare($before);
SELECT $delta.Rows AS $row FIELDS name = $row.Name, before = $row.Before,
    after = $row.After, changed = $row.Changed, increased = $row.Increased
    WHERE $row.Changed == [STATIC:UQL.Runtime.UqlCheckOutcome].Pass
    INTO $changes LIMIT 128;
This explicit cold method compares frozen cells only, with no getters, graph reads,
automatic baseline advancement or mutation of the input snapshots. At most 128
cells per input form at most 256 union-label rows, baseline order then current-only.
Before/After retain detached evidence using the shared 4096-character transfer bound;
comparisons use those retained cells, so clipped evidence cannot conclusively pass.
Missing labels, different recorded Paths, unavailable cells or incompatible numeric
domains are Inconclusive, not Unchanged or fabricated object creation/removal.

Rows expose Name, Before, After, Changed, Unchanged, Increased, Decreased,
OrderingSupported, Reason, OrderingReason. Classifications are UqlCheckOutcome:
compare to Pass explicitly, not true. Equality reuses CHECK's frozen semantics;
Increased/Decreased support primitive numeric values only, not strings, chars,
booleans, enums, tokens or vectors. OrderingSupported describes type/availability
eligibility; nonfinite/mixed-domain numerics can still be Inconclusive. Numeric
Unchanged need not imply identical runtime types; token equality is not equality
of object interiors. Selected routes do not establish containing-entity identity.

Both snapshots must be Complete, coverage-complete and individually SameWindow,
with matching positive Activation/ProcessId and baseline CaptureId <= current.
Equal IDs permit frozen self-comparison, not a second sampling event. The method
checks pair provenance, NOT invoking-process ownership; CHECK's ownership rule is
unchanged. Different capture windows are allowed; no elapsed-time/frame-perfect
delta or entity-generation correlation is inferred. Baseline never advances itself.

UqlObservationComparison exposes BaselineCaptureId/CurrentCaptureId,
BaselineActivation/CurrentActivation, BaselineProcessId/CurrentProcessId,
BaselineStart/BaselineEnd, CurrentStart/CurrentEnd, InputComparable/InputReason,
EqualityCoverageComplete, OrderingCoverageComplete, CoverageComplete,
ChangedCount, UnchangedCount, IncreasedCount, DecreasedCount,
EqualityInconclusiveCount, OrderingInconclusiveCount, InconclusiveCount, Rows,
Summary and Text; Format(maxChars) bounds rendering. InconclusiveCount is a union
of row gaps, not their double-counted sum. Overall coverage conservatively requires
both equality and ordering; string rows may have EqualityCoverageComplete=true
but CoverageComplete=false. Rows propagates that into SELECT even after an empty
filter; unknown order is not evidence that nothing increased. No source snapshot,
raw target, process, frame or reader delegate is retained by the comparison.
Full construction precedes normal expression assignment; a failure or STOP before
assignment preserves the old destination. Downstream SELECT keeps its existing
Pending/Cancelled publication contract. Use $before=$after explicitly to roll the
baseline, and bound retained history. Live candidate resampling remains separate.

UqlEvidenceStamp records activation/process/group, actual Source, declared Script,
SourceVersion, Block, Line/Column/Instruction, SchedulerStep and ExecutionWindow, plus
optional Frame/Time/Clock/ClockError and actual Hook/publication/parent/depth context.
SchedulerStep counts scheduler steps, NOT Unity frame numbers (WAIT FRAME with a host frame clock uses the actual frame; see HELP WAIT). PHASE is
author intent, not a scheduler or HOOK label. Nested publications restore parent context;
resumed event waiters report the actual notification, not their BLOCK's assumed name.
Scheduled continuation does not claim a still-active previous HOOK phase.

Standalone hosts default to unknown evidence frame/time/clock; stale Tick values are
not relabeled as sampling timestamps. Set group.EvidenceClock explicitly, for example:
group.EvidenceClock = () => new UqlEvidenceClock(gameSeconds, gameFrame, "game-clock");
Unity hosts may choose UqlUnityEvidenceClock.Sample for realtime and current play frame.
Provider errors/non-finite time/negative frame give unknown values plus ClockError.
Providers must not recursively execute UQL. Sampling happens only for explicit evidence,
not ordinary alias reads. Frozen evidence text contains these provenance fields and
unknown markers; Format(maxChars) remains bounded. Existing 16-byte instruction layout
and ordinary ALIAS/path fast routes are unchanged. Offline doubles do not verify Unity
frame timing or IL2CPP metadata preservation; preserve selected reflected members/types.
Reference topic · Language referenceCONSOLELOGOpt-in readback of Unity Console messages (log, warning, error, assert, exception) through UQL.Runtime.UqlConsoleLog: a bounded ring with sequence cursors and explicit missed counts. Capture starts only when enabled and is not retroactive.

Opt-in readback of Unity Console messages (log, warning, error, assert, exception) through UQL.Runtime.UqlConsoleLog: a bounded ring with sequence cursors and explicit missed counts. Capture starts only when enabled and is not retroactive.

Where to use it

Reference topic; opt-in API, no new grammar

Example

INVOKE [STATIC:UQL.Runtime.UqlConsoleLog].Enable(512);
VALUE $mark = 0; VALUE $report = null;
$mark = [STATIC:UQL.Runtime.UqlConsoleLog].Cursor;
// ... run the action under test ...
$report = [STATIC:UQL.Runtime.UqlConsoleLog].Read($mark, 50, 2);   // 2 = errors and worse
LOG $report.Text; NEWLINE;

Detailed reference

From the in-tool help for CONSOLELOG.

CONSOLE READBACK (opt-in)
INVOKE [STATIC:UQL.Runtime.UqlConsoleLog].Enable(512);      // 1..4096 entries; idempotent; subscribes to Unity's threaded log callback
$mark = [STATIC:UQL.Runtime.UqlConsoleLog].Cursor;          // sequence of the newest message so far (0 when none)
$report = [STATIC:UQL.Runtime.UqlConsoleLog].Read($mark, 50, 2);   // Read(afterSequence = 0, max = 100, minimumSeverity = 0)
$all = [STATIC:UQL.Runtime.UqlConsoleLog].Read($mark, 50);       // trailing minimumSeverity defaults to 0; Read() also uses the C# defaults
LOG $report.Text; NEWLINE;                                    // summary + entries, exceptions/errors with their first stack lines
SELECT $report.Entries AS $e FIELDS seq = $e.Sequence, sev = $e.Severity, msg = $e.Message INTO $rows LIMIT 50;
Severity: 0 Log, 1 Warning, 2 Error, 3 Assert, 4 Exception. Cursor is the last sequence examined: pass it to the next Read.
Report: Entries, Cursor, Missed (messages after your cursor that were overwritten or cleared), DroppedTotal, MoreAvailable, Enabled,
StaleCursor, SpansReload, ReloadAfterSequence, ReloadUtc (see the reload paragraph below).
Text is the default 65536-character view. Format(maxChars) never exceeds the requested character budget;
zero/negative budgets return empty text. Truncated views carry a marker when it fits; tiny budgets show only a prefix.
Read the structured report for counts/coverage: a short text prefix is not evidence that no messages exist.
Capture is OFF until Enable and is not retroactive.
DOMAIN RELOAD (revision 46): in the Editor an enabled capture is sticky for the Editor session. Before a domain reload
(C# refresh, Play Mode entry with domain reload) the capacity, next sequence and dropped total are kept in SessionState;
capture resumes before Play Mode Awake/OnEnable/Start with continuing sequence numbers, so errors of the first Play frames
are captured. Enable in Edit Mode, take the Cursor, STARTPLAY, then read from that cursor. The ring itself is cleared:
a read whose window spans the newest reload counts the cleared entries in Missed, sets SpansReload, ReloadAfterSequence (#N)
and ReloadUtc, and adds the line: ! Domain reload at <UTC> after #N: entries up to #N were cleared; messages logged during
the reload itself were not captured. Script VALUEs do not survive a reload: keep the cursor in a register or output.txt and
pass it to a BLOCK argument after compiling the group again. A cursor beyond the newest message (an Editor restart or
Reset restarted the numbering, or it was never issued) sets StaleCursor: the read lists from the oldest kept entry with a
note instead of an empty result. A new Editor session starts with capture off; a player build never persists anything.
Clear() forgets stored entries but never reuses sequence numbers; Disable() unsubscribes and ends the Editor-session
stickiness (the next reload does not resume capture). Messages are clipped to 2048 characters
(stacks 4096). The callback only copies strings into a fixed ring under a lock and never logs itself. CONSOLE LOG/WARNING/ERROR
WRITE to the Console (and are captured when enabled); this API only READS. It does not read Unity's private Console history.
HOST CONSOLE (revision 55): independently of this opt-in ring, the connected Editor host captures every message itself and
appends it to Workspace/Hosts/<host-id>/Console/console.txt with the logging run's request, group and process; the run
evidence 'Console start:'/'Console end:' lines give a call's window (HELP HOSTCONSOLE). Agents outside UQL read that file.
Reference topic · Language referenceHOSTCONSOLEThe addressed Editor host's own Unity Console capture (always on while UQL is connected, independent of UqlConsoleLog): Workspace/Hosts/<host-id>/Console/console.txt, one ENTRY per message with its sequence number, severity and the UQL request, group and process that logged it; host.txt Console: and the run evidence Console start:/Console end: lines give the window of a call. Lost messages are stated (LOST, GAP). Alias: CONSOLE FILE.

The addressed Editor host's own Unity Console capture (always on while UQL is connected, independent of UqlConsoleLog): Workspace/Hosts/<host-id>/Console/console.txt, one ENTRY per message with its sequence number, severity and the UQL request, group and process that logged it; host.txt Console: and the run evidence Console start:/Console end: lines give the window of a call. Lost messages are stated (LOST, GAP). Alias: CONSOLE FILE.

Where to use it

Reference topic; Editor file host, not a command

Example

HELP HOSTCONSOLE;

Detailed reference

From the in-tool help for HOSTCONSOLE.

HOSTCONSOLE (HOST CONSOLE PUBLICATION, revision 55)
Not a command. While the Editor host is connected it captures every Unity Console message itself (independent of the
opt-in UqlConsoleLog ring, HELP CONSOLELOG) and appends it to Workspace/Hosts/<host-id>/Console/console.txt. Read the file
with FileShare.ReadWrite | FileShare.Delete; it is append-only and renamed to console.1.txt at consoleFileMegabytes (one
older generation). Records, one per line (values bare or quoted with \n \r \t \" \\ \uXXXX escapes):
UQL-CONSOLE 1 host=<id>                                   first line of each file
HEADER utc=<O> session=<id> reason=connect|rotation capturing=true|false captureStart=<O> capacity=<n> next=<seq>
       dropped=<n> missed=<n> gaps=<n> pending=<n> [note="..."]   at each connect and after a rotation
ENTRY seq=<n> utc=<O> session=<id|none> severity=Log|Warning|Error|Assert|Exception request=<id|none> group=<key|none>
      process=<id|none> message="..." stack="..."            one per message, in sequence order
LOST from=<seq> to=<seq> count=<n> reason=overflow|capacity|reload text="..."   numbered messages never published
GAP after=<seq> from=<O> to=<O> reason=domain-reload|capture-off text="..."     capture was off (count unknown)
NOTE utc=<O> session=<id> text="..."                     e.g. a rotation that a reader deferred
Sequence numbers increase for the Editor process (across domain reloads) and, after an Editor restart, continue after the
newest number in console.txt. request/group/process name the UQL run whose statement or getter logged the message (set
around each process run, HOOK dispatch, group tick and the compile); messages of other threads or of game code outside a
run are request=none group=none process=none. Messages are clipped at 2048 characters, stacks at 4096, with
'... <clipped: shown of total characters>'.
Cursors: host.txt 'Console: capturing=<bool> next=<seq> dropped=<n> missed=<n> gaps=<n> pending=<n> file=<path>' (as of
its UTC). The run evidence of a START and of a compile has 'Console start: <seq>' (the number the next message got at
acceptance) and 'Console end: <seq>' (the newest number at the terminal state; 'pending' before; nothing logged when end <
start): read ENTRY records with start <= seq <= end and request= your request for the run's own messages. Without the
capture both lines say 'unavailable (why)'; so do they (and host.txt says next=unknown) while the numbering is not yet based
on console.txt (its newest number could not be read at connect; the first write renumbers).
Nothing is lost silently: past consoleCapacity unpublished messages are dropped (LOST overflow), a domain reload carries
the unpublished ones in SessionState (262144 characters; beyond: LOST reload, counted missed) and the reload itself is a
GAP. A user's Disconnect stops the capture; a later Connect states the window as a GAP. The capture never writes to the
Unity Console. Limits: consoleCapacity, consoleFileMegabytes (HELP LIMITS).
Reference topic · Language referenceSESSIONSThe addressed Editor host's session log (Workspace/Hosts/<host-id>/sessions.log: Editor starts, connects, reloads, Play transitions, C# refresh states, compiles, runs and their ends, quits) and the classification of how the previous Editor ended (host.txt Previous editor:, previous-editor.txt with the crash folder, signal and stack excerpt). Readable while Unity is not running. Alias: CRASH.

The addressed Editor host's session log (Workspace/Hosts/<host-id>/sessions.log: Editor starts, connects, reloads, Play transitions, C# refresh states, compiles, runs and their ends, quits) and the classification of how the previous Editor ended (host.txt Previous editor:, previous-editor.txt with the crash folder, signal and stack excerpt). Readable while Unity is not running. Alias: CRASH.

Where to use it

Reference topic; not a command

Example

HELP SESSIONS;

Detailed reference

From the in-tool help for SESSIONS.

SESSIONS (EDITOR SESSION LOG AND CRASH CLASSIFICATION)
Not a command. The addressed Editor host keeps Workspace/Hosts/<host-id>/sessions.log, the session log
(requests.log is the request journal), readable while Unity is not running. One line per event:
<utc> <EVENT> editor=<id> pid=<n> [session=<id>] key=value ... Values are bare or quoted with \\ \" \r \n \t
and \uXXXX; a null value is the bare word unknown.
START (first connect of an Editor process: Unity version, project, process start, log path), CONNECT and
DISCONNECT (every host session and why it ended), SCRIPTS, RELOAD, REFRESH (C# refresh states), PLAY,
COMPILE (state=started before a group compile and its initializers, then the result), CSHARP (inside that
bracket, or alone for a compile without activation: state=compiling unit=<hash16> group=<g> before the C# compile of a CSHARP unit
and its Assembly.Load, state=done status=<s> loaded=<L>/<limit> after it; HELP "CSHARP FUNCTIONS"), RUN and END (BLOCKs
started by START, the Editor or AWAKE; END when the BLOCK and every process it started have ended), STOP
(around a STOP and its DEFER cleanup), STALL (no host tick for 60 s or more), QUIT-REQUESTED,
QUIT-CANCELLED, QUIT, PREVIOUS, NOTE (NOTE ... disconnect=cancelled: the DISCONNECT before it did not
happen, for example a refused Disconnect, and the connection went on). Never written per instruction, per HOOK call or per tick;
HOOK-entered BLOCKs have no RUN line. A RUN without a later END of the same editor= was running (or ended
within the last poll) when that Editor ended. QUIT-REQUESTED alone does not mean the Editor is quitting.
A CSHARP state=compiling without its state=done names the step that was running: Previous editor: then says
'... while group <g> was compiling C# unit <hash16> (CSHARP backend compile or Assembly.Load)'.
Unity notes: EditorApplication.Exit (also from a BLOCK) raises quitting but not wantsToQuit, so no QUIT-REQUESTED line is
written for it; EditorApplication.delayCall is not processed while the Editor runs in the background, so work queued
there waits for focus. RELOAD cause=: refresh (with request=<id>), play, scripts (a compile finished within 60 s), startup
(the first reload of an Editor process in its first 10 minutes) or unknown. Values with a / (processes="1/1") are quoted.
At the first connect of a new Editor process the host classifies the previous Editor as clean-quit,
crashed, crashed-while-quitting, quit-incomplete, os-restarted, exited-without-report, ended-unclean,
disconnected-before-end or unknown, from the session log, the previous host.txt, Unity's crash folders
(%LOCALAPPDATA%\Temp\Unity\Editor\Crashes\Crash_<UTC>, read only; a folder counts only when its Editor.log
names that Editor's process id and this project) and the previous Editor log.
host.txt 'Previous editor:' has one line; previous-editor.txt has the details: last sign of life, open
runs, the crash folder, the signal line and the line before it, a stack excerpt (the first 4 frames and
every UQL.Runtime/UQL.Editor frame, at most 18), possible error lines of the log and a NEXT line. Use
previous-editor.txt only when its Classified: editor equals host.txt Editor start: editor=.
While it runs, host.txt says 'Previous editor: classifying (started <utc>)'. A clean quit gives only
'Previous editor: quit cleanly at <utc>'; nothing is written to the Unity Console.
The host keeps sessions.log open for appending: read it with FileShare.ReadWrite | FileShare.Delete.
At 1 MiB it becomes sessions.1.log (one older generation); the new file starts with CONTINUE and one
OPEN line per run still open. host.txt 'Session log:' names the file, or '...; buffering <n> line(s)
(not on disk)' while lines wait in memory (at most 256) because the file could not be written.
After an unclean end do not resend the last request blindly; check what it changes; compile your groups
again (an Editor restart releases every group).
Reference topic · Language referenceJOURNALWhich log is which: requests.log is the request journal, sessions.log the session log.

Which log is which: requests.log is the request journal, sessions.log the session log.

Where to use it

Reference topic; not a command

Example

HELP JOURNAL;

Detailed reference

From the in-tool help for JOURNAL.

JOURNAL: UQL keeps two logs. requests.log is the request journal (compile and execution requests, queueing,
results and host notes; HELP SCRIPT); sessions.log is the session log of Editor starts, reloads, runs and crashes (HELP SESSIONS).
Unity Console messages are a third file: Console/console.txt, the host console publication (HELP HOSTCONSOLE).
UQL's own edits (EDIT, Explorer) are recorded in Edits/edits.txt, the edit log (HELP EDITLOG).
Reference topic · Language referenceEDITLOGUQL's own edit log and dirty marking (revision 56): every Edit Mode script EDIT and every Explorer edit leaves a record (target identity, member path, before and after value, source, request/group/process; Play Mode and player script EDITs with editLog = 2) in Workspace/Hosts/<host-id>/Edits/edits.txt and UqlEditLog.Read; in Edit Mode the owning scene or Prefab stage is marked dirty at the end of the host tick. Never Unity Undo; no undo command. EDITLOG [count] [FROM first] INTO $h reads records, newest first, as an immutable report (Rows[0] = first: Owner, Path, Member, OldValue, NewValue); FROM skips that many of the newest records (EDITLOG 20 FROM 40 = the 20 records 40 back from the newest). Filters by meaning (revision 63), context only: FOR <object> (records whose owner is the object or, for a GameObject, one of its components), REQUEST "<id>", GROUP "<name>", MEMBER "<text>" (the member path contains it); count and FROM then bound the matching records. A restoring EDIT's row names the record it put back (Restores). Switches: Limits rows editLog and editDirty (0..2) and LIMITOPT. Alias: EDIT LOG.

UQL's own edit log and dirty marking (revision 56): every Edit Mode script EDIT and every Explorer edit leaves a record (target identity, member path, before and after value, source, request/group/process; Play Mode and player script EDITs with editLog = 2) in Workspace/Hosts/<host-id>/Edits/edits.txt and UqlEditLog.Read; in Edit Mode the owning scene or Prefab stage is marked dirty at the end of the host tick. Never Unity Undo; no undo command. EDITLOG [count] [FROM first] INTO $h reads records, newest first, as an immutable report (Rows[0] = first: Owner, Path, Member, OldValue, NewValue); FROM skips that many of the newest records (EDITLOG 20 FROM 40 = the 20 records 40 back from the newest). Filters by meaning (revision 63), context only: FOR <object> (records whose owner is the object or, for a GameObject, one of its components), REQUEST "<id>", GROUP "<name>", MEMBER "<text>" (the member path contains it); count and FROM then bound the matching records. A restoring EDIT's row names the record it put back (Restores). Switches: Limits rows editLog and editDirty (0..2) and LIMITOPT. Alias: EDIT LOG.

Where to use it

Script BLOCK / terminal; read-only, Execute grant only; also EDITOR EDITLOG; HELP EDITLOG is the reference topic

Example

VALUE $h = null;
EDITLOG 20 INTO $h;
LOG $h.Text;

Detailed reference

From the in-tool help for EDITLOG.

EDITLOG (UQL'S OWN EDIT LOG AND DIRTY MARKING, revision 56)
Not a statement that changes anything (EDITLOG reads it). A game-state write of a script EDIT, UNSAFE EDIT, compound enum edit (|=, &=, &= ~), HOOK or DEFER
cleanup BLOCK, or of the Explorer leaves a record in UQL's own bounded edit log: the target's identity, the member
path, the before and the after value, the source line and the origin (group, activation, process, request).
With the default editLog = 1 the log records Edit Mode EDITs and every Explorer edit; Play Mode and player script
EDITs are recorded only with editLog = 2 (LIMITOPT editLog = 2; for one group, <Limits editLog="2" /> for all).
In Edit Mode the owning scene or Prefab stage is also marked dirty, so Unity's save prompts, File > Save and SCENE
see agent edits. UQL never uses Unity Undo: Ctrl+Z does not revert a UQL edit and EDITOR UNDOLOG does not
list it. There is no undo command; the Edit Log window (Tools > UQL Edit Log) only shows records: see HISTORY AND
RESTORING below. To restore a value, write the before value back with EDIT (EDITLOG lists it) or DEFER CALL.

HISTORY AND RESTORING (EDITLOG, REVISION 61)
There is no undo command and no REVERT statement, and the Edit Log window only shows records: putting a value back is an ordinary, visible EDIT.
EDITLOG [count] [FROM first] INTO $h; (also EDITOR EDITLOG) stores records, newest first, as an immutable report: count is
how many (0..1000, default 50), FROM how many of the newest to skip (0 or more, default 0), so EDITLOG 100 FROM 100 is the
second hundred. Rows[0] is the first record of THIS report (Rows[i].Position = FROM + i = how many records are newer) and keeps its index while new edits are logged (a later EDITLOG is a new snapshot whose
indices differ: never reuse a row number across two reports). LOG $h.Text; prints one line per row.
A row has Id, Utc, Mode, Group, Source, Request, OwnerRef (#<id>, static:<Type>, m<n>), OwnerType, OwnerName, Scene,
Path (the EDIT's path text) and Member (.Hp, .Numbers[1]) as text for reading, Leaf, ValueType, OldText, NewText, the
typed OldValue / NewValue (HasOldValue / HasNewValue tell a real null from not available: not read, clipped, a type that does
not round-trip or one that cannot be found), Owner (the live Unity object, or null when it is gone, was never a Unity object,
now has another type, or the record is from another Editor session, so a restore through Owner cannot hit another object),
State (Applied, or Restored once a later EDIT was tagged restores=<id>), Restores (on that restoring EDIT: the id it put back),
SupersededBy (a newer successful record writes the same owner and member), Restorable (the log has what a
restore needs: restore=text, a Unity-object or static owner whose object still exists, both typed values) and Reason (why
not, ending with NEXT). The line's other keys (revision 71): Batch (the log flush the record belongs to), KeyText (the display
text of a [KEY:?] map key), Frame (the Unity frame of a Play Mode record), Writes (how many writes of one tick to the target
the record stands for: the first before, the last after; 1 when the line has no writes= key), Error (the exception text of a
setter-threw record), Dirty (the dirty= outcome: marked, pending, play, off, ...), Phase (main, or cleanup for a DEFER cleanup
BLOCK) and Clipped (before, after or both). A key the line does not have reads as "" (text) or -1 (Batch, Frame).
EditorId names the Editor session that wrote the record ("?" when it is unknown), and Foreign is true when that is not the
current Editor session: such a row is history only and its Owner is not resolved.
String data never becomes executable path text,
so a Path or Member is for reading: take the member from the listing and write it in the EDIT yourself.
  VALUE $h = null;
  EDITLOG 20 INTO $h; LOG $h.Text;      // the 20 newest;  EDITLOG 20 FROM 40 INTO $h;  = the 20 before the newest 40
  // The row says: [0] ... (Game.Hero).Hp: 5 -> 7  [restorable]. Put it back only if nobody changed it since:
  IF $h.Rows[0].Restorable && $h.Rows[0].Owner != null && $h.Rows[0].Owner.Hp == $h.Rows[0].NewValue { EDIT $h.Rows[0].Owner.Hp = $h.Rows[0].OldValue; }
The guard compares the current value with NewValue, so restoring the older of two edits to the same member (5 -> 7, then
7 -> 9) is refused: the current value is 9. The restoring EDIT is logged like any EDIT.
Filters (context only, they never restore anything): EDITLOG [count] [FROM first] [FOR <object>] [REQUEST "<id>"] [GROUP "<name>"]
[MEMBER "<text>"] INTO $h; every given condition must hold. FOR matches the live owner (the object itself or, for a GameObject, one
of its components; a destroyed FOR object is an Error report), REQUEST and GROUP the record's request= / group= text exactly, MEMBER
a part of the member path (.Hp, [KEY:). count and FROM bound the matching records, Total counts the matches, the Filter line of the
text names the conditions. A filtered read takes the whole memory ring and the last 1 MiB of the files.
  EDITLOG 20 FOR $hero INTO $h;                    // everything UQL changed on $hero and its components, newest first
  EDITLOG REQUEST "uqlrun-20261021-0102-3344" INTO $h;  EDITLOG GROUP "Combat" MEMBER ".Hp" INTO $h;
THE EDIT LOG WINDOW (Tools > UQL Edit Log, Editor only; refined in revision 71) shows the same rows and changes nothing. It has
no Revert, restore, Clear or EDIT-text button. It reads the log only on Refresh, on a filter, count or page change, on a
selection change while Selected is on, and with Auto (off by default) at most once per second while the window is visible.
First toolbar: Refresh, Auto, the count (records per page), Selected (FOR the selection), Group / Member / Request (applied
with Enter) and Copy (the report text). Second toolbar: |< < rows a-b of Total > >| (FROM), a search over the loaded page
(owner, member, values, source, group, request, id) and Cards / Text.
Cards show two lines per record. The first line has a state colour (green restorable, blue restored, amber superseded, grey
not restorable, red write failed; its tooltip is the Reason), the owner's icon, name and type, the member and the local time.
The second line has old -> new, a delta for numbers, xN for coalesced writes, PLAY, cleanup and the source line.
The selected row's details pane has:
  Ping / Select, enabled only while Owner is live ("owner gone" or "other Editor" otherwise);
  the hierarchy, scene, path, member, leaf and value type;
  the full old and new value (up to 16000 characters each);
  the change: a number's delta, removed and added flags, the changed parts of a vector, colour, rect or struct (colours also
  as two swatches), the changed middle of a string;
  the state, the record keys and the origin: actor, group, source, block, request, activation, process, mode, epoch, id,
  local and UTC time.
Restores and Superseded by select that row when it is on the page. Text shows the EDITLOG report text.
Floats: == is exact. $row.HoldsNew($current) compares with NewValue exactly, except the float family (float, double, Vector2/3/4,
Quaternion, Color, Rect), which is equal within 10^-digits relative, where digits is the Limits row editPrecision (default 6, 0 = exact;
LIMITOPT editPrecision = 0; per group). A Quaternion and its negation are the same rotation; a normalizing setter then still passes.
Linking the restore: call INVOKE [STATIC:UQL.Runtime.UqlEditLog].Restores($row.Id); right before the restoring EDIT (inside the guard).
That EDIT line then carries restores=<id>, EDITLOG shows the original as Restored, and the restoring EDIT is a record of its own that can
be restored the same way. The tag belongs to the calling process, serves one EDIT and expires at the next host tick:
  IF $r.Restorable && $r.Owner != null && $r.HoldsNew($r.Owner.position) { INVOKE [STATIC:UQL.Runtime.UqlEditLog].Restores($r.Id); EDIT $r.Owner.position = $r.OldValue; } Count 0..1000 (default 50); a
count outside it, or a negative FROM, is stated in RequestedCount / AppliedCount / RequestedFrom / From / Text; a FROM beyond the
records the log holds gives an empty report that says so. Records come from the memory ring; a reload starts a new
ring, so when the ring holds fewer records than asked the report also reads the last 1 MiB of Edits/edits.1.txt and edits.txt
(Note and Status Partial say when a file was cut or unreadable; FilesRead says it was read). Programmatic reads:
[STATIC:UQL.Runtime.UqlEditHistory].FromLogAndFiles() and Read(lines, context) give records with Status, Reversible and
Reason. A record is a candidate only with restore=text, a Unity-object or static owner, a non-native leaf, the same Editor
session as now (an unknown session, from a file window that lost its OPEN line, never is) and the current mode (a Play Mode
record only inside its own Play session). An Edit Mode record stays a candidate after a Play session: the session ids of
Edit scene objects were unchanged after an Edit -> Play -> Edit round trip (Sample 2022.3), and a recreated object simply
gives a null Owner. The report holds the live Owner and value objects until the VALUE is released.

WHAT IS LOGGED
- editLog = 1 (default): the group's Edit Mode EDITs (also the DEFER cleanup EDITs a Play transition runs after Edit
  Mode was left) and every Explorer edit in any mode. editLog = 2: also Play Mode and player EDITs (EDIT-UNDO-PLAY's
  seed; more cost). editLog = 0: nothing of this group. MARK lines record UqlEditLog.MarkDirty calls.
- Not logged: writes into a UQL VALUE (EDIT $vec.x = 1 on a VALUE that holds a struct), refused EDITs (validation,
  conversion, readonly or missing key failures changed nothing), INVOKE and method effects, named commands (they
  report their own changes), host C# calls of the public UqlScriptWrite.Write, and getter side effects.
- A write that coalesces: the same statement writing the same target again in the same host tick (a WHILE loop on one
  field) is one line with the first before value, the last after value and writes=N.

WHERE AND HOW
- File: Workspace/Hosts/<host-id>/Edits/edits.txt (the file host; one older generation edits.1.txt after it reaches
  editLogFileBytes). In memory: [STATIC:UQL.Runtime.UqlEditLog].Read(after, max) (players and hosts without a file too).
  A host tick's lines are appended by the next poll (a held file keeps them pending, never lost; read edits.txt with
  FileShare.ReadWrite | FileShare.Delete); at a reload or Play transition unwritten lines are spilled and the next
  session appends them. host.txt: Edits: records=N pending=N dropped=N repeats=N marks=N assets-marked=N
  assets-unmarked=N held=N mark-failures=N last=<id> file=<path> (plus stages-unmarked=N after assets-unmarked, throttle-full=N, settings-dirty=N and wrong-thread=N when not 0;
  wrong-thread counts EDITs attempted off the main thread in this whole Editor process, not one group).
- One line per record: <utc> <KIND> key=value ... (the sessions.log shape). The file starts with UQL-EDITS 1. Kinds:
  OPEN (log id, host, session, editor, revision, unity, platform, mode), EDIT, MARK, DROPPED (records not kept:
  count, first, last, source, reason), REPEAT (a hook site's summed window), NOTE (housekeeping), CONTINUE (after a
  rotation); REVERT, CREATE and DESTROY are reserved. Readers ignore unknown keys and kinds and skip broken lines.
- EDIT keys in order (optional ones omitted): id (<log>-<seq>: a 32-hex log id per domain and a sequence number that
  also counts dropped and throttled records, so gaps are visible), batch (host tick; reversals group by batch and
  process), mode (Edit, Play, Transition, Player), actor (script, explorer), phase (main, cleanup), group,
  activation, process, request (the request id copied when the EDIT ran, or none), source (Name.uql:line:column; the
  Explorer writes explorer), block, path (the EDIT's path text), frame (Play only), epoch (the number of Play Mode
  entries in this Editor process, omitted at 0; EDIT-UNDO uses it to tell that a Play session ran), owner (#<id> UqlUnityIds id of the
  nearest live Unity object on the write chain, static:<Type> for a static root, m<n> for a plain managed root, none),
  ownerType, ownerName, scene, sceneHandle, stage, asset, hierarchy (Root/Child/...), via=capture and viaPath (written
  through a BUCKET entry), member (from the owner to the leaf: .name, [i], [i, j], [KEY:"text"], [KEY:12], [KEY:?]
  with keyText), leaf (field, property, element, map, native), valueType, before, beforeType, after, afterType,
  writes, restore, result (ok or setter-threw with error), dirty, dirtyError, dirtyReason, dirtyOwner, ownerKind,
  overrides, persistent, clipped.
- Values: a string is always quoted ("null", "unknown" and "" stay strings), null is the bare word null; numbers use
  the invariant culture (floats round-trip), enums their names, Unity math types the tuple text EDIT accepts
  ((1, 2, 3)), a Unity object reference #<id> "<name>" (<Type>). Other structs show their fields only ({a=1, b=2}),
  other references <Type #m<n>>. beforeType/afterType appear when the runtime type differs from valueType. Identity
  texts are clipped at 512 characters (4096 per line) and values at editLogValueCharacters, with
  '… (+N chars; M total)' and clipped=before/after/both.
- restore: text (the line alone can restore it within the Editor session: Unity id or static owner, textual steps,
  a before value that round-trips with its type), domain (needs live references: a managed root, a captured path, a
  struct or reference value, a non-text key, a clipped value), none (before not read, setter threw, steps truncated).

WHICH BEFORE VALUES ARE READ (the log never runs code the EDIT would not run)
- In every mode (Edit, Play, players): fields, arrays, BCL List<T>, Dictionary, SortedDictionary, SortedList and
  Hashtable entries, the value a compound enum edit or the Explorer already read, native elements when native reads
  are granted, and a curated list of engine property getters without side effects: Object.name/hideFlags,
  GameObject.layer/tag/isStatic, Transform pose (position, localPosition, rotation, localRotation, eulerAngles,
  localEulerAngles, localScale, parent), RectTransform layout, Behaviour/Renderer/Collider enabled, isTrigger,
  Renderer.sharedMaterial, Rigidbody/Rigidbody2D velocity and mass values, SpriteRenderer color/sprite/flip, and the
  properties of Unity math structs.
- Every other getter is never called, whatever its assembly (game code, UnityEngine.UI, Unity.* packages, the BCL, and
  engine getters that log, copy arrays or instantiate such as Renderer.material, Material.color, Mesh.vertices): the
  line says before="<not read: property getter not on the before-read list>" with restore=none. Other placeholders:
  <not read: no getter>, <not read: reference UI>, <not read: custom IList>, <not read: custom IDictionary>,
  <not read: native read not granted>, <unreadable: Type: message>.

HOOK THROTTLE
A BLOCK entered by game code through a HOOK can edit on every Editor update. Per site (group, BLOCK, statement, owner,
member) the first 8 records of a 10 s window are logged; the rest take ids but are summed into one REPEAT line (count,
first, last, firstBatch, lastBatch, the last after value; restore=none) when the window ends. Dirty marking still sees
every one. For hook-driven tooling groups use LIMITOPT editLog = 0; add editDirty = 0 only when those edits must not
be saved.

SWITCHES AND SIZES (Limits rows; HELP LIMITS)
- editLog 0..2 and editDirty 0..2 are group rows: the preset (<Limits editLog="0" editDirty="0" />) sets them for every
  group and LIMITOPT editLog = 2; or LIMITOPT editDirty = 0; for one group (the larger value wins between sources).
  editDirty = 1 (default) marks scenes and Prefab stages and records prefab-instance overrides; 2 also marks saveable
  assets, which Unity then saves without a prompt at the next save; 0 marks nothing.
- editLogEntries (records waiting for formatting in one host tick; later ones are dropped and counted, keep-first),
  editLogMemoryCharacters (lines kept for Read), editLogValueCharacters (one value), editLogFileBytes (rotation).

API: [STATIC:UQL.Runtime.UqlEditLog] (players too; no new grammar)
- MarkDirty(target): marks a GameObject, Component, asset or Scene now (Edit Mode), writes a MARK line and returns the
  outcome text (marked: Scene (path) / already dirty: ... / asset marked: ... / not marked: <reason>). It ignores
  editDirty (an explicit call is a decision), so it also marks a saveable asset; a not-saveable asset is never marked.
  While the user's Editor switch 'Allow saving / discarding changes' is off (HELP CONSENT) it does not mark an asset either
  and returns not marked: <asset> ('Allow saving / discarding changes' is off: Unity writes a marked asset without asking at
  the next save or at Editor quit).
- FlushDirty(): marks what is pending now (for an isDirty check in the same tick); returns the number marked.
- Cursor: the newest line number of this log (it formats what is pending first). LogId: this domain's log id.
- Read(after, max = 50): the lines after a cursor: Entries (Number, Seq, Id, Kind, Line, Get(key), IsQuoted(key)), Text,
  Cursor, Missed (lines that left memory), StaleCursor (a cursor from another domain: read edits.txt), Dropped,
  FilePath, Summary.
- Recipes:
  INVOKE $go.SetActive(false);
  INVOKE [STATIC:UQL.Runtime.UqlEditLog].MarkDirty($go);       // after a raw INVOKE that changed a scene object
  VALUE $mark = 0; VALUE $r = null;
  $mark = [STATIC:UQL.Runtime.UqlEditLog].Cursor;
  EDIT $player.transform.position = (4, 2, 3);
  $r = [STATIC:UQL.Runtime.UqlEditLog].Read($mark, 20); LOG $r.Text;
  INVOKE [STATIC:UQL.Runtime.UqlEditLog].FlushDirty();         // need isDirty in the same tick

DIRTY OUTCOMES (dirty=)
marked / already (the scene; already dirty scenes are not marked again), stage-marked / stage-already (the open Prefab
stage; with Prefab Mode auto-save on, Unity saves the stage within one update), stage-unmarked (revision 74: not marked
because Prefab Mode auto-save is on or in an unknown state, so a mark would save the prefab at once, and the user's Editor
switch 'Allow saving / discarding changes' is off; the edit stays in memory: it is lost when the stage closes, but with
auto-save on any later change in this stage saves it together with that change), overrides=recorded/deferred/
not-recorded/failed (prefab instances), asset (editDirty = 2), asset-unmarked (editDirty = 1: the change stays in
memory; Unity writes it only if something else saves that asset; since revision 74 also with editDirty = 2 or MarkDirty
while 'Allow saving / discarding changes' is off, with that reason), not-saveable-asset (imported, built-in or package
asset: never saved), settings-dirty (a project-settings static such as Physics.gravity: Unity marks its settings asset itself;
restore it with DEFER CALL), not-saved (DontSaveInEditor
object or ancestor), preview (a LoadPrefabContents preview scene: save it with PrefabUtility.SaveAsPrefabAsset),
no-scene, in-memory (a new Material or ScriptableObject.CreateInstance; with dirtyOwner and ownerKind=in-memory the
scene of the component that holds it was marked; otherwise call MarkDirty on that component), destroyed,
none:native (native memory is never serialized), none:static, none:managed, none:unknown-owner (a captured path that
reached no Unity object), off (editDirty = 0), play (Play Mode: never marked; persistent=yes for an asset that keeps
the change in memory), transition, held:test-run (marked after TEST RUN's start hold), no-editor (player or plain
host), failed (with dirtyError; the EDIT itself was written).

TIMING AND PLAYERS
Marks happen once per object at the end of the host tick (and at Play transitions and C# refresh); FlushDirty() marks at
once. Formatting is time-sliced (4 ms per Editor update, 1 ms in Play Mode and players). Players log only Explorer edits
by default (editLog = 2 adds script EDITs) and mark nothing; without a channel workspace the log stays in memory (Read).
Reference topic · Language referenceLIMITSOne global limits preset per Conductor workspace, stored in Config/Conductor.xml <Limits .../>: BUCKET entries, RECORD/LOG/SELECT/OBSERVE characters, registry and output.txt sizes, process/CALL/history limits and scheduler/hook budgets. Group values apply at each group's next compile; host.txt shows the effective values. Quick presets (default, agent, large-data, play-safe, low-memory) give a starting point: <Limits preset="large-data" />.

One global limits preset per Conductor workspace, stored in Config/Conductor.xml <Limits .../>: BUCKET entries, RECORD/LOG/SELECT/OBSERVE characters, registry and output.txt sizes, process/CALL/history limits and scheduler/hook budgets. Group values apply at each group's next compile; host.txt shows the effective values. Quick presets (default, agent, large-data, play-safe, low-memory) give a starting point: <Limits preset="large-data" />.

Where to use it

Reference topic; Conductor Config / Editor Limits section, not UQL syntax

Example

<Limits bucketEntries="200000" logCharacters="262144" />
Read this topic in your connected host.

The detailed LIMITS report uses your host’s current settings and capabilities. Enter HELP LIMITS; in the UQL Terminal to see it. The website does not connect to or inspect your Unity project.

Reference topic · Language referenceGAMEDifferences between game-time controls and Editor Play Mode controls.

Differences between game-time controls and Editor Play Mode controls.

Where to use it

Reference topic; not a command

Example

HELP GAME;

Detailed reference

From the in-tool help for GAME.

GAME TIME CONTROL
PAUSE;  // Time.timeScale = 0; repeated PAUSE retains the previous positive scale
PLAY;   // if currently paused, restore that scale (default 1 if externally paused)
TIMESCALE = 2;   // finite, non-negative scalar; TIMESCALE = 0 pauses scaled time
These commands work in regular BLOCKs and terminal, including players.
This does not pause the Editor, Update, unscaled time, audio or all game subsystems.
UQL terminal/TRACE use unscaled host time and can remain active to issue PLAY.
State is engine-global and persists after script/terminal disposal. Use PLAY to resume.
PAUSEMODE; // pause Editor Play Mode, without changing timeScale
PLAYMODE;  // resume Editor Play Mode; does not start a new session
STARTPLAY; // request entry into Editor Play Mode
STOPPLAY;  // request exit from Editor Play Mode
STARTPLAY/STOPPLAY queue a transition on a later EditorApplication.update after the
host Tick returns, independently of inspector repaint. A one-shot QueuePlayerLoopUpdate
requests engine progress; it does not guarantee background entry or steal OS focus.
Duplicate pending requests coalesce; conflicting requests are rejected. Compilation/import
delays dispatch. A pending transition waits while it progresses: compilation or import is
observed, or the mode moves toward the target (revision 53, IO-ADAPTIVE). It times out after
progressSeconds (Limits preset, default 60) without progress, or at progressCapSeconds
(default 1800) in total, and its status names the last observed state; both are observed
when Editor updates resume. An already-dispatched native transition is not cancelled.
STARTPLAY while the Editor has compiler errors is refused at once ('STARTPLAY refused: the
Editor has compiler errors ...'): Unity does not enter Play Mode until they are fixed.
STOPPLAY is never refused for them. host.txt Editor transition: shows a finished status
(completed, timed out, refused, failed) until a host.txt that contains it was published, then
15 s more, and then idle again.
EDITOR CONSENT (revision 74; HELP CONSENT): STARTPLAY, STOPPLAY, PAUSEMODE and PLAYMODE need the
user's Editor switch 'Allow interruptions' (UQL window, Request channel; on by default; only the user
switches it). While it is off, STARTPLAY and STOPPLAY are refused at the request (a transition that
is already pending is not cancelled by that check) and at the dispatch when the switch went off while
the request was queued; PAUSEMODE and PLAYMODE are refused in Play Mode. A request that changes
nothing is not refused: STARTPLAY in Play Mode, STOPPLAY in Edit Mode, PAUSEMODE while paused,
PLAYMODE while running. host.txt Editor transition: shows the refusal like the compiler-error one:
  STARTPLAY refused (UQL406): 'Allow interruptions' is off in the UQL window (only the user can
  switch it), so UQL does not change the Editor's Play mode; nothing was changed. NEXT: ask the user
  to switch on 'Allow interruptions' (UQL window, Request channel), then run STARTPLAY again.
At the dispatch it says '... was switched off before the request was dispatched; nothing was
changed.', PAUSEMODE/PLAYMODE '... so UQL does not press the Editor's Pause button; ...'. With the
switch off the user's own PLAYMODE; typed into the runtime terminal while paused is refused too.
Process warning (revision 74): a control command that is refused or ignored (the switch, compiler
errors, another pending transition, 'PAUSEMODE ignored: Editor is not in Play Mode.', a player's
Editor-only text) also counts one process warning (PROCESSES warnings=, run evidence firstWarning=)
with that text; the process continues.
The current host's host.txt reports actual Playing, Run in background and Editor transition state.
It also identifies the connected project name/path, configured product name, Unity version,
process ID (where available) and host kind. Identity is cached at connection; session IDs
change across reconnect/reload. Project name is the folder name, not the product name.
Addressed Editor hosts claim one channel; different projects use independent channels.
Verify expected project path and fresh session/timestamp before sending mutations.
Domain reload resets in-memory request status; actual Playing remains authoritative.
Application.isFocused means Game View focus in Editor, not OS window focus. Use
EditorApplication.isFocused to query OS focus. Both properties are read-only.
EDIT [STATIC:UnityEngine.Application].runInBackground = true; permits background play
where supported; it does not by itself start Play Mode. This is engine-global, opt-in,
and is not automatically changed/restored by UQL. No hard background timing guarantee.
They do not change Application.isPlaying in the calling instruction.
Do not chain PAUSEMODE immediately after STARTPLAY expecting Play Mode to be ready.
Editor controls use #if UNITY_EDITOR. In players they log an unsupported message and
continue. Transitions can reload scripts/destroy the terminal; do not rely on following
instructions surviving STOPPLAY/STARTPLAY. The runtime overlay is not an Edit Mode window;
STARTPLAY is usable from an Editor host that runs UQL while not playing.
While Editor-paused, the enabled terminal pumps unscaled debug updates so PLAYMODE can
be submitted. This does not advance game frames; UQL scheduler ticks are not engine frames.
Host can replace group.GameControl (IUqlGameControl), disable it with null, or override
commands. Optional IUqlTimeScaleControl / IUqlEditorGameControl add the new capabilities.
Unsupported/disabled control reports a message instead of breaking execution.
Reference topic · Language referenceSCENEScene discovery with FIND/COLLECT and session identities, and the SCENE commands (OPEN, LOAD, UNLOAD, SETACTIVE, SAVE, LIST) that change which scenes are loaded, with dirty-scene protection and a waiting, evidence-bearing result.

Scene discovery with FIND/COLLECT and session identities, and the SCENE commands (OPEN, LOAD, UNLOAD, SETACTIVE, SAVE, LIST) that change which scenes are loaded, with dirty-scene protection and a waiting, evidence-bearing result.

Where to use it

Reference topic; FIND/COLLECT are commands; SCENE <verb> is the command family

Example

HELP SCENE;
SCENE LIST INTO $s;

Detailed reference

From the in-tool help for SCENE.

SCENE DISCOVERY / PROGRAMMATIC EXPLORER
VALUE $root = null;
FIND "MonoManagers" IN SCENE INTO $root;  // first exact name, null if missing
ALIAS $manager = $root;                   // immutable path to the VALUE slot
BUCKET $matches; COLLECT "MonoManagers" IN SCENE INTO $matches;
BUCKET $children; COLLECT CHILDS $root INTO $children;
COLLECT CHILDS RECURSIVE $root INTO $children; // preorder descendants, excludes root
BUCKET $parts; COLLECT COMPONENTS $root INTO $parts;
BUCKET $cameras; COLLECT COMPONENTS $root OF UnityEngine.Camera INTO $cameras;
ITERATE $parts AS $entry {
    RECORD $entry[TYPENAME]; RECORD NEWLINE;
    RECORD BLUEPRINT $entry;
}
REGISTER managers;
BUCKET $roots; COLLECT ROOTS IN SCENE INTO $roots;
ITERATE $roots AS $go {
    READ $go[NAME];
    COLLECT COMPONENTS $go INTO $parts; // no RESOLVE intermediary required
}

FIND/COLLECT are executable BLOCK commands (or temporary terminal entry commands).
They do not turn ALIAS into a runtime assignment. Name matching is exact/case-sensitive.
FIND accepts a string expression: FIND "Enemy" IN SCENE INTO $root; uses a literal,
while FIND $name IN SCENE INTO $root; reads a string VALUE/path. Bare Enemy is a path,
not an implicit string; a valid path returning text still works. Captured string paths
are resolved directly. Null or non-string inputs produce a process diagnostic.
All loaded valid scene objects participate, including inactive/persistent objects.
No silent discovery cap. First match order is Unity discovery order, not a stable save ID.
COLLECT appends captured weak session paths; all duplicates remain individually resolvable.
CHILDS/COMPONENTS accept captured BUCKET entries directly, resolving each input once.
COMPONENTS OF Type uses a compile-time qualified type name or registered alias and Unity's
typed GetComponents API. Derived components and interfaces match. Only matching components
get captured paths. Missing-script slots are skipped; a capacity/read failure adds nothing.
The input can be a GameObject or Component (its owner), including captured entries.
This filters one object's attached components, not a recursive scene/member scan.
ROOTS selects parentless GameObjects in the same scene scope, not assets or descendants.
It enumerates loaded GameObject metadata (including persistent roots), without scanning
members or creating a captured path for every child. It is not a constant-time lookup.
ROOT $root INTO $pathOrTextValue; binds/exports the same identity explicitly (HELP ROOT).
FIND INSTANCEID $id INTO $root; finds an object again by its 64-bit session id (HELP INSTANCEID).
Bucket capacity failure leaves prior contents intact; CLEAR the bucket before refreshing.
Scene scans and capture compilation are synchronous setup work, not hot path reads.
Nested ITERATE supports hierarchical queries; a single expression accepts one range.
Native collection queries require explicit grants (Settings / ENABLE UNSAFE READ; HELP NATIVE). General WHERE/sorting
is not added. Use IF inside your loops.

SCENE COMMANDS (CHANGE WHICH SCENES ARE LOADED)
VALUE $r = null; VALUE $s = null;
SCENE LIST INTO $s;                                    // read: Execute grant only; works in every mode
SCENE OPEN "Assets/Scenes/Level2.unity";             // single; refused if a scene it closes is dirty
SCENE OPEN "Level2" SAVE CHANGES;                    // save the dirty scenes it closes, then open (Edit grant)
SCENE OPEN ACTIVE DISCARD CHANGES REPORT $r;           // reload the active scene, dropping its unsaved changes (Edit grant)
SCENE LOAD "Arena_Lighting" TIMEOUT 600 FRAME;       // additive
SCENE LOAD BUILD 3 REPORT $r;                          // Build Settings index (enabled entries, in order)
SCENE SETACTIVE "Arena_Lighting";
SCENE UNLOAD "Arena_Lighting";
SCENE SAVE ACTIVE;   SCENE SAVE ALL;   SCENE SAVE $untitled AS "Assets/Scenes/Generated.unity";   // Edit grant
SCENE UNLOAD "ProbeScene" DISCARD CHANGES NOWAIT;      // allowed in DEFER cleanup; waiting forms are UQL218 there

Targets: ACTIVE; BUILD n (these two are keywords only when written bare: a string such as "ACTIVE" or "BUILD 0", or a VALUE
holding it, is a scene name); a string with / or ending .unity is an asset path (loaded scenes, then Build Settings, then
project scene assets in the Editor); any other string is a scene name (a unique loaded scene; for OPEN/LOAD otherwise a
unique Build Settings file name, then a unique project scene); an integer is a loaded scene's handle (the report's
64-bit Handle, never narrowed); a Scene value must be one of the scene manager's scenes (a Prefab-stage preview scene,
the DontDestroyOnLoad scene or a stale value is refused by name). More than one candidate is refused with up to 10 paths,
no match with similar names. OPEN and LOAD need a path: an untitled scene is refused (SCENE SAVE ... AS first).
Modes: Edit Mode (UQL Editor service) opens, closes and saves with EditorSceneManager; Play Mode loads enabled Build
Settings scenes with SceneManager.LoadSceneAsync and any other scene asset with LoadSceneAsyncInPlayMode (Route says a
player cannot load it); players load enabled Build Settings scenes only; SAVE is Edit Mode only. Without the Editor
service, Edit Mode scene commands are Unavailable. Every mutation is dispatched on a later Editor update, outside any VM
instruction, so [ExecuteAlways] Awake/OnEnable/OnDestroy and scene callbacks run with no UQL instruction executing.
Never used: SaveOpenScenes, SaveModifiedScenesIfUserWantsTo, SaveCurrentModifiedScenesIfUserWantsTo,
EnsureUntitledSceneHasBeenSaved (modal dialogs stop the host).
Dirty-scene protection (Edit Mode): OPEN closes every loaded scene, UNLOAD closes its target. If one of them has unsaved
changes (UQL EDITs mark scenes dirty since revision 56) the command is Refused and lists them; nothing is saved, opened or
closed. SAVE CHANGES saves them first (an untitled dirty scene is refused: it has no path), DISCARD CHANGES drops them and
the report's Discarded lists them. A Prefab stage with unsaved changes refuses every Edit Mode scene command (Unity would show
a modal prompt). The decision is made again at the dispatch: a scene dirtied while the request waited refuses it.
Editor consent (revision 74; HELP CONSENT): in Edit Mode OPEN, LOAD, UNLOAD and SETACTIVE need the user's Editor switch
'Allow interruptions' (on by default). While it is off they are Refused before the target is resolved (so a would-be
no-change is refused too), with the Error
  UQL406: 'Allow interruptions' is off in the UQL window (only the user can switch it), so UQL does not change the scenes
  open in the Editor (Edit Mode); SCENE LIST still works and Play Mode scene commands are not affected
SCENE SAVE (a dirty target, ALL with dirty scenes, AS) and SAVE CHANGES / DISCARD CHANGES with dirty scenes need, in Edit
Mode, the switch 'Allow saving / discarding changes' (off by default and off again after every Editor start). While it is
off they are Refused with UQL407, for example
  UQL407: SAVE CHANGES would save <labels>, but 'Allow saving / discarding changes' is off in the UQL window (only the
  user can switch it)
nothing is saved or dropped, and the scenes stay dirty, so closing without saving still undoes UQL's edits. A clean SAVE
target stays a no-change, SAVE CHANGES / DISCARD CHANGES without dirty scenes proceed, and a Play Mode DISCARD CHANGES keeps
its note. Both switches are read again at the dispatch ('UQL406: 'Allow interruptions' was switched off before the request
ran; nothing was changed', 'UQL407: 'Allow saving / discarding changes' is off in the UQL window and the request would save
<labels>; nothing was changed'; these dispatch refusals carry no Next). At the request the report's Next names the switch;
a refused DISCARD CHANGES lists nothing in Discarded (nothing was dropped; Dirty lists the dirty scenes). No Unity
Console line. While saves are off, the Next
of a dirty-scene refusal ends: With 'Allow saving / discarding changes' off (UQL window), SCENE SAVE, SAVE CHANGES and
DISCARD CHANGES are refused: ask the user to save or revert these scenes, or to switch it on.
Host protection: with a runtime terminal (its GameObject is the group's HostAnchor) OPEN is refused while the host lives in any
loaded scene (it closes all of them and recreates a reopened one) and UNLOAD while the host lives in its target scene, unless
the host is in DontDestroyOnLoad; no SAVE/DISCARD CHANGES policy overrides it, LOAD and SETACTIVE are not affected, and the
check is repeated at the dispatch. The Editor file host has no anchor, so the check is inert there.
Waiting: the statement waits like WAIT UNTIL (the process shows Waiting). TIMEOUT n FRAME|SECOND bounds it; on expiry a
request that Unity has not started is withdrawn (nothing changed), a started Unity operation continues as an orphan (Unity
cannot cancel a scene load) and SCENE LIST shows it. Without TIMEOUT the progress rule applies: Failed after
progressSeconds without progress while frames advance (cap progressCapSeconds); these two keys come from the Limits
preset, not LIMITOPT. SETACTIVE and SAVE take no TIMEOUT. One waiting command exists at a time (a second is refused and
names the holder); at most 8 requests are queued. NOWAIT returns Started; the request survives the group (DEFER cleanup),
and its outcome goes to the host journal. STOP, ABORT or group release withdraws a still-queued request.
Run evidence: every waiting command leaves one SCENE row, a Cancelled row included when STOP, ABORT, a group release or a Play
transition ended the statement (a request Unity already runs stays an orphan and the row says orphan=yes). A NOWAIT command's
row says Started; its final outcome is only in the host journal (requests.log).
Result: SCENE ... REPORT $r stores a UqlSceneReport (Operation, Status Completed|NoChange|Started|Refused|Failed|TimedOut|
Cancelled|Unavailable, Success, Changed, RequestState, Error, Next, Text, Mode, Route, Resolution, TargetPath, TargetHandle,
Dirty, Saved, Discarded, Before, After, ActiveBefore, ActiveAfter, Events, Orphans, Frames, Seconds, StaleRoots, ...);
success is silent. Without REPORT success logs one line; a failure logs the full report text and fails the process with a
one-line error (DEFER cleanup still runs). SCENE LIST INTO $s stores a UqlSceneListReport. StaleRoots counts the issuing
group's ROOT identities that died while the command ran.
Grants: SAVE and the SAVE / DISCARD CHANGES policies need Edit (compile-time UQL403); at run time also the user's Editor switch 'Allow saving / discarding changes' (UQL407, off by default);
everything else needs Execute only (in Edit Mode OPEN / LOAD / UNLOAD / SETACTIVE also need 'Allow interruptions', UQL406).
HOOK: SCENE publishes no HOOK. Cost: nothing runs unless a SCENE statement executes; ordinary path reads, ALIAS execution and
the 16-byte instruction layout are unchanged.
Reference topic · Language referencePATCHINGOptional IL patch points (PATCH-LANG): PATCH declarations, APPLY / REMOVE / ENABLE / DISABLE PATCH, PATCHCONTEXT in the hook BLOCK and PATCHINFO; what the optional executor does, and what a result does and does not prove.

Optional IL patch points (PATCH-LANG): PATCH declarations, APPLY / REMOVE / ENABLE / DISABLE PATCH, PATCHCONTEXT in the hook BLOCK and PATCHINFO; what the optional executor does, and what a result does and does not prove.

Where to use it

Reference topic; the PATCH command family needs the optional UQL IL Patch module

Requires the relevant optional module. Check the module requirements in your installed version.

Example

HELP PATCHING;

Detailed reference

From the in-tool help for PATCHING.

PATCH POINTS (optional UQL IL Patch module)
Named observation points inside already loaded game methods, installed without editing or recompiling the game's source.
A real game call reaches the point, the HOOK BLOCK runs synchronously and the original method continues. It is not a
breakpoint, not a body replacement and not arbitrary C#.

PATCH $damage = TYPE(Game.Health).ApplyDamage(TYPE(System.Int32), TYPE(System.Boolean)) AT LINE 84 HOOK DamagePoint CONTEXT;
BLOCK Install     { APPLY PATCH $damage WAIT; PATCHINFO $damage; }
BLOCK DamagePoint { RECORD FIELDS who=PATCHCONTEXT.THIS, damage=PATCHCONTEXT.damage, point=PATCHCONTEXT.POINT; RECORD NEWLINE; REGISTER Hits; }
BLOCK Pause  { DISABLE PATCH $damage; }     BLOCK Resume { ENABLE PATCH $damage; }
BLOCK Remove { REMOVE PATCH $damage WAIT; }

Declaration: PATCH is an immutable descriptor (global or BLOCK scope, like ALIAS); declaring or compiling it changes nothing.
The overload types select the method by metadata; the method is not called. The method must be declared on the named type
(a base-class method: name the base type) and have an IL body. Refused in this version, with a NEXT line: generic types and
methods, ref / out / in and pointer parameters, by-reference returns, abstract, extern and accessor (property / event /
operator) targets. Points: AT ENTRY (default, needs no symbols), AT EXIT (normal return), AT LINE n [COLUMN c] [SOURCE "path"]
(an exact compiled sequence point; the observation runs before it; never a nearest line). The executor states which points
and context shapes it serves; a refusal is a compile error (UQL462). What an installed executor serves is shown by host.txt
'Patches:' (name, version and points) and PATCHINFO (the point facts). The UQL IL Patch addon 10 serves ENTRY, normal EXIT
and exact LINE points; PATCHCONTEXT.THIS works on ordinary instance methods of reference types (also parameterless Unity
callbacks such as Update), and captured arguments only in its tested (int, bool) profile.
HOOK names a parameterless BLOCK of the same group; hook identity is the BLOCK name, so every group with a BLOCK of that
name receives the publication, as for every HOOK.
Requests: APPLY and REMOVE never block the Editor; the executor installs and removes from its own idle pump. WAIT yields
the process until the request is final (Succeeded, Failed, Cancelled, Expired); it is not a wait for a hit. The wait has a
last-resort cap (the Limits preset's progress cap, 1800 s by default) after which it is Expired. ENABLE and DISABLE are
immediate flags on an installed point and keep the lease; REMOVE disables first. Ownership belongs to the host and the
group's hook hub, not to one compile: recompiling the same declaration keeps its point serving the new BLOCKs (APPLY then
confirms it), a changed point / HOOK / capture set must REMOVE first, a second declaration of the same method is refused, a
failed cleanup keeps a retained lease until a REMOVE retry succeeds. A reset hub (Play start, domain reload) ends the point.
A group keeps the executor it was compiled with; when another one registers, compile the group again.
PATCHCONTEXT (CONTEXT declarations only, in the hook BLOCK itself): THIS, ARGn, a parameter name, POINT. Typed from the
declaration; only what the BLOCK reads is captured. There is no context after a WAIT (a WAIT EVENT resumed by a later call of the
point reads that new call), in a CALL-ed / START-ed BLOCK, or when the BLOCK was started by TRIGGER or C#; copy values into VALUEs
first. A BLOCK that reads PATCHCONTEXT is named only by CONTEXT declarations. A parameter named like a keyword (point, arg0) is read
in any spelling but capitals; PATCHCONTEXT.POINT stays the keyword. Another declaration's call (another group) and a
point installed with another capture set are refused, never read.
Evidence: one PATCH row per APPLY / REMOVE / ENABLE / DISABLE in the run evidence (op, status, patch, target, hook, receipt,
wait, process, seconds, orphan, error, detail). host.txt 'Patches:' names the executor (name, version, points) and counts requests. PATCHINFO
reports the request, the point, the lease and hit counters; a counter the executor does not measure is 'unknown'.
Grants: the declaration and the four verbs need Events (UQL403), PATCHINFO needs Execute only. Diagnostics: UQL460 module
not installed, UQL461 target, UQL462 point / executor refusal, UQL463 HOOK BLOCK, UQL464 PATCH symbol misuse, UQL465 duplicate
method and point (warning), UQL466 PATCHCONTEXT.
Limits of the technique (stated, not hidden): inlined or prewarmed call sites can bypass a late patch; no hit does not prove
the path never ran; removing a detour does not promise reversal of runtime or JIT metadata; no zero-GC, crash-free,
arbitrary-method, CoreCLR, Unity 6 or IL2CPP claim. Cost: nothing runs unless a PATCH statement executes or a patched call
arrives; ordinary path reads, ALIAS execution and the 16-byte instruction layout are unchanged.
Reference topic · Language referenceKBASSET-KB: the agents' own persistent asset knowledge - KB NOTE, KB FIND and KB FORGET, subjects and handles, fingerprints and stale notes, RELATED [DEPTH 1..3] (sprites, texture, direct dependencies and, from the reverse dependency index, the assets that use it), KB COMPACT, the store file Workspace/Knowledge/<host-id>/assets.kb, the host.txt Knowledge line, the reports and the limits.

ASSET-KB: the agents' own persistent asset knowledge - KB NOTE, KB FIND and KB FORGET, subjects and handles, fingerprints and stale notes, RELATED [DEPTH 1..3] (sprites, texture, direct dependencies and, from the reverse dependency index, the assets that use it), KB COMPACT, the store file Workspace/Knowledge/<host-id>/assets.kb, the host.txt Knowledge line, the reports and the limits.

Where to use it

Reference topic; KB NOTE, KB FIND and KB FORGET are the commands

Example

HELP KB;

Detailed reference

From the in-tool help for KB.

KB (ASSET KNOWLEDGE STORE, revision 69)
A store agents write for themselves: once you have worked out what an asset is or does, note it against the asset's
stable identity and find it again later by any handle you have, instead of re-reading code, ScriptableObjects and prefabs.

VALUE $r = null; VALUE $k = null; VALUE $c = null; VALUE $sprite = null;
KB NOTE $sprite TEXT "Icon of item sword_03 (ItemDatabase row 41); shown in the shop and the inventory grid." FIELDS item = "sword_03", tier = 2 TAGS "item", "weapon" ALIAS "item:sword_03" REPORT $r;
KB FIND "item:sword_03" INTO $k;   LOG $k.Text;
KB FIND TAG "weapon" FIELD tier = 2 COUNT 20 INTO $k;
KB FIND TEXT CONTAINS "shop" COUNT 20 FROM 20 INTO $k;
KB FIND $sprite RELATED INTO $k;   LOG $k.Text;
KB FIND $sprite RELATED DEPTH 2 INTO $k;
KB FIND $sprite HISTORY INTO $k;
KB FORGET $k.Notes[0].Id REASON "the item was removed";
KB COMPACT REPORT $c;   LOG $c.Text;

Grammar:
  KB NOTE <subject> TEXT <text> [FIELDS k = v, ...] [TAGS t, ...] [ALIAS a, ...] [REPLACES <noteId>] [REPORT $r];
  KB FIND <condition> ... [RELATED [DEPTH n]] [HISTORY] [COUNT n] [FROM k] INTO $r;     DEPTH: an integer literal 1..3 (default 1)
      <condition> := <subject-or-handle> | TAG <t> | FIELD <k> = <v> | TEXT CONTAINS <s>
  KB FORGET <noteId> [REASON <text>];
  KB COMPACT [REPORT $r];
KB starts a statement only before NOTE, FIND, FORGET or COMPACT, and not while a host command named KB is registered.
Inside a BLOCK or in the terminal; options in any order, each once. A FIELDS / FIELD key is a name or a quoted text.
Subjects (KB NOTE): an asset object (its GUID and local file id; a sub-asset such as a Sprite inside a texture has its own),
a 32-hex GUID (the main asset), "guid:lfid", an asset path "Assets/..." or "Packages/...", an alias of an earlier note,
or the name of a noted asset (in the Editor also of exactly one project asset). Session instance ids and scene objects are
not subjects. Without the Editor's asset identity (players, plain hosts) a GUID or "guid:lfid" is taken as written and
only the store's own aliases, names and paths resolve; an asset object is refused there.
Handles (KB FIND): an asset object or "guid:lfid" finds the notes of that object and of its whole asset (bare GUID notes);
a GUID finds every note of the asset file, its sub-assets included; an asset path finds the notes written with that path
and those of the asset's GUID (a moved asset keeps its GUID); any other text matches an alias or the recorded name.
Matching ignores case; conditions combine with AND; results are newest first. COUNT (default 50, 0..1000; a clamp is
stated) and FROM (skip the k newest) bound the matching notes; Total counts all matches. TEXT CONTAINS "" matches every note.
FIELDS values are stored as text (numbers in invariant culture, bools true / false, enum names); FIELD k = v compares that
text. REPLACES hides the old note from KB FIND (Replaced, ReplacedBy) and links the new one (Replaces): repeat the ALIAS,
TAGS and FIELDS you want to keep. KB FORGET appends a tombstone; HISTORY lists forgotten and replaced notes too, flagged.
Freshness: in the Editor KB NOTE stores the fingerprint of the subject's asset file, AssetDatabase.GetAssetDependencyHash
(it changes with the file, its import settings and what it depends on) and the main asset's type (fingerprint=<hash>/<type>;
a sprite's note carries its texture file's). KB FIND checks every note it returns, one read per asset file, and sets
Freshness Fresh, Stale or Unknown. Stale, with StaleReason (several joined with "; "): content changed (the hash differs),
moved to <path> (the GUID resolves to another path; the note follows the GUID and keeps its old Path), type changed to
<type> (was <type>), missing asset (the GUID has no asset now). A stale note is still returned, marked in its head line, for
example [stale: content changed], and the header counts them (Freshness: 1 stale, 2 fresh, 0 unknown). It may still be
right: check it, then REPLACES writes the corrected note. Unknown (FreshnessReason), never Stale: a note without a
fingerprint (written without the Editor's asset identity, or before revision 68), a host without an asset identity
(players, plain hosts), an identity that failed, or no hash to compare. Freshness is per asset file: a changed sprite
sheet makes the notes of all its sprites stale.
RELATED [DEPTH n]: KB FIND <handle> RELATED also returns the notes of the subjects related to each handle subject. A
sub-asset reaches its main asset (texture of sword_03) and the assets that use its file (user of Items.png); a main asset
reaches its sub-assets (sprite of Items.png, from AssetDatabase.LoadAllAssetRepresentationsAtPath), the assets its file
uses directly (dependency of Hero.prefab, from AssetDatabase.GetDependencies(path, false): every note of that asset file)
and the assets that use its file (user of Items.png, from the reverse dependency index: every note of the user's file). A
GUID or asset path handle already finds its sub-assets' notes, so only its dependencies and users are related; an alias
or a name walks from the subjects of its notes. DEPTH 2 or 3 walks breadth first from the subjects the previous hop
reached (a main asset as above; a dependency or a user its own dependencies and users); Via is then the chain back to the
handle, for example "user of Items.png <- dependency of Hero.prefab" (Shop.prefab uses Items.png, which Hero.prefab
uses), and UqlKbRelation.Depth the hop. Every subject is searched once, cycles included, at the first hop that reaches it;
a handle subject's own file is not entered again. A user relation is file-level: Shop.prefab uses the file Items.png, not
necessarily the sprite you asked about. The other conditions still apply (AND); COUNT / FROM bound all matches. Each note
reached through a relation carries Via ("sprite of Items.png"; "" for the handle's own notes); Relations lists the
related subjects searched (Kind sprite / sub-asset / texture / main asset / dependency / user, Via, From, Depth, Subject,
Guid, LocalId, Path, Type, Name, Notes). Bounded for the whole walk: at most 256 related subjects are searched, the ones
with notes first; at most 256 subjects are walked (handle subjects first) and none once 256 related subjects were found;
RelationsStatus Cut and the Related line state what was left out (RelationsFound counts all found). Partial: the asset
identity failed during the walk, or the reverse dependency index is not ready; Unavailable: no asset identity in this
host (only the handle's own notes are listed).
Reverse dependency index (what uses an asset): built on demand by the Editor's asset identity for the first KB FIND ...
RELATED and kept for the domain. The asset paths under Assets/ (AssetDatabase.GetAllAssetPaths) are listed once, then the
direct dependencies of each asset are read once, 4 ms per Editor update (the KB FIND that needs it and the Editor's pump
share that slice), so the Editor is never blocked. Until it is ready a KB FIND searches the uses read so far:
RelationsStatus Partial, ReverseIndex Building, ReverseIndexDone of ReverseIndexTotal assets, and the line Reverse index
(what uses an asset): building - 120 of 450 assets read (26%) - run KB FIND again later (WAIT 1 SECOND in a loop until
RelationsStatus is not Partial). An asset import, refresh, move or delete (EditorApplication.projectChanged) makes it
stale: the next KB FIND ... RELATED builds it again, and a change during a build restarts it. Assets whose read failed
are counted and named; Failed (the project could not be listed, or 16 assets in a row could not be read; tried again by
the next KB FIND ... RELATED) and Unavailable (an identity without a project listing) give no user relations.
Reports: KB NOTE ... REPORT $r stores a UqlKbNoteReceipt (Verb, Status Written|Memory|Pending|NoChange|Refused|Error,
Success, Error, Text, Id, Note, Replaced, File). KB FIND ... INTO $k stores a UqlKbReport (Status Complete|Memory|Error,
Success, Error, Text, Notes, Total, From, RequestedCount, AppliedCount, CountClamped, History, Filter, File, StoreNotes,
FreshCount, StaleCount, UnknownCount, Related, RelationsStatus, Relations, RelationsFound, RelatedNotes, Depth,
ReverseIndex, ReverseIndexDone, ReverseIndexTotal). KB COMPACT ... REPORT $c stores a UqlKbCompactReceipt (Status
Compacted|Memory|NoChange|Error, Success, Error, Text, Kept, Dropped, Forgotten, Replaced, OtherLines, LinesBefore,
LinesAfter, BytesBefore, BytesAfter, File, Backup).
A note (UqlKbNote): Id, Utc, Subject, Guid, LocalId, Path, Type, Name, Aliases, Tags, Fields (Key, Value; Field("key")),
Text, Replaces, ReplacedBy, Replaced, Forgotten, ForgottenUtc, ForgetReason, Group, Request, Process, Host, Session,
Revision, Provenance, Fingerprint, Freshness, Stale, StaleReason, FreshnessReason, Via, Related. A note is a claim with
provenance, not a fact the store verifies: path, type and name are those at write time.
Output rule: KB NOTE without REPORT, KB FORGET and KB COMPACT without REPORT log one line on success; a refusal or an
error logs the full text and fails the process with a one-line error (DEFER cleanup still runs). With REPORT the receipt
is stored and the process continues (a refusal or an error is logged and counted as a warning). KB FIND stores its
report; a failed FIND is logged and warned, and the process continues. A Pending write is a warning.
Store: Workspace/Knowledge/<host-id>/assets.kb in the channel workspace (not Config, not the Unity project); one line per
record, values bare or quoted (\\ \" \r \n \t \uXXXX), a list value with its items separated by \n (fields as key=value):
  UQL-KB 1                                                    the first line of the file
  <utc> OPEN log=<log> host= session= revision=               the first write of each domain
  <utc> NOTE id=<log>-<seq> subject=<guid>[:<lfid>] path= type= name= fingerprint= aliases= tags= fields= text= replaces= group= request= process= host= session= revision=
  <utc> FORGET id=<id> reason= group= request= process= host= session= revision=
  <utc> COMPACT log=<log> kept= forgotten= replaced= lines= bytes= group= request= process= host= session= revision=
Readers skip unknown kinds and keys and broken lines (an open quote, or no revision=, the last key of every NOTE / FORGET
line: a line cut off by a crash is ended by the next write and stays skipped; revision 67 readers skip fingerprint=). Append-only, no cap but the disk. The host reads the file at its
first KB statement and again whenever its length changed (another writer), and appends each NOTE / FORGET at once; a held
file is retried briefly, then the line stays pending in memory (Status Pending) and is written first by the next KB NOTE /
FORGET (a domain reload loses it). Read the file with FileShare.ReadWrite | FileShare.Delete. The terminal, players and
hosts without a Conductor workspace keep one memory store per domain (Status Memory; lost at a domain reload).
KB COMPACT: rewrites the store without its forgotten and replaced notes. The NOTE lines of current notes are kept unchanged
(ids, provenance, unknown keys), and lines of record kinds a newer revision wrote are kept too; the NOTE lines of the
dropped notes, their tombstones, the OPEN / COMPACT housekeeping lines and broken lines are dropped. The file gets a new
header, this host's OPEN line and one COMPACT line with the counts; lines still pending in memory are written with it.
It is written as assets.kb.new, which replaces assets.kb atomically (File.Replace); the previous file stays as
assets.kb.1 (an older assets.kb.1 is replaced: one generation). The file must not change between the read and the
replace (another writer): then, and when the replace fails, assets.kb is left as it was (Status Error). NoChange when
nothing is to drop. HISTORY no longer lists the dropped notes; assets.kb.1 still has them. A memory store drops them in
memory (Status Memory).
host.txt: 'Knowledge: notes=N subjects=N aliases=N bytes=N reverse-index=<state> file=<path>' (after 'Patches:'), once
this domain read or wrote the host's store (its first KB statement): the current notes, their distinct subjects and
aliases, the file length, the reverse index (none, building:<read>/<assets>, ready, stale, failed or unavailable) and the
path, last because it may contain spaces. Counters only: the line is recounted after a change of the store, never read
from the file for host.txt.
Limits: TEXT up to 16384 characters; at most 32 tags, 32 aliases and 32 fields per note; a tag or alias up to 256
characters, a field key up to 128 and a value up to 1024 characters, each one line. Ids: <log>-<seq>, the log part new in
every domain.
Grants: Execute only (the store is not game or project state; KB COMPACT too). Diagnostics: UQL480 KB syntax (also a DEPTH
outside 1..3), UQL481 REPORT / INTO destination, UQL482 a literal operand or a list out of bounds, UQL483 COUNT / FROM not
an integer.
Not yet (later slices of ASSET-KB): the MCP uql_kb tool (the store read without Unity), and scene objects, types, HOOK
points and DOD meanings as subjects. Cost: nothing runs unless a KB statement executes (the freshness check and RELATED
read the asset identity only inside KB FIND; the reverse index is built only for a KB FIND ... RELATED and pumped only
while it is built); ordinary path reads, ALIAS execution and the 16-byte instruction layout are unchanged.
Reference topic · Language referenceCSHARP FUNCTIONSCSHARP-LANG: named C# functions next to the BLOCKs - CSHARP declarations and CSHARP USING lines, CALL ... INTO, the csharp grant, the compile lifecycle and the CSharp: result line, the assembly budget (csharpAssemblies), what a body can see and what it is not tracked for, UQL490-496 and the evidence. Needs the optional Editor-only module UQL CSharp Load.

CSHARP-LANG: named C# functions next to the BLOCKs - CSHARP declarations and CSHARP USING lines, CALL ... INTO, the csharp grant, the compile lifecycle and the CSharp: result line, the assembly budget (csharpAssemblies), what a body can see and what it is not tracked for, UQL490-496 and the evidence. Needs the optional Editor-only module UQL CSharp Load.

Where to use it

Reference topic; CSHARP and CSHARP USING are the declarations, CALL calls a function

Requires the relevant optional module. Check the module requirements in your installed version.

Example

HELP "CSHARP FUNCTIONS";

Detailed reference

From the in-tool help for CSHARP FUNCTIONS.

CSHARP FUNCTIONS (named C# functions, revision 72; optional Editor-only module UQL CSharp Load)
A group can declare named C# functions next to its BLOCKs and call them from any BLOCK with CALL. The optional module
compiles the group's C# when the group is compiled and loads it into the Editor domain; a call runs synchronously on the
Editor main thread, like an INVOKE of the same code. It is not a project script refresh (EditorRequest REFRESH_SCRIPTS
stays that), not an inline EVAL, not a sandbox and not for players. Without the module UQL runs as before, and a compile
of a group with a CSHARP declaration fails with one UQL490.

UQLSCRIPT EnemyProbe;
CSHARP USING "System.Text";
CSHARP CountActive(string tag) RETURNS int {
    int n = 0;
    foreach (var go in GameObject.FindGameObjectsWithTag(tag)) if (go.activeInHierarchy) n++;
    return n;
}
CSHARP Describe(Transform t, float scale) RETURNS string {
    return new StringBuilder(t.name).Append(" @ ").Append((t.position * scale).ToString("F2")).ToString();
}
ALIAS $player = [SCENE:Player];
BLOCK Main {
    VALUE $active = 0; VALUE $text = "";
    CALL CountActive("Enemy") INTO $active;
    CALL Describe($player.transform, 0.5) INTO $text;   // 0.5 is a double; it converts to float because it fits
    LOG LINE $active; LOG LINE $text;
}

Grammar (script level; UQL keywords ignore case, the C# text keeps C#'s rules):
  CSHARP Name(<C# parameters>) [RETURNS <C# type>] { <C# method body> }
  CSHARP USING "<using text>";          one using directive, written without 'using' and ';'
  CALL Name[(<expr>, ...)] [INTO $v];     inside a BLOCK; the parentheses may be left out for no parameters
CSHARP starts a declaration only at a statement start (after ;, { or }, after another declaration's body, or where the
header of a declaration without a body stopped), and not while a host command named CSHARP is registered; CSHARP USING is
read as ordinary UQL. The header (name, parameter list,
RETURNS type) and the body are raw C# text, copied verbatim into the unit: a } or the word BLOCK inside a C# string, char
literal or comment means nothing to UQL. A declaration inside a BLOCK is one UQL491 ('CSHARP declarations must be at
script level. NEXT: move the declaration out of the BLOCK, next to the BLOCKs.'); a forgotten body is one UQL491 and never
swallows the next BLOCK or CSHARP declaration.
Names: a UQL identifier that is also a C# identifier (letters, digits and _, not starting with a digit). Refused (UQL491):
a C# keyword, reserved or contextual (C# is case-sensitive: select is refused, Select is not); a name starting with __uql
in any case; ToString, Equals, GetHashCode, GetType, Finalize, MemberwiseClone and ReferenceEquals; a duplicate; a BLOCK
name of the group (BLOCKs and CSHARP functions share one name space across all sources). No overloads and no generic
functions. UQL words such as Block or Value are allowed.
Parameters: Type name, split at top-level commas (commas inside <>, () and [] belong to the type): int, Vector3,
List<GameObject>, (int, string), int[,], Dictionary<string, float>. Refused in this version, with a NEXT line: ref, out,
in, params, this, scoped, ref readonly, default values, attributes and RETURNS ref. Without RETURNS, or with RETURNS void,
the function returns nothing.
CSHARP USING: in any source, double or single quotes; the group uses the union of its lines, exact duplicates and the
default usings dropped. The text is not empty, has no ; { } quote, backslash, line break, // or /*, and does not start
with using. Forms: "System.Text", "static UnityEngine.Mathf", "V3 = UnityEngine.Vector3". Default usings: System,
System.Collections.Generic, System.Linq, UnityEngine; with them Object and Random are ambiguous (CS0104): write
UnityEngine.Object / UnityEngine.Random, or add an alias using. UnityEditor is not a default: CSHARP USING "UnityEditor";.
A group with USING lines but no CSHARP function compiles no C# (the lines still need the grant).
C# rules inside a body (the lexer reads them; a violation is UQL100 and the rest of the source is not parsed): # starts a
directive only as the first non-blank character of a line; a regular string, the text of a regular $"..." and a char
literal cannot cross a line (use @"..." or """..."""), verbatim and raw strings can; #if / #elif / #else / #endif and
#region / #endregion balance inside each body, and every #if branch ends at the brace depth where its #if started. UQL
reads the disabled #if branches that C# skips, so their text must still have closed strings and balanced braces.

Calls: CALL of a CSHARP name checks the argument count and the INTO target when the group is compiled, and each argument
against the compiled C# parameter type after the C# compile, before activation (UQL494), with the INVOKE rules: exact,
C# implicit widening (int to long, float or double), double to float when the value fits, numeric literals, tuple shapes
such as (1, 2, 3) to Vector3, null for a reference or a Nullable. An argument whose UQL type is object (an untyped VALUE,
a path) is converted when the CALL runs; a value that does not fit fails the process with a core text (UQL500, below)
before the body runs, so it is never blamed on the body. Paths and BUCKET entries are read live. A UnityEngine.Object
passes as its managed reference (a destroyed one compares equal to null in C#). INTO needs a writable VALUE whose type
accepts the return type (an untyped VALUE always does); a function without a return value refuses INTO. A value-type
result is stored like an INVOKE result.
CALL of a CSHARP function also works in DEFER cleanup BLOCKs, hook BLOCKs and AWAKE BLOCKs.
Not in this version: a call inside an expression (VALUE $v = Name(...), IF, LOG, RECORD FIELDS: write CALL ... INTO $v and
use $v); SCAN / SELECT WHERE; CHECK operands (CALL INTO a VALUE, OBSERVE it, CHECK the cell); a function as a HOOK
receiver, a PATCH HOOK target, a path root or a value (UQL494); START or DEFER CALL of a function (wrap the CALL in a
BLOCK); an inline CSHARP { } inside a BLOCK; [STATIC:UqlCSharpUnits.*] and TYPE(UqlCSharpUnits.*) (refused at bind time:
the generated names change with every unit).

Compile lifecycle (the file-channel host: compile requests, the UQL window, the MCP tools):
1. The UQL compile (synchronous, as always) builds one C# unit per group: namespace UqlCSharpUnits, a static class
   __UqlUnit_<hash16> in an assembly UqlCSharpUnit_<hash16>, the functions in ordinal name order, one adapter per
   function. hash16 is the first 16 hex digits of the unit's SHA-256 hash; the unit text holds no source names, group
   names or positions, so the same functions and USING lines give the same unit whatever the source order or the edits
   elsewhere. The Editor's live syntax analysis never compiles C#. When the UQL compile fails, no C# compile is made.
2. The C# compile: the host hands the unit to the module once per group compile, on the Editor main thread, outside VM
   execution. In this version it is synchronous: the Editor waits for it (a first compile takes seconds, a reused unit
   is instant) and the host.txt heartbeat pauses meanwhile.
   A first CSHARP compile after a domain reload can take seconds even for a small unit (the installed compiler starts),
   and the host heartbeat pauses meanwhile.
3. Binding: C# errors and warnings are mapped to the .uql text, the loaded type is checked against the unit, one delegate
   per function is bound and every CALL site is checked against the compiled parameter types.
4. Activation (hooks, AWAKE BLOCKs) only after that. Any failure in steps 2-3 fails the compile and the previous active
   version keeps running (Previous version running: yes).
A check-only compile (see Budget) stops after step 2: its C# errors and warnings are reported as above, but nothing is
loaded or bound, the argument types of the CALL sites (UQL494) are checked only at activation and step 4 does not happen.
C# errors are compile errors of the group: in the same Result and CompileDiagnostic file as UQL errors and in Diagnostic
counts:, never in the Unity Console. The Result gets one CSharp: line before Diagnostic counts:, for example
  CSharp: unit 3fa2c9e1d0b74a55 ready, new assembly, 0.41 s; assemblies 12/100 (88 left)
  CSharp: unit 3fa2c9e1d0b74a55 ready, new assembly from the image cache, 0.02 s; assemblies 13/100 (87 left)
  CSharp: unit 3fa2c9e1d0b74a55 ready, reused; assemblies 12/100 (88 left)
  CSharp: check only, nothing loaded; call sites are checked at activation
  CSharp: failed, 3 errors, 2 warnings
  CSharp: failed, assembly limit (100/100)
The other failure forms are 'failed, stale reference', 'failed, backend refused', 'failed, backend changed', 'failed,
contract break', 'failed, still compiling in the backend (cancelled)' and 'failed, <n> call site errors'. A number the
module did not measure prints unknown ('ready, new assembly, time unknown; ...'). '; <U> warnings without a source
location' ends any form when the module reported warnings that point nowhere: they are counted there, not listed.

Budget: Mono cannot unload an assembly, so every distinct unit that is loaded stays in the Editor domain until the next
domain reload. csharpAssemblies (Limits preset, a workspace row: default 100, 1..4096; LIMITOPT refuses it; HELP LIMITS)
bounds them; at the limit the next new load is refused with UQL496, and UQL never reloads the domain by itself. A unit
that is already loaded is reused and counts nothing (it keeps the references and defines it was first compiled with until
the domain reloads), so compiling an unchanged CSHARP set again is free, while every activated edit of a body, a header
or a USING line costs one assembly. Iterate with check-only compiles and activate when the group compiles: a check
loads and runs nothing and costs no assembly (its call sites are checked at activation). The check-only forms are the
compile request with a sixth line CHECK (revision 75; HELP SCRIPT), MCP uql_compile (its default) and the host API
UqlFileWorkspace.Compile(group, activate: false). The compile request without CHECK, the UQL window's Compile, uql_run
and uql_compile activate:true activate: with grants:["csharp"] a successful C# compile then loads one assembly, which
the next activation of the same set reuses (same hash); a failing C# compile loads nothing. The CSharp: line shows the
remaining budget; a C# refresh (EditorRequest REFRESH_SCRIPTS) reloads the domain, resets the count and releases every
group (compile them again).

Grant: csharp, off by default, never implied by execute or another grant and not part of All (the Editor's All switch
keeps meaning the five ordinary grants). The CSHARP declarations, the CSHARP USING lines and every CALL of a CSHARP
function (also one in another source of the group) need it: UQL403 'CSharp permission is disabled for source ...'.
Config: <Source file="Probe.uql" execute="true" csharp="true">, written only when true (an older Config denies it);
MCP: grants:["csharp"]; a file host without a Conductor store: UqlFileRegistration.AllowCSharp. Closing it stops the
group, like every grant reduction. The UQL window has no csharp switch yet: use Config or the MCP grants.
Hosts: only the file-channel host runs the C# step. The in-game terminal and direct UqlScriptCompiler callers get UQL490
'this host does not compile CSHARP yet', a player the Editor-only text.

Execution: a call runs on the owning thread (the Editor main thread) inside the VM step and blocks the Editor while it
runs. There is no time limit: a C# loop that never ends freezes the Editor, and nothing can interrupt it. A throw inside
the body fails the process with UQL500 at the CALL, 'CSHARP <F> threw <Exception.FullName>: <message>' (operation CSharp,
failure kind Statement, the first five stack frames in the failure context, whose changed= says that the body's effects,
scene changes included, are not tracked); DEFER cleanup runs and the group stays active. Reentry: while a body runs, its
hub's VM is running, so a HOOK publication from inside the body into the same hub (game code that publishes a HOOK, a
patched method, UQLHooks.Trigger) is refused and counted as a reentry refusal. Lazy results: a body that returns an
IEnumerable from yield, an unmaterialized LINQ query or a Task runs body code later (ITERATE, LOG, formatting), outside
the CALL's counters and exception text: return ToList() or ToArray() instead.
What a body can see: by default every non-dynamic assembly loaded in the Editor domain that has a file (the UnityEngine
and UnityEditor modules, the project's and the packages' assemblies), except generated units, the module's compiler and
UQL's own assemblies (UQL.Runtime, UQL.Editor and the assemblies of the IL Patch and CSharp Load modules), so a body
cannot reach the UQL API by name; a game API whose signature exposes a UQL type gives CS0012. C# accessibility applies: a non-public game member is CS0122 (use reflection inside the body). Defines:
the Editor's active script defines plus UQL_CSHARP. Language: what the module reports (host.txt CSharp: line), at least
C# 8.0; unsafe code off, nullable annotations off. A body gets its arguments and returns one value; it has no UQL API. Not
a sandbox: a body can do anything the Editor process can do (reflection included).
Scene changes made by a body are outside UQL's edit tracking: not in EDITLOG or Edits/edits.txt, not restorable there,
and they do not mark Edit Mode scenes dirty, so they can be lost or left unsaved. Change scene state with EDIT in UQL, or
call Undo.RecordObject and EditorSceneManager.MarkSceneDirty inside the body (CSHARP USING "UnityEditor"; and
CSHARP USING "UnityEditor.SceneManagement";).

Diagnostics, one message per line (UQL492-496 without a position of their own are placed at the first CSHARP
declaration's name):
UQL100, the lexer (the rest of the source is not parsed):
  CSHARP body of <Name> is not closed: <reason>
  CSHARP header is not closed: <reason>
    <reason> is one of:
    the { here has no matching }
    the string that starts here has no closing quote
    the verbatim string that starts here has no closing quote
    the raw string that starts here has no closing """
    the char literal that starts here is not closed
    the comment that starts here has no */
    the interpolation hole that starts here has no closing }
    nesting limit 64 reached
  a C# string cannot cross a line; use @"..." or """..."""
    (a char literal that crosses a line is 'CSHARP body of <Name> is not closed: the char literal that starts here is not closed')
  braces differ between #if branches
  #if without #endif in this body
  #endif without #if
  #else without #if
  #elif without #if
  #region without #endregion in this body
  #endregion without #region
UQL403, the csharp grant is closed: CSharp permission is disabled for source <file>. NEXT: open the csharp grant ...
UQL490, once per compile at the first CSHARP declaration (the names stay registered, so the CALLs add no other error):
  optional module "UQL CSharp Load" is not installed (no CSHARP backend is registered). NEXT: install Addons/UqlCSharpLoad, or remove the CSHARP declarations.
  CSHARP runs only in the Unity Editor (the optional module "UQL CSharp Load" is Editor-only).
  this host does not compile CSHARP yet. NEXT: compile the script as a file-channel group (uql_run or the UQL window).
  the CSHARP backend reports C# <v>; CSHARP needs C# 8.0 or later.
UQL491, the declaration (one per declaration):
  CSHARP declarations must be at script level. NEXT: move the declaration out of the BLOCK, next to the BLOCKs.
  CSHARP <Name> needs (<C# parameters>) after its name. NEXT: write CSHARP <Name>(<C# parameters>) [RETURNS <C# type>] { ... }.
  CSHARP <Name>(...) needs a { C# body }. NEXT: add the body: CSHARP <Name>(...) { ... }.
  CSHARP <Name>(...) expects RETURNS <C# type> or the { C# body } after its parameters, found '<text>'. NEXT: write CSHARP <Name>(<C# parameters>) [RETURNS <C# type>] { ... }.
  CSHARP needs a C# name first: CSHARP Name(<C# parameters>) [RETURNS <C# type>] { ... }.
    (for CSHARP int Count(...) it adds: NEXT: write CSHARP Count(...) RETURNS int.)
  CSHARP <Name>: '<text>' is not a C# type. NEXT: RETURNS takes one type such as int, Vector3, List<GameObject> or (int, string).
  CSHARP <Name>: the parameter '<text>' uses <ref|out|in|params|this|scoped|ref readonly>; v1 takes ordinary parameters. NEXT: return the value instead.
  CSHARP <Name>: the parameter '<text>' has a default value; v1 needs every argument. NEXT: remove '= ...'.
  CSHARP <Name>: the parameter '<text>' has an attribute; v1 takes ordinary parameters. NEXT: remove [...].
  CSHARP <Name>: the parameter '<text>' needs a type and a name, for example int count.
  CSHARP <Name>: RETURNS ref is not supported in v1. NEXT: return the value.
  '<name>' is a C# keyword. NEXT: choose another name for the CSHARP function.
  '<name>' starts with __uql, which UQL reserves for its generated code. NEXT: choose another name.
  '<name>' is a member of System.Object. NEXT: choose another name.
  '<name>' is not a C# identifier. NEXT: use letters, digits and _ (not starting with a digit).
  Duplicate CSHARP function: <name>. NEXT: rename one of them (CSHARP functions have no overloads in v1).
  CSHARP <name> has the name of a BLOCK of this group. NEXT: rename the function or the BLOCK.
  CSHARP USING text must not contain '<c>'. NEXT: write CSHARP USING "System.Text";      (<c>: ; { } " ' \ // /*)
  CSHARP USING text must not contain a line break. NEXT: write CSHARP USING "System.Text";
  CSHARP USING text must not start with 'using'. NEXT: write CSHARP USING "System.Text";
  CSHARP USING text must not be empty. NEXT: write CSHARP USING "System.Text";
  CSHARP USING takes one string. NEXT: CSHARP USING "System.Text";
UQL492, a C# error at its mapped position (it fails the compile):
  <Id>: <Message>                         for example CS1002: ; expected
  <Id>: <Message> (generated wrapper)     an error in UQL's own wrapper text
  <Id>: <Message> (no source location)    an error without a location
  An error that only an adapter cast or call has (a parameter or the return type) adds the NEXT:
  UQL passes arguments and results as objects: ref struct, pointer and by-ref types cannot be parameters or results in v1; take ordinary types and call the Span API inside the body.
UQL493, a C# warning with a location (<Id>: <Message>; it never blocks). Warnings without a location are only counted.
UQL494, call sites and misuse:
  CALL <F> needs <n> argument(s), got <m>      (written 1 argument, 2 arguments)
  argument <k> of <F> is <uqlType>; the C# parameter <p> is <csType>      (<uqlType>: a type name, null or a tuple)
  <F> returns nothing; remove INTO
  CALL <F> INTO $<v>: <F> returns <csType>; $<v> holds <uqlType>. NEXT: use an untyped VALUE or one of type <csType>.
  INTO requires CALL and a writable VALUE.
  START needs a BLOCK; <F> is a CSHARP function. NEXT: wrap the CALL in a BLOCK
  DEFER CALL needs a BLOCK; <F> is a CSHARP function. NEXT: wrap the CALL in a BLOCK
  '<F>' is a CSHARP function; call it with CALL <F>(...) INTO $v      (a path root, a value or a HOOK target)
UQL495, the module's compiled unit breaks the contract. Each text starts with CSHARP unit <h16>: and its NEXT is
report it to the backend's owner (Addons/UqlCSharpLoad); the previous version keeps running.
  the backend returned no type for a Ready compile
  the backend returned type <X>, expected UqlCSharpUnits.__UqlUnit_<h16>
  the backend returned assembly <X>, expected UqlCSharpUnit_<h16>
  the backend returned type <X>, which is not a static class
  the backend returned type <X> whose methods cannot be read (<ExceptionType>)
  the backend returned a unit without <F>(<n> parameters) as a public static non-generic method without by-ref parameters
  the backend returned a unit without __uql_call_<F>(object[])
  the backend returned a type for a check-only compile
  the backend reported Ready with an error diagnostic (<Id>)
UQL496, the C# compile ended without C# diagnostics:
  the Editor domain already holds <L> C# assemblies from CSHARP (limit csharpAssemblies). NEXT: compile an unchanged CSHARP set (it is reused), raise csharpAssemblies in the Limits preset, or reload the domain with a C# refresh (EditorRequest REFRESH_SCRIPTS).
  a referenced assembly changed on disk (<ticket.Error>); wait for Unity's domain reload, then compile again
  the backend refused: <ticket.Error>
  the backend refused: it threw <ExceptionType>: <message>
  the backend refused: it returned no ticket
  the CSHARP backend changed while compiling. NEXT: compile the group again
  the C# compile is still running in the backend; compile the group again in a moment (a finished compile is reused)
UQL497-499: reserved (UQL497: CSHARPINFO, S2).
UQL500, at run time (operation CSharp, failure kind Statement):
  CSHARP <F> threw <Exception.FullName>: <message>
  argument <k> of <F>: <value description> does not fit the C# parameter <p> (<csType>)      <value description>: null or a <TypeFullName> value
  argument <k> of <F>: <read error>      the live read of a path or BUCKET entry argument failed; the body did not run
  CSHARP <F> is not bound: the group was compiled without activation or was released. NEXT: compile the group again

Evidence: each C# compile (check or load, hit or miss, success or failure) writes one CSHARP row into the compile's run
evidence:
  CSHARP op=compile|check status=Ready|Failed|Cancelled|Expired unit=<hash16> group=<g> functions=N backend="<name version>"
    cache=hit|miss new=yes|no seconds=0.412|unknown errors=E warnings=W unlocated=U loaded=L/limit
    assembly="UqlCSharpUnit_<hash16>" source="csharp-<hash16>.cs" error="..."
and keeps the unit text once per hash and session as Workspace/Hosts/<host-id>/Runs/<session-id>/csharp-<hash16>.cs (next
to the compile's evidence), so a unit=<hash16> can be read back after a domain reload. A process that called C# adds
csharpCalls=N csharpExceptions=E to its PROCESS row, and runs.txt RUN rows add the totals (omitted when 0); calls have
counters only, no per-call text. host.txt, after 'Patches:', once a module is registered or a unit was requested in this
domain: 'CSharp: <name> <version> (C# <lang>, sync|async); units <N> (ready <r>, failed <f>, cancelled <c>, expired <x>,
open <o>; cache hits <h>); assemblies <L>/<M>; calls <C>, exceptions <E>' ('CSharp: no backend registered; units ...'
without a registered module). The session log brackets every C# compile (CSHARP state=compiling / state=done; HELP
SESSIONS), so a crash inside it shows in host.txt Previous editor:.
Not yet (later slices): CSHARPINFO (S2); an asynchronous compile with a parked activation (S2); the Editor's csharp
switch and a colour for C# text (S3); an inline form, calls inside expressions, REF / OUT parameters, line numbers of
exceptions inside a body, the in-game terminal and CSHARP REFERENCE lines (later).
Cost: nothing runs unless a group declares CSHARP; the only new VM code is the CSharpCall case. Ordinary path reads,
ALIAS execution and the 16-byte instruction layout are unchanged.
Reference topic · Language referenceEXPLORERLazy member trees, paging, editing, and session paths.

Lazy member trees, paging, editing, and session paths.

Where to use it

Reference topic; not a command

Example

HELP EXPLORER;

Detailed reference

From the in-tool help for EXPLORER.

INTERACTIVE EXPLORER
Explorer scans loaded runtime scenes, including inactive objects and persistent objects.
Left search filters GameObject names only across the full loaded scene set (no 4096 cap).
Choose a GameObject; open its separate right-side Components button, then expand a component.
GameObject reference fields and Transform's GameObject branch have the same button.
Component lists are independent of ordinary member expansion. Drag the splitter to resize.
Refresh re-scans manually; automatic scene refresh is limited to every 2s while open.
Open member branches with +. Managed collections page by 32, with original index/key.
The index field + Go (or Enter while focused) jumps to an exact zero-based index.
Invalid input keeps the current page. Beyond-end pages are empty; scan budgets remain.
Transform/RectTransform rows use Children / GameObject buttons instead of collection
paging. Children has its own pages and index field; unopened branches are not read.
Select a writable simple field, enter a value and Apply. A reference field instead accepts
a source path or null (HELP EDIT). EDIT conversion/write rules apply;
errors appear on the row. Read-only members/history cannot be edited. The disabled editor
shows its reason in the status line and tooltip. Selected scene/member rows are highlighted.
Copy path copies a [ROOT:...] session path; identically named objects remain distinct.
These paths are session-local, not save IDs. Pin LIVE or TRACE registers without leaving
Explorer. The terminal input remains usable in every tab. Pinning does not resubmit the
terminal script. Add READ inserts equivalent UQL into input; it does not execute it.
Binding, reflection, scene scans and edits happen outside GUI drawing. Only visible rows
are drawn; member snapshots refresh while Explorer is open. There is no method-call UI.
Native collections also page by 32 after ENABLE UNSAFE READ (or read/query/observation
permissions in Settings). Only explicitly opened native branches are read. Closed native
rows do not call Count, IsCreated, getters or enumerators. Known Count appears once opened.
Hash map keys appear next to indexed values. Page snapshots and nested native fields are
read-only: copy the source path and use UNSAFE EDIT to mutate an existing element.
Scan/member budgets and host guards apply; queues need their entire Count within budget.
Jobs/storage must remain safe throughout sampling; enabling a view does not synchronize jobs.
Reference topic · Language referenceCAPABILITIESShared built-in command/reference cards, metadata-only host context and explicit unsupported/deferred targets. Documentation is not permission or readiness proof.

Shared built-in command/reference cards, metadata-only host context and explicit unsupported/deferred targets. Documentation is not permission or readiness proof.

Where to use it

Reference topic / cold host API; CATALOG accepts this selector

Example

CATALOG CAPABILITIES;
VALUE $catalog = null;
$catalog = [STATIC:UQL.Runtime.UqlCapabilityCatalog].Capture();
RECORD $catalog.Text; REGISTER capabilities;
Read this topic in your connected host.

The detailed CAPABILITIES report uses your host’s current settings and capabilities. Enter HELP CAPABILITIES; in the UQL Terminal to see it. The website does not connect to or inspect your Unity project.

Reference topic · Language referenceACCEPTANCEQualified recorded test evidence with date, scope, backend and limitations. Historical records do not attest the current binary or grant universal live/player acceptance.

Qualified recorded test evidence with date, scope, backend and limitations. Historical records do not attest the current binary or grant universal live/player acceptance.

Where to use it

Reference topic / cold host API; no tests are executed by this view

Example

CATALOG ACCEPTANCE;
RECORD [STATIC:UQL.Runtime.UqlCapabilityCatalog].FormatAcceptance(); REGISTER acceptance;
Read this topic in your connected host.

The detailed ACCEPTANCE report uses your host’s current settings and capabilities. Enter HELP ACCEPTANCE; in the UQL Terminal to see it. The website does not connect to or inspect your Unity project.

Reference topic · Language referenceFIELDSFormats constant labels and values into one output append using PRINTOPT, separated by '; ', without a newline. LOG LINE FIELDS adds an explicit line end. Expressions run once in source order; the formatted output limit truncates with a marker.

Detailed reference

From the in-tool help for FIELDS.

LABELED OUTPUT (compiled labels; no runtime template parser)
LOG LINE FIELDS health = $boss.health, "current position" = $boss.transform.position;
RECORD LINE FIELDS before = $oldCount, after = $newCount, changed = $oldCount != $newCount;
REGISTER test_result;

Shape: LOG|RECORD FIELDS label = expression [, label = expression ...];
Labels are bare identifiers or quoted text literals. Labels are fixed at compilation;
duplicate exact labels, empty labels and trailing commas are compile diagnostics.
Each expression is evaluated once from left to right. PRINTOPT formats each resulting
value. The single append is: health = value; current position = value. An OBSERVE cell
($snap["ms"]) prints its value only, formatted like the plain value, with showtypes=false (the
default; revision 54: 'ms = 12.5', 'ok = False'); showtypes=true keeps the whole cell
'ms [Value] System.Single = 12.5', and a
cell without a value (Missing, ReadError, Truncated, Destroyed, ...) always keeps its status
and reason. Like LOG, a System.Type prints its full name (System.Collections.Generic.List`1
[System.Int32]) and a UqlDiagnostic its source, code and text ('file.uql(3,5) UQL600: ...').
No implicit
newline or separator is added before/after the statement; use NEWLINE/RECORD NEWLINE.
Alternatively insert LINE (or NEWLINE) before FIELDS: LOG LINE FIELDS ...; or
RECORD LINE FIELDS ...;. It uses the same FIELDS append followed by the existing
line-end instruction. This is source shorthand, not a new format or atomic snapshot.
Expression/getter/method side effects are not rolled back if a later field fails.
Instruction budgets can split expression evaluation across scheduler turns. One append
is not an atomic multi-path game snapshot or an unconditional same-frame guarantee.

RECORD builds the whole statement before appending to its process buffer. An expression,
formatting or quota error therefore leaves prior pending text unchanged, then fails
that process. The existing process recording quota applies (default 1048576 characters,
group.MaxRecordingCharacters; Conductor preset key recordCharacters, HELP LIMITS).
REGISTER is still explicit; FIELDS does not write files or create a registry itself.
In RECORD LINE/NEWLINE FIELDS, the following line end has its own quota check:
if the values fill the buffer exactly, they remain pending and the line end fails.
Scheduler budgets may also separate the append and line end. A legacy IUqlOutput
without a line adapter receives the existing value callback then an empty Log callback;
the prefix does not promise one callback. PRINTOPT and normal LOG behavior are unchanged.

LOG uses group.MaxFormattedOutputCharacters (default 131072) per FIELDS statement.
The same limit bounds plain LOG / CONSOLE LOG of a string, number or enum and LOG of
OBSERVE/CHECK/SELECT values. Clipped plain text ends with an explicit marker, e.g.
"... <LOG truncated: 131072 of 400000 characters>"; text within the limit is unchanged.
Excess output is shortened with [FIELDS output truncated], within the same limit; an
extremely small limit can shorten the marker too. LOG never silently claims a complete
unbounded report. IUqlTextOutput receives one append without an end-line request. A
legacy IUqlOutput receives one string Log entry, not one entry per field. With no output
sink, LOG is discarded as before. Expression evaluation still occurs.

This syntax is command-owned formatting, not a new expression/string-template engine.
Literal labels and expression registers are prepared during compilation. Ordinary LOG,
RECORD, path reads and 16-byte instructions keep their existing fast paths.
Reference topic · Language referenceWAITWaits for Unity frames (FRAME: actual frames when the host has a frame clock, otherwise scheduler steps), host time (SECOND), or a condition (UNTIL). EVENT/UNTIL optionally accept TIMEOUT and INTO an outcome VALUE. The process and its RECORD buffer survive the wait.

Detailed reference

From the in-tool help for WAIT.

COOPERATIVE WAITS AND OUTCOMES
WAIT 2 FRAME;                       // actual Unity frames with a host frame clock, else scheduler steps
WAIT 0.5 SECOND;                    // host clock; eligible scheduler turn
VALUE $outcome = null;              // untyped VALUE, or UqlWaitOutcome-typed VALUE
WAIT EVENT DamageApplied TIMEOUT 60 FRAME INTO $outcome;
WAIT UNTIL $ready TIMEOUT 2 SECOND INTO $outcome;
IF $outcome == [STATIC:UQL.Runtime.UqlWaitOutcome].TimedOut {
    RECORD "Timed out waiting for readiness."; REGISTER test_result;
}

TIMEOUT and INTO are optional, but only EVENT/UNTIL support them. Syntax order:
WAIT EVENT name [TIMEOUT expression FRAME|SECOND] [INTO $outcome];
WAIT UNTIL expression [TIMEOUT expression FRAME|SECOND] [INTO $outcome];
INTO requires a writable, untyped VALUE or a VALUE typed UQL.Runtime.UqlWaitOutcome.
For EVENT/UNTIL, Matched means a hook claimed the waiter or the condition evaluated true. TimedOut means
the deadline was processed first. None is the initial/in-progress outcome. Cancelled is
available in stopped/failed process snapshots; cancellation does not resume the BLOCK
or assign its INTO destination. A later wait replaces the process's last wait outcome.

The timeout expression is evaluated once on entry. FRAME uses a nonnegative integer; SECOND uses finite
nonnegative host seconds.

FRAME TIMING. A host with a frame clock (UqlScriptGroup.FrameClock: the Unity Conductor and built-in terminal
bind Time.frameCount while playing) measures WAIT n FRAME (n >= 1) and TIMEOUT n FRAME in ACTUAL frames: the
frame is sampled once at the WAIT instruction and the wait resumes no earlier than that frame + n, even when the
wait was issued by a hook before the host tick of the same frame, and extra scheduler ticks inside one frame
(terminal submit, paused debug pump, duplicate ticks) cannot satisfy it. A skipped-frame gap resumes once at the first
tick past the deadline (no replay). This is eligibility, not a guarantee of the exact next frame (the host slot must tick
and the budget must remain) and not a phase guarantee within the frame. WAIT 0 FRAME, hosts without a frame clock,
and Edit Mode (no game frame) count scheduler ticks as before. An unavailable clock does not wake or expire an
already anchored actual-frame wait; a new wait with no available frame clock uses scheduler-step fallback.
FrameClock must be monotonic for a group's lifetime. Custom/injected hosts must recreate their group/session on
frame epoch reset (for example a new Play session), rather than carrying old actual-frame deadlines into it.
WAIT UNTIL still polls the condition once per scheduler step; only its FRAME deadline moves to actual frames. Invalid/overflowing
durations fail the process with a source diagnostic instead of silently wrapping.
WAIT EVENT ... TIMEOUT 0 ... completes immediately without registering a waiter.
WAIT UNTIL evaluates its condition first, including timeout zero: true wins at that poll.
An UNTIL condition may span budgeted instructions; polling is cooperative, not atomic.
User getters/methods cannot be interrupted by a timeout or instruction budget.

Event deadlines are processed by group.Tick, not by a hook publication clock check.
If a hook claims an overdue waiter before the next Tick processes its timeout, Matched
wins. If Tick processes the timeout first, the later hook cannot claim that waiter.
New waits never consume the publication that created them; another matching hook is
required. Timeout cleanup unlinks both event and timer registrations. STOP/ABORT/failure
also unregister waits, with no continuation and no implicit RECORD commit.

Unity Conductor/terminal use an unscaled clock sampled at the wait instruction. Custom
hosts can set group.WaitClock in Tick(timeSeconds)'s clock domain. Pausing a host that
does not Tick postpones processing; TIMEOUT is not a wall-clock interrupt or frame-perfect
promise. Hook dispatch does not advance scheduler steps. See HELP HOOK for budgets.

OPTIONAL C# PHASE HOST (developer-owned groups only; no UQL PHASE keyword).
UqlUnityPhaseDriver.TryBind(newGroup, UqlExecutionPhase.AfterUpdate, out driver, out error)
is an explicit Play-Mode binding before START/HOOK/Tick. BeforeUpdate, AfterUpdate,
BeforeLateUpdate and AfterLateUpdate bracket Unity's script Update/LateUpdate anchors.
This is not globally first/last against every plugin, FixedUpdate or an arbitrary method.
Conductor and terminal are NOT automatically routed through this adapter.
One scheduler owner and selected slot serve each bound group; direct group.Tick is
refused while owned. Wrong slots and duplicate same-frame callbacks do not advance
steps or spend another budget. WAIT eligibility still uses a live frame clock sampled
at its instruction; synchronous HOOK and WAIT EVENT continuations remain at their caller.
FrameClock/WaitClock must not be replaced while leased. Clock/epoch regression faults
the binding and cancels its processes rather than silently rebasing old deadlines.
driver.TryRelease/Dispose cancels processes before releasing ownership/restoring clocks;
release during HOOK/VM work disables pumping and completes at the next idle callback.
TryRefresh explicitly checks/repairs our nodes in the CURRENT PlayerLoop; TryIsInstalled
is a cold actual-placement query, not a cached flag. No per-frame whole-loop scan occurs.
TryUninstall removes only our nodes, preserving unrelated plugin changes. Play-session
reset and Editor Play exit/reload release owned bindings. Recreate groups in a new epoch.
Editor domain load restores only main-thread ownership and cleanup subscriptions,
including reloads while Play continues; it does not install nodes or rebind groups.
The core UqlPhaseScheduler can be pumped explicitly by a custom host with a live frame
clock. Neither core nor Unity adapter supplies paused/Edit control-plane scheduling.
DLL/offline checks are not actual Unity phase/player acceptance.

PROCESSES; reports IDs, source/version, instruction location, waits, deadlines and outcomes.
LastWaitKind retains the matched/timed-out/cancelled wait's kind after WaitKind becomes
None. The text report keeps that provenance and event name, including cancellation.
WaitStartedHostFrame and DeadlineHostFrame retain the last wait's actual-frame metadata; historical text labels
them last-started-frame/last-deadline-frame. WakeHostFrame describes a live timer only (-1 after it is removed).
A new wait replaces the metadata, including clearing actual-frame fields for a scheduler-step/SECOND wait.
Event snapshots also report HookReceiverCount and HookWaiterCount at inspection time;
these describe registered hub routes/waiters, not proof of an installed C# sender.
Aborted groups can retain registered routes; dispatch skips them until reactivated.
Host APIs: process.GetSnapshot(); group.TryGetProcessSnapshot(id, out snapshot);
group.GetProcessSnapshots(); group.TryStopProcess(id). IDs are stable within one group
activation only. Snapshots contain strings/scalars, not retained game values; explicitly
requesting them allocates. Finished history is opt-in: group.ProcessHistoryCapacity
defaults to 0 (maximum 4096). Conductor opts into 1024 (Limits preset key processHistory,
16..4096; HELP LIMITS); older completed IDs are evicted.
Group inspection/configuration requires an idle, live owning-thread group. Snapshots
cannot prove that a hook sender exists or will fire; they show only registered wait state.
Reference topic · Language referenceCAPTURERenders an explicit Camera/GameObject or independent SCENE view once and atomically publishes a PNG. Optional REPORT stores immutable file/view/time/frame metadata in a VALUE. A full Captures folder rotates: the oldest UQL captures are removed first and reported (captureArchiveFiles/captureArchiveMegabytes, HELP LIMITS). A camera render never contains screen-space overlay UI: for the screen as the player sees it use CAPTURE GAME VIEW.

Detailed reference

From the in-tool help for CAPTURE.

CAMERA CAPTURE (for the composited screen with overlay UI see GAME VIEW CAPTURE at the end)
CAPTUREOPT width=1024, height=0, ppu=0;
CAMERAOPT transparent=false;
VALUE $shot = null;
CAPTURE [SCENE:Main Camera].Camera INTO market_view REPORT $shot;
IF $shot.Success { RECORD $shot.Text; REGISTER camera_capture; }
CAPTURE [SCENE:Main Camera].Camera INTO market_view;
A reference whose Camera/GameObject was destroyed gives Success=false with 'CAPTURE target was
destroyed: the referenced UnityEngine.Camera no longer exists ...' (revision 54; no scene
fallback): find the camera again and capture through the new reference.

INDEPENDENT SCENE VIEW (does not move or clone the game camera):
CAPTUREOPT width=512,height=512,ppu=32;
CAMERAOPT orthographic=true,orthographicsize=4;
CAPTURE SCENE FROM p(0,0,-10) ROTATION p(0,0,0) INTO map_view REPORT $shot;
CAPTURE SCENE FROM p(0,0,-10) LOOKAT p(0,0,0) INTO map_view REPORT $shot;
FROM and ROTATION/LOOKAT accept Vector3 VALUE/path expressions, evaluated once
at the command. Euler rotation is world degrees; LOOKAT names a world point.
Use one orientation mode. Inputs must be finite; LOOKAT must differ from FROM.
An owned hidden non-saving disabled camera is created for the render and released
in finally, immediately also in Play Mode, so same-frame FIND/COLLECT/SPATIAL and
gameplay root enumeration never see it. No gameplay scripts, AudioListener or
camera stack are cloned. A null or non-Vector3 dynamic pose gives a Success=false
report; the process continues.

CAPTUREOPT contains ONLY width, height and ppu. CAMERAOPT contains orthographic,
orthographicsize, fieldofview, nearclip, farclip, cullingmask, transparent,
renderer and postprocessing. Both capture forms honor these explicit overrides.
CAMERAOPT null clears a setting; unspecified values inherit the borrowed camera.
Owned scene defaults: orthographic=true, size=5, fieldofview=60, nearclip=0.3,
farclip=1000, cullingmask=-1, opaque background, no postprocessing/empty stack.
Set CAMERAOPT orthographic=false,orthographicsize=null and CAPTUREOPT ppu=0
for perspective output.
fieldofview is vertical degrees 1..179; nearclip>=0.0001, farclip>nearclip and
<=10000000; cullingmask is a signed 32-bit layer bitmask, not object isolation.
Each options declaration must leave a valid profile; explicit clips must agree.
One clip override may conflict with inherited camera values and reports an error
at capture time. Signed numeric literals are allowed, not general expressions.
No aspect option: two positive output dimensions set the ratio. Missing dimensions
use the borrowed ratio or scene16:9; both zero use camera pixels or scene1024x576.
The capture camera aspect matches final width/height. Positive PPU computes actual
pixel sizes at the chosen ratio, rather than treating width/height as exact pixels.
All settings are literal top-level declarations; pose can be dynamic.
Borrowed-camera overrides are temporary and restored in finally. Aspect restore
resets to automatic when the original numeric value equals the reset ratio;
otherwise the saved explicit value is restored. Unity exposes no public getter
for a manual aspect fixed exactly equal to the default, so that case becomes auto.

Independent views support Built-in and compatible URP. URP binds package metadata
once, prepares an owned Base camera and validates renderer choice before mutation.
CAMERAOPT renderer=default (or -1) selects the project default; an index>=0 selects
a renderer. null inherits a borrowed choice. postprocessing accepts boolean/null.
These two options require URP. Borrowed Overlay cameras are rejected explicitly;
use their Base camera (whose existing stack is included). Owned Base stacks are
empty. Owned URP views evaluate volumes on the Default layer, triggered at the
capture position (URP defaults); a project whose post-processing volumes sit on
another layer gets no post effects there. A temporary URP data component added to
a borrowed camera is removed immediately. A borrowed URP capture renders the game
camera itself, so URP advances that camera's motion-vector/TAA history for one
extra render; it is not rewound. Invalid indices, missing renderers/metadata or
unsupported requests give diagnostics, not silent renderer fallback. No mandatory
URP assembly reference.
HDRP/custom independent providers remain explicit. Hosts may implement
IUqlSceneCameraRenderer; old providers receive copied options.Camera metadata.
The new scene request is UqlSceneCaptureView, containing no object references.
Asset preview/contact sheets, automatic bounds fitting and region tiling are not
implemented by this command.

INTO names the output PNG, not a VALUE slot. A bare name, string literal or
string VALUE is accepted. Names are simple filenames without directory separators,
control characters or platform-invalid filename characters (maximum 96 characters).
REPORT requires an untyped writable VALUE declared first.
Without REPORT the metadata is printed directly. Failures return Success=false,
Error and a diagnostic output; they do not terminate the process. Path evaluation
errors before CAPTURE still follow the normal process error rules.

Conductor writes Outputs/Hosts/<host-id>/Captures/<name>.png (or the configured
output root). An addressed host never writes another host's capture folder.
The same name atomically replaces the previous PNG. A ready report is emitted only
after the full PNG has been published. A PNG that another process holds (an image viewer,
an antivirus or indexer scan) is retried for up to 5 x ioSyncMilliseconds, drawn from the host
tick's I/O budget (ioTickMilliseconds and its attempts, shared with the host's publications, which
the time writing the PNG's temp file counts toward; HELP LIMITS); then the
capture fails explicitly ('the target is busy (another process holds it): retry the CAPTURE'), the
previous PNG stays and no older capture is removed. A PNG that failed that way under 250 ms ago gets
one attempt without waiting, so a loop of captures cannot stall the Editor. The PNG a capture
replaces is kept under a hidden .uql-capture-*.previous name until the capture is done; if it
cannot be deleted then, the report adds one 'Cleanup:' line naming it and the next capture retries
the delete. RECORD $shot.Text; REGISTER captures;
stores its metadata using the ordinary process buffer and registry archive.
Standalone hosts may assign group.CameraCapture with their own directory/provider.
The runtime terminal defaults to Application.persistentDataPath/UQL/Captures.

Capture permission is separate from Edit. New and pre-existing Config entries
without capture=true have it disabled. Enable Capture (or All) in Permissions.
Direct compiler callers may supply their own IUqlPermissionPolicy as usual.

Output defaults are width=1024,height=0,ppu=0. CAMERAOPT defaults are all null.
In a Conductor workspace the width/height defaults come from the Limits preset (capture.width,
capture.height; HELP LIMITS); this group's own CAPTUREOPT keys override them.
transparent=true requests transparent black; final alpha depends on the renderer
and effects. Decimal literals use invariant '.' .

Built-in rendering uses Camera.Render. SRP uses RenderPipeline.StandardRequest
only after SupportsRenderRequest succeeds. URP normally requires a Base camera
and captures its camera stack; unsupported HDRP/custom targets report an error.
No URP/HDRP assembly dependency, runtime code generation or UnityEditor API is used.
A graphics device is required. Camera CAPTURE is an explicit camera render, not a screenshot
of the Game View, Scene View or desktop: screen-space overlay UI is never in it. For the
composited Game View frame use CAPTURE GAME VIEW (GAME VIEW CAPTURE at the end of this guide).

Rendering, GPU readback, PNG encoding and file publication are synchronous on
the owning Unity main thread. The command can stall that thread; use on demand.
The VM instruction budget cannot interrupt rendering. Camera render callbacks
may run user code. Nested capture is refused; call outside render callbacks.
No coroutine, timeScale wait or end-of-frame wait is required in this first version.

Reports retain strings/numbers/value structs/timestamps, not Camera references or image bytes.
RequestUtc/RequestFrame precede capture work; RenderUtc/RenderFrame identify the
explicit render call; ReadyUtc follows publication. SchedulerStep is a UQL
scheduler step, not a Unity frame. A HOOK selects when this extra render is
requested; it does not sample the last normal game render or promise frame-perfect
Game View output. Camera target/viewport/clear settings/orthographic size and the
previous RenderTexture.active are restored in finally; owned textures are released.

Limits: each side <=4096, <=4194304 pixels, <=20 MiB encoded PNG. These bounds
cover UQL allocations/files, not arbitrary allocations performed by a render
pipeline or user callback.

CAPTURE ARCHIVE (rotation). The Captures folder keeps at most captureArchiveFiles
PNG files (default 256, 1..100000) and captureArchiveMegabytes MiB (default 256,
1..65536). They are workspace values of the Limits preset (HELP LIMITS): the folder
is shared by every group of the host, so LIMITOPT refuses them. A capture that
would exceed them first removes the OLDEST UQL captures there (by last write time,
then name) until the new PNG fits, and its report gets one line
  Archive rotated: N old capture(s) removed (oldest first, ...): a.png, b.png
(at most 8 names, then '+M more'; .ArchiveRotated / .ArchiveRotatedFiles hold all).
Only top-level files named <capture name>.png that start with PNG data are
removed; other files are counted but never removed, subfolders and links are never
touched (a link in the folder refuses the capture). Replacing a name does not
count twice. When rotation cannot make room (a PNG larger than the size limit,
other files filling the folder) the capture is refused with an explicit error
naming the limits, and nothing is removed. A capture that cannot be removed
(read-only, held open by another process) is kept and still counted, the next
older capture is removed instead and the report adds one line
  Archive rotation skipped: N old capture(s) could not be removed and were kept ...
(.ArchiveRotationSkippedFiles); only if that leaves no room is the capture refused,
naming the file, the removals made and the limits. Older captures are removed only after the
new PNG was published; when the rotation then cannot make room, the new PNG is not kept (it is
removed again, or the previous PNG of that name is put back). A capture path you already hold
(an earlier report, RECORD text, run evidence) may disappear after later captures:
copy a PNG elsewhere to keep it.
Lowering a limit removes the excess oldest captures at the next capture. The
terminal's persistentDataPath/UQL/Captures and a host's own UqlCameraCapture rotate
the same way with their MaxArchiveFiles/MaxArchiveBytes (256 files / 256 MiB).

Read metadata through $shot.FilePath, .Width, .Height, .CameraId, .CameraName,
.Pipeline, .RequestFrame, .RenderFrame, .RequestUtc, .RenderUtc, .ReadyUtc,
.SchedulerStep, .Success, .Error, .Text, .ArchiveRotated, .ArchiveRotatedFiles,
.ArchiveRotationSkippedFiles, .FileBytes (the published PNG length, every form).
GAME VIEW facts (defaults in camera and SCENE reports): .Composited, .Route, .Mode, .ViewType,
.ViewCount, .FrameMin, .FrameMax, .ObservedUtc, .FileWrittenUtc, .Alpha, .OverlayRefreshed.
Effective render-boundary view:
.SourceMode (Camera/Scene; GameView), .Position, .Rotation (Quaternion), .Orthographic,
.OrthographicSize, .FieldOfView, .Aspect, .NearClip, .FarClip, .CullingMask.
CameraId is the camera's Int64 session id ($camera[INSTANCEID], HELP INSTANCEID).
Scene CameraId is ephemeral, not a reusable ROOT/session target. Custom providers
must populate their own view metadata. HELP CAPTUREOPT/CAMERAOPT use the same guide.
PNG readiness means the closed/atomically published file, not AssetDatabase import
or .meta availability. No AssetDatabase.Refresh or Unity focus is needed to read it.

GAME VIEW CAPTURE (CAPTURE GAME VIEW, revision 73): the screen as the player sees it
VALUE $hud = null;
CAPTURE GAME VIEW INTO hud_check;                 // success: one LOG line; failure: the full report text
CAPTURE GAME VIEW INTO hud_check REPORT $hud;     // success: silent; failure: the full text is logged too
IF $hud.Success { LOG LINE $hud.FilePath; }

The PNG is the Game View's final composited frame: every camera and camera stack, post-processing,
the final blit, screen-space overlay UI and OnGUI, as Unity's own end-of-frame screenshot
(ScreenCapture.CaptureScreenshot) writes it. A camera CAPTURE of the same moment has no screen-space
overlay UI. UQL reaches ScreenCapture through a cold reflection binding and adds no runner object,
coroutine, PlayerLoop node or render callback (idle cost: one integer compare per host tick).
GAME and VIEW are two words directly after CAPTURE (any case); CAPTURE GameView INTO x,
CAPTURE Game.View INTO x and CAPTURE gameView.Camera INTO x stay camera captures of those paths.
INTO takes camera CAPTURE's name operand (bare name, quoted name or string VALUE; at most 96
characters); REPORT needs an untyped writable VALUE (UQL200). Script BLOCK or terminal with the
Capture permission (UQL403; no new grant). It waits, so it is refused in an initializer and in
cleanup (UQL218, HELP CLEANUP).

Output: the process waits (wait=Capture in PROCESSES and process snapshots) until Unity wrote the
frame and UQL checked and published it as Captures/<name>.png, typically 1-2 frames in Play Mode.
The run evidence CAPTURE row is Pending meanwhile, then Ready or Failed. Without REPORT a success
prints one LOG line:
  CAPTURE GAME VIEW <name>: <W>x<H>, <x.x> MiB, Play frames <F1>-<F2> -> <path>
(a player: Player frames; Edit Mode: Edit (<n> repaint(s), <s.ss> s)), followed when they apply by
', N old capture(s) rotated', '; Game tab brought to front' and '; overlay may be stale (<reason>)'.
With REPORT a success is silent. A failure stores the report as well, logs its full Text and counts
one process warning; the process always continues (GAME VIEW never fails it).
Since revision 74 that warning reads 'CAPTURE GAME VIEW <name>: <error>', so run evidence firstWarning= starts
with the reason (for example a hidden-tab refusal, UQL406); the report and the LOG line keep the full Text.

Report members for GAME VIEW (camera and SCENE reports keep the value in brackets):
  Composited        true [false]
  Route             ScreenCapture.CaptureScreenshot, end of frame (Play Mode, players) or
                    ScreenCapture.CaptureScreenshot, Game View repaint (Edit Mode) [null]
  Mode              Play, Edit or Player [null]
  ViewType          the view's type, UnityEditor.GameView or
                    UnityEditor.DeviceSimulation.SimulatorWindow; null in a player [null]
  ViewCount         play mode views open in the Editor; 0 in a player [0]
  FrameMin          the issue frame (Time.frameCount); -1 in Edit Mode [-1]
  FrameMax          the frame of the tick that saw the file; -1 in Edit Mode [-1]
  ObservedUtc       the tick that saw the file [default]
  FileWrittenUtc    the staged file's LastWriteTimeUtc, which the rename keeps [default]
  Alpha             none (PNG color type 2, RGB) or present (6, RGBA) [null]
  FileBytes         the published PNG length in bytes (set by every CAPTURE form)
  OverlayRefreshed  the screen-space overlay UI was rebuilt for this frame: always in Play Mode
                    and players, in Edit Mode only when the overlay refresh ran [false]
SourceMode is GameView, CameraId 0, CameraName null, RenderFrame -1 and RenderUtc default; the pose
and projection members stay default. Pipeline is the active render pipeline asset's type name, or
Built-in. Text adds 'Source: composited Game View frame (...); not a camera render', Route, Mode,
View, Size (with the expected size), Alpha, File bytes, Frame range, the observed, written and ready
UTC lines and, when they apply, 'View tab:', 'View note:', 'Shared render:', 'Overlay refresh:' and 'Size note:' lines;
a failure lists the frames and seconds waited, renderFrameInterval, the repaints, the view and focus
facts and the console errors, and ends with 'Nothing was published.'

Which frame: in Play Mode the end of one rendered frame in FrameMin..FrameMax. ScreenCapture does not
name the exact frame, so RenderFrame stays -1: never compare it with a camera report's RenderFrame.
FrameMin is the issue frame, in Play Mode the same Time.frameCount as a camera CAPTURE just before it
in the same tick. A capture requested from a synchronous HOOK during Update includes that frame's
changes.
Edit Mode (through the UQL Editor host): in one tick it shows the Game tab if it is hidden,
refreshes the screen-space overlay by rendering a hidden helper camera (revision 74), issues the
screenshot and repaints the Game view; while the file is pending it repaints at most every 250 ms
(the count is in the text). The helper is a temporary, disabled camera (HideAndDontSave, culling
mask 0, solid clear, its own 16x16 target) placed like Camera.main; it renders once and is
destroyed, and its pixels are never read. That render lays out every screen-space UI canvas for the
Game view. Camera.main is not rendered or changed (no target, aspect or mask change, none of its
render callbacks); the global RenderPipelineManager camera events fire once with the helper, as for
CAPTURE SCENE. The text then says 'Overlay refresh: rendered a hidden helper camera (16x16, culling
mask 0) before the issue (Edit Mode; screen-space UI laid out for the Game view; Main Camera
untouched)'. (Revision 73 rendered Camera.main itself at 16x16, which left Screen Space - Camera
canvases laid out at 16x16.) Without an enabled MainCamera-tagged camera, with a render pipeline
that cannot render the helper (no StandardRequest support), during another camera capture, inside a
HOOK publication from game code or a camera render callback ('skipped: inside a rendering or HOOK
callback', revision 74: no nested render there) or when that render throws, the refresh is skipped:
OverlayRefreshed = false, an 'Overlay refresh: skipped
...' line and the LOG suffix 'overlay may be stale'; the world is fresh either way. When Camera.main
renders for another screen size than the Game view (its pixel size divided by its viewport rect, so a
split-screen or letterboxed Main Camera adds nothing; Edit Mode with several play mode views), the 'Overlay
refresh:' line adds '; Main Camera renders <w>x<h> but the Game view is <W>x<H> (several play mode
views?): Screen Space - Camera UI may be laid out for <w>x<h>', and the View note adds that in Edit
Mode screen-space UI and the camera aspect can follow another view's size.
Edit Mode never queues a player loop update.

Visible tab: a Game view that is not the shown tab of its dock renders no frame (a file written later
would be stale), so the view must be shown at the request, on every poll and when the file is seen;
hiding or closing it while the capture is pending fails the capture. What happens with a hidden Game
tab is decided by the user's Editor switch 'Allow interruptions' (UQL window, Request channel; on by
default; stored for the project on this machine in EditorPrefs, never in Config, so an agent cannot
change it; HELP CONSENT). Revision 73's Config root attribute gameViewToFront is gone: it is ignored
and dropped at the next Config save.
- on: the Game view's tab is selected in its dock (DockArea.selected; keyboard focus does not
  move), the capture runs, and when no capture is queued or pending the previous tab is put back,
  only if that dock still shows the Game view (a layout changed meanwhile is left alone). The
  request that switched the tab gets a 'View tab:' line and the LOG suffix. Two captures in one
  BLOCK switch once; a WAIT between them switches and restores twice. The tab is also put back at a
  Play Mode transition, an assembly reload and Editor quit. On a Unity version without the dock
  members the tab is shown with Focus() instead, which moves keyboard and game input focus.
- off: the capture is refused (UQL406) and its NEXT names the switch; no Unity Console line:
  'CAPTURE GAME VIEW refused (UQL406): the Game view is a background tab behind "<title>" and a
  hidden Game view renders no frame; 'Allow interruptions' is off in the UQL window (only the user
  can switch it), so UQL does not bring the Game tab to the front. Nothing was captured. NEXT: ask
  the user to show the Game tab, or to switch on 'Allow interruptions' (UQL window, Request channel),
  then CAPTURE GAME VIEW again.' A capture queued before the switch went off fails at its issue: 'the
  Game tab is hidden and 'Allow interruptions' was switched off while the capture was queued (UQL406;
  NEXT: ...); nothing was issued.' A Game view that is already shown is never refused, and putting
  the previous tab back is never refused.
host.txt: 'Game View tab: bring to front for CAPTURE GAME VIEW (interruptions=on)' or
'Game View tab: refuse when hidden (interruptions=off)', plus '; last: <note>' (shown, put back,
already back or refused, with the UTC), and 'Game View capture waiting: ...' while a capture is
pending.
Side effects of showing the tab: in Play Mode, showing a hidden Game tab changes Screen.width/height for
game code twice per capture (Unity reports 640x480 while the Game tab is hidden and the Game view
size while it is shown) and fires the game's resize and layout handlers; the Scene view is hidden
while the Game tab is in front (its duringSceneGui handlers pause).

Same frame, one render (pair rule, revision 74): Unity renders every camera, Built-in and URP/SRP
alike, in PostLateUpdate, after all Update and LateUpdate code of that frame, so two screenshots
requested in the same frame can only show the same image. CAPTURE GAME VIEW requests for the same
view in the same frame (Play Mode and players: the same Time.frameCount) or in the same Edit Mode
host tick therefore share one issue: one tab show, one overlay refresh, one CaptureScreenshot, one
repaint stream and one tab put-back. Each request still gets its own PNG (a copy of the one file),
its own CAPTURE row and report and a 'Shared render:' line ('one Game View frame for <n> captures
requested in the same frame <F>: "<a>", "<b>"' or '... in the same Edit Mode host tick: ...');
the LOG line of a later request ends '; shared frame with "<first>"', and only the first request
carries the 'View tab:' line. Stopping the first request hands the frame to the next one (no second
issue); a failure of the shared frame after its issue fails every request that shares it ('the shared
Game View frame of "<first>" failed: <error>'), and a first request that fails or is stopped before
its issue hands the request to the next one, which then issues itself. In Edit Mode a request that
joins an already issued capture renders the overlay helper once more, so screen-space UI shows its
changes. Requests made inside a HOOK publication from game code (a BLOCK that game code entered
through a HOOK point, for example during Update or in a render callback) never share a frame: they
neither join nor lead one, because game code can make them before or after that frame renders. A
request made in a later frame or host tick waits in the queue and gets a fresh frame of its own. Two
captures in one process never share (the statement waits for its PNG); to see two moments from two
processes, put WAIT 1 FRAME (or a later tick) between their STARTs.
Counters (diagnostics, revision 74): [STATIC:UQL.Runtime.UqlGameViewCapture].TabSelects, .TabRestores
and .ScreenshotIssues count the Game tabs UQL brought to the front, the tabs it put back (not one
that was already back) and the screenshots it issued, in this Editor domain. UQL never resets them:
compare a value before and after an action (deltas only).

Refused at the request (Success=false with a NEXT; nothing is issued): no Game view open (plus one
Unity Console warning per Editor process; open Window > General > Game), another window maximized
(Shift+Space: the Game view is not on screen), Play Mode paused (only hosts that run scripts while
paused reach this; resume Play), the Game view not placed in a window, Game View visibility not
verifiable on this Unity version, several play mode views without Unity's main-view binding, Edit
Mode without the UQL Editor host, no graphics device or batch mode, an expected size over the
limits, a full queue, the built-in Screen Capture module disabled or stripped, a thread other than
the Unity main thread, a hidden Game tab while 'Allow interruptions' is off (UQL406, above).
Several play mode views: Unity captures its main (last focused) view; UQL only selects that view's
own tab, so the main view stays the same, and ViewCount > 1 adds a 'View note:' naming it. The
Device Simulator view is accepted (device resolution, no bezel).

Size: the PNG has the Game view's render size (its resolution menu: a fixed size, or the window
pixels with Free Aspect); the zoom slider does not change it. CAPTUREOPT, CAMERAOPT and the Limits
capture.* defaults do not apply; a group that declares CAPTUREOPT or CAMERAOPT gets warning UQL484
once. Limits: at most 4096 per side and 16,777,216 pixels, checked against the expected size before
the issue (Handles.GetMainGameViewSize() in the Editor, never Screen; Screen.width/height in a
player), and at most 4*W*H+H+1 MiB bytes. The file must be an 8-bit RGB or RGBA PNG with its IEND
trailer (header and trailer are read, the image is never decoded); 'Size note:' when its size
differs from the expected one. Contents: Game View gizmos when the Gizmos toggle is on, never the
Stats overlay; floating windows over the Game view never appear. Alpha: none on 2022.3 (read .Alpha
rather than assuming it). HDR display output and XR stereo are not certified.
Shared slot: Unity keeps one screenshot request. A CaptureScreenshot call by game code in the same
frame replaces this request or is replaced by it (the later call wins): the game's own screenshot can
be lost, or this capture ends with the 'no file' failure, which names this cause.
Cost: one full PNG encode on the main thread at the end of the frame: about 40 ms at 1017x664, 110 ms
at 1080p and 450 ms at 4K on the test machine. UQL itself does no readback, decode or re-encode (Edit
Mode adds the hidden helper camera render, about 2-3 ms). Through the MCP server a PNG over 4 MiB is attached as a
preview; Unity never resamples.

Waiting and failures while pending: the queue is host-wide and FIFO, at most 8 requests (the issued
one included); Unity serves at most one screenshot per rendered frame, so a ninth is refused at
once. Play paused (also Error Pause) or frames stalled while a capture is issued: host.txt shows the
waiting line and the run evidence gets one note after 2 s; after progressSeconds (Limits, default
60) without frame progress the capture fails, the CAPTURE row turns Failed at once and the process
stores the report when it runs again. A request at the head of the queue whose process does not run
for progressSeconds fails as well. No file while frames render: after 30 x renderFrameInterval
frames (Play) or 8 repaints (Edit Mode), and at least max(2 s, ioRetryMaxMilliseconds), the capture
fails with the view, focus and pause facts. A staged file or a destination that another process
holds is retried on later ticks within ioRetrySeconds (at least 6 attempts). STOP, ABORT, a group
release, a Play Mode transition or an assembly reload while queued or pending: the CAPTURE row
becomes Failed 'cancelled: <cause>; nothing published.' and the tab is put back. Failure texts list
up to 8 Unity Console errors logged since the request when UqlConsoleLog is enabled (HELP
CONSOLELOG); otherwise they point at Console/console.txt after the host console's sequence number
(HELP HOSTCONSOLE), or say that console capture is off.
Staging: Unity writes Captures/.uql-staging/gv-<32 hex>.png; UQL checks it and renames it to
<name>.png (the archive rotation of camera captures applies; the staging folder is never counted or
rotated). Staged files older than 60 s that no request owns are swept at the next CAPTURE GAME VIEW
and when the host disconnects. A failed capture leaves the previous <name>.png in place.
Players: Mode Player, the expected size from Screen.width/height; on Android and iOS the capture
folder must lie under Application.persistentDataPath. Player captures are not verified yet.
Reference topic · Language referenceSPATIALProduces frozen scene geometry, or refines a previous SPATIAL report without rereading Unity. Chain type/region and ACTIVE/LAYER/ENABLED/TRIGGER selection before NEAR/RADIUS/NEAREST in XY/XZ/XYZ, then project collider bounds/rects with SELECT. Original geometry evidence and incomplete source coverage survive refinement.

Detailed reference

From the in-tool help for SPATIAL.

BOUNDED SCENE / SPATIAL CONTEXT
VALUE $space = null;
SPATIAL IN SCENE CENTER v3(0,0,0) SIZE v3(20,20,4) INTO $space;
SPATIAL IN ACTIVE SCENE INTO $space;
SPATIAL IN SCENE("Assets/Scenes/Market.unity") INTO $space;
SPATIAL IN SCENE($sceneNameOrHandle) INTO $space;
SPATIAL IN $selectedBucket CENTER $center SIZE $size OF UnityEngine.Collider2D INTO $space;
SPATIAL IN $gameObject INTO $space;
RECORD $space.Text; REGISTER geometry;

VALUE $near = null; VALUE $geometry = null;
SPATIAL IN $space OF UnityEngine.Collider2D
    ACTIVE true ENABLED true TRIGGER false
    NEAR v3(0,0,0) RADIUS 12 PLANE XY DISTANCE BOUNDS NEAREST 16 INTO $near;
SELECT $near.Colliders AS $collider
    FIELDS name=$collider.ObjectName, root=$collider.Root,
           distance=$collider.Distance, rect=$collider.WorldRect
    WHERE $collider.MatchesComponentFilter
    INTO $geometry LIMIT 64;
RECORD $geometry; REGISTER nearby_obstacles;

Grammar: SPATIAL IN SCENE|ACTIVE SCENE|SCENE(selector)|expression
         [CENTER expression SIZE expression] [OF Type]
         [ACTIVE bool] [LAYER integer] [ENABLED bool] [TRIGGER bool]
         [NEAR expression [RADIUS expression] [PLANE XY|XZ|XYZ]
          [DISTANCE POSITION|BOUNDS] [NEAREST expression]] INTO $value;
IN SCENE means all loaded scenes, including inactive and DontDestroyOnLoad objects.
Editor preview/Prefab Mode catalog objects are excluded unless SPATIALOPT preview=true.
ACTIVE SCENE freezes the active handle at command start. SCENE(selector) evaluates once
and requires an exact loaded SceneManager name/path or integer scene handle (Int32, Int64 or
UInt64; a SceneHandle on Unity 6000.6+; never narrowed, HELP INSTANCEID). Matching is
case-sensitive; ambiguous names fail (use a unique path or handle). Empty loaded scenes
are valid. Persistent/preview scenes absent from SceneManager require an explicit target
or all-loaded catalog. Scene/preview exclusions count against budgets, not coverage errors.
IN expression accepts GameObject/Component (its owner), a BUCKET of captured Unity
targets, or a published noncancelled SPATIAL report. OF is a compile-bound owner filter:
any assignable component qualifies the owner; all its retained component metadata stays.
CENTER/SIZE are finite Vector3 values;
SIZE must be nonnegative. Bounds are inclusive world AABBs, not precise collider overlaps.
INTO requires an untyped writable VALUE. Reads are sequential across VM scheduler steps;
the report is not an atomic physics snapshot. User getters/material instances are not read.

SPATIALOPT maxvisited=50000, maxobjects=512, maxcomponents=4096,
           maxcells=1024, maxtext=262144, children=true, inactive=true, tiles=false, preview=false;
In a Conductor workspace the max* defaults come from the Limits preset (spatial.* keys, HELP LIMITS).
Literal group declarations, copied at command start. Only selected targets/hierarchy are
visited; IN SCENE starts from Unity's loaded object catalog. Its initial Resources lookup
allocates the catalog before maxvisited can bound processing. BUCKET entries are captured
at command start so another process may change the bucket without invalidating the query.
Hierarchy changes and destroyed/unloaded objects can still produce unavailable targets.
The preview option affects scene/catalog selection only, not an explicit hierarchy/BUCKET.
FIND/COLLECT scope and normal path instructions are unchanged.

Before NEAR, CENTER/SIZE, OF, ACTIVE, LAYER, ENABLED and TRIGGER may appear in any
order, once each. New state qualifiers require an existing report source, just like
NEAR; they do not add automatic scene/getter reads. ACTIVE tests the captured owner
active state, LAYER an exact integer layer 0..31 (not a mask/name). ENABLED requires
captured HasEnabled; TRIGGER requires a collider kind. Unknown capability is a
nonmatch, not false. OF, ENABLED and TRIGGER must match the SAME component on an
owner. Filter operands are strict boolean/integer values sampled once at command
start, not strings or implicit conversions. Invalid operands preserve the old VALUE.
SPATIALOPT inactive=false still excludes inactive owners before ACTIVE; use
inactive=true (default) to query ACTIVE false.
Rows.Components and Colliders keep ALL snapshots of qualifying owners; use
each flat row's MatchesComponentFilter to project only the eligible colliders.
NEAR requires a report source; survey a selected scene/hierarchy once, then refine.
It freezes a finite Vector3 anchor once. RADIUS is inclusive, finite and nonnegative;
NEAREST is a positive integer capped by SPATIALOPT maxobjects. PLANE defaults XYZ
(world 3D); XY/XZ ignore the omitted coordinate. DISTANCE defaults POSITION (owner
pivot); BOUNDS measures to the closest retained component AABB satisfying the same
OF/ENABLED/TRIGGER conjunction. No known eligible bounds means the owner is excluded. This is not
exact collider shape distance or navigation. Remaining NEAR options may appear in
any order once; all require NEAR. Without NEAR, report refinement preserves earlier
distance/plane context but does not claim that the new stage ranked its output.
OF/state/region/radius selection precedes ranking within one command. CENTER/SIZE
keeps its pivot-or-any-known-bounds semantics, independent of component state.
Chain separate
commands to express nearest-N then OF instead; that can return fewer than N owners.
Ranking scans the whole supplied row domain (bounded top-N storage); it does not
stop after the first N matches. Ties use owner instance ID (Int64) then source ordinal.
Refinement applies visit/object/component limits and carries SourceCoverageComplete
and bounded SourceSummary. Empty/fewer outputs cannot erase upstream truncation.
Reports are frozen; refinements perform no Unity catalog, ROOT resolution, getter,
hierarchy/child or tile rereads. Destroying actual objects does not invalidate frozen
geometry, although session ROOT text may no longer resolve. Refresh with a new survey.

Transforms include world Position/Rotation and LocalScale. Component rows retain identity,
Kind, Enabled/HasEnabled, IsTrigger, WorldBounds/HasBounds and CellBounds/HasCellBounds.
Collider/Renderer bounds come from Unity's world AABB. A disabled collider may report empty
bounds. Tilemap local bounds transform all eight corners; no shader/render modification.
tiles=true samples only an explicit region of a rectangular Grid. Rotated/scaled grids
and tile anchor offsets are accounted for; each candidate cell (including empty/outside
cells) consumes maxcells. Other layouts return TileRegionsSkipped, never guessed coverage.

Report: Text, Summary, Scope, TypeFilter, HasRegion, Region, Published, Cancelled, Truncated,
TextTruncated, CoverageComplete, Visited, Objects, Components, CellsVisited, Tiles, Errors,
UnavailableTargets, InactiveSkipped, TypeFiltered, RegionFiltered, Duplicates,
TileRegionsSkipped, HierarchyDepthStops, Limit, MaxVisited, MaxObjects, MaxComponents,
MaxCells, MaxText, StartFrame, EndFrame, StartedUtc, FinishedUtc, Rows,
PreviewSkipped, SceneFiltered, PreviewIncluded, SelectedSceneHandle, SelectedSceneName,
SelectedScenePath,
StartedEvidence, FinishedEvidence, HasExecutionEvidence, SingleExecutionWindow, SingleFrame.
Refinement properties: IsRefinement, SourceCoverageComplete, SourceSummary,
GeometryStartedEvidence, GeometryFinishedEvidence, GeometryStartedUtc,
GeometryFinishedUtc, GeometryStartFrame, GeometryEndFrame, HasGeometryEvidence,
HasNear, Near, Plane, Metric, HasRadius, Radius, HasNearest, Nearest,
DistanceFiltered, RankedOut, StateFiltered, ActiveFilter, LayerFilter,
EnabledFilter, TriggerFilter, Colliders. Nullable filters describe this stage only.
Rows add HasDistance/Distance. Colliders is a flat read-only collider snapshot view:
ObjectName/ObjectRoot/ObjectInstanceId/Layer/Active plus Type/Kind/InstanceId/Root,
WorldBounds, Enabled/IsTrigger, MatchesComponentFilter, HasDistance/Distance and HasWorldRect/WorldRect/Plane.
Distance on a collider row is its owner's ranking distance, not per-collider ranking.
WorldRect is a world-AABB projection, valid only with HasWorldRect in XY/XZ, never
screen pixels; XYZ has no 2D rect. Multiple colliders remain distinct rows. SELECT
can narrow further and project only needed fields; filtering after NEAREST may reduce
the count. The explicit state qualifiers run before ranking, but arbitrary predicates
before ranking and per-collider ranking remain later query extensions.
Original geometry stamps remain separate from current refinement execution stamps.
StartedEvidence/SingleFrame on a refinement describes filtering, not a resampled scene.
Rows also retain SceneHandle/ScenePath to distinguish identically named additive scenes.
Every id/handle (row InstanceId/ParentInstanceId/SceneHandle, component and tile InstanceId,
TilemapInstanceId, collider ObjectInstanceId/InstanceId/SceneHandle, SelectedSceneHandle) is an
Int64 Unity session identity (HELP INSTANCEID); an unknown SCENE(handle) lists the loaded handles.
StartFrame/EndFrame are raw, UNVALIDATED Unity frameCount values; Edit Mode may retain
old play frames. StartedEvidence/FinishedEvidence use the OBSERVE/TRACE host-clock contract
with nullable Frame/Time, source/version/process/activation/window and HOOK context.
Missing/failed clocks remain unknown (ClockError records a provider failure). Unity's
opt-in evidence provider reports an unknown frame in Edit Mode. SingleExecutionWindow and
SingleFrame compare known endpoints, not all intervening reads or an atomic snapshot.
Cancellation never invokes the clock provider; its finishing Frame/Time are unknown.
Rows contain frozen strings/numbers/Unity value structs and read-only component/tile lists.
No live game objects remain in the report; Root tokens resolve only in the owning session.
TextTruncated is presentation-only: use Rows/counters for retained results. Truncated or
errors/unavailable/tile/depth gaps make CoverageComplete false. STOP records a cancelled
LastSpatialReport and releases the walker. This does not prove navigation or gameplay.
Reference topic · Language referenceMETHODSFinds method signatures without invoking them. Optional NAME, COUNT and exact PARAMS filters produce a bounded immutable report in VALUE; PRINTOPT controls discovery and display.

Detailed reference

From the in-tool help for METHODS.

SELECTIVE METHOD DISCOVERY
VALUE $report = null;
METHODS IN $character NAME Move INTO $report;                    // all Move overloads
METHODS IN $character NAME Move COUNT 2 INTO $report;            // two parameters
METHODS IN $character NAME Move PARAMS(float, float) INTO $report;
METHODS IN $character NAME Reset PARAMS() INTO $report;          // zero parameters
METHODS IN $character NAME Change PARAMS(ref int) INTO $report;
METHODS IN $character NAME Change PARAMS(out float) INTO $report;
METHODS IN [STATIC:Game.DebugActions] NAME Reset INTO $report;
PRINTOPT methoddefaults = true;
METHODS IN $character NAME Move INTO $report; // optional/default annotations
LOG $report.Text;
RECORD $report.Text; REGISTER method_search;

Use the report's .Text property to print or record the discovered signatures.
LOG/RECORD $report follows PRINTOPT object display; it does not select Text implicitly.
The structured Methods entries and counters remain available through ordinary paths.

NAME is an exact case-sensitive literal (quotes optional for a simple name).
NAME, COUNT and PARAMS are optional, in that order. Omitted PARAMS matches any signature;
PARAMS() means zero parameters. PARAMS uses exact types, not invocation conversions.
ref/out/in modes differ: in = a C# in parameter (by-ref with IsReadOnlyAttribute); an
interop [In] ref and a C# 12 ref readonly parameter are ref. int[] and jagged array types
are supported. Use qualified type names or registered aliases for custom parameter types.
No generic inference occurs. To call a found out/ref or generic-only signature, use
HELP "REFLECTION CALLS"; in parameters are called directly (HELP VALUES).
COUNT is a literal 0..64; if both COUNT and PARAMS are supplied they must agree.
IN accepts a live reference, Type, STATIC scope or captured BUCKET entry.
INTO requires an untyped writable VALUE. A successful query replaces its previous report.
Null/destroyed targets fail through ordinary process diagnostics, without assigning a report.
The target expression itself may contain explicitly requested getters/methods.

The result is immutable display data: Text, Matches, Visited, Truncated and Methods.
Each Methods entry contains Name, DeclaringType, Signature, IsStatic, ParameterCount,
Parameters and ParametersTruncated. Parameters holds at most 64 immutable descriptors:
Name, TypeName, Mode (Value/Ref/Out/In), IsParams, IsOptional, HasDefaultValue,
MetadataAvailable, DefaultKind, DefaultText and DefaultTextTruncated.
HasDefaultValue is known only when MetadataAvailable=true; false availability is not
proof of absence. Optionalness and a metadata default are independent: a required
parameter may have a recorded default but still must be supplied when invoking it.
DefaultKind distinguishes None, Constant, Null, ZeroInitialized, Missing, DbNull,
Unsupported and Unavailable. Missing/DBNull are not fabricated null defaults;
default(struct) and generic zero defaults are displayed without constructing values.
DefaultText is escaped, invariant, capped at 256 UTF-16 units and descriptive only:
it is not guaranteed executable UQL syntax. Enum names/numeric values and DateTime
ticks retain their metadata meaning; no timezone is inferred. Custom constant
attribute subclasses are unsupported (constructors/Value are not executed).
Metadata failures/excessive attribute metadata report Unavailable. Discovery does
not prove an invocation overload is usable. More than 64 parameters keeps the actual
ParameterCount, marks ParametersTruncated and makes the discovery report incomplete.
No target, delegate, default object or MethodInfo is retained in the report. Discovery never invokes
listed methods or reads properties. Metadata caches contain no game object instances.
It is cold synchronous reflection, not a frame-perfect/hard-time/zero-GC operation.

PRINTOPT inheritedmembers, methodinherited, methodinstance, methodengine, nonpublic,
static, methodparamnames, methoddefaults, methodreturns and modifiers apply. showmethods only controls
ordinary blueprint inclusion; it is not required for an explicit METHODS query.
STATIC scopes search static signatures; ordinary reference/Type queries require static=true
to include static methods. Engine signatures are public only. The receiver's own engine
methods are discoverable; inherited engine/platform signatures require methodengine=true.
Property/event accessors and compiler-generated methods are excluded.
methoddefaults defaults to false, preserving existing signature text. Enable it for
[optional] and default/unavailable annotations in METHODS and blueprint signatures.
It does not affect COUNT/PARAMS exact filtering or method invocation; descriptors
remain available when display is off. MaxValueCharacters additionally bounds each
displayed default; DefaultTextTruncated identifies the frozen metadata text cap.
Reports list declarations through the enabled class ancestry, not virtual dispatch targets;
overrides/hiding can appear separately with their DeclaringType. Inherited interface
declarations are not walked; query the desired interface Type explicitly.

Result/text budgets use the bounded blueprint MaxMembers/MaxCharacters host settings.
Scanning is capped at 16384 metadata entries; each type retains at most 4096 declared
signatures. Truncated=true and a text marker mean the result is not exhaustive. Zero
matches with Truncated=false is still limited by visibility and IL2CPP preservation.
Preserve game types/methods in IL2CPP; discovery cannot recover stripped metadata.
Reference topic · Language referenceCONSOLEExplicitly sends one formatted message to Unity Debug.Log. Does not change ordinary LOG routing or append to RECORD. Avoid high-volume calls; Unity console logging can be expensive.

Detailed reference

From the in-tool help for CONSOLE.

EXPLICIT UNITY CONSOLE OUTPUT
CONSOLE LOG "Message";
CONSOLE WARNING "Warning";
CONSOLE ERROR "Error";
CONSOLE WARNING; // optional empty message
CONSOLE LOG $boss.health;
Each call emits one standalone Unity console entry, synchronously on the execution thread.
Delivery is best effort: if the Unity log handler throws or console logging is unavailable,
the message is skipped without failing the process or recursively logging the failure.
Without Unity compilation symbols, console delivery is a no-op. Invalid UQL syntax or
errors while evaluating the message expression still follow normal UQL diagnostics.
PRINTOPT formats values, but never redirects ordinary LOG to Unity Console.
There is no automatic throttling, async queue or hidden conversion of LOG calls.
Avoid these commands in high-frequency loops; Unity logging and stack traces can be costly.
CONSOLE ERROR does not throw a UQL execution error. Unity Error Pause/log handlers still apply.
The connected Editor host publishes them, like every Console message, in Console/console.txt with this run's
request, group and process (HELP HOSTCONSOLE).
These messages do not append to RECORD, registry archives or the host's normal output buffer.
Ordinary LOG/BLUEPRINT remain in the host output. Conductor's Output button, beside Stop group,
opens a read-only viewer for the selected group's output with Follow and Copy controls.
The viewer shows the existing bounded buffer and does not execute scripts or read game paths.
Both command forms work in script BLOCKs and terminal input. Unity player console behavior is
platform-controlled; no Editor assembly is required for player logging. Disabled logging
may produce no visible message. This feature does not configure build file paths or persistence.
Reference topic · Language referenceINDEXBrowse the in-tool reference topics and their related commands.

Detailed reference

From the in-tool help for INDEX.

UQL TERMINAL — QUICK START
Every submission is compiled UQL, not a separate shell language. End statements with ;
READ 2 + 3;                         // show a value
ALIAS $health = Boss.Health;        // path relative to the configured root
READ $health;                      // read its current value
EDIT $health = 80;                  // write to game data

HELP topics (quotes optional for a simple name):
HELP "PATHS";      roots, aliases, dynamic selectors and dictionary indexing
HELP "SCRIPT";     scopes, BLOCK, CALL/START, loops and WAIT
HELP "LIVE";       INSPECT, BLUEPRINT, refresh settings and safety
HELP "BUCKET";     captured paths and RESOLVE
HELP "RECORD";     buffered text and REGISTER
HELP "UI";         window size, fonts, scrollbars and session controls
HELP "SAFETY";     side effects, limits, IL2CPP and release builds
HELP LIMITS;        workspace limits preset (Config <Limits/>): BUCKET, RECORD, LOG, SELECT, budgets
HELP LIMITOPT;      one group's own limits over the preset (LIMITOPT bucketEntries = 500000;)
HELP QUERY;         managed ranges, bounds, budgets, numeric ITERATE
HELP NATIVE;        native query grants, snapshot ITERATE and UNSAFE EDIT
HELP PRINTOPT;      group display profile and common Unity values
HELP TRACE;         independent per-member changes, TRACEOPT, frame labels
HELP SCENE;         FIND/COLLECT scene objects, children and components
HELP ROOT;          bind an exact session identity or export its path text
HELP STATIC;        read, blueprint and trace a whole static scope
HELP HISTORY;       TRACE history (not input history)
HELP EXPLORER;      interactive tree, edit, paging and session paths
HELP CATALOG;       symbols, scripts, blocks, registers, traces and processes
HELP CAPABILITIES;  built-in cards, metadata context and unsupported/deferred targets
HELP ACCEPTANCE;    dated offline/API/live evidence scopes, not current-binary proof
HELP EDIT;          value/reference assignment, null and source paths
HELP VALUES;        p/v3, color, bounds and contextual tuple constructors
HELP "REFLECTION CALLS"; out/ref arguments, generic-only methods and constructors (no C# bridge)
HELP GAME;          TIMESCALE / PAUSE / PLAY, and Editor-only play controls
HELP METHODS;       selective method signatures without invoking them
HELP SCAN;          bounded scene/member/value/reference discovery
HELP CODE;          read-only C# call/write/event candidates and context filters
HELP OBSERVATIONS;  named before/after evidence, typed checks and provenance
HELP SESSIONS;     Editor session log and how the previous Editor ended (crash, kill, quit)
HELP PATCHING;     optional IL patch points: PATCH, APPLY / REMOVE, PATCHCONTEXT, PATCHINFO
HELP KB;           your own asset knowledge across sessions: KB NOTE, KB FIND, KB FORGET
HELP CAPTURE;      camera CAPTURE, CAPTURE SCENE and CAPTURE GAME VIEW (the screen with overlay UI)
HELP "CSHARP FUNCTIONS"; C# functions called with CALL (optional Editor module)
HELP CONSENT;       the user's Editor switches: Allow interruptions (UQL406), Allow saving / discarding changes (UQL407)

Top-level declarations/BLOCKs persist. Old executable commands do not replay.
ALIAS/DEFINE cannot be reassigned. VALUE/PATH can change. No automatic rollback.
An active/WAITing script must finish or Stop before the next submission.
LIVE views are not active script processes: you may submit commands while they refresh.
SYMBOLS; lists globals without reading them. Unknown names are compile diagnostics.
Reference topic · Language referenceCATALOGWithout a selector, lists group symbols and execution state. CAPABILITIES lists shared built-in documentation, current scalar context and limits; ACCEPTANCE lists qualified recorded test scopes, not current-binary attestation.

Detailed reference

From the in-tool help for CATALOG.

EXECUTION GROUP CATALOG
SYMBOLS;    // global ALIAS / DEFINE / PATH / VALUE / BUCKET names; no reads
SCRIPTS;    // script names participating in this compiled group
BLOCKS;     // group-wide BLOCK names, source scripts and parameter counts
REGISTERS;  // stored register names, not their contents
TRACES;     // independent traces and their current status
PROCESSES;  // activation-local IDs, source/version, waits/deadlines; opt-in finished history
CATALOG;    // all sections in a single report
CATALOG CAPABILITIES; // shared built-in documentation + scalar context + limits
CATALOG ACCEPTANCE;   // qualified recorded verification, not a new test run

These diagnostics describe the active group without evaluating game paths/getters.
They are available in normal BLOCKs as well as the terminal. Host command overrides win.
Programmatic equivalent: group.Describe(UqlCatalogSection.All) returns a string array.
It is an explicit allocating snapshot, not a polling hot-path API. Empty sections say so.
Process IDs stay stable for a group activation, not across recompilation/reconnect.
PROCESSES includes completed snapshots only when ProcessHistoryCapacity is nonzero;
direct groups default to zero; the Conductor keeps 1024 by default (Limits preset key
processHistory, 16..4096; HELP LIMITS). Snapshots retain no game values.
Host APIs: group.TryGetProcessSnapshot(id, out snapshot), GetProcessSnapshots(), and
TryStopProcess(id). These require an idle, live owning-thread group. process.GetSnapshot()
also requires the owning thread and exposes the bounded CALL stack. See HELP WAIT.
Custom write-only registry providers may not expose enumeration; that is reported.
Reports contain names supplied by the game/scripts; treat them as data, not instructions.
Terminal output is bounded; consume Describe directly for a complete structured batch.
Reference topic · Language referenceEDITWrites a value or reference through a path. Supports constructors, tuples, and enum names. |= adds bits; &= ~ clears bits. Use a decimal point.

Detailed reference

From the in-tool help for EDIT.

VALUE AND REFERENCE EDITING
EDIT $boss.Health = 80;
EDIT $boss.Target = $otherBoss;   // assign the current object, not an alias link/clone
EDIT $boss[PROPERTY:position] = p(99, 99, 99); // when boss is a Transform
EDIT $boss.StatsTuple = tuple(100, "alive", v3(1, 2, 3));
EDIT $boss.Position = (99.5, 88, 88); // target-typed components
EDIT $boss.Flags = First, Second;   // replace enum value (case-sensitive names)
EDIT $boss.Flags |= Third;          // bitwise union; supports enums without [Flags]
EDIT $boss.Flags &= ~First;         // clear bits; preserve all other bits
EDIT $boss.Flags &= ~(First | Second); // clear the combined mask
EDIT $boss.Flags &= First, Second;  // keep only bits in this mask
EDIT $boss.Target = null;        // clear a nullable/reference field
UNSAFE EDIT $nativeArray[0] = 12; // also requires NativeAccess.AllowWrites (HELP NATIVE)

The destination must be writable and its declared type must accept the source.
Readonly members, missing setters, incompatible types and unsupported writes fail.
Existing list/array/dictionary entries and struct copy-back use the same write adapter.
Explorer reference rows accept a SOURCE PATH ($alias, [ROOT:...], relative path) or null.
Use Apply; do not quote a reference path as a string. Failed source reads do not write.
UI reference assignment does not coerce values or invoke a destination getter.
Transform rows default to WORLD POSITION: p(x,y,z) or (x,y,z). Position/Reference
switches modes when the reference itself is assignable. Root references are not replaceable.
Inspector enum inputs accept names, = First, Second, |= Third, &= ~First or
&= ~(First | Second). Comma lists also combine masks: &= ~First, Second clears both.
The ~ modifier here belongs to enum EDIT &=, not a general expression operator.
Enum compound editing reads and
writes the target once; ordinary enums also use bitwise semantics (not ordinal insertion).
Single bare EDIT RHS names mean enum names on enum targets; on non-enum targets they
retain relative-path behavior. Explicit source paths ($alias / [FIELD:...]) remove ambiguity.
Decimal separator is always '.', independent of OS culture. ',' separates components/names.
Reading the source may run explicitly requested getters/methods; setters can run game code.
Destroyed Unity source references are rejected by the reference UI; clear with null.
Replacing a field reference changes game state. This is not ALIAS rebinding and has no
automatic undo/transaction rollback for user setter side effects.

SAVING AND THE EDIT LOG
In Edit Mode an EDIT marks what it changed for saving, once per object at the end of the host tick: the object's
scene (in Prefab Mode the stage; a prefab instance also records its override). RenderSettings and LightmapSettings
mark the active scene. An asset (ScriptableObject, Material) is marked only with editDirty = 2, because Unity then
saves it without asking; with the default 1 the line says dirty=asset-unmarked. Imported, built-in and package
assets are never marked (dirty=not-saveable-asset). While the user's Editor switch 'Allow saving / discarding changes' is
off (the default; HELP CONSENT) an asset is not marked even with editDirty = 2 or MarkDirty (dirty=asset-unmarked), and an open
Prefab stage is not marked while Prefab Mode auto-save is on or in an unknown state (dirty=stage-unmarked); scenes are always marked.
Physics, Time, QualitySettings and other project-settings statics
are reported as dirty=settings-dirty: Unity marks their settings asset itself when a value changes (probed for Physics),
so the next project save may write the change; restore them with DEFER CALL.
UQL never uses Unity Undo: Ctrl+Z does not revert a UQL edit, and EDITOR UNDOLOG does not list it. Restore values
with DEFER CALL, or read the before values from the edit log. A scene stays dirty after a restore (Unity has no
public "clean again"); a test that restores everything it changes may use LIMITOPT editDirty = 0.
Play Mode EDITs are never marked: Play changes are discarded at exit. An asset changed in Play Mode keeps the
change in memory, unmarked.
Every Edit Mode EDIT is also written to the edit log with its before and after value (HELP EDITLOG); editLog = 2
logs Play Mode and player EDITs too. A HOOK BLOCK that edits on every update is summed into REPEAT lines; for such
tooling groups use LIMITOPT editLog = 0.
Off for one group: LIMITOPT editLog = 0, editDirty = 0; (the larger value wins between sources).
Off for all groups: the Limits preset (<Limits editLog="0" editDirty="0" />).
INVOKE calls (SetActive, Instantiate, AddComponent, SetParent, ...) are not tracked: after one, call
INVOKE [STATIC:UQL.Runtime.UqlEditLog].MarkDirty($go); (UQL219 warns in Edit Mode).
An in-memory object (new Material, ScriptableObject.CreateInstance) edited through its own variable cannot be traced
to a scene: call MarkDirty on the component that holds it.
Reference topic · Language referenceROOTRegisters a discovered reference under a session identity. Binds a PATH or exports ROOT path text into VALUE; not a universal persistent identity for value types or field locations.

Detailed reference

From the in-tool help for ROOT.

EXACT SESSION ROOTS
VALUE $found = null;
FIND "MonoManagers" IN SCENE INTO $found;
PATH $stable;
VALUE $code = null;
IF $found != null {
    ROOT $found INTO $stable; // bind PATH to this exact reference
    ROOT $found INTO $code;   // store its [ROOT:...] path as string data
    LOG $code; NEWLINE;
    READ $stable;
}

ROOT is executable in BLOCKs or the terminal. Declare its destination beforehand.
Destination must be a mutable PATH or string/object VALUE, never ALIAS/DEFINE/BUCKET.
VALUE output remains text; it is not implicitly evaluated. Copy it into explicit path syntax.
Unity objects/components and managed class references are supported; captured BUCKET
entries are resolved once. Null, destroyed objects, boxed structs and static scopes reject
the operation without changing the destination. Use [STATIC:Type] for a static scope.
The same reference gets the same code in a registry; duplicate names remain distinct.
Rename, reparenting or replacing the original field does not retarget an existing ROOT.
These are weak session identities, not save IDs and not pins: GC/destroy/reset can expire
them. Expired keys fail instead of falling back to a same-named object; the failure names
the reason when the registry knows it: object destroyed (also after its entry was pruned),
collected/unloaded, not registered here, a key of another group/activation, or a malformed
(mistyped/truncated) key. uql_ is reserved
for generated ROOT locators. Share group.RootRegistry with other hosts to share identities.
Terminal submissions preserve the registry; session Reset clears it. ROOT path preparation
runs only on this explicit command, not on ordinary ALIAS reads.
SCENE/name-based ALIAS/PATH definitions do not freeze object identity. COLLECT already
captures exact weak session roots, so its BUCKET entries need no extra ROOT for identity.
Reference topic · Language referenceBUCKETStores captured paths, not object snapshots. Iteration and reads automatically resolve each entry.

Detailed reference

From the in-tool help for BUCKET.

BUCKET / CAPTURED PATHS
BUCKET $paths;
VALUE $i = 0;
ADD Enemies[$i].Health TO $paths; // no target getter executes during ADD
ADD Enemies[FROM: 0 COUNT: 4].Health TO $paths; // enumerate source, freeze each index
$i = 1;                         // does not change the captured index 0
VALUE $value = null;
RESOLVE $paths[0] INTO $value;   // execute the captured path NOW
READ $value;
ITERATE $paths AS $entry { READ $entry; TRACE $entry; }
TRACE $paths[0];                // re-read the captured target each sample
READ $paths[0].Health;          // for paths targeting an object with Health
REMOVE 0 FROM $paths;
CLEAR $paths;

ADD freezes required VALUE/parameter values and all PATH bindings, not the final value.
BLOCK locals may be captured and read after the BLOCK returns. Objects are not deep-copied.
Collection reordering can change which object a captured index reaches.
The list is ordered and permits duplicates. Mutating it during ITERATE invalidates iteration.
BUCKET cannot be reassigned. RESOLVE needs a previously declared writable VALUE.
RESOLVE explicitly reads a SNAPSHOT. TRACE $value cannot recover its original path.
For live reads keep the entry: TRACE $paths[0]; or PATH $live = $paths[0]; TRACE $live;
READ/LOG/RECORD/BLUEPRINT/INSPECT/TRACE/OBSERVE and collection iteration resolve entries on use.
Expressions do not: $sum + $entry or $entry > 3 fails with a hint naming RESOLVE, and == / !=
compare the entry itself, not its value. RESOLVE $entry INTO $value; first, then compute with $value.
ITERATE retains the path entry in its loop variable, not a cached target object.
EDIT with a member suffix writes through an entry: capture an object, then EDIT $entry.Health = 5;
changes that object's member (class targets; detached captured structs cannot be copied back).
EDIT $entry = 5; on a loop variable (or a VALUE holding an entry) only replaces that slot: it then
holds 5 instead of the entry and the captured leaf is NOT written. To change a captured leaf,
EDIT an ordinary live path (ALIAS $h = $enemy.Health; EDIT $h = 5;) or capture its owner instead.
Tracing $paths[0] follows bucket slot 0; tracing a loop $entry retains that entry even
after the loop ends. Clearing/reordering the bucket can invalidate/change slot paths.
Bulk ADD evaluates the source collection, but does not read each captured leaf.
It publishes the batch only on success; failure leaves existing entries unchanged.
A BUCKET holds at most group.MaxBucketEntries captured paths (default 100000; Conductor preset
key bucketEntries, HELP LIMITS); a capture past it adds nothing: ADD and query capture fail
with "BUCKET entry limit exceeded (bucketEntries=N; raise it with LIMITOPT or the Limits preset).",
SCAN/COLLECT with "... exceeds BUCKET capacity; no ... entries added (bucketEntries=N; ...)".
One group raises its own capacity with LIMITOPT bucketEntries = 500000; (before its BUCKETs are created;
in the terminal it also resizes the BUCKETs of earlier submissions).
A captured path itself is never an EDIT target in this version (see the EDIT lines above).
Reference topic · Language referenceRECORDAppends text to a process-local buffer. RECORD LINE expression/FIELDS/BLUEPRINT appends then ends its line; NEWLINE is a synonym. Bare RECORD NEWLINE ends the pending line; standalone NEWLINE affects only LOG. CALL and WAIT preserve the buffer; START/new terminal submissions do not inherit it. Completion does not auto-commit.

Detailed reference

From the in-tool help for RECORD.

RECORD / REGISTER
RECORD "Boss report";
RECORD LINE;                  // explicitly finish the current line
RECORD Boss.Health;           // snapshot as text at this moment
RECORD FIELDS health = $boss.health, state = $boss.state; // one labeled append
RECORD BLUEPRINT Boss;        // same PRINTOPT member dump as READ/BLUEPRINT
REGISTER "combat";          // commit the batch; clear buffer on success
RECORD "later";
REGISTER "combat";          // append, not overwrite the register
CLEAR RECORD;                // discard only uncommitted lines (optional)
REGISTERS;                   // terminal: list stored names
SHOWREGISTER "combat";      // terminal: print the stored lines

LOG/READ do not automatically record. CALL shares its process buffer; START has its own.
Conductor retains LOG/BLUEPRINT in a bounded per-activation output buffer (16777216 characters by default, preset key
outputCharacters up to 67108864; then one <output limit reached ...> marker)
and periodically writes the current host's Outputs/Hosts/<host-id>/Logs/<group-name--id>/output.txt (appended within one activation:
each flush writes only the new text, and the Editor Output view indexes only the appended part). This is not a registry
archive and can be replaced by the next activation. A bare runtime group without an
IUqlOutput sink does not retain LOG output.
LOG and RECORD append without separators. LOG NEWLINE; / RECORD NEWLINE; end a line.
Single-statement line forms append first, then end their stream's line:
LOG LINE $boss.health;
LOG NEWLINE FIELDS health = $boss.health, position = $boss.transform.position;
RECORD LINE $boss.health;
RECORD LINE FIELDS health = $boss.health;
RECORD NEWLINE BLUEPRINT $boss;
LINE and NEWLINE are synonyms in this prefix; all existing bare commands remain valid.
These compile to the same output + line-end instructions as two separate statements.
They do not reduce VM instruction cost or add an atomic value-plus-newline guarantee.
PRINTOPT, process ownership and quotas are unchanged. The line end has its own budget
and RECORD quota check; if the value fills the buffer exactly, it remains pending when
the newline fails. With a legacy sink, callbacks retain the existing two-step behavior.
LOG FIELDS / RECORD FIELDS add '; ' between their own labeled values, with no implicit
line end. See HELP "RECORD FIELDS"; for atomic buffer quota handling and LOG limits.
NEWLINE; is shorthand for LOG NEWLINE; (not RECORD). Older LINE spellings still work.
For example, RECORD "a"; NEWLINE; RECORD "b"; REGISTER joined; records one line, ab.
RECORD "a"; RECORD NEWLINE; RECORD "b"; REGISTER split; records two lines, a and b.
Embedded \n also ends a line. READ/BLUEPRINT stay separate output blocks.
REGISTER combat; also transfers the unfinished last line. Quotes are optional for names.
Each terminal submission starts a NEW process; pending RECORD is NOT inherited.
A normal BLOCK activation also starts a new process. CALL uses the caller's process.
Finishing/RETURN/STOP does not clear the buffer on the process object, nor commit it.
A host retaining that process can inspect GetPendingRecords(); scripts cannot recover it
from another process. Put RECORD and REGISTER in the same submission/process.
WAIT preserves pending text because the same process resumes. Committed registers
survive later terminal submissions; they are separate from the process buffer.
Failed REGISTER preserves the buffer for host recovery
and stops that process. Default buffer: 1048576 characters (group.MaxRecordingCharacters; Conductor
preset key recordCharacters, HELP LIMITS; one group: LIMITOPT recordCharacters = 4194304;); overflow is
an error, not truncation, and its message names recordCharacters and the value in force.
Default store is memory (64 names / 1048576 total characters), NOT a file. The Conductor
file workspace raises its per-activation memory registry to 256 names / 16777216 characters
(preset keys registryNames / registryCharacters, up to 4096 / 67108864; HELP LIMITS; one group:
LIMITOPT, not in the terminal, whose shared registry its host sizes); refusals name the limit and its
key, and nothing of the batch is committed.
Reset retains registers; destroying an owned terminal model releases its memory store.
Host IUqlRegistry implementations can persist batches; they must implement atomic commit.
Conductor keeps named registry archives in Outputs/Registeries/<safe-name>.txt. Only NEW
batches are appended, in commit order, including writes from multiple groups using the
same registry name. Recompile/reconnect/restart preserves the existing file. Old file
contents are never loaded back into the group's memory registry (a rewrite streams them).
CLEAR REGISTER combat; clears that group's memory record and queues a zero-length file.
It also works after recompiling, when the record exists only on disk. CLEAR RECORD only
discards the current process buffer. Other groups keep their own memory records, but
only their future commits can append to the shared archive; old records are not replayed.
Clears and appends are ordered before each periodic flush, not IO per LOG/RECORD. A flush
appends only the new batches to the archive while the file still has the length this host
left; CLEAR REGISTER, a missing archive or a file changed by someone else is rewritten by
atomic replacement of the streamed old contents plus the batches (same bytes either way).
Failed writes stay queued for retry without duplicating committed batches. Queue defaults:
16 Mi characters / 256 files per host (the default registry size); an overflowing REGISTER
fails before memory commit and leaves its process buffer available for recovery. Memory
registry limits still apply.
Dispose attempts a final flush; on failure it throws IOException and keeps pending data
retryable. Resolve the disk error and retry FlushRegisters/Dispose before dropping the host.
Only successfully flushed data is durable; crashes before flush can lose pending batches.
One file host should own an output directory; concurrent hosts/external writers are not
coordinated. Archived files can grow until explicitly cleared; flush IO scales with the new
batches, not the archive size. A reader holding an archive without write sharing (the default
File.ReadAllText) defers that batch to the next flush; the archive is never copied for it.
Read host files with FileShare.ReadWrite | FileShare.Delete.
IUqlClearableRegistry is the optional clear contract for custom providers. The default
terminal has no automatic archive; CLEAR REGISTER there clears memory only.
EXPORTREGISTER combat, "report.txt"; // optional: host must configure ExportDirectory
Export is UTF-8, does not overwrite files, accepts file names only, retains register data.
A temp file another process holds for a moment is retried within the same window as CAPTURE (up to
5 x ioSyncMilliseconds from the tick's I/O budget); then the export fails explicitly ('busy, retry the
EXPORTREGISTER'), and a temp it could not delete after a failure is named in the error.
Reference topic · Language referencePRINTOPTDisplays a value or range results as standalone output using PRINTOPT. Skipped with a diagnostic in the regular script profile.

Detailed reference

From the in-tool help for PRINTOPT.

GROUP DISPLAY PROFILE
PRINTOPT branchclasses = true, depth = 2, showtypes = true, refids = true,
         showprops = true, propnames = true, propsignatures = true,
         readprops = false, vectors = true,
         transformposition = true, transformrotation = false, transformscale = false;
PRINTOPT inheritance = true, interfaces = true, attributes = true;

Top-level literal declaration in scripts; last setting in source order wins.
Terminal/UI update the same group profile; display reads do not interpret option strings.
LOG and RECORD use this profile too, including values read synchronously inside a HOOK.
Example: LOG "pos="; LOG p(1,2,3); NEWLINE; produces pos=(1, 2, 3) by default.
They append inline values/member dumps without adding a final newline. Text/numbers/null
keep their literal append behavior; READ/BLUEPRINT remain independent output blocks.
vectors=false deliberately hides compact vector coordinates; showtypes=true adds the
type to complex root values. Class dumps obey fields/properties/branch/depth settings.
Formatting happens during execution, never later on GUI repaint.
Display budgets: maxchars (128..131072, default 32768) and maxmembers (1..1024, default 256)
end with a marker when hit; maxvalue (16..4096, default 256) is the per-value text length (a
longer string member ends with a bare ...). Example: PRINTOPT maxvalue = 4096, maxchars = 131072;
branchclasses defaults false; depth is 0..4 and defaults 0. In a Conductor workspace the defaults of
depth/maxchars/maxmembers/maxvalue come from the Limits preset (print.depth, print.maxchars, ...; HELP LIMITS);
this group's own PRINTOPT keys override them for this group only. When two sources of one group set a key to
different values, the later source in compile order wins and a UQL213 warning names both values. Cycles/member budgets bound
automatic recursion. Explorer can explicitly open a branch, to a maximum depth of 32.
showprops includes properties. propnames and propsignatures independently display names
and get/set signatures (both default true). Neither enables getter execution;
readprops separately enables it. Canonical access paths keep their real member names.
vectors supports Vector2/3/4, Vector2Int/3Int, Quaternion, Color/Color32, Rect/RectInt,
Bounds/BoundsInt, LayerMask, Matrix4x4, Ray/Ray2D and Plane;
Mathematics int/uint/bool/float/double vectors (2..4),
their 2..4 x 2..4 matrices, half/half2/3/4, quaternion and RigidTransform.
Matrices display named columns c0, c1, ...; values use invariant decimal dots.
TimeSpan and DateTimeOffset also display their values. Mathematics is optional: public field
metadata is cached without an assembly dependency, getters, operators or generated code.
structvalues (default true) adds a compact field-only preview for other custom structs:
up to 8 fields, two nested preview levels, bounded by MaxValueCharacters. No arbitrary
ToString/getters/native internals. Field/nonpublic/read settings still apply; explicit
expansion remains available. Disable with PRINTOPT structvalues = false;
inheritance/interfaces/attributes default false. They show type and declared member
metadata in text and inspector snapshots. Attribute constructors are never called.
Metadata is bounded, cached lazily and requires surviving IL2CPP reflection metadata.
valuetuples (default true) renders ValueTuple contents in LOG/RECORD/READ/BLUEPRINT/LIVE as
(Item1 = value, Item2 = value, ...), including nested/long tuples within text/depth budgets.
Tuple source-language element names are not runtime type names; ItemN labels are used.
Transform position/rotation are world-space; scale is labelled localScale.
refids uses Unity session ids (#<id>, HELP INSTANCEID) or weak session-managed ids printed #m<n>, never memory addresses.
Closed collections show only reliably known Count/Length, never enumerate for a count.
Extras: showfields, showmethods (signatures only), nonpublic, static, paths.
inheritedmembers (default true) includes game-base members; false shows only concrete
declared members. inheritance only displays the type header: it is not a member filter.
methodinherited (true) can hide inherited signatures without hiding inherited fields.
methodinstance (true) includes instance signatures; static (false) also applies to methods.
methodengine (false) includes inherited public engine/platform signatures only, never
engine field/getter reads. methodparamnames (true) controls parameter names;
methoddefaults (false) shows optional/default annotations without invoking methods
or user constant attributes; METHODS descriptors remain available when it is false.
methodreturns (true) controls return types independently of field showtypes. modifiers
(false) shows access modifiers. nonpublic applies to game signatures, not engine internals.
For targeted signature discovery use METHODS; no listed method is automatically invoked.
Other output/member budgets are host/UI settings, not executable path syntax.
Reference topic · Language referenceHISTORYAppends retained history, or an ordered incremental batch SINCE a typed cursor. Cursor advances only after the registry accepts the batch; explicit GAP markers report retention loss/clears. Does not stop or clear the TRACE.

Detailed reference

From the in-tool help for HISTORY.

TRACE / PER-MEMBER CHANGE HISTORY
TRACEOPT interval = 0.25, depth = 2, capacity = 128, fields = true,
         properties = true, readprops = false, collections = true, initial = true,
         transformposition = true, transformrotation = false,
         transformscale = false, transformchildren = true,
         gameobjectcomponents = true, gameobjectchildren = true;
TRACEOPT logtime = true, logframe = true, showtime = false, showframe = false;
TRACEOPT manual = true;   // disable ALL periodic samples, including the initial one
TRACE Boss;
TRACE Enemies[FROM: 0 COUNT: 4].Health;
TRACES;                  // list trace ids
HISTORY 1;               // dump TRACE #1 events
CLEAR HISTORY 1;         // discard events, retain baselines/bindings
TRACEPAUSE 1; TRACERESUME 1;
STOPTRACE 1;             // release bindings, retain logs (start new TRACE to restart)
UNTRACE 1;               // remove bindings and logs
REGISTERTRACE 1, combat; // append retained events; does not clear TRACE logs
TRACEAPPLY 1;           // apply current TRACEOPT to one existing active trace
TRACEAPPLY ALL;         // apply to all active traces, including paused traces
UPDATE TRACES;          // sample this group's active traces NOW, ignoring interval
UPDATE TRACE #1 #3 #5;   // sample selected trace IDs in this group, in written order
UPDATE TRACE #1, #3;     // commas are optional; # and positive decimal IDs are required

TRACE works in regular BLOCKs and terminal commands. It is not a LIVE option.
UPDATE TRACES is executable, not an options declaration. Put it inside a HOOK BLOCK
at the exact observation point. Hooks do NOT sample traces automatically.
Paused/stopped traces stay paused/stopped. Unchanged values do not produce new events.
Explicit sampling does not postpone the next periodic sample; TRACEAPPLY only changes options.
manual=false is the compatibility default. manual=true is explicit-only, even at interval=0.
Manual mode does not implicitly sample when starting, resuming, applying options or drawing UI.
TRACEOPT affects new traces; use TRACEAPPLY id/ALL to switch existing traces to manual mode.
In a Conductor workspace the defaults of depth/capacity/maxmembers/maxvalue come from the Limits
preset (trace.* keys, HELP LIMITS); this group's own TRACEOPT keys override them.
Set manual=false and apply again to resume periodic reads (interval is retained).
Typed identities and incremental exports:
VALUE $trace = null; VALUE $cursor = null;
TRACE $boss.health INTO $trace;
UPDATE TRACE $trace PHASE AfterDamage;
UPDATE TRACES PHASE EndOfTest;
HISTORY $trace; TRACEPAUSE $trace; TRACERESUME $trace;
TRACEAPPLY $trace; STOPTRACE $trace; CLEAR HISTORY $trace;
REGISTERTRACE $trace, combat SINCE $cursor INTO $cursor LIMIT 64;

INTO on TRACE requires a writable VALUE accepting UqlTraceHandle. Management commands
accept handles or legacy IDs; UPDATE accepts handles mixed with #ID selectors.
PHASE is a constant name/string (up to 128 characters), not a scheduling command.
The handle contains service/creation-activation/trace identities, no target, path or
group reference. A fresh normal activation/service rejects old handles even if #1
exists again. A terminal's retained shared TRACE service intentionally keeps handles
valid across submissions; Reset/disposal/UNTRACE invalidates them. Do not serialize
handles for another host/session. Numeric IDs remain compatible, without that safety.

SINCE requires null or an immutable UqlTraceCursor; INTO requires a writable cursor
VALUE. LIMIT is a literal integer 1..4096 (default 4096). Export takes an ordered prefix
within its 262144-character batch budget. The returned cursor acknowledges only that
prefix; more=true means repeat with that cursor. Successful export does not clear
history. Failed/throwing registry append does not replace the destination cursor.
Cursor.HasMore, HadLoss and ExportedEvents are frozen accepted-batch metadata, not
live history queries; WHILE $cursor.HasMore can drain the remaining export pages.
An empty repeated export adds no duplicate event text. Cursor belongs to the same
service/activation/trace. Ring eviction, global budgets, option trimming and explicit
clears produce TRACE GAP (missing-count=unknown); another trace's sequence numbers
are not loss. Clear keeps the baseline; its history generation is reported explicitly.
Registry acceptance/pending file publication is NOT guaranteed durable disk flush.
The two-argument REGISTERTRACE form still appends all retained history every time.

Exported events retain sequence/sample/options version, service/creation activation,
PHASE and frozen source/window/clock/HOOK provenance. Actual UPDATE source differs
from trace creation origin. Periodic host samples have no fabricated executing BLOCK;
frame/time can be unknown. All members read sequentially, never an atomic game snapshot.
Retained event data has no game references; captured read bindings retain their own
lifetime until STOP/UNTRACE. Normal ALIAS reads and 16-byte instructions are unchanged.

Legacy numeric selectors refer to TRACE IDs listed by TRACES/History, not aliases, object IDs or member IDs.
IDs belong to the current group/terminal session; never assume IDs survive a fresh activation.
Removed IDs are not reused within that runtime. Duplicate selectors sample only once.
Unknown ID fails the command before ANY selected target is read; paused/stopped IDs are skipped.
Selection limit: 1024 entries. Values/paths/getters are resolved at the instruction, not at compile.
Each sampled trace records its own actual start clock/frame; its members are read
sequentially, and several selected traces may have distinct start stamps. This is
not an atomic snapshot of the entire game. logtime/logframe must be enabled to retain them.
Terminal periodic sampling runs after its scheduler in MonoBehaviour.Update (default .25s),
not LateUpdate/end-of-frame. Relative order against other Update methods is unspecified.
Native permission/lifetime rules and member budgets also apply to explicit sampling.
INSPECT path HISTORY n; was removed. Each TRACE starts an independent process.
Options are top-level literals copied on Start; later TRACEOPT affects future traces.
logtime/logframe control metadata retention in NEW events; both default true.
showtime/showframe control History panel labels, not retained/exported data; default true.
hidetime/hideframe are inverse aliases for showtime/showframe. Apply to existing traces
with TRACEAPPLY id/ALL or the buttons. Old recorded events remain unchanged.
Disabled time is NaN (HasTime=false), disabled frame is -1 (FrameRecorded=false).
Exports/HISTORY keep recorded metadata even when the UI hides it. Hidden is not redacted.
TRACEAPPLY explicitly updates existing options, retaining selections, baselines and logs.
Capacity reduction evicts oldest member events; changes are tagged with OptionsVersion.
Rebinding happens at the next sample, never while drawing GUI. Stopped traces stay stopped.
Defaults: manual false, interval .25s, depth 1, capacity 128 per member, maxmembers 512, maxvalue 2048,
fields true, properties/readprops false, nonpublic/collections/initial true.
Depth 0..16; capacity 1..4096. maxmembers bounds discovery; incompleteness is explicit.
A traced value (or read error) longer than maxvalue keeps its start and ends with
'… (+N chars; M total)': N characters cut, M the original length (within maxvalue).
No string option dispatch during reads; metadata is bound per actual runtime type.
Each member has its own enabled state, baseline and changes-only history.
Class/struct fields recurse to depth; cycles stop. Property getters require readprops.
Collections track reference identity and Count/Length, not all elements; TRACE a range
for element data. Never enumerate to count. Native collections stay opaque.
Transform/RectTransform are NOT collection metrics: their explicit flags select world
position/rotation, localScale and childCount. Depth must allow children (at least 1 for
a root Transform). No child enumeration, Count lookup or arbitrary engine reflection.
Opt-in GameObject flags discover components and child objects within depth/maxmembers.
Depth 1 includes immediate object/component identities; depth 2 also reads component fields.
New objects are labelled observed (not a claim about their actual creation time).
Missing live objects are labelled left observed hierarchy; destroyed Unity references
are labelled destroyed. If the weak wrapper is gone the label is no longer observable.
Objects created and destroyed between samples are invisible; place UPDATE TRACES at
the relevant hook points if those intermediate changes must be observed.
Component/child keys containing [COMPONENT#id] or [GAMEOBJECT#id] are diagnostic identities,
not executable paths. They and their member suffixes are for log filtering only.
The History tab shows event text on the left, trace/member selection on the right.
The selected trace's member tree is inserted immediately below its header.
Expand/collapse and enable individual branches. Selecting a member filters its own log.
Keep up follows the last event; scrolling up pauses following, not recording.
Compact/Tail parts abbreviate the whole path; Copy full path copies the real path.
HISTORY/REGISTERTRACE retain full paths even when the UI abbreviation is enabled.
Untoggle all disables all members and future discoveries. Selecting one member enables
its ancestors only, not siblings. Toggle all restores all members. Recording is not cleared.
History TRACEOPT offers defaults plus explicit Apply to selected/all active trace buttons.
Logs store text/errors, timestamps, real host frame numbers, sample and event sequences,
not target objects. Print values are bounded; equal truncated displays can compare equal.
TRACE freezes slot/PATH operands like BUCKET; referenced object contents remain live.
Stop releases its capture. Later terminal submissions retain traces until Stop/Reset.
Hidden UI and Pause LIVE do not pause TRACE; disabling its MonoBehaviour stops Update.
Max 32768 events / 4194304 text characters per service; oldest events evicted, counted
per member. This is a payload budget, not an exact total heap-byte ceiling.
Default capture is periodic; interval = 0 samples each host Tick, not every frame change.
UI supplies Time.frameCount. Headless hosts pass frameNumber or get frame=unknown.
Scheduler Tick is NOT Unity frame. No HOOK or frame-perfect guarantee in this version.

Need a hand?

Send your Unity and UQL versions, the command you tried, and the result you expected to deadbeakofficial@gmail.com.