Add Unity Pipeline package support

This commit is contained in:
ud18010
2026-07-31 17:34:04 +08:00
parent d1a526094e
commit 786b7ffff9
590 changed files with 51995 additions and 2 deletions
@@ -0,0 +1,25 @@
* [Home](index.md)
* Guides
* [Creating commands](creating-commands.md)
* [Creating authoring commands](authoring-commands.md)
* [Safety & mutations](safety-and-mutations.md)
* [Connectivity](connectivity.md)
* [Runtime connection & setup](runtime-setup.md)
* [Hot reload](hot-reload.md)
* [Tests architecture](testing.md)
* Command reference
* [Asset & file commands](commands/assets-and-files.md)
* [Scene commands](commands/scenes.md)
* [GameObject & component commands](commands/gameobjects-and-components.md)
* [Prefab commands](commands/prefabs.md)
* [Script commands](commands/scripts.md)
* [Animation commands](commands/animation.md)
* [Material & shader commands](commands/materials.md)
* [Baking commands](commands/baking.md)
* [Navigation & selection commands](commands/navigation.md)
* [Capture commands](commands/capture.md)
* [Build, compilation & test commands](commands/build-and-compilation.md)
* [Project settings commands](commands/project-settings.md)
* [Package Manager commands](commands/package-manager.md)
* [Editor lifecycle & observability commands](commands/editor-lifecycle-and-observability.md)
* [Runtime commands](commands/runtime.md)
@@ -0,0 +1,319 @@
# Creating authoring commands
*Authoring commands* are the subset of commands that **create or mutate project content** — assets,
scenes, GameObjects, components — on behalf of an agent. They build on the base command API in
[Creating commands](creating-commands.md); this page covers the four concerns that are specific to
content authoring:
- **The authoring root** — the sandbox that bare paths resolve against and writes are confined to.
- **`ObjectRef`** — how a command *receives* a reference to an existing object.
- **`AuthoringResult`** — how a command *returns* the identity of an object it created or touched.
- **Undo/redo** — grouping a command's scene mutations into a single, revertible step.
Together these let one command's output feed the next command's input, so an agent can chain calls
(`create_gameobject``add_component``set_component_properties``create_prefab`) without ever
handling a raw Unity object itself. If you want to support a content type the package doesn't cover
yet (materials, audio, lighting, terrain, …), this is the pattern to follow.
Read [Creating commands](creating-commands.md) first — this page assumes you know how `[CliCommand]`,
`[CliArg]`, `MainThreadRequired`, and the response envelope work.
## Authoring vs. management commands
Not every state-changing command is an *authoring* command. This page — and the [checklist](#checklist-for-a-new-authoring-command)
at the end — applies to commands that **create or mutate project content** (assets, scenes,
GameObjects, components) and hand the agent back an object identity.
**Management commands** change *configuration* or *drive tooling* rather than author content:
project settings (`Editor/Commands/ProjectSettings/`), builds (`Build/`), and packages
(`PackageManager/`). They are a **different category** and deliberately do
**not** follow the full authoring contract. They share only the cross-cutting safety conventions
(the `confirm`/`dry_run` gate and, where relevant, `ObjectResolver`/`ProjectPaths`) — see
[Safety & mutations](safety-and-mutations.md).
| Concern | Authoring command | Management command |
|---|---|---|
| Object input | `ObjectRef``ObjectResolver.TryResolve` | same, when it references an object (e.g. a scene in the build list) |
| Path input | `ProjectPaths.Resolve` (confined to the authoring root) | as needed; may be unconfined by design (e.g. a build output path) |
| Undo | scene/object mutations wrapped in `AuthoringUndoScope` + registered `Undo` APIs | **none** — settings / AssetDatabase / UPM writes don't participate in Undo, so no scope; note `Not undoable via Ctrl+Z.` in the description instead |
| Destructive gate | `confirm`/`dry_run` where destructive | `confirm`/`dry_run` where destructive (same convention) |
| Return value | `AuthoringResult` via `ObjectResolver.Describe` | a domain model (e.g. `ProjectSettingsResponse`, `PackageMutationResponse`) or a plain result object |
| Failure | **throw** (`ArgumentException` / `InvalidOperationException`) | throw, **or** return a structured `{ success = false, code, error }` object — consistent within the area |
If you're adding a config/build/package command, follow the management column and the shared safety
conventions; the checklist below is for content-authoring commands.
## The building blocks
| Type | Namespace | Role |
|------|-----------|------|
| `ProjectPaths` | `Unity.Pipeline.Editor.Authoring` | Resolve/confine agent-supplied paths to the authoring root. |
| `ObjectRef` | `Unity.Pipeline.Models` | Input handle to an existing object (asset or scene object). |
| `AuthoringResult` | `Unity.Pipeline.Models` | Output identity of an object your command created or acted on. |
| `ObjectResolver` | `Unity.Pipeline.Editor.Authoring` | `TryResolve(ObjectRef …)` (handle → object) and `Describe(object)` (object → `AuthoringResult`). |
| `AuthoringUndoScope` | `Unity.Pipeline.Editor.Authoring` | Collapses all `Undo`-registered mutations in its lifetime into one editor undo step. |
Authoring commands are Editor-only. Put them under `Editor/Commands/<Area>/` in the
`Unity.Pipeline.Editor.Commands.<Area>` namespace (see `Editor/Commands/Authoring/AuthoringConfigCommands.cs`).
## The authoring root (`set_authoring_root`)
Agents pass **bare, relative paths** (`"Materials/Stone"`), not full project paths. `ProjectPaths`
resolves those against a configurable **authoring root** and *confines* every write to it. The root
defaults to `Assets` (full project access); an agent can narrow it to a sub-folder to sandbox itself:
```
get_authoring_root → { "root": "Assets" }
set_authoring_root --root Assets/AgentWork
```
These are just thin commands over `ProjectPaths.AuthoringRoot` (`Editor/Commands/Authoring/AuthoringConfigCommands.cs`):
```csharp
[CliCommand("set_authoring_root", "Set the base folder (under Assets/) that bare authoring paths resolve against and are confined to. Use 'Assets' for full project access.")]
public static object SetAuthoringRoot(
[CliArg("root", "Project-relative folder under Assets/, e.g. Assets/AgentWork. Use 'Assets' to allow the whole project.", Required = true)] string root)
{
// Throws ArgumentException for invalid roots (outside Assets/ or containing ".."); the
// server surfaces that message to the caller.
ProjectPaths.AuthoringRoot = root;
return new { root = ProjectPaths.AuthoringRoot };
}
```
**Every path parameter your command accepts must go through `ProjectPaths.Resolve`.** This is the
sandbox boundary — it rejects `..` traversal and anything that escapes the root, and it lets callers
omit the `Assets/` prefix. Do not build asset paths by string concatenation.
```csharp
var normalized = ProjectPaths.Resolve(path, out var error);
if (normalized == null)
throw new ArgumentException(error); // e.g. "Path '../secrets' must not contain '..'."
// normalized is now a project-relative path guaranteed to live under the authoring root.
```
Resolution rules (`Editor/Authoring/ProjectPaths.cs`):
- Bare paths (`"Materials/Stone"`) are taken relative to the root → `Assets/AgentWork/Materials/Stone`.
- Explicit `Assets/…` / `Packages/…` paths are used as-is (but still confined to the root).
- Absolute paths must live under the project root and are converted to project-relative.
- `..` anywhere, or a result outside the root, returns `null` + an `error` string.
## Receiving objects: `ObjectRef`
When a command needs to act on an object that *already* exists, take an `ObjectRef` parameter. The
agent supplies **one** of several forms; `ObjectResolver.TryResolve` tries them in order — `globalId`,
`path`, `guid` (+ optional `fileId`), `instanceId`, `hierarchyPath` — and hands you the live object:
```csharp
public static Renderer ResolveRenderer(ObjectRef target)
{
if (!ObjectResolver.TryResolve(target, out var obj, out var error))
throw new ArgumentException(error);
var go = obj as GameObject ?? (obj as Component)?.gameObject;
var renderer = go != null ? go.GetComponent<Renderer>() : null;
if (renderer == null)
throw new ArgumentException($"Object '{target}' has no Renderer.");
return renderer;
}
```
Resolve **outside** any undo scope / before mutating, so a bad handle fails before your command
changes anything (see `create_gameobject`, which resolves its `parent` before entering the scope).
When the handle is a plain string (the usual agent input), a value with a file extension and no
leading `/` — e.g. `"Materials/Floor.mat"` — is taken as an asset path and normalized under the
authoring root, so the `Assets/` prefix is optional (mirroring path-taking commands). A leading `/`
or an extension-less value stays a `hierarchyPath`; a dotted scene name like `"Cube.001"` still
resolves because the `path` branch falls back to a hierarchy lookup.
## Returning objects: `AuthoringResult`
Any command that creates or modifies an object should return its identity so the agent can reference
it in a follow-up call. Don't build this by hand — call `ObjectResolver.Describe(obj)`, which fills in
the right fields for the object kind:
- **Assets** get `assetPath`, `guid`, `fileId`, `type` (+ `globalId`).
- **Scene / loaded objects** get `instanceId`, `hierarchyPath`, `type` (+ `globalId`).
```csharp
var result = ObjectResolver.Describe(asset) ?? new AuthoringResult { Type = nameof(Material) };
result.AssetPath = assetPath; // ensure the path is set even if Describe returned a fresh result
return result;
```
`AuthoringResult` is **identity only** — no success flag, no message. Success/failure and timing live
in the outer `CommandExecutionResponse` (the server adds them). To report a failure, **throw**
(`ArgumentException` for bad input, `InvalidOperationException` for an operation that failed); the
server converts the exception into a failure envelope. For a batch, return a model that holds an
`AuthoringResult[]` (see `CreateGameObjectsResult`).
## Undo/redo
Undo is Unity's native `UnityEditor.Undo`, grouped per command by `AuthoringUndoScope` so a single
call reverts as a single Ctrl+Z step. Register each mutation with the matching `Undo` API **inside**
the scope:
```csharp
using (new AuthoringUndoScope("Set Material"))
{
Undo.RecordObject(renderer, "Set Material"); // record BEFORE mutating
renderer.sharedMaterial = material;
EditorSceneManager.MarkSceneDirty(renderer.gameObject.scene);
}
```
Which `Undo` call to use:
| Mutation | Call |
|----------|------|
| New scene object | `Undo.RegisterCreatedObjectUndo(obj, name)` |
| Change fields on an existing object | `Undo.RecordObject(obj, name)` / `RegisterCompleteObjectUndo` (before the change) |
| Add a component | `Undo.AddComponent(go, type)` |
| Reparent | `Undo.SetTransformParent(child, parent, name)` |
| Serialized properties | `SerializedObject` + `so.ApplyModifiedProperties()` (registers undo itself) |
> **Important caveat.** `AssetDatabase` operations are **not** part of Unity's undo system. Creating a
> folder or asset, importing, `AssetDatabase.CreateAsset`, `SaveAsPrefabAsset`, and file writes are
> **not undone** by Ctrl+Z. `AuthoringUndoScope` only covers scene/object mutations. If your command
> writes to disk, say so in its description and don't rely on undo to clean up — validate up front and
> fail before writing.
## Worked example — a new content type
Say the package has no material (rendering) commands and you want to add them. Two commands cover the
whole pattern: one that **creates an asset** (path handling + `AuthoringResult` out, no undo because
it's an `AssetDatabase` op) and one that **mutates a scene object** (`ObjectRef` in + undo).
```csharp
using System.IO;
using Unity.Pipeline.Commands;
using Unity.Pipeline.Editor.Authoring;
using Unity.Pipeline.Models;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace Unity.Pipeline.Editor.Commands.Rendering
{
/// <summary>Authoring commands for materials (rendering).</summary>
public static class MaterialCommands
{
[CliCommand("create_material",
"Create a Material asset (default shader 'Standard') under the authoring root. " +
"NOTE: asset creation is not undoable via Ctrl+Z.")]
public static AuthoringResult CreateMaterial(
[CliArg("path", "Asset path relative to the authoring root; the Assets/ prefix and the .mat extension are optional. e.g. Materials/Stone", Required = true)] string path,
[CliArg("shader", "Shader name to assign. Defaults to 'Standard'.")] string shader = "Standard")
{
// 1. Resolve + confine the path (the sandbox boundary).
var normalized = ProjectPaths.Resolve(path, out var error);
if (normalized == null)
throw new ArgumentException(error);
if (!normalized.EndsWith(".mat", System.StringComparison.OrdinalIgnoreCase))
normalized += ".mat";
var found = Shader.Find(shader);
if (found == null)
throw new ArgumentException($"Shader '{shader}' was not found.");
// 2. Do the work (AssetDatabase op — no undo scope; it wouldn't be undoable anyway).
EnsureParentFolder(normalized);
var material = new Material(found);
AssetDatabase.CreateAsset(material, normalized);
AssetDatabase.SaveAssets();
// 3. Return the created object's identity so the agent can reference it next.
var result = ObjectResolver.Describe(material) ?? new AuthoringResult { Type = nameof(Material) };
result.AssetPath = normalized;
return result;
}
[CliCommand("set_material", "Assign a material asset to a Renderer on a scene GameObject.")]
public static AuthoringResult SetMaterial(
[CliArg("target", "Handle of the GameObject (or Renderer) to modify.", Required = true)] ObjectRef target,
[CliArg("material", "Handle of the material asset to assign (path/guid/globalId).", Required = true)] ObjectRef material)
{
// Resolve both handles up front, before mutating, so a bad handle changes nothing.
var renderer = ResolveRenderer(target);
if (!ObjectResolver.TryResolve(material, out var matObj, out var matError))
throw new ArgumentException(matError);
if (matObj is not Material mat)
throw new ArgumentException($"'{material}' is not a Material.");
using (new AuthoringUndoScope("Set Material"))
{
Undo.RecordObject(renderer, "Set Material"); // record BEFORE the change
renderer.sharedMaterial = mat;
EditorSceneManager.MarkSceneDirty(renderer.gameObject.scene);
}
return ObjectResolver.Describe(renderer);
}
private static Renderer ResolveRenderer(ObjectRef target)
{
if (!ObjectResolver.TryResolve(target, out var obj, out var error))
throw new ArgumentException(error);
var go = obj as GameObject ?? (obj as Component)?.gameObject;
var renderer = go != null ? go.GetComponent<Renderer>() : null;
if (renderer == null)
throw new ArgumentException($"Object '{target}' has no Renderer.");
return renderer;
}
// Mirrors the shared helper used by the built-in asset commands.
private static void EnsureParentFolder(string assetPath)
{
var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/');
if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent))
return;
// Create intermediate folders (see create_folder / CreateFolderRecursive).
Directory.CreateDirectory(ProjectPaths.ProjectRoot + "/" + parent);
AssetDatabase.Refresh();
}
}
}
```
An agent chains them by feeding the first result into the second:
```
create_material --path Materials/Stone --shader Standard
→ { "assetPath": "Assets/AgentWork/Materials/Stone.mat", "guid": "…", "type": "Material" }
set_material --target '{"hierarchyPath":"/Ground"}' --material '{"path":"Assets/AgentWork/Materials/Stone.mat"}'
→ { "instanceId": …, "hierarchyPath": "/Ground", "type": "MeshRenderer" }
```
## Checklist for a new authoring command
For *content-authoring* commands. Config/build/package commands follow the lighter
[management-command conventions](#authoring-vs-management-commands) instead.
- [ ] Editor-only, under `Editor/Commands/<Area>/`, `static` (any accessibility — `public`/`internal`/`private`), tagged `[CliCommand]`.
- [ ] Every path parameter resolved through `ProjectPaths.Resolve` (never concatenated).
- [ ] Existing-object inputs taken as `ObjectRef`, resolved via `ObjectResolver.TryResolve`; resolve **before** mutating.
- [ ] Scene/object mutations wrapped in an `AuthoringUndoScope` and registered with the matching `Undo` API.
- [ ] `AssetDatabase` writes noted as non-undoable in the description; validate before writing.
- [ ] Returns `AuthoringResult` (via `ObjectResolver.Describe`) or a model containing `AuthoringResult[]`.
- [ ] Reports failures by throwing; never build the response envelope yourself.
## Build & verify
New commands register automatically after the next recompile (see
[Creating commands → Discovery](creating-commands.md#discovery)). Drive the live editor to verify:
```
command recompile
command recompile_status # poll until done
command create_material --path Materials/Stone
```
## See also
- [Creating commands](creating-commands.md) — the base command API this page builds on.
- [Asset & file commands](commands/assets-and-files.md) — reference for the built-in asset commands.
- [GameObject & component commands](commands/gameobjects-and-components.md) — the scene-mutation commands.
@@ -0,0 +1,191 @@
# Animation commands
Author animation assets: AnimationClips (and their float curves), AnimatorControllers (parameters, layers, states, transitions), and Timeline assets. Create commands write under the authoring root and follow the shared `confirm`/`dry_run` convention.
## AnimationClips
### `create_animation_clip`
Create an empty .anim AnimationClip asset under the authoring root, with an optional frame rate and loop flag.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | `` | Asset path ending in .anim, relative to the authoring root. The Assets/ prefix is optional. |
| `frameRate` | no | `60` | Sampling frame rate of the clip. |
| `loop` | no | `false` | If true, set the clip's loop-time flag in its AnimationClipSettings. |
| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. |
| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. |
**Returns:** `AuthoringResult`
### `set_animation_curve`
Add or replace a single float curve binding on an AnimationClip (via AnimationUtility.SetEditorCurve). Replacing an existing binding overwrites it rather than duplicating.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `clip` | yes | `` | Reference to the AnimationClip to edit (path / guid / globalId). |
| `path` | no | `""` | GameObject path relative to the animated root the property lives on. Empty string targets the root. |
| `type` | yes | `` | Component type the property lives on, e.g. "Transform", "UnityEngine.Light". Resolved via the component TypeResolver. |
| `property` | yes | `` | Curve property name, e.g. "m_LocalPosition.x", "m_LocalScale.y", "localEulerAnglesRaw.z". |
| `keys` | yes | `` | Keyframes: `[{ time, value, inTangent?, outTangent?, weightedMode?: "None"\|"In"\|"Out"\|"Both" }]`. Omitted tangents default to 0 (flat); this is NOT Unity's Auto tangent mode. |
| `dry_run` | no | `false` | If true, validate type/property/keys without writing the curve. |
**Returns:** `SetAnimationCurveResult`
### `get_animation_clip`
Read an AnimationClip's metadata and all float curve bindings (optionally with keyframes).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `clip` | yes | `` | Reference to the AnimationClip to read (path / guid / globalId). |
| `includeKeys` | no | `false` | If true, include each binding's keyframes. |
**Returns:** `AnimationClipInfo`
### `remove_animation_curve`
Remove a float curve binding from an AnimationClip (SetEditorCurve(clip, binding, null)). Destructive: requires confirm=true.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `clip` | yes | `` | Reference to the AnimationClip to edit (path / guid / globalId). |
| `path` | no | `""` | GameObject path relative to the animated root the binding lives on. Empty string targets the root. |
| `type` | yes | `` | Component type of the binding to remove, e.g. "Transform". Resolved via the component TypeResolver. |
| `property` | yes | `` | Curve property name to remove, e.g. "m_LocalPosition.x". |
| `confirm` | no | `false` | Must be true to actually remove the binding (destructive guard). |
| `dry_run` | no | `false` | If true, report the binding that would be removed without removing it. |
**Returns:** `SetAnimationCurveResult`
## AnimatorControllers
### `create_animator_controller`
Create an .controller AnimatorController asset (with a default Base Layer) under the authoring root.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | `` | Asset path ending in .controller, relative to the authoring root. The Assets/ prefix is optional. |
| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. |
| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. |
**Returns:** `AuthoringResult`
### `add_animator_parameter`
Add a parameter (Float | Int | Bool | Trigger) to an AnimatorController. A duplicate name returns code 'duplicate_parameter'.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `controller` | yes | `` | Reference to the AnimatorController to edit (path / guid / globalId). |
| `name` | yes | `` | Parameter name. |
| `type` | yes | `` | Parameter type: Float \| Int \| Bool \| Trigger. |
| `defaultValue` | no | `` | Default value for Float/Int/Bool (ignored for Trigger). |
| `dry_run` | no | `false` | If true, validate inputs without writing the parameter. |
**Returns:** `object`
### `add_animator_layer`
Add a layer to an AnimatorController.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `controller` | yes | `` | Reference to the AnimatorController to edit (path / guid / globalId). |
| `name` | yes | `` | Layer name. |
| `weight` | no | `1` | Layer weight. |
| `blendingMode` | no | `Override` | Blending mode: Override \| Additive. |
| `dry_run` | no | `false` | If true, validate inputs without writing the layer. |
**Returns:** `object`
### `add_animator_state`
Add a state to a layer, optionally with a motion (AnimationClip or BlendTree) and as the layer default. A layer name with no match returns code 'layer_not_found'.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `controller` | yes | `` | Reference to the AnimatorController to edit (path / guid / globalId). |
| `layer` | no | `0` | Layer index (int) or name (string). Default 0 (Base Layer). |
| `name` | yes | `` | State name. |
| `motion` | no | `` | Optional AnimationClip or BlendTree asset to assign as the state's motion. |
| `isDefault` | no | `false` | If true, set this state as the layer's default state. |
| `position` | no | `` | Optional [x, y] node position in the graph (cosmetic). |
| `dry_run` | no | `false` | If true, validate inputs without writing the state. |
**Returns:** `object`
### `add_animator_transition`
Add a transition between two states (or from AnyState/Entry, to Exit) on a layer, with optional conditions. Validates that the states exist and each condition's parameter exists and its mode matches the parameter type.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `controller` | yes | `` | Reference to the AnimatorController to edit (path / guid / globalId). |
| `layer` | no | `0` | Layer index (int) or name (string). Default 0 (Base Layer). |
| `fromState` | yes | `` | Source state name, or the special "AnyState" / "Entry". |
| `toState` | yes | `` | Destination state name, or the special "Exit". |
| `conditions` | no | `` | Optional conditions: `[{ parameter, mode: "If"\|"IfNot"\|"Greater"\|"Less"\|"Equals"\|"NotEqual", threshold? }]`. |
| `hasExitTime` | no | `false` | If true, the transition uses exit time. |
| `exitTime` | no | `0` | Normalized exit time (0..1) when hasExitTime is set. |
| `duration` | no | `0.25` | Transition duration in seconds. |
| `hasFixedDuration` | no | `true` | If true, duration is in seconds; otherwise normalized. |
| `dry_run` | no | `false` | If true, validate everything (states, parameters, mode/type) without writing the transition. |
**Returns:** `object`
### `get_animator_controller`
Read an AnimatorController's full structure: parameters, layers, states (with motion / default), and transitions (with conditions).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `controller` | yes | `` | Reference to the AnimatorController to read (path / guid / globalId). |
**Returns:** `AnimatorControllerInfo`
## Timeline
The Timeline commands require the `com.unity.timeline` package.
### `create_timeline`
Create a .playable TimelineAsset under the authoring root (optional frame rate).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | `` | Asset path ending in .playable, relative to the authoring root. The Assets/ prefix is optional. |
| `frameRate` | no | `60` | Timeline frame rate. |
| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. |
| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. |
**Returns:** `object`
### `add_timeline_track`
Add a track (Animation | Audio | Activation | Control | Playable | Signal | Marker) to a TimelineAsset, optionally nested under a parent group/track.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `timeline` | yes | `` | Reference to the TimelineAsset to edit (path / guid / globalId). |
| `trackType` | yes | `` | Track type: Animation \| Audio \| Activation \| Control \| Playable \| Signal \| Marker. |
| `name` | no | `` | Optional track display name. |
| `parentTrack` | no | `` | Optional name of an existing group/track to nest the new track under. |
| `dry_run` | no | `false` | If true, validate inputs without writing the track. |
**Returns:** `object`
### `add_timeline_clip`
Add a clip to a named track on a TimelineAsset. For Animation tracks pass an AnimationClip asset; for Audio tracks an AudioClip.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `timeline` | yes | `` | Reference to the TimelineAsset to edit (path / guid / globalId). |
| `track` | yes | `` | Target track name. |
| `start` | yes | `` | Clip start time in seconds. |
| `duration` | yes | `` | Clip duration in seconds. |
| `asset` | no | `` | Source asset: for Animation tracks an AnimationClip; for Audio tracks an AudioClip. Required for those track types. |
| `dry_run` | no | `false` | If true, validate inputs without writing the clip. |
**Returns:** `object`
### `get_timeline`
Read a TimelineAsset's structure: frame rate, duration, and its tracks with their clips.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `timeline` | yes | `` | Reference to the TimelineAsset to read (path / guid / globalId). |
**Returns:** `object`
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,150 @@
# Asset & file commands
Commands for creating, importing, moving, copying, renaming, deleting and finding project assets, plus folder and text-file operations. Every agent-supplied path is funnelled through the authoring-root sandbox (it rejects `../` and out-of-project writes); destructive or overwriting operations require `confirm=true` and support `dry_run`. AssetDatabase create/move/copy/rename/delete are not part of Unity's Undo system.
### `create_asset`
Create a new ScriptableObject (or other UnityEngine.Object) asset of the given type at a path under the authoring root.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Asset path relative to the authoring root, including extension (e.g. Data/Config.asset or Materials/Wall.mat). The Assets/ prefix is optional. |
| `type` | yes | | Fully-qualified or short type name to instantiate (e.g. UnityEngine.Material, MyGame.GameConfig). Must derive from UnityEngine.Object and be creatable. |
| `shader` | no | `` | Material-only (ignored otherwise): shader name to assign (e.g. Standard, "Universal Render Pipeline/Lit"). When omitted, defaults to "Universal Render Pipeline/Lit" if a Scriptable Render Pipeline is active, otherwise the built-in "Standard" shader (falling back to "Standard" if URP/Lit is unavailable). |
| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. Ignored when the path is empty. |
| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. |
**Returns:** `AuthoringResult`
**Notes:** `confirm=true` required to overwrite an existing asset; supports `dry_run`.
### `import_asset`
Import an external file (e.g. a texture, model, audio clip) into the project by copying it to a path under the authoring root, then importing it.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `source` | yes | | Absolute filesystem path to the external file to import. |
| `path` | yes | | Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional. |
| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the destination path. |
| `dry_run` | no | `false` | If true, validate inputs and report what would be imported without writing anything. |
**Returns:** `AuthoringResult`
**Notes:** `confirm=true` required to overwrite an existing asset; supports `dry_run`.
### `move_asset`
Move (or rename via a new path) an asset to a new location under the authoring root. Preserves the asset's GUID.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `asset` | yes | | Reference to the asset to move (path / guid / globalId). |
| `destination` | yes | | Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional. |
| `dry_run` | no | `false` | If true, validate the move (via AssetDatabase.ValidateMoveAsset) without performing it. |
**Returns:** `AuthoringResult`
**Notes:** Supports `dry_run`.
### `copy_asset`
Copy an asset to a new path under the authoring root. The copy gets a fresh GUID.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `asset` | yes | | Reference to the asset to copy (path / guid / globalId). |
| `destination` | yes | | Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional. |
| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the destination path. |
| `dry_run` | no | `false` | If true, validate inputs and report what would be copied without writing anything. |
**Returns:** `AuthoringResult`
**Notes:** `confirm=true` required to overwrite an existing asset; supports `dry_run`.
### `rename_asset`
Rename an asset in place (keeps it in the same folder, keeps its GUID).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `asset` | yes | | Reference to the asset to rename (path / guid / globalId). |
| `new_name` | yes | | New file name WITHOUT a folder path. The extension is preserved if omitted. |
| `dry_run` | no | `false` | If true, validate the rename without performing it. |
**Returns:** `AuthoringResult`
**Notes:** Supports `dry_run`.
### `delete_asset`
Delete an asset from the project. Destructive: requires confirm=true.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `asset` | yes | | Reference to the asset to delete (path / guid / globalId). |
| `confirm` | no | `false` | Must be true to actually delete. Without it the command refuses (destructive guard). |
| `dry_run` | no | `false` | If true, report the asset that would be deleted without deleting it. |
**Returns:** `AuthoringResult`
**Notes:** Destructive — `confirm=true` required; supports `dry_run`. Not undoable via Unity's Undo.
### `find_assets`
Find assets by type and/or name and/or label, returning their path, GUID and type. At least one filter is required.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `type` | no | `` | Type name to filter by (e.g. Material, GameObject, ScriptableObject, MyGame.GameConfig). Resolved to a System.Type and matched against each asset's actual main type. |
| `name` | no | `` | Name substring to filter by (AssetDatabase name filter). |
| `label` | no | `` | Asset label to filter by (AssetDatabase 'l:' filter). |
| `search_in` | no | `` | Folder to scope the search to, relative to the authoring root (default: the authoring root). |
| `limit` | no | `200` | Maximum number of results to return (default 200). |
**Returns:** `FindAssetsResult`
**Notes:** At least one of `type`, `name`, or `label` is required.
### `set_import_settings`
Set import settings on an asset's AssetImporter (e.g. a texture's isReadable) and re-import it.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `asset` | yes | | Reference to the asset whose importer to edit (path / guid / globalId). |
| `settings` | yes | | JSON object of importer property/field names to values, e.g. {"isReadable": true, "textureType": "NormalMap"}. |
| `dry_run` | no | `false` | If true, validate which settings would apply (and which are unknown) without writing or re-importing. |
**Returns:** `SetImportSettingsResult`
**Notes:** Supports `dry_run`. Import settings live in the asset's .meta file and are not part of Unity's Undo system.
### `get_import_settings`
Read an asset's import settings, structured by importer type (texture/model/audio), including the default-platform fields and (for textures/audio) one platform override block.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `asset` | yes | | Reference to the asset whose importer to read (path / guid / globalId). |
| `platform` | no | `Default` | Platform whose override to read: Default \| Standalone \| iOS \| Android \| WebGL \| tvOS. |
**Returns:** `GetImportSettingsResult`
### `create_folder`
Create a folder under the authoring root (creates intermediate folders).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Folder path relative to the authoring root (default Assets/); the Assets/ prefix is optional. e.g. Gameplay/Enemies or Assets/Gameplay/Enemies |
**Returns:** `AuthoringResult`
### `read_text_file`
Read a UTF-8 text file under the authoring root and return its contents.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Text file path relative to the authoring root. The Assets/ prefix is optional. |
| `max_bytes` | no | `1048576` | Reject files larger than this many bytes (default 1048576 = 1 MiB) to avoid huge payloads. |
**Returns:** `ReadTextFileResult`
**Notes:** `MainThreadRequired = true`.
### `write_text_file`
Write UTF-8 text to a file under the authoring root, then import it. Overwriting an existing file requires confirm=true.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Text file path relative to the authoring root, including extension. The Assets/ prefix is optional. |
| `contents` | yes | | The full text content to write (replaces the file). |
| `confirm` | no | `false` | Required (true) only when overwriting an existing file at the path. |
| `dry_run` | no | `false` | If true, validate inputs and report what would be written without writing anything. |
**Returns:** `AuthoringResult`
**Notes:** `confirm=true` required to overwrite an existing file; supports `dry_run`. Filesystem writes are not part of Unity's Undo system.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,140 @@
# Baking commands
Bake and clear precomputed scene data: lightmaps, NavMesh, and occlusion culling. Each `bake_*` runs asynchronously (returns immediately) — poll the matching `*_bake_status` until `completed`. The `clear_*` commands are destructive and require `confirm=true`. The `get_*_settings` / `set_*_settings` pairs read and tune the bake parameters.
## Lighting
### `bake_lighting`
Trigger an async lightmap bake of the open scene(s) via Lightmapping.BakeAsync(). Returns immediately; poll `lighting_bake_status` until completed.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `confirm` | no | `false` | Recommended (true): a bake overwrites existing lightmap data. Accepted for parity; not required. |
| `dry_run` | no | `false` | If true, validate there is an open bakeable scene and return the current lighting settings without baking. |
**Returns:** `object`
### `lighting_bake_status`
Get the status of the last lighting bake: idle | baking | completed.
**Returns:** `string`
### `cancel_lighting_bake`
Cancel an in-progress lighting bake (Lightmapping.Cancel()).
**Returns:** `object`
### `clear_baked_lighting`
Clear baked lightmap data for the open scene(s). Destructive: requires confirm=true.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `confirm` | no | `false` | Must be true to actually clear (destructive, not undoable via Unity's Undo). |
| `include_disk_cache` | no | `false` | If true, also clear the GI disk cache (Lightmapping.ClearDiskCache()). |
| `dry_run` | no | `false` | If true, report what would be cleared without clearing. |
**Returns:** `object`
### `get_lighting_settings`
Read the active LightingSettings (lightmapper, bounces, resolution, directional mode, AO, etc.).
**Returns:** `LightingSettingsResult`
### `set_lighting_settings`
Apply a subset of lighting settings to the active LightingSettings. Returns `{ applied[], unknown[] }`.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | yes | `` | JSON object with a subset of lighting fields to set (same names/enums as get_lighting_settings). |
| `dry_run` | no | `false` | If true, validate the keys and report applied/unknown without changing anything. |
**Returns:** `object`
## NavMesh
### `bake_navmesh`
Trigger an async legacy NavMesh bake of the open scene(s) via UnityEditor.AI.NavMeshBuilder. Returns immediately; poll `navmesh_bake_status` until completed.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `confirm` | no | `false` | Accepted for parity (a bake overwrites the existing NavMesh); not required. |
| `dry_run` | no | `false` | If true, validate there is an open scene and return current NavMesh settings without baking. |
**Returns:** `object`
### `navmesh_bake_status`
Get the status of the last NavMesh bake: idle | baking | completed.
**Returns:** `string`
### `cancel_navmesh_bake`
Cancel an in-progress NavMesh bake (NavMeshBuilder.Cancel()).
**Returns:** `object`
### `clear_navmesh`
Clear the baked NavMesh for the open scene(s). Destructive: requires confirm=true.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `confirm` | no | `false` | Must be true to actually clear (destructive, not undoable via Unity's Undo). |
| `dry_run` | no | `false` | If true, report what would be cleared without clearing. |
**Returns:** `object`
### `get_navmesh_settings`
Read the default agent's legacy NavMesh bake settings (agentRadius/Height/Slope/Climb, minRegionArea, voxelSize).
**Returns:** `NavMeshSettingsResult`
### `set_navmesh_settings`
Apply a subset of legacy NavMesh bake settings to the default agent. Returns `{ applied[], unknown[] }`.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | yes | `` | JSON object with a subset of NavMesh fields to set (same names as get_navmesh_settings). |
| `dry_run` | no | `false` | If true, validate the keys and report applied/unknown without changing anything. |
**Returns:** `object`
### `bake_navmesh_surfaces`
Bake NavMeshSurface components (AI Navigation package). v1 stub: returns package_not_found when the package is absent.
**Returns:** `object`
## Occlusion culling
### `bake_occlusion_culling`
Trigger an async occlusion-culling bake of the open scene(s) via StaticOcclusionCulling.GenerateInBackground(). Returns immediately; poll `occlusion_bake_status` until completed.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `smallest_occluder` | no | `` | Smallest object that will occlude others (meters). Defaults to Unity's current value. |
| `smallest_hole` | no | `` | Smallest gap geometry can have that the view can see through (meters). Defaults to Unity's current value. |
| `backface_threshold` | no | `` | Backface threshold (1-100); lower trims more backfaces. Defaults to Unity's current value. |
| `confirm` | no | `false` | Accepted for parity (a bake overwrites existing occlusion data); not required. |
| `dry_run` | no | `false` | If true, validate there is an open scene and report the parameters that would be used without baking. |
**Returns:** `object`
### `occlusion_bake_status`
Get the status of the last occlusion bake: idle | baking | completed.
**Returns:** `string`
### `cancel_occlusion_bake`
Cancel an in-progress occlusion bake (StaticOcclusionCulling.Cancel()).
**Returns:** `object`
### `clear_occlusion_culling`
Clear baked occlusion-culling data for the open scene(s). Destructive: requires confirm=true.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `confirm` | no | `false` | Must be true to actually clear (destructive, not undoable via Unity's Undo). |
| `dry_run` | no | `false` | If true, report what would be cleared without clearing. |
**Returns:** `object`
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,188 @@
# Build, compilation & test commands
These commands drive the build/compile/test dev loop, plus build configuration: triggering Player builds and reading the resulting BuildReport, switching the active build target, enumerating targets, reading/writing EditorUserBuildSettings, and listing Build Profiles. Several commands are asynchronous: trigger the operation, then poll a matching `*_status` command until it reports completion. The client must tolerate connection errors during a domain reload (recompile, target switch) or a long blocking build.
### `build`
Trigger an async Player build and report the full BuildReport. Returns immediately (queued); poll build_status until status is 'completed'. DetailedBuildReport is included by default unless 'options' is supplied. Use dry_run to validate without building.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | no | `` | BuildTarget name (e.g. StandaloneWindows64). Defaults to the active target. Must be installed. |
| `outputPath` | no | `` | Output path (absolute, or relative to the project root). Defaults to the last/auto path. |
| `profileName` | no | `` | Build Profile name to activate before building (Unity 6 only; ignored otherwise). |
| `options` | no | `` | BuildOptions names. Omit to get just DetailedBuildReport; supplying any disables that default. |
| `scenes` | no | `` | Scene asset paths to build (e.g. Assets/Scenes/Main.unity). Defaults to EditorBuildSettings. |
| `confirm` | no | `false` | Acknowledge and run the build; without it the call is refused. Use `dry_run` to validate only. |
| `dry_run` | no | `false` | Validate target/outputPath/scenes without building. |
Supported `options` values (case-insensitive): `Development`, `AllowDebugging`, `ConnectWithProfiler`, `EnableHeadlessMode`, `SymlinkSources`, `BuildAdditionalStreamedScenes`, `CleanBuildCache`, `DetailedBuildReport`. Any unrecognized value is a validation error.
**Returns:** `object` (transient payloads: `queued` / `busy` / `dry_run` / `error`; the finished report is read via `build_status`).
**Notes:** `MainThreadRequired = false`. Async — validates + queues, returns `queued` immediately, then an editor tick runs the (blocking) build; poll `build_status` until status is `completed`. Only one build at a time (returns `busy` otherwise). Mutating: gated by the `confirm`/`dry_run` convention — pass `confirm=true` for a real build, or `dry_run=true` to validate target/outputPath/scenes without building (nothing is queued on a dry run or on validation failure).
### `build_status`
Status of the current/most recent build: idle | queued | building | completed, with the full BuildReport (files, packedAssets, buildSteps, errors, warnings) once completed. Retained until the next build.
No parameters.
**Returns:** `string` (JSON). `idle` when no build has run; `queued`/`building` (the latter with live `elapsedMs`) while in progress; a full `BuildReportResult` once `completed`.
`BuildReportResult` fields (returned when `status` is `completed`):
| Field | Description |
|-------|-------------|
| `status` | Always `completed` here. |
| `buildId` | Id returned by the triggering `build` call. |
| `result` | `Succeeded` \| `Failed` \| `Cancelled` \| `Unknown`. |
| `platform` | Build target the report is for. |
| `outputPath` | Final output location. |
| `totalSizeBytes` | Total build size in bytes. |
| `buildTimeMs` | Total build duration in milliseconds. |
| `buildStartedAt` / `buildEndedAt` | ISO-8601 timestamps (omitted when unset). |
| `totalWarnings` / `totalErrors` | Aggregate counts from the report summary. |
| `files` | Output files (path, role, sizeBytes). Present only on success. |
| `packedAssets` | Packed bundles with per-asset breakdown. Present only on success and requires DetailedBuildReport. |
| `buildSteps` | Per-step name, durationMs, depth, and messages. |
| `errors` / `warnings` | Build issues, each with `message` and best-effort `file`. |
**Notes:** `MainThreadRequired = false`. Reads a Temp status file off-thread, so polling keeps working while a build holds the main thread. The file also survives the domain reload a build can incur, so the last report is retained until the next build.
### `switch_build_target`
Switch the active build target (destructive, long-running: triggers a full reimport + domain reload). Requires confirm=true. Returns immediately; poll switch_build_target_status.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | `` | BuildTarget name to switch to (must be installed; see list_build_targets). |
| `confirm` | no | `false` | Apply the switch. Without it the call is refused. |
**Returns:** `object` (`switching` / `busy` / `completed` / `error`). Returns `completed` immediately if already on the requested target.
**Notes:** `MainThreadRequired = false`. Async — validates + queues, returns `switching` immediately, then an editor tick performs the (blocking) switch; poll `switch_build_target_status` until `completed`. Only one switch at a time (returns `busy` otherwise). Mutating and confirm-gated: without `confirm=true` the call is refused. The status file survives the domain reload the switch causes, and is reconciled against the active target on the next load.
### `switch_build_target_status`
Status of the last target switch: idle | switching | completed (with success + activeBuildTarget).
No parameters.
**Returns:** `string` (JSON). `idle`, `switching`, or `completed` (with `success` and `activeBuildTarget`, or `errors` on failure).
**Notes:** `MainThreadRequired = false`. Reads a Temp status file off-thread, so it keeps answering while the switch holds the main thread.
### `list_build_targets`
List the known BuildTarget values with their group and whether build support is installed.
No parameters.
**Returns:** `object` (list of `BuildTargetInfo`: `name`, `displayName`, `targetGroup`, `isInstalled`), sorted by group then name. Obsolete and sentinel targets are excluded.
**Notes:** `MainThreadRequired = true`.
### `get_build_settings`
Read the current build configuration from EditorUserBuildSettings / EditorBuildSettings.
No parameters.
**Returns:** `object` (`BuildSettingsResult`).
`BuildSettingsResult` fields:
| Field | Description |
|-------|-------------|
| `activeBuildTarget` | Active BuildTarget name. |
| `activeBuildTargetGroup` | Active BuildTargetGroup name. |
| `developmentBuild` | Whether a Development Player is configured. |
| `allowDebugging` | Whether script debugging is allowed. |
| `connectWithProfiler` | Whether the Profiler auto-connects. |
| `buildScriptsOnly` | Whether only scripts are built (skip data). |
| `symlinkSources` | Whether runtime/plugin sources are symlinked. |
| `il2CppCodeGeneration` | `OptimizeSpeed` \| `OptimizeSize` for the active target. |
| `scenes` | Build Settings scene list (each: `path`, `guid`, `enabled`). |
**Notes:** `MainThreadRequired = true`.
### `set_build_settings`
Set mutable EditorUserBuildSettings fields. Does NOT manage scenes (use add_scene_to_build / remove_scene_from_build) or switch target (use switch_build_target). Use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Fields to change; omitted fields are left unchanged. |
| `confirm` | no | `false` | Apply the changes. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields (a structured input DTO; every field is optional — only supplied fields change):
| Field | Description |
|-------|-------------|
| `developmentBuild` | Build a Development Player (enables the debugger/profiler). |
| `allowDebugging` | Allow script debugging (only effective with developmentBuild=true). |
| `connectWithProfiler` | Auto-connect the Profiler (only effective with developmentBuild=true). |
| `buildScriptsOnly` | Build only the scripts (skip data) for faster iteration. |
| `symlinkSources` | Symlink runtime/plugin sources instead of copying (where supported). |
| `il2CppCodeGeneration` | IL2CPP code generation for the active target: OptimizeSpeed \| OptimizeSize. |
**Returns:** `object` (`SetBuildSettingsResult`: `success`, `dryRun`, `applied` map of fields that changed, `skipped` map of supplied fields that already matched, `message`).
**Notes:** `MainThreadRequired = true`. Mutating: refused unless `confirm=true` (or `dry_run=true` to preview). Fields already at the requested value are reported under `skipped` rather than re-applied. Fails if no `settings` object is provided.
### `list_build_profiles`
List Build Profile assets in the project (Unity 6 only). Returns feature_unavailable on earlier versions.
No parameters.
**Returns:** `object` (list of `BuildProfileInfo`: `name`, `guid`, `platform`, `isActive`), or `{ error, code = "feature_unavailable" }` on editors older than Unity 6.
**Notes:** `MainThreadRequired = true`.
### `recompile`
Force a script recompile (works while unfocused/minimized). Poll recompile_status for completion.
No parameters.
**Returns:** `object`
**Notes:** `MainThreadRequired = true`. Async — poll `recompile_status` until status is `completed` or `up_to_date`. A successful compile triggers a domain reload, so the triggering request cannot stay open.
### `recompile_status`
Get the status of the last recompile: idle | triggered | compiling | completed | up_to_date.
No parameters.
**Returns:** `string`
**Notes:** `MainThreadRequired = false`.
### `list_tests`
List all available tests (EditMode and/or PlayMode) without running them.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `mode` | no | `all` | Test mode: all, editor, playmode (default: all) |
**Returns:** `TestListResponse`
**Notes:** `MainThreadRequired = true`.
### `run_tests`
Execute Unity tests with filtering options.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `mode` | no | `all` | Test mode: all, editor, playmode (default: all) |
| `filter` | no | `` | Test name filter pattern (case-insensitive partial match) |
| `filter_type` | no | `testName` | Filter type: testName, assembly, category (default: testName) |
| `include_explicit` | no | `false` | Include tests marked with [Explicit] attribute |
| `async_tests` | no | `false` | Run asynchronously - return immediately, poll /test-status for results |
| `timeout` | no | `300` | Test execution timeout in seconds (default: 300) |
**Returns:** `TestExecutionResponse`
**Notes:** `MainThreadRequired = true`. Synchronous by default; with `async_tests=true` it returns immediately — poll `test_status` for results.
### `test_status`
Get status of running async test execution.
No parameters.
**Returns:** `string`
**Notes:** `MainThreadRequired = false`.
### `cancel_tests`
Cancel running test execution.
No parameters.
**Returns:** `object`
**Notes:** `MainThreadRequired = true`.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,58 @@
# Capture commands
Commands that render a camera, the Scene View, or a UI Toolkit element to a PNG and return it base64-encoded so an agent can "see" the editor (or a running player) without a display.
### `capture_game_view`
Render a camera to a PNG. Returns it inline as base64, unless `save_path` is set — then the result is **path-only** (no base64) so agent tool results stay small; pass `include_inline_image=true` to get both.
Parameter interactions: `include_inline_image` is only meaningful together with `save_path` (without one, the inline image is always returned). `max_resolution` only applies when an inline image is actually returned — i.e. no `save_path`, or `save_path` + `include_inline_image=true`; it has **no effect** when `save_path` is set without `include_inline_image=true`.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `width` | no | `1280` | Output width in px (default 1280; capped 4096). |
| `height` | no | `720` | Output height in px (default 720; capped 4096). |
| `camera` | no | `` | Optional camera name; defaults to Camera.main, else the first enabled camera. |
| `save_path` | no | `` | Optional project-relative path to write the PNG (e.g. Screenshots/foo.png). When set, the result omits the inline base64 image unless `include_inline_image=true`. |
| `include_inline_image` | no | `false` | Also return the image inline as base64 when `save_path` is set. |
| `max_resolution` | no | `0` | Cap on the inline image's longest edge (e.g. 512), preserving aspect ratio. No effect when `save_path` is set without `include_inline_image=true`. The `save_path` file keeps the requested resolution; a downscaled inline copy is reported via `inlineWidth`/`inlineHeight`. |
**Returns:** `CaptureResult`
### `capture_scene_view`
Render the active Scene View to a PNG. Same result contract and parameter interactions as `capture_game_view`: inline base64, or path-only when `save_path` is set (opt back in with `include_inline_image=true`; `max_resolution` has no effect when `save_path` is set without it).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `width` | no | `1280` | Output width in px (default 1280; capped 4096). |
| `height` | no | `720` | Output height in px (default 720; capped 4096). |
| `save_path` | no | `` | Optional project-relative path to write the PNG (e.g. Screenshots/foo.png). When set, the result omits the inline base64 image unless `include_inline_image=true`. |
| `include_inline_image` | no | `false` | Also return the image inline as base64 when `save_path` is set. |
| `max_resolution` | no | `0` | Cap on the inline image's longest edge (e.g. 512), preserving aspect ratio. No effect when `save_path` is set without `include_inline_image=true`. The `save_path` file keeps the requested resolution; a downscaled inline copy is reported via `inlineWidth`/`inlineHeight`. |
**Returns:** `CaptureResult`
### `capture_editor_element`
Capture a UI Toolkit VisualElement (by selector) from an EditorWindow to a PNG; returns path + base64.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `window` | yes | `` | EditorWindow type name (e.g. InspectorWindow) or window title to capture from. |
| `selector` | yes | `` | Element selector: '#name', '.class', a type name (e.g. Button), descendant (space) / child ('>') chains, optional pseudo-states (:checked,:hover,:focus,:active,:enabled,:disabled,:not(...)). |
| `output` | no | `` | Output PNG path (absolute, or relative to the project root). Defaults to a timestamped file under <project>/Temp/pipeline-screenshots/. |
**Returns:** `CaptureElementResponse`
**Notes:** `MainThreadRequired = true`. Unity 6000.7+ only.
### `capture_runtime_element`
Capture a UI Toolkit VisualElement (by selector) from a live runtime panel (UIDocument or PanelRenderer) to a PNG; returns path + base64.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `panel` | no | `` | Name of the target panel: matches the PanelSettings asset name or the host GameObject name (UIDocument or PanelRenderer). Optional when exactly one panel exists. |
| `selector` | yes | `` | Element selector: '#name', '.class', a type name (e.g. Button), descendant (space) / child ('>') chains, optional pseudo-states (:checked,:hover,:focus,:active,:enabled,:disabled,:not(...)). |
| `output` | no | `` | Output PNG path (absolute, or relative to Application.persistentDataPath). Defaults to a timestamped file under Application.persistentDataPath. |
**Returns:** `CaptureElementResponse`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. Unity 6000.7+ only.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,115 @@
# Editor lifecycle & observability commands
Commands to control Editor play mode, focus, and menus, and to observe the Editor's state, console, and performance.
### `editor_play`
Enter Unity Editor play mode.
No parameters.
**Returns:** `string`
### `editor_stop`
Exit Unity Editor play mode.
No parameters.
**Returns:** `string`
### `editor_pause`
Pause Unity Editor play mode.
No parameters.
**Returns:** `string`
### `editor_status`
Get detailed Unity Editor status and state information.
No parameters.
**Returns:** `StatusResponse`
### `editor_focus`
Bring the Unity Editor window to the foreground.
No parameters.
**Returns:** `string`
**Notes:** `MainThreadRequired = true`.
### `menu`
Execute an Editor menu item by path, or list available items when no path is given.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | no | `` | Menu item path to execute, e.g. "Assets/Reimport All". Omit to list available menu items. |
**Returns:** `MenuResponse`
**Notes:** `MainThreadRequired = true`.
### `screenshot`
Capture the Scene or Game view as a PNG and return its file path.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `view` | no | `game` | Which view to capture: 'game' (default) or 'scene' |
| `output` | no | `` | Output PNG path (absolute, or relative to the project root). Defaults to a timestamped file under <project>/Temp/pipeline-screenshots/. |
| `width` | no | `0` | Output width in pixels. 0 (default) uses the view camera's current width. |
| `height` | no | `0` | Output height in pixels. 0 (default) uses the view camera's current height. |
**Returns:** `ScreenshotResponse`
**Notes:** `MainThreadRequired = true`.
### `set_autotick`
Keep the editor ticking while unfocused by forcing EditorApplication.SignalTick at a throttled rate.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `enable` | no | `true` | Enable (true) or disable (false) auto-tick mode |
| `interval_ms` | no | `16` | Minimum milliseconds between forced ticks. 0 = every update (max rate, pegs a CPU core). Default 16 (~60Hz). |
**Returns:** `string`
**Notes:** `MainThreadRequired = true`. State is static and resets on domain reload (turns itself off after a recompile).
### `get_console_logs`
Read recently captured Editor console logs (structured).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `severity` | no | `all` | Filter: all | log | warning | error. 'all' = every entry; 'log' = Log only; 'warning' = Warning only; 'error' = Error/Exception/Assert only. |
| `limit` | no | `100` | Max entries to return (most-recent first), capped at 1000. |
**Returns:** `object`
### `clear_console`
Clear the captured log buffer and the Unity Editor console.
No parameters.
**Returns:** `object`
### `get_performance_stats`
Read render, memory, and frame-timing stats (structured, read-only).
No parameters.
**Returns:** `PerformanceStats`
### `get_authoring_root`
Get the base folder (under Assets/) that bare authoring paths resolve against.
No parameters.
**Returns:** `object`
### `set_authoring_root`
Set the base folder (under Assets/) that bare authoring paths resolve against and are confined to. Use 'Assets' for full project access.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `root` | yes | `` | Project-relative folder under Assets/, e.g. Assets/AgentWork. Use 'Assets' to allow the whole project. |
**Returns:** `object`
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,169 @@
# GameObject & component commands
Commands for creating GameObjects, querying the scene hierarchy, mutating the core GameObject/Transform surface, and adding/removing components and editing their serialized properties. Scene mutations are wrapped in Unity's Undo system (so a multi-step action reverts as one collapsible step) and are blocked during Play mode. Objects are referenced by an `ObjectRef` handle (globalId/path/guid/instanceId/hierarchyPath), and results come back as `AuthoringResult` identities you can chain into a follow-up call.
### `create_gameobject`
Create an empty GameObject or a built-in primitive (cube/sphere/capsule/cylinder/plane/quad) in the active scene.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `name` | no | `` | Name for the new GameObject. Defaults to 'GameObject' (or the primitive name). |
| `primitive` | no | `` | Optional primitive type: cube, sphere, capsule, cylinder, plane, quad. Omit for an empty GameObject. |
| `parent` | no | `` | Optional parent handle (globalId/path/guid/instanceId/hierarchyPath). The new object becomes a child of it. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `create_gameobjects`
Batch-create N empty GameObjects or primitives in one call. Optional positions/rotations/scales are arrays of [x,y,z] (length must equal count). Returns the created identities.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `name` | no | `` | Base name. With count>1 and no explicit names, objects are suffixed Name1..NameN. |
| `primitive` | no | `` | Optional primitive type: cube, sphere, capsule, cylinder, plane, quad. Omit for empty GameObjects. |
| `parent` | no | `` | Optional parent handle. Every created object becomes a child of it. |
| `count` | no | `1` | How many GameObjects to create. Default 1. |
| `positions` | no | `` | Local positions, one [x,y,z] per object. Length must equal count when supplied. |
| `rotations` | no | `` | Local Euler rotations (degrees), one [x,y,z] per object. Length must equal count when supplied. |
| `scales` | no | `` | Local scales, one [x,y,z] per object. Length must equal count when supplied. |
**Returns:** `CreateGameObjectsResult`
**Notes:** Undo-able (the whole batch reverts as one step); blocked during Play mode.
### `find_gameobjects`
Find GameObjects in loaded scenes by name, tag, component type, and/or hierarchy path (filters are combined). Returns structured identities.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `name` | no | `` | Exact name to match. |
| `tag` | no | `` | Tag to match (e.g. 'Player'). |
| `type` | no | `` | Component type name to match (e.g. 'Rigidbody', 'UnityEngine.Camera'). |
| `hierarchy_path` | no | `` | Exact hierarchy path to match (e.g. '/Root/Child'). |
| `include_inactive` | no | `true` | Include inactive GameObjects. Default true. |
**Returns:** `FindGameObjectsResult`
### `set_transform`
Set a GameObject's local position/rotation(euler)/scale. Omitted channels are left unchanged.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject to modify. |
| `position` | no | `` | Local position as [x,y,z]. |
| `rotation` | no | `` | Local rotation as Euler angles [x,y,z] in degrees. |
| `scale` | no | `` | Local scale as [x,y,z]. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `set_parent`
Reparent a GameObject under a new parent, or detach it to scene root when no parent is given.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject to reparent. |
| `parent` | no | `` | Handle of the new parent. Omit (or empty) to move the object to the scene root. |
| `world_position_stays` | no | `true` | Keep the object's world position when reparenting. Default true. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `set_active`
Set a GameObject's active self-state (activeSelf).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject. |
| `active` | yes | | Desired active state. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `set_tag`
Set a GameObject's tag (the tag must already exist in the project).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject. |
| `tag` | yes | | Tag to assign (must exist in the Tag Manager). |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `set_layer`
Set a GameObject's layer by name or numeric index (0-31).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject. |
| `layer` | yes | | Layer name (e.g. 'UI') or numeric index 0-31. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `rename_gameobject`
Rename a GameObject.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject. |
| `name` | yes | | New name. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `delete_gameobject`
Delete a GameObject from the scene (reversible via Undo).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject to delete. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode. The result describes the object's identity captured before destruction.
### `add_component`
Add a component (by type name) to a GameObject.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the GameObject. |
| `type` | yes | | Component type name (e.g. 'Rigidbody' or 'UnityEngine.Camera'). |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `remove_component`
Remove a component from a GameObject. Provide either a component handle (target) or a GameObject handle (target) plus a type name.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the component to remove, OR of the GameObject when 'type' is given. |
| `type` | no | `` | Component type name to remove from the target GameObject (omit when 'target' already points at a component). |
**Returns:** `AuthoringResult`
**Notes:** Undo-able; blocked during Play mode.
### `get_component_properties`
Get a component's serialized properties as a JSON map. Address the component by handle, or by GameObject handle + type.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the component, OR of the GameObject when 'type' is given. |
| `type` | no | `` | Component type name on the target GameObject (omit when 'target' is a component handle). |
**Returns:** `ComponentPropertiesResult`
### `set_component_properties`
Set serialized properties on a component (one Undo step). 'properties' maps property name -> value; object references accept an ObjectRef handle.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Handle of the component, OR of the GameObject when 'type' is given. |
| `properties` | yes | | Map of serialized property name to value. Vectors/colors are arrays; object refs are handle objects. |
| `type` | no | `` | Component type name on the target GameObject (omit when 'target' is a component handle). |
**Returns:** `ComponentPropertiesResult`
**Notes:** Undo-able (one Undo step); blocked during Play mode. An unknown property name fails the whole batch (no partial apply).
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,55 @@
# Material & shader commands
Read and edit material shader properties, and discover/introspect shaders so an agent can pick a valid shader name and property set.
## Materials
### `get_material_properties`
Read a material's shader, render queue, enabled keywords, and all shader properties with their current values (Color as [r,g,b,a], Vector as [x,y,z,w], Texture as an object reference).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `material` | yes | `` | Reference to the .mat asset (or a loaded material) to read (path / guid / globalId / instanceId). |
**Returns:** `MaterialPropertiesResult`
### `set_material_properties`
Set shader properties on a material (Float/Range/Int=number; Color=[r,g,b,a] or "#RRGGBBAA" hex; Vector=[x,y,z,w]; Texture=an object reference or null to clear), optionally reassign the shader, set the render queue, and toggle keywords. Unknown names / type mismatches are reported in `unknown[]`.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `material` | yes | `` | Reference to the .mat asset (or a loaded material) to edit (path / guid / globalId / instanceId). |
| `shader` | no | `` | Reassign the material's shader by name (e.g. "Standard", "Universal Render Pipeline/Lit", or a Shader Graph shader name). Applied before properties so new property names resolve against the new shader. |
| `properties` | no | `` | JSON object of shader property name -> value. Names must include the leading underscore (e.g. _BaseColor). Float/Range/Int=number; Color=[r,g,b,a] or hex string; Vector=[x,y,z,w]; Texture=an object reference {guid/path} or null. |
| `renderQueue` | no | `` | Explicit render queue, or -1 to inherit from the shader. Omit to leave unchanged. |
| `enableKeywords` | no | `` | Shader keywords to enable (e.g. _NORMALMAP, _EMISSION). |
| `disableKeywords` | no | `` | Shader keywords to disable. |
| `confirm` | no | `false` | Reserved for parity; editing an existing material is non-destructive and undoable, so it is not required. |
| `dry_run` | no | `false` | If true, validate the shader, resolve property names and texture refs, and report applied[]/unknown[] without writing anything. |
**Returns:** `SetMaterialPropertiesResult`
## Shaders
### `list_shaders`
Discover available shaders so an agent can pick a valid name for set_material_properties / create_asset. Returns `[{ name, assetPath|null, isBuiltin, isSupported }]`.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `filter` | no | `` | Case-insensitive substring matched against the shader name (e.g. "URP", "Lit"). |
| `includeBuiltin` | no | `true` | Include built-in/engine shaders (those with no project asset path). |
| `limit` | no | `200` | Maximum number of shaders to return. |
**Returns:** `object` (list of `ShaderInfo`)
### `get_shader_properties`
Introspect a shader's declared property list (name, description, type Color|Vector|Float|Range|TexEnv|Int, range, textureDimension, flags). Provide `shader` (by name) OR `material` (read the shader off that material).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `shader` | no | `` | Shader name (e.g. "Universal Render Pipeline/Lit"). Provide this OR 'material'. |
| `material` | no | `` | Reference to a material to read the shader from instead of naming it. Provide this OR 'shader'. |
**Returns:** `ShaderPropertiesResult`
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,32 @@
# Navigation & selection commands
Commands to read and drive the Editor selection, and to run Unity Search queries. All commands are read-only or non-destructive and run on the main thread.
### `get_selection`
Read the current Editor selection as structured object identities.
No parameters.
**Returns:** `SelectionResult`
### `set_selection`
Set the Editor selection to the given assets/scene objects.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `instance_ids` | no | `` | Scene/loaded object instance IDs to select. |
| `paths` | no | `` | Asset paths to select (e.g. Assets/Foo.prefab). |
**Returns:** `SelectionResult`
### `search`
Run a Unity Search query and return structured results.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `query` | yes | `` | Unity Search query string, e.g. 't:Material', 'p: my asset', 'h: Main Camera'. |
| `limit` | no | `50` | Max results to return (capped 200). |
**Returns:** `SearchResult`
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,70 @@
# Package Manager commands
These commands query and modify the project's UPM package set (list, search, add, remove, resolve, status) over `UnityEditor.PackageManager`. Read-only queries block until the registry responds and return synchronously; mutating commands (`package_add`/`package_remove`) require `confirm=true`, support `dry_run` previews, and are async by default (poll `package_status`) with an optional `wait=true` to block until done.
### `package_list`
List packages by scope: installed (default) | available (registry) | all (both). Returns the full result synchronously — available/all block until the registry query completes.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `scope` | no | `installed` | Which packages to list: installed (default) | available | all. |
| `include_indirect` | no | `true` | Include indirect (transitive) installed dependencies (applies to scope=installed/all). |
| `offline` | no | `false` | For available/all: query the local cache instead of the registry. |
**Returns:** `object`
**Notes:** `MainThreadRequired = false`. Synchronous — `available`/`all` start a registry query and block until it completes (up to a 25s timeout); `installed` reads the resolved set inline on the main thread.
### `package_search`
Search packages available in the registry. Provide a name (e.g. com.unity.foo) or omit to list all. Returns the full result synchronously (blocks until the registry query completes).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `query` | no | `` | Package name to search for. Omit/empty to list all available packages. |
| `offline` | no | `false` | Search the local cache only. |
**Returns:** `object`
**Notes:** `MainThreadRequired = false`. Synchronous — blocks until the registry query completes (up to a 25s timeout). Each result is flagged with whether it is currently installed.
### `package_add`
Add a UPM package by name@version, git URL, or 'file:' local path. Async by default (returns in_progress; poll package_status); pass wait=true to block until added. A recompile/domain reload follows — poll recompile_status. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `identifier` | yes | `` | Package to add: 'com.unity.foo@1.2.3', a git URL, or 'file:../Path'. |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
| `wait` | no | `false` | Block until the operation completes and return the result (synchronous). Default: return immediately and poll package_status. |
**Returns:** `object`
**Notes:** `MainThreadRequired = false`. Mutating — requires `confirm=true`; `dry_run=true` returns a preview without applying. Async by default (returns `in_progress`; poll `package_status`); with `wait=true` it blocks until completion (up to a 25s timeout). A successful add triggers a recompile/domain reload — poll `recompile_status`. Returns `busy` if another package operation is already in progress.
### `package_remove`
Remove a UPM package by name. Async by default (returns in_progress; poll package_status); pass wait=true to block until removed. A recompile/domain reload follows — poll recompile_status. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `name` | yes | `` | Package name to remove (e.g. com.unity.foo). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
| `wait` | no | `false` | Block until the operation completes and return the result (synchronous). Default: return immediately and poll package_status. |
**Returns:** `object`
**Notes:** `MainThreadRequired = false`. Mutating — requires `confirm=true`; `dry_run=true` returns a preview without applying. Async by default (returns `in_progress`; poll `package_status`); with `wait=true` it blocks until completion (up to a 25s timeout). A successful remove triggers a recompile/domain reload — poll `recompile_status`; the reload can drop a synchronous reply, so `package_status` confirms the outcome. Returns `busy` if another package operation is already in progress.
### `package_resolve`
Resolve/refresh packages from the manifest (re-fetch and re-link). May trigger a recompile/domain reload — poll recompile_status. Its outcome is recorded for package_status.
No parameters.
**Returns:** `object`
**Notes:** `MainThreadRequired = true`. Fire-and-forget — `Client.Resolve()` schedules a resolve on a later tick, so the response returns before any reload. May trigger a recompile/domain reload — poll `recompile_status`. Its outcome is recorded in the status file, so `package_status` validates it.
### `package_status`
Status of the last async package operation (add/remove/resolve): idle | in_progress | completed | failed, with the added package, manifest, and any error.
No parameters.
**Returns:** `string`
**Notes:** `MainThreadRequired = false`. Reads a Temp status file that survives the domain reload an add/remove/resolve triggers, so a lost synchronous reply or an interrupted async op is recoverable by polling. Returns `{"status":"idle"}` when no operation has run.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,84 @@
# Prefab commands
Commands covering the prefab lifecycle an agent needs to build content procedurally: saving a configured GameObject as a prefab asset, instantiating it into a scene, deriving a variant, applying/reverting instance overrides, unpacking, and editing prefab contents through the prefab stage. Asset paths are sandboxed to the authoring root; scene-side mutations are Undo-able, but prefab asset writes are AssetDatabase operations and are not part of Unity's Undo system.
### `create_prefab`
Save a GameObject as a prefab asset at a project path; the source becomes a connected instance.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `source` | yes | | Reference to the source GameObject to save as a prefab (globalId/path/guid/instanceId/hierarchyPath). |
| `path` | yes | | Prefab asset path relative to the authoring root (the Assets/ prefix is optional and the .prefab extension is added if missing). e.g. Prefabs/Enemy or Prefabs/Enemy.prefab |
**Returns:** `AuthoringResult`
**Notes:** Scene-side effects are Undo-able; the prefab asset write is not undoable.
### `instantiate_prefab`
Instantiate a prefab asset into a loaded scene and return the created instance.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `prefab` | yes | | Reference to the prefab asset to instantiate (path/guid/globalId). |
| `scene_path` | no | `` | Optional path of a loaded scene to instantiate into; defaults to the active scene. |
| `name` | no | `` | Optional name for the created instance; defaults to the prefab name. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able.
### `create_prefab_variant`
Create a prefab variant asset that inherits from a base prefab.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `base` | yes | | Reference to the base prefab asset (path/guid/globalId). |
| `path` | yes | | Variant prefab asset path relative to the authoring root (.prefab added if missing). |
**Returns:** `AuthoringResult`
**Notes:** Prefab asset write is not undoable.
### `apply_prefab_overrides`
Apply a prefab instance's overrides back to its source prefab asset.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `instance` | yes | | Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId). |
**Returns:** `AuthoringResult`
**Notes:** Scene-side effects are Undo-able; the asset write is not. The instance's source prefab asset must live under the authoring root.
### `revert_prefab_overrides`
Revert a prefab instance's overrides so it matches its source prefab asset.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `instance` | yes | | Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId). |
**Returns:** `AuthoringResult`
**Notes:** Undo-able.
### `unpack_prefab`
Unpack a prefab instance into plain GameObjects (outermost level or completely).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `instance` | yes | | Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId). |
| `completely` | no | `false` | If true, unpack all nested prefab levels (Completely); if false, only the outermost level (OutermostRoot). |
**Returns:** `AuthoringResult`
**Notes:** Undo-able.
### `save_prefab_contents`
Open a prefab asset in an isolated prefab stage, apply a declarative edit, and save it back (nested-prefab safe).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `prefab` | yes | | Reference to the prefab asset to edit (path/guid/globalId). |
| `rename_child` | no | `` | Optional child name (relative path under the root, e.g. 'Body/Head') to rename. |
| `new_name` | no | `` | New name for the child identified by rename_child. |
| `set_active_child` | no | `` | Optional child name (relative path under the root) whose active state to set. |
| `active` | no | `true` | Active state to apply when set_active_child is provided. |
**Returns:** `AuthoringResult`
**Notes:** Prefab asset write (prefab-stage save) is not part of Unity's Undo system. The prefab asset must live under the authoring root.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,239 @@
# Project settings commands
Read and change a representative slice of Unity's project-wide settings (Audio, Graphics, Input, Physics, Player, Quality, Tags & Layers, Time). `get_*` commands read a group's current values into a `ProjectSettingsResponse`; `set_*` commands mutate them through the shared `confirm`/`dry_run` convention, so `confirm=true` is required to apply and `dry_run=true` previews the change without applying it. Every command in this group is `MainThreadRequired = true`. On a `set_*`, omitted fields are left unchanged, and the group is re-read after the write so the response reflects the resulting state. Settings writes are not undoable via Ctrl+Z.
### `get_audio_settings`
Read project Audio settings (volume, rolloff scale, doppler factor).
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_audio_settings`
Change project Audio settings. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Fields to change; omitted fields are left unchanged (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `volume` | no | `` | Global audio volume (0..1). |
| `rolloffScale` | no | `` | Global rolloff scale. |
| `dopplerFactor` | no | `` | Global doppler factor. |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`.
### `get_graphics_settings`
Read GraphicsSettings (default render pipeline).
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_graphics_settings`
Set the default render pipeline asset. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Fields to change; omitted fields are left unchanged (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `renderPipelineAsset` | no | `` | Reference (path / guid / globalId) to a RenderPipelineAsset to set as the default. Pass an empty reference (`{}`) to select the built-in pipeline; omit to leave unchanged. |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`.
### `get_input_settings`
Read the legacy Input Manager axes (names and count).
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_input_settings`
Tune a legacy Input Manager axis (sensitivity/gravity/dead) by name. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Axis change. 'axis' selects the axis by name; omitted numeric fields are left unchanged (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `axis` | yes | | Name of the axis to modify (e.g. 'Horizontal'). |
| `sensitivity` | no | `` | New sensitivity. |
| `gravity` | no | `` | New gravity. |
| `dead` | no | `` | New dead-zone size. |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`.
### `get_physics_settings`
Read Physics settings (gravity, solver iterations, bounce threshold).
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_physics_settings`
Change Physics settings. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Fields to change; omitted fields are left unchanged (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `gravityX` | no | `` | Gravity X component. |
| `gravityY` | no | `` | Gravity Y component (e.g. -9.81). |
| `gravityZ` | no | `` | Gravity Z component. |
| `defaultSolverIterations` | no | `` | Default solver iteration count. |
| `bounceThreshold` | no | `` | Bounce threshold velocity. |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`.
### `get_player_settings`
Read PlayerSettings (company/product/version, scripting backend, API level).
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_player_settings`
Change PlayerSettings. Requires confirm=true; use dry_run to preview. Scripting backend / API level changes trigger a domain reload.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Fields to change; omitted fields are left unchanged (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `companyName` | no | `` | Company name. |
| `productName` | no | `` | Product name. |
| `bundleVersion` | no | `` | Bundle/application version string. |
| `scriptingBackend` | no | `` | Scripting backend (e.g. Mono2x, IL2CPP). Triggers a domain reload. |
| `apiCompatibilityLevel` | no | `` | API compatibility level (e.g. NET_Standard_2_0, NET_Unity_4_8). Triggers a domain reload. |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. Changing `scriptingBackend` or `apiCompatibilityLevel` triggers a domain reload (`requiresDomainReload`); scripting-backend / API-level changes are read and written against the active build target.
### `get_quality_settings`
Read QualitySettings (current level, level names, vSync, anti-aliasing).
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_quality_settings`
Change QualitySettings. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Fields to change; omitted fields are left unchanged (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `level` | no | `` | Quality level index (see levelNames from get_quality_settings). |
| `vSyncCount` | no | `` | VSync count (0 = off, 1, 2). |
| `antiAliasing` | no | `` | MSAA sample count (0, 2, 4, 8). |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`.
### `get_tags_layers`
Read the project's tags and (named) layers.
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_tags_layers`
Add/remove tags and assign user layer names (index 8-31). Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Tag/layer changes to make (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `addTags` | no | `` | Tag names to add. |
| `removeTags` | no | `` | Tag names to remove. |
| `setLayers` | no | `` | User layer assignments (index 8-31); array of layer-assignment objects (fields below). |
`setLayers[]` (layer-assignment) fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `index` | yes | | Layer index (8-31 for user layers). |
| `name` | yes | | Layer name (empty string clears the slot). |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. User layers are indices 8-31 (0-7 are reserved).
### `get_time_settings`
Read Time settings (fixedDeltaTime, maximumDeltaTime, timeScale).
No parameters.
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`.
### `set_time_settings`
Change Time settings. Requires confirm=true; use dry_run to preview.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `settings` | no | `` | Fields to change; omitted fields are left unchanged (fields below). |
| `confirm` | no | `false` | Apply the change. Without it the call is refused. |
| `dry_run` | no | `false` | Preview the change without applying it. |
`settings` fields:
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `fixedDeltaTime` | no | `` | Fixed timestep in seconds (e.g. 0.02). |
| `maximumDeltaTime` | no | `` | Maximum allowed timestep in seconds. |
| `timeScale` | no | `` | Time scale (1 = real-time). |
**Returns:** `ProjectSettingsResponse`
**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,162 @@
# Runtime commands
Commands served by the Player / dev-build server. Many require a Development build running `RuntimePipelineManager` — see [Runtime setup](../runtime-setup.md). Commands marked `RuntimeOnly` are only registered in a player build.
### `runtime_status`
Get comprehensive runtime application status.
No parameters.
**Returns:** `RuntimeStatusResponse`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`.
### `quit`
Gracefully quit the Unity application.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `exitCode` | no | `0` | Exit code for the application |
**Returns:** `string`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`.
### `set_target_framerate`
Set the target frame rate for the application.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `frameRate` | yes | `` | Target frame rate (-1 for platform default, 0 for unlimited) |
**Returns:** `string`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`.
### `set_timescale`
Set the time scale for the application.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `scale` | yes | `` | Time scale multiplier (0.0 to pause, 1.0 for normal speed) |
**Returns:** `string`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`.
### `simulate_key`
Simulate a keyboard key event (Input System). Drives the running app.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `key` | yes | `` | Input System Key name, e.g. Space, W, Enter, LeftArrow. |
| `action` | no | `press` | down \| up \| press (down+up). |
**Returns:** `InputSimulationResponse`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. Requires the Input System package (`ENABLE_INPUT_SYSTEM`); reports unavailable otherwise.
### `simulate_pointer`
Simulate a mouse/pointer event at screen coordinates (Input System).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `x` | yes | `` | Screen X in pixels (origin bottom-left). |
| `y` | yes | `` | Screen Y in pixels (origin bottom-left). |
| `action` | no | `click` | move \| down \| up \| click (down+up). |
| `button` | no | `left` | left \| right \| middle. |
**Returns:** `InputSimulationResponse`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. Requires the Input System package (`ENABLE_INPUT_SYSTEM`); reports unavailable otherwise.
### `log`
Write a message to Unity console.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `message` | yes | `` | Message to log to console |
| `level` | no | `info` | Log level: info, warning, error |
**Returns:** `string`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`.
### `console`
Get captured Unity console output (Editor or Player; supports tail, level filtering, and follow via a cursor).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `tail` | no | `100` | Maximum number of most-recent entries to return |
| `level` | no | `log` | Minimum severity to include: log | warn | error |
| `since` | no | `-1` | Cursor: only return entries newer than this seq. Use the 'cursor' from a previous response to follow. |
**Returns:** `ConsoleLogResponse`
**Notes:** `MainThreadRequired = false`. Available in both the Editor and player builds.
### `eval`
Evaluate C# code dynamically using Roslyn compiler.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `code` | yes | `` | C# code to evaluate |
| `timeout` | no | `5000` | Timeout in milliseconds |
**Returns:** `EvalResponse`
**Notes:** `MainThreadRequired = true`. Available on both editor and runtime.
### `eval_file`
Evaluate C# code read from a `.cs` file on disk. A convenience alternative to `eval` for code
too long to pass inline — edit the file, then evaluate it. The resolved source is run through the
same evaluation path as `eval`.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `file` | yes | `` | Path to a `.cs` file to evaluate |
| `timeout` | no | `5000` | Timeout in milliseconds |
The `file` is read on the Unity side (relative paths resolve against the Unity process working
directory) and must end in `.cs`. A missing file, a non-`.cs` extension, or an empty file returns
a `Bad Request`.
**Returns:** `EvalResponse`
**Notes:** `MainThreadRequired = true`. Available on both editor and runtime.
### `reload_file`
Compile and apply in-place [HotReload] edits from a source file.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `filename` | yes | `` | Source file containing [HotReload] methods (e.g. Assets/Scripts/Player.cs) |
| `timeout` | no | `30000` | Compilation timeout in milliseconds |
| `assemblyDir` | no | `` | Directory to save compiled assemblies to disk (optional, default is in-memory only) |
| `pdb` | no | `false` | Emit debug symbols (portable PDB) mapped to the original source so breakpoints bind in your editor. Compiles unoptimized. |
**Returns:** `HotReloadResponse`
**Notes:** `MainThreadRequired = true`. See [Hot reload](../hot-reload.md).
### `reload_file_override`
Compile and apply hot reload file changes immediately.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `filename` | yes | `` | Hot reload source file to compile (e.g. PlayerTweaks.cs) |
| `timeout` | no | `30000` | Compilation timeout in milliseconds |
| `assemblyDir` | no | `` | Directory to save compiled assemblies to disk (optional, default is in-memory only) |
**Returns:** `HotReloadResponse`
**Notes:** `MainThreadRequired = true`. See [Hot reload](../hot-reload.md).
### `hotreload_status`
Show current hot reload registry status and statistics.
No parameters.
**Returns:** `HotReloadResponse`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`.
### `cleanup_hotreload`
Remove old hot reload DLL versions and clear registry.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `assemblyDir` | yes | `` | Directory containing assemblies to cleanup |
| `force_domain_reload` | no | `true` | Force Unity domain reload after cleanup |
**Returns:** `HotReloadResponse`
**Notes:** `MainThreadRequired = true`, `RuntimeOnly`.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,93 @@
# Scene commands
Commands for creating, opening, saving and inspecting scenes, controlling the active scene, snapshotting a scene's hierarchy, and managing the Build Settings scene list. Mutating scene operations are blocked while the editor is entering or in play mode (they fail with a recoverable error before touching any state); read-only commands are safe in play mode.
### `create_scene`
Create a new scene and save it to the given path under the authoring root.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Scene path relative to the authoring root (default Assets/); the Assets/ prefix and the .unity extension are optional. e.g. Scenes/Level1 |
| `additive` | no | `false` | Open the new scene additively alongside currently open scenes instead of replacing them. |
| `template` | no | `empty` | Initial contents: 'empty' (default) for a blank scene, or 'default' to seed a Main Camera + Directional Light matching Unity's built-in 3D template. |
**Returns:** `AuthoringResult`
**Notes:** Blocked during Play mode.
### `open_scene`
Open an existing scene from the given path.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Scene path relative to the authoring root (default Assets/); the Assets/ prefix and the .unity extension are optional. |
| `additive` | no | `false` | Open additively alongside currently open scenes instead of replacing them. |
**Returns:** `AuthoringResult`
**Notes:** Blocked during Play mode.
### `save_scene`
Save an open scene. Saves the active scene when no path is given.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | no | `` | Path of the open scene to save (authoring-root relative; Assets/ prefix and .unity optional). Omit to save the active scene. |
**Returns:** `AuthoringResult`
**Notes:** Blocked during Play mode.
### `save_all`
Save all open scenes that have unsaved changes.
No parameters.
**Returns:** `object`
**Notes:** Blocked during Play mode.
### `list_open_scenes`
List all currently open scenes with their load/active/dirty state.
No parameters.
**Returns:** `object`
### `set_active_scene`
Set which open scene is the active scene (new objects are created in the active scene).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Path of an already-open scene to make active (authoring-root relative; Assets/ prefix and .unity optional). |
**Returns:** `AuthoringResult`
**Notes:** Blocked during Play mode.
### `get_scene_hierarchy`
Return the GameObject tree of an open scene (or the active scene). Each node carries instanceId + hierarchyPath usable by GameObject commands.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | no | `` | Path of the open scene to snapshot (authoring-root relative; Assets/ prefix and .unity optional). Omit for the active scene. |
**Returns:** `SceneHierarchy`
### `add_scene_to_build`
Add a scene to the Build Settings scene list (idempotent). Optionally enable it.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Scene path to add (authoring-root relative; Assets/ prefix and .unity optional). |
| `enabled` | no | `true` | Whether the scene is enabled in the build list. |
**Returns:** `object`
**Notes:** Blocked during Play mode.
### `remove_scene_from_build`
Remove a scene from the Build Settings scene list (idempotent).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `path` | yes | | Scene path to remove (authoring-root relative; Assets/ prefix and .unity optional). |
**Returns:** `object`
**Notes:** Blocked during Play mode.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,55 @@
# Script commands
Commands for creating C# script files, attaching MonoBehaviours to GameObjects, and reading/writing serialized fields. Writing a `.cs` file does not make its type available — Unity must import and compile it (a domain reload) first. The flow is: `create_script``recompile` → poll `recompile_status` (until completed/up_to_date) → `attach_script`.
### `create_script`
Create a new C# script (default base class MonoBehaviour) from a template under the authoring root. NOTE: the type does not exist until a recompile completes — to attach it, call recompile, poll recompile_status, then attach_script.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `name` | yes | | Class/file name without extension, e.g. PlayerController. Must be a valid C# identifier. |
| `path` | no | `` | Folder (relative to the authoring root; the Assets/ prefix is optional) to write the .cs into. Defaults to the authoring root. |
| `namespace` | no | `` | Optional namespace to wrap the class in. Omit for the global namespace. |
| `base_class` | no | `MonoBehaviour` | Base class to derive from. Defaults to MonoBehaviour. |
| `overwrite` | no | `false` | Overwrite the file if it already exists. Defaults to false (an existing file is an error). |
**Returns:** `AuthoringResult`
**Notes:** Does not trigger a recompile; the created type is not usable until a recompile completes (poll `recompile_status`).
### `attach_script`
Add a MonoBehaviour to a GameObject by its (compiled) type name OR by its script asset path. Provide exactly one of 'type' or 'script'. If the type isn't compiled yet, returns a recoverable error: recompile, poll recompile_status, then retry.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Reference to the GameObject to add the component to (globalId/path/guid/instanceId/hierarchyPath). |
| `type` | no | `` | Component type name to add, e.g. PlayerController or Game.Player.PlayerController. Must already be compiled. Mutually exclusive with 'script'. |
| `script` | no | `` | Script asset path, e.g. 'Assets/Pool/Scripts/CueShooter.cs'. The backing class is resolved via MonoScript.GetClass(), so the class name may differ from the filename. Mutually exclusive with 'type'. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able. Provide exactly one of `type` or `script`. A not-yet-compiled type returns a recoverable error (recompile, poll `recompile_status`, then retry).
### `set_serialized_field`
Set a serialized field on a component/asset. Supports primitives, enums, Vector/Color/Rect/Bounds, object references (value = an ObjectRef: asset by guid/fileId/path or scene object by instanceId/hierarchyPath), and array elements via 'name.Array.data[i]' (or 'name.Array.size' to resize).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Reference to the component or asset to modify (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given. |
| `field` | yes | | SerializedProperty path, e.g. 'speed', 'settings.speed', or 'waypoints.Array.data[0]'. |
| `value` | yes | | JSON value to assign. For object references pass an ObjectRef object (or null to clear). For enums pass the value name. |
| `component` | no | `` | Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able.
### `get_serialized_fields`
Read serialized fields of a component/asset. Returns each top-level field's name, type and value (object references are returned as re-usable handles). Pass 'field' to read a single SerializedProperty path.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | | Reference to the component or asset to read (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given. |
| `field` | no | `` | Optional single SerializedProperty path to read (e.g. 'speed' or 'items.Array.data[0]'). Omit to read all top-level fields. |
| `component` | no | `` | Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle. |
**Returns:** `object`
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).
@@ -0,0 +1,178 @@
# Connectivity
How a client reaches a running Unity instance: the loopback-only HTTP servers, their port ranges, the port descriptor file used for discovery, and the bearer-token authentication every request must carry.
The rest of this page covers the implementation. If you just want to connect, start with the two sections below.
## Connecting to a running Editor
Connections go through the `unity` CLI. Run `unity command` with no command name to connect to a Unity instance and list its available commands:
```bash
# Auto-discover a Unity instance from the current directory
unity command
# Connect to a specific project
unity command --project-path /path/to/your/unity/project
```
Once connected, run any command by name, e.g. `unity command editor_status`.
## Connecting to a running Player (game)
To target a running development Player instead of the Editor, use `--runtime` (by process name) or `--runtime-path` (by the location of the runtime port file). These options go **after** `command` and **before** the command name:
```bash
# By Player process/executable name
unity command --runtime MyGame.exe runtime_status
# By the folder/bundle where the runtime port file lives
unity command --runtime-path "C:\Builds\MyGame" runtime_status # Windows: next to the .exe
unity command --runtime-path "/Users/me/Builds/MyGame.app" runtime_status # macOS: the .app bundle
```
> The Runtime server only runs in a **development Player build** with the runtime manager enabled — see [Runtime connection & setup](runtime-setup.md).
## Finding the port in the Unity logs
The [port descriptor file](#port-descriptor-file) is the primary discovery channel, but the server also reports itself to the Unity log when it starts and stops — useful when you can't read the descriptor file directly. Look for `Pipeline`-prefixed lines.
- **Runtime (Player)** — logs its port **and** the descriptor file location on start, and a line on stop:
```
Pipeline: Runtime server started successfully on port 7901
Pipeline: Runtime descriptor written to /path/to/MyGame/.unity-pipeline-runtime-port
Pipeline: Runtime server stopped
```
- **Editor** — logs its port when the server is (re)started from the **Pipeline ▸ Start Server** menu or re-opened by its watchdog (`Pipeline Server started on port 7801`). Its descriptor always lives at the fixed `Library/Pipeline/.unity-pipeline-port` path.
### Where the logs live
**Editor log** (`Editor.log`):
| OS | Path |
|----|------|
| Windows | `C:\Users\<user>\AppData\Local\Unity\Editor\Editor.log` |
| macOS | `~/Library/Logs/Unity/Editor.log` |
**Player log** (`Player.log`):
| OS | Path |
|----|------|
| Windows | `C:\Users\<user>\AppData\LocalLow\<company>\<product>\Player.log` |
| macOS | `~/Library/Logs/<company>/<product>/Player.log` |
(`<company>` and `<product>` are the project's **Company Name** and **Product Name** from Player Settings.)
## Loopback-only binding
Both the Editor and Runtime servers bind to the **IPv4 loopback** (`127.0.0.1`) — plus the `localhost` hostname for compatibility:
```csharp
if (Socket.OSSupportsIPv4)
m_HttpListener.Prefixes.Add($"http://127.0.0.1:{m_Port}/");
m_HttpListener.Prefixes.Add($"http://localhost:{m_Port}/");
```
The server is never exposed on a routable interface — it is reachable only from the same machine.
Clients should connect to **`127.0.0.1`** explicitly rather than `localhost`. Unity's Mono `HttpListener` only reliably serves the IPv4 loopback: a request arriving over the IPv6 loopback (`::1`) is answered with `400` because Mono mis-parses the bracketed `[::1]` host. Since `localhost` resolves to `::1` or `127.0.0.1` non-deterministically (notably on Windows with Node's default DNS order), dialing `localhost` caused intermittent connection failures — dialing `127.0.0.1` avoids the IPv6 path entirely.
In addition, the server refuses any request that carries an `Origin` header (legitimate CLI/CI clients never send one), which blocks a browser page from reaching the local server and short-circuits CORS preflights.
## Port ranges
Each server type picks the first free port in its range (or you can pin one explicitly):
| Server | Production range | Test range |
|--------|------------------|------------|
| **Editor** | `7800``7849` | `7850``7899` |
| **Runtime** (Player) | `7900``7949` | `7950``7999` |
If no port in the range is free, startup throws (`No available ports in range …`).
## Port Descriptor File
When a server starts, it writes a small JSON **instance descriptor** so clients can discover it. This is the only discovery channel — there is no broadcast or registry.
| Server | Descriptor path |
|--------|-----------------|
| **Editor** | `<projectPath>/Library/Pipeline/.unity-pipeline-port` |
| **Runtime** | `<workingDirectory>/.unity-pipeline-runtime-port` |
The Editor descriptor lives under the git-ignored `Library/` folder. The file is created with permissions restricted to the current user (it carries the auth token). The server rewrites it on every heartbeat to refresh `lastHeartbeat`, and deletes it on shutdown.
The Runtime descriptor is written next to the Player, at `{Application.dataPath}/..`:
- **Windows / Linux** — beside the executable, e.g. `C:\Builds\MyGame\.unity-pipeline-runtime-port`.
- **macOS** — `Application.dataPath` is `<Game>.app/Contents`, so the descriptor lands at the **`.app` bundle root**: `MyGame.app/.unity-pipeline-runtime-port`. (The file is inside the `.app` bundle.) This is why `unity command --runtime-path` takes the `.app` bundle path on macOS — see [Runtime connection & setup](runtime-setup.md).
> Test servers do **not** write a descriptor (they override `WritesDescriptor => false`) — the test already knows its port, so it never clobbers the live server's file. See [Tests architecture](testing.md).
### Editor descriptor fields
```json
{
"pid": 12345,
"port": 7800,
"projectPath": "/path/to/Project",
"projectName": "Project",
"unityVersion": "6000.x.y",
"mode": "editor",
"startedAt": "2026-06-25T10:00:00Z",
"lastHeartbeat": "2026-06-25T10:05:00Z",
"evalToken": "<base64 token>"
}
```
| Field | Meaning |
|-------|---------|
| `pid` | Process id of the Unity Editor. |
| `port` | Port the server is listening on. |
| `projectPath` | Absolute path to the Unity project. |
| `projectName` | Project folder name. |
| `unityVersion` | Editor version string. |
| `mode` | `"editor"` or `"batchmode"`. |
| `startedAt` | When the instance started (UTC). |
| `lastHeartbeat` | Last heartbeat (UTC), refreshed on status calls. |
| `evalToken` | Bearer token for authenticating requests. |
### Runtime descriptor fields
The runtime descriptor shares `pid`, `port`, `unityVersion`, `startedAt`, `lastHeartbeat`, and `evalToken`, and adds:
| Field | Meaning |
|-------|---------|
| `platform` | Unity runtime platform (e.g. `WindowsPlayer`). |
| `buildGuid` | Unique build identifier (`Application.buildGUID`). |
| `workingDirectory` | Directory the Player is running from. |
(The runtime descriptor carries `platform`/`buildGuid`/`workingDirectory` in place of the editor's `projectPath`/`projectName`/`mode`.)
## Authentication
Every request must authenticate with a bearer token:
```
Authorization: Bearer <evalToken>
```
- The server **generates the token at startup** (`SecurityTokenManager.GetOrCreateToken()` — 256 bits of CSPRNG output, base64-encoded). In the Editor the token is persisted in `SessionState`, so it **survives domain reloads** within an editor session (recompiles, entering play mode) — long-lived clients (MCP sessions, IDE integrations) keep working instead of getting `401` after every reload. It is regenerated only when the Editor **restarts**, or on an explicit rotation (`SecurityTokenManager.ClearCache()` / `RotateToken()`). Player builds use a per-process token.
- The token is published in the descriptor's `evalToken` field. The descriptor is **re-advertised with the live token on every heartbeat**, so the port file never advertises a token the server would reject (e.g. after a reload or rotation).
- The server validates the bearer token on **every** request (before routing) using a constant-time comparison. A missing or wrong token returns `401 Unauthorized`.
## Discovering and calling an instance
A client connects by:
1. Reading the descriptor file (editor: `Library/Pipeline/.unity-pipeline-port`).
2. Taking the `port` and `evalToken` from it.
3. Sending requests to `http://127.0.0.1:<port>/...` with `Authorization: Bearer <evalToken>`.
Endpoints exposed by the server include `/api/status`, `/api/editor_status`, `/api/commands` (lists available commands), `/api/exec` (POST — runs a command), and `/api/test-status`.
## See also
- [Runtime connection & setup](runtime-setup.md) — enabling the server in a Player build.
- [Creating commands](creating-commands.md) — authoring the commands clients call.
@@ -0,0 +1,189 @@
# Creating commands
A *command* is a `static` method that the Pipeline server can invoke over HTTP. The method's accessibility does not matter — `public`, `internal`, and `private` static methods can all be registered. This page covers the command-authoring API: how to declare a command, describe its parameters, return a result, and have it discovered automatically.
## The handler + response pattern
Authoring a command has two halves:
1. **The handler** — your `static` method, tagged `[CliCommand]`. It does the work and returns a value.
2. **The response** — the server wraps whatever your handler returns in a [`CommandExecutionResponse`](#the-commandexecutionresponse-envelope) and serializes it to JSON for the client.
You never build the HTTP response yourself. Return a `string`, a number, an anonymous object, a typed model, or `null`; the server takes care of the envelope, timing, and error reporting.
## Declaring a command
Tag a `static` method with `[CliCommand]` (the examples below use `public`, but any accessibility works):
```csharp
[CliCommand("name", "description", MainThreadRequired = true, RuntimeOnly = false)]
public static <ReturnType> Handler(...);
```
| Argument | Meaning |
|----------|---------|
| `name` | Unique command name used by the client (`unity command <name>`). |
| `description` | Human-readable text shown in help and the `/api/commands` listing. |
| `MainThreadRequired` | Whether the handler must run on Unity's main thread. **Default `true`.** |
| `RuntimeOnly` | Whether the command is hidden from an Editor server's command listing. **Default `false`.** |
The method **must be `static`**, but its accessibility does not matter: `public`, `internal`, and `private` static methods can all be registered. `CommandRegistry` invokes handlers through reflection, so a `private` handler runs exactly like a `public` one. Only a non-static (instance) method fails to register — `CommandRegistry` skips it and logs a warning.
### Describing parameters
Tag each parameter with `[CliArg]`:
```csharp
[CliArg("name", "description", Required = false, DefaultValue = null)]
```
| Property | Meaning |
|----------|---------|
| `name` | Parameter name as it appears in client arguments (`--name value`). |
| `description` | Human-readable description for help text. |
| `Required` | Whether the parameter must be supplied. Defaults to `false` — but if the parameter has no C# default value it is treated as required. |
| `DefaultValue` | Value used when the client omits the parameter (a C# default value takes precedence). |
`[CliArg]` is optional metadata. A parameter without it still works: its name defaults to the C# parameter name and `Required` defaults to "does this parameter lack a C# default value?".
## Worked example 1 — returning a string
A command can return a plain `string`. The server places it in the response `result` field.
```csharp
using Unity.Pipeline.Commands;
using UnityEditor;
using UnityEngine;
public static class PlayModeCommands
{
[CliCommand("editor_play", "Enter Unity Editor play mode")]
public static string EnterPlayMode()
{
if (EditorApplication.isPlaying)
return "Already in play mode";
EditorApplication.isPlaying = true;
return "Entered play mode";
}
}
```
Calling `editor_play` yields a `CommandExecutionResponse` whose `result` is `"Entered play mode"`.
## Worked example 2 — returning a response model
For richer results, return a model. Returning a type that extends `CommandExecutionResponse` (like `EvalResponse`) lets you populate response fields directly; you can also return any plain serializable model (like `AuthoringResult`) and let the server wrap it.
```csharp
using Unity.Pipeline.Commands;
using Unity.Pipeline.Models;
using Unity.Pipeline.Compilation;
public static class CodeEvalCommand
{
[CliCommand("eval", "Evaluate C# code dynamically using Roslyn compiler", MainThreadRequired = true)]
public static EvalResponse EvaluateCode(
[CliArg("code", "C# code to evaluate", Required = true)] string code,
[CliArg("timeout", "Timeout in milliseconds")] int timeout = 5000)
{
if (string.IsNullOrWhiteSpace(code))
return EvalResponse.EvalFailure("Bad Request", "Code parameter is required and cannot be empty");
var result = EvalCodeCompiler.CompileAndExecuteOnMainThread(code, timeout, null);
return result ?? EvalResponse.EvalFailure("Unknown Error", "Compilation returned null result");
}
}
```
`EvalResponse` adds `output` and `diagnostics` on top of the standard envelope. Another common shape is a domain model such as `AuthoringResult` — the canonical identity (asset path, GUID, instance id, hierarchy path) of an object a command created, returned so the client can reference it in a follow-up call.
## Structured (multi-field) parameters
When a command needs a structured argument with several fields, don't spread them across many `[CliArg]` parameters — declare a small DTO that implements `IStructuredCommandInput` and take it as a single parameter. The type is advertised to clients as a nested JSON **object** schema in `GET /api/commands` (instead of collapsing to `string`), and the value is deserialized automatically via Newtonsoft — no extra wiring.
```csharp
[CliCommand("set_time_settings", "Change Time settings. Requires confirm=true; use dry_run to preview.")]
public static ProjectSettingsResponse Set(
[CliArg("settings", "Fields to change; omitted fields are left unchanged.")] TimeSettingsInput settings = null,
[CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false,
[CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false)
{ /* ... */ }
public class TimeSettingsInput : IStructuredCommandInput
{
[CliArg("fixedDeltaTime", "Fixed timestep in seconds (e.g. 0.02).")]
public float? FixedDeltaTime { get; set; }
[CliArg("timeScale", "Time scale (1 = real-time).")]
public float? TimeScale { get; set; }
}
```
`JsonSchemaGenerator` reflects over the type's public, writable fields and properties to emit `{ "type": "object", "properties": { ... } }`, recursing into nested `IStructuredCommandInput` members and arrays/lists of them. Member metadata mirrors command parameters:
- `[CliArg(name, description, Required = ...)]` controls the property name, description, and whether it appears in the schema's `required` array.
- Without a `[CliArg]`, the member (or its Newtonsoft `[JsonProperty]`) name is used and it is optional. Use nullable types (`float?`) for "omitted = leave unchanged" semantics.
- `[JsonIgnore]` members are omitted from the schema.
`[CliArg]` is valid on parameters, fields, and properties, so the same attribute annotates DTO members. Most commands that take an `IStructuredCommandInput` are mutations — pair the DTO with `confirm`/`dry_run` and follow the [safety conventions](safety-and-mutations.md) (inline gate + `AuthoringUndoScope`).
## The `CommandExecutionResponse` envelope
Whatever your handler returns, the client receives a `CommandExecutionResponse`:
| Field | Type | Meaning |
|-------|------|---------|
| `success` | `bool` | Whether the command ran without throwing. |
| `command` | `string` | The command name. |
| `result` | `object` | Your handler's return value (a string, model, anonymous object, or `null`). |
| `executionTimeMs` | `long?` | How long the command took. |
| `error` | `string` | Error summary when `success` is `false`. |
If your handler throws, the server catches it and returns a failure envelope with `success = false` and the exception message in `error` — you do not need to catch-and-wrap yourself unless you want a tailored message.
## `MainThreadRequired`
- **Default: `true`.** Most Unity APIs (scene, GameObject, asset, play-mode access) must run on the main thread. The server marshals these handlers onto the main thread via its dispatcher.
- **Set `false` only** for handlers that are thread-safe and read-only / pollable (e.g. a status or buffer-read command). These run on a background thread so they never block the main thread or deadlock against a busy editor.
When in doubt, leave it `true`.
## `RuntimeOnly`
- **Default: `false`** — the command is advertised in an Editor server's `/api/commands` listing.
- **Set `true`** to hide a command from the Editor command listing. It remains **executable**; it is simply not advertised when a client is connected to an Editor (Runtime/Player servers still list it). Use this for commands that only make sense against a running Player.
## Discovery
Commands are discovered by `CommandRegistry`, which scans for `[CliCommand]`-tagged methods through a pluggable `ICommandDiscovery`:
- In the **Editor**, `TypeCacheCommandDiscovery` provides fast `TypeCache`-based discovery.
- In a **Player**, the registry falls back to reflection over loaded assemblies.
Results are cached until the next domain reload. **A newly added command becomes available after the next recompile** — no registration call is needed; just declare it and recompile.
## Minimal custom command template
```csharp
using Unity.Pipeline.Commands;
public static class MyCommands
{
[CliCommand("my_command", "What this command does")]
public static object MyCommand(
[CliArg("text", "Some input", Required = true)] string text,
[CliArg("count", "How many times")] int count = 1)
{
// Do work on the main thread (MainThreadRequired defaults to true).
return new { echoed = text, count }; // anonymous object → response.result
}
}
```
Recompile, then invoke it from your client (`unity command my_command --text hello --count 3`).
## See also
- [Command reference](commands/runtime.md)
- [Connectivity](connectivity.md) — how clients reach the server and authenticate.
@@ -0,0 +1,145 @@
# Hot reload
Apply edited C# to running code without restarting Play Mode or rebuilding the Player. Two flavors are supported: **in-place** reload of a tagged method body, and **override** reload that routes a method through a separately-compiled replacement.
Hot reload runs in **Editor Play Mode and Mono standalone development builds only** — not IL2CPP. Like code eval, it is gated behind `#if UNITY_EDITOR || (UNITY_STANDALONE && DEBUG)`.
## Flavor 1 — in-place (`reload_file`)
Tag the method you want to be reloadable with `[HotReload]`, then edit its body and apply the file. The running instance picks up the new body.
```csharp
using Unity.Pipeline.HotReload;
using UnityEngine;
public class Spinner : MonoBehaviour
{
public float rotationSpeed = 90f;
[HotReload]
void Update()
{
transform.Rotate(Vector3.up, rotationSpeed * Time.deltaTime);
}
}
```
Edit the body of `Update`, then apply it:
```bash
unity command reload_file "<absolute path>/Spinner.cs"
# Emit debug symbols so breakpoints bind (compiles unoptimized):
unity command reload_file "<absolute path>/Spinner.cs" --pdb
```
`reload_file` parameters:
| Arg | Default | Meaning |
|-----|---------|---------|
| `filename` | *(required)* | Source file containing `[HotReload]` methods. |
| `timeout` | `30000` | Compilation timeout (ms). |
| `assemblyDir` | `null` | Optional directory to also save the compiled assembly to disk (default: in-memory only). |
| `pdb` | `false` | Emit a portable PDB mapped to the original source so debugger breakpoints bind. Compiles unoptimized. |
**Constraints (in-place):** the `[HotReload]` method must be a **`void` instance method** that is **`public`**, and reload works on **Mono only**. The CodeGen ILPostProcessor skips static methods and value-returning methods at build time (with a warning), so only matching methods are weaved for dispatch.
## Flavor 2 — override (`reload_file_override`)
When you want to swap behavior from a *separate* file (leaving the original untouched), tag the method with `[HotReloadWithOverrides]` and route it through `HotReloadHelper.ExecuteWithHotReload`:
```csharp
using Unity.Pipeline.HotReload;
using UnityEngine;
public class BossController : MonoBehaviour
{
[HotReloadWithOverrides]
void Update()
{
HotReloadHelper.ExecuteWithHotReload(this, "Update", OriginalUpdate);
}
public void OriginalUpdate()
{
transform.Rotate(45 * Time.deltaTime, 0, 0);
}
}
```
Put the tweaked behavior in a **separate file** as a **`public static` method** tagged `[HotReloadOverrideMethod("Type.Method")]`. The override **takes the target instance as its first parameter**:
```csharp
// BossOverrides.cs — a separate file
using Unity.Pipeline.HotReload;
using UnityEngine;
public static class BossOverrides
{
[HotReloadOverrideMethod("BossController.Update")]
public static void TweakedUpdate(BossController instance)
{
instance.transform.Rotate(0, 90 * Time.deltaTime, 0); // new behaviour
}
}
```
Apply the override file:
```bash
unity command reload_file_override "<absolute path>/BossOverrides.cs"
```
`reload_file_override` parameters:
| Arg | Default | Meaning |
|-----|---------|---------|
| `filename` | *(required)* | The override source file to compile. |
| `timeout` | `30000` | Compilation timeout (ms). |
| `assemblyDir` | `null` | Optional directory to also save the compiled assembly to disk (default: in-memory only). |
The override method's signature must be `public static <ReturnType> Name(<TargetType> instance, ...)` — return type and trailing parameters matching the original. Do **not** redeclare the target type in the override file (a common cause of "signature mismatch"). Until an override is applied, `ExecuteWithHotReload` calls `OriginalUpdate`; once applied, dispatch routes to the override.
`ExecuteWithHotReload` has matching overloads for both value-returning (`Func<object>`) and void (`Action`) originals:
```csharp
public static object ExecuteWithHotReload<T>(T instance, string methodName, Func<object> originalMethod, params object[] parameters);
public static void ExecuteWithHotReload<T>(T instance, string methodName, Action originalMethod, params object[] parameters);
```
## Supporting commands
- `hotreload_status` — show registry stats (which methods have overrides registered).
- `cleanup_hotreload` — remove old hot-reload assemblies and clear the registry.
## Architecture
The pipeline that turns an edited source file into running code:
1. **Compile (Roslyn, in-memory).** `RoslynCompilationService.Compile` parses and compiles the source to a `DynamicallyLinkedLibrary` entirely in memory — IL bytes in one `MemoryStream`, and (when `pdb`/`EmitDebugInformation` is requested) a **portable PDB** in another. **Nothing is written to disk** by default. When emitting debug info it compiles unoptimized (`OptimizationLevel.Debug`) so sequence points survive and breakpoints can bind.
2. **Load into the running AppDomain.** The IL (and optional PDB) bytes are loaded via `PipelineUtils.LoadFromBytes`, which selects the load mechanism by Unity version:
```csharp
public static Assembly LoadFromBytes(byte[] bytes, byte[] pdb = null)
{
#if UNITY_6000_5_OR_NEWER
return UnityEngine.Assemblies.CurrentAssemblies.LoadFromBytes(bytes, pdb);
#else
return System.Reflection.Assembly.Load(bytes, pdb);
#endif
}
```
On Unity 6000.5+ it uses Unity's `CurrentAssemblies.LoadFromBytes`; on older versions it falls back to `Assembly.Load(bytes, pdb)`. Either way the freshly compiled code becomes a **sibling assembly** loaded next to the original in the live AppDomain.
3. **Dispatch.** Calls are routed through `HotReloadRegistry`. The registry keys dispatch on `TypeName.MethodName`; when an override is registered for that id, `TryInvokeHotReload` invokes it with the instance as the first argument (marshaling to the main thread via the injected `Dispatcher` if the override requires it). If no override is registered, the original code runs.
4. **In-place weaving (CodeGen).** For the in-place flavor, the **`HotReloadInPlaceILPostProcessor`** (built on Mono.Cecil, in the `Unity.Pipeline.CodeGen` assembly) weaves a dispatch prologue into every `[HotReload]` method **at build/compile time**. That prologue checks the registry for a reloaded body and calls it instead of the original — which is how an edited `[HotReload]` body takes effect without changing the call sites. The post-processor enforces the void-instance-method constraint, skipping (with a warning) any static or value-returning `[HotReload]` method.
Because hot reload depends on Mono's ability to load a sibling assembly and dispatch into it, it is limited to **Editor Play Mode and Mono standalone dev builds — not IL2CPP**.
## See also
- [Runtime connection & setup](runtime-setup.md) — enabling hot reload in a Player build.
- [Command reference](commands/runtime.md)
@@ -0,0 +1,267 @@
# Pipeline Documentation
`com.unity.pipeline` lets a client — CLI, CI, or an agent — drive a running Unity Editor (or a
development Player) over a local HTTP API by executing registered commands. This is the documentation
index; the [README](../README.md) has the full narrative overview, install steps, and CLI walkthrough.
## Guides
| Page | What it covers |
|------|----------------|
| [Creating commands](creating-commands.md) | The command-authoring API: `[CliCommand]`/`[CliArg]`, the handler + response pattern, and the `MainThreadRequired` / `RuntimeOnly` flags. |
| [Creating authoring commands](authoring-commands.md) | Building content-authoring commands: the authoring root sandbox, `ObjectRef` in / `AuthoringResult` out, and undo grouping — with a worked example for a new content type. |
| [Safety & mutations](safety-and-mutations.md) | Conventions shared by state-changing commands: the `confirm`/`dry_run` gate, Undo grouping via `AuthoringUndoScope`, and the path sandbox. |
| [Connectivity](connectivity.md) | How servers bind localhost, the port ranges, the port/descriptor file, and the bearer-token auth workflow. |
| [Runtime connection & setup](runtime-setup.md) | Running the server in a development Player via `RuntimePipelineManager` and the dev-build gating. |
| [Hot reload](hot-reload.md) | The two hot-reload flavors (in-place and override) with examples, plus the Roslyn / in-memory-assembly architecture. |
| [Tests architecture](testing.md) | Writing command tests via `PipelineClient` (over HTTP) and via direct command calls. |
## Command reference
| Page | Commands |
|------|----------|
| [Asset & file commands](commands/assets-and-files.md) | Create / import / move / copy / rename / delete / find assets, import settings, folders, text files. |
| [Scene commands](commands/scenes.md) | Create / open / save scenes, build-settings list, hierarchy, active scene. |
| [GameObject & component commands](commands/gameobjects-and-components.md) | Create / find / transform / parent / tag / layer GameObjects; add / remove / read / set components. |
| [Prefab commands](commands/prefabs.md) | Create, instantiate, variant, apply / revert overrides, unpack, edit prefab contents. |
| [Script commands](commands/scripts.md) | Create and attach scripts; get / set serialized fields. |
| [Animation commands](commands/animation.md) | Create AnimationClips (+ curves), AnimatorControllers (parameters / layers / states / transitions), and Timeline assets. |
| [Material & shader commands](commands/materials.md) | Read / set material shader properties and keywords; list and introspect shaders. |
| [Baking commands](commands/baking.md) | Bake / clear lighting, NavMesh, and occlusion culling (async — poll the matching `*_bake_status`). |
| [Navigation & selection commands](commands/navigation.md) | Read / set the Editor selection; run Unity Search queries. |
| [Capture commands](commands/capture.md) | Screenshot the game / scene view and capture UI Toolkit visual elements. |
| [Build, compilation & test commands](commands/build-and-compilation.md) | Build the Player, switch build target, read/write build settings, list targets/profiles, recompile scripts, and run tests (async — poll the matching `*_status`). |
| [Project settings commands](commands/project-settings.md) | Read / change Audio, Graphics, Input, Physics, Player, Quality, Tags & Layers, and Time settings (`get_*`/`set_*`, gated by `confirm`/`dry_run`). |
| [Package Manager commands](commands/package-manager.md) | List / search / add / remove / resolve UPM packages and poll operation status. |
| [Editor lifecycle & observability commands](commands/editor-lifecycle-and-observability.md) | Play / stop / pause, focus, menus, screenshots, console logs, performance stats, authoring root. |
| [Runtime commands](commands/runtime.md) | Player-side commands: status, quit, frame rate, time scale, log, console, eval, hot reload. |
## Command index
Every available command, grouped by area. Each name links to its full reference (parameters + return type).
### Asset & file commands
| Command | Description |
|---------|-------------|
| [`create_asset`](commands/assets-and-files.md#create_asset) | Create a ScriptableObject / Object asset at a path. |
| [`import_asset`](commands/assets-and-files.md#import_asset) | Import an external file into the project. |
| [`move_asset`](commands/assets-and-files.md#move_asset) | Move / rename an asset (keeps its GUID). |
| [`copy_asset`](commands/assets-and-files.md#copy_asset) | Copy an asset (fresh GUID). |
| [`rename_asset`](commands/assets-and-files.md#rename_asset) | Rename an asset in place. |
| [`delete_asset`](commands/assets-and-files.md#delete_asset) | Delete an asset (needs confirm). |
| [`find_assets`](commands/assets-and-files.md#find_assets) | Find assets by type / name / label. |
| [`set_import_settings`](commands/assets-and-files.md#set_import_settings) | Set an asset's importer settings and re-import. |
| [`get_import_settings`](commands/assets-and-files.md#get_import_settings) | Read an asset's importer settings. |
| [`create_folder`](commands/assets-and-files.md#create_folder) | Create a folder under the authoring root. |
| [`read_text_file`](commands/assets-and-files.md#read_text_file) | Read a UTF-8 text file. |
| [`write_text_file`](commands/assets-and-files.md#write_text_file) | Write a UTF-8 text file, then import it. |
### Scene commands
| Command | Description |
|---------|-------------|
| [`create_scene`](commands/scenes.md#create_scene) | Create and save a new scene. |
| [`open_scene`](commands/scenes.md#open_scene) | Open an existing scene. |
| [`save_scene`](commands/scenes.md#save_scene) | Save an open scene. |
| [`save_all`](commands/scenes.md#save_all) | Save all dirty open scenes. |
| [`list_open_scenes`](commands/scenes.md#list_open_scenes) | List open scenes and their state. |
| [`set_active_scene`](commands/scenes.md#set_active_scene) | Set which open scene is active. |
| [`get_scene_hierarchy`](commands/scenes.md#get_scene_hierarchy) | Return a scene's GameObject tree. |
| [`add_scene_to_build`](commands/scenes.md#add_scene_to_build) | Add a scene to Build Settings. |
| [`remove_scene_from_build`](commands/scenes.md#remove_scene_from_build) | Remove a scene from Build Settings. |
### GameObject & component commands
| Command | Description |
|---------|-------------|
| [`create_gameobject`](commands/gameobjects-and-components.md#create_gameobject) | Create a GameObject or primitive. |
| [`create_gameobjects`](commands/gameobjects-and-components.md#create_gameobjects) | Batch-create GameObjects / primitives. |
| [`find_gameobjects`](commands/gameobjects-and-components.md#find_gameobjects) | Find GameObjects by name / tag / component / path. |
| [`set_transform`](commands/gameobjects-and-components.md#set_transform) | Set local position / rotation / scale. |
| [`set_parent`](commands/gameobjects-and-components.md#set_parent) | Reparent a GameObject (or detach to root). |
| [`set_active`](commands/gameobjects-and-components.md#set_active) | Set a GameObject's active state. |
| [`set_tag`](commands/gameobjects-and-components.md#set_tag) | Set a GameObject's tag. |
| [`set_layer`](commands/gameobjects-and-components.md#set_layer) | Set a GameObject's layer. |
| [`rename_gameobject`](commands/gameobjects-and-components.md#rename_gameobject) | Rename a GameObject. |
| [`delete_gameobject`](commands/gameobjects-and-components.md#delete_gameobject) | Delete a GameObject (undoable). |
| [`add_component`](commands/gameobjects-and-components.md#add_component) | Add a component by type name. |
| [`remove_component`](commands/gameobjects-and-components.md#remove_component) | Remove a component. |
| [`get_component_properties`](commands/gameobjects-and-components.md#get_component_properties) | Read a component's serialized properties. |
| [`set_component_properties`](commands/gameobjects-and-components.md#set_component_properties) | Set a component's serialized properties. |
### Prefab commands
| Command | Description |
|---------|-------------|
| [`create_prefab`](commands/prefabs.md#create_prefab) | Save a GameObject as a prefab. |
| [`instantiate_prefab`](commands/prefabs.md#instantiate_prefab) | Instantiate a prefab into a scene. |
| [`create_prefab_variant`](commands/prefabs.md#create_prefab_variant) | Create a prefab variant. |
| [`apply_prefab_overrides`](commands/prefabs.md#apply_prefab_overrides) | Apply instance overrides to the source. |
| [`revert_prefab_overrides`](commands/prefabs.md#revert_prefab_overrides) | Revert instance overrides. |
| [`unpack_prefab`](commands/prefabs.md#unpack_prefab) | Unpack a prefab instance. |
| [`save_prefab_contents`](commands/prefabs.md#save_prefab_contents) | Edit a prefab in an isolated stage and save. |
### Script commands
| Command | Description |
|---------|-------------|
| [`create_script`](commands/scripts.md#create_script) | Create a C# script from a template. |
| [`attach_script`](commands/scripts.md#attach_script) | Attach a MonoBehaviour by type / asset. |
| [`set_serialized_field`](commands/scripts.md#set_serialized_field) | Set a serialized field on a component / asset. |
| [`get_serialized_fields`](commands/scripts.md#get_serialized_fields) | Read serialized fields. |
### Animation commands
| Command | Description |
|---------|-------------|
| [`create_animation_clip`](commands/animation.md#create_animation_clip) | Create an empty .anim AnimationClip. |
| [`set_animation_curve`](commands/animation.md#set_animation_curve) | Add / replace a float curve on a clip. |
| [`get_animation_clip`](commands/animation.md#get_animation_clip) | Read a clip's curves and metadata. |
| [`remove_animation_curve`](commands/animation.md#remove_animation_curve) | Remove a curve binding (needs confirm). |
| [`create_animator_controller`](commands/animation.md#create_animator_controller) | Create an .controller AnimatorController. |
| [`add_animator_parameter`](commands/animation.md#add_animator_parameter) | Add a parameter to a controller. |
| [`add_animator_layer`](commands/animation.md#add_animator_layer) | Add a layer to a controller. |
| [`add_animator_state`](commands/animation.md#add_animator_state) | Add a state to a layer. |
| [`add_animator_transition`](commands/animation.md#add_animator_transition) | Add a transition between states. |
| [`get_animator_controller`](commands/animation.md#get_animator_controller) | Read a controller's full structure. |
| [`create_timeline`](commands/animation.md#create_timeline) | Create a .playable Timeline asset. |
| [`add_timeline_track`](commands/animation.md#add_timeline_track) | Add a track to a Timeline. |
| [`add_timeline_clip`](commands/animation.md#add_timeline_clip) | Add a clip to a Timeline track. |
| [`get_timeline`](commands/animation.md#get_timeline) | Read a Timeline's structure. |
### Material & shader commands
| Command | Description |
|---------|-------------|
| [`get_material_properties`](commands/materials.md#get_material_properties) | Read a material's shader and properties. |
| [`set_material_properties`](commands/materials.md#set_material_properties) | Set material shader properties / keywords. |
| [`list_shaders`](commands/materials.md#list_shaders) | Discover available shaders. |
| [`get_shader_properties`](commands/materials.md#get_shader_properties) | Introspect a shader's property list. |
### Baking commands
| Command | Description |
|---------|-------------|
| [`bake_lighting`](commands/baking.md#bake_lighting) | Async lightmap bake (poll `lighting_bake_status`). |
| [`lighting_bake_status`](commands/baking.md#lighting_bake_status) | Status of the last lighting bake. |
| [`cancel_lighting_bake`](commands/baking.md#cancel_lighting_bake) | Cancel an in-progress lighting bake. |
| [`clear_baked_lighting`](commands/baking.md#clear_baked_lighting) | Clear baked lightmaps (needs confirm). |
| [`get_lighting_settings`](commands/baking.md#get_lighting_settings) | Read the active LightingSettings. |
| [`set_lighting_settings`](commands/baking.md#set_lighting_settings) | Apply a subset of lighting settings. |
| [`bake_navmesh`](commands/baking.md#bake_navmesh) | Async legacy NavMesh bake (poll `navmesh_bake_status`). |
| [`navmesh_bake_status`](commands/baking.md#navmesh_bake_status) | Status of the last NavMesh bake. |
| [`cancel_navmesh_bake`](commands/baking.md#cancel_navmesh_bake) | Cancel an in-progress NavMesh bake. |
| [`clear_navmesh`](commands/baking.md#clear_navmesh) | Clear the baked NavMesh (needs confirm). |
| [`get_navmesh_settings`](commands/baking.md#get_navmesh_settings) | Read legacy NavMesh bake settings. |
| [`set_navmesh_settings`](commands/baking.md#set_navmesh_settings) | Apply a subset of NavMesh settings. |
| [`bake_navmesh_surfaces`](commands/baking.md#bake_navmesh_surfaces) | Bake NavMeshSurface components (AI Navigation). |
| [`bake_occlusion_culling`](commands/baking.md#bake_occlusion_culling) | Async occlusion bake (poll `occlusion_bake_status`). |
| [`occlusion_bake_status`](commands/baking.md#occlusion_bake_status) | Status of the last occlusion bake. |
| [`cancel_occlusion_bake`](commands/baking.md#cancel_occlusion_bake) | Cancel an in-progress occlusion bake. |
| [`clear_occlusion_culling`](commands/baking.md#clear_occlusion_culling) | Clear baked occlusion data (needs confirm). |
### Navigation & selection commands
| Command | Description |
|---------|-------------|
| [`get_selection`](commands/navigation.md#get_selection) | Read the current Editor selection. |
| [`set_selection`](commands/navigation.md#set_selection) | Set the Editor selection. |
| [`search`](commands/navigation.md#search) | Run a Unity Search query. |
### Capture commands
| Command | Description |
|---------|-------------|
| [`capture_game_view`](commands/capture.md#capture_game_view) | Render a camera to a PNG (base64). |
| [`capture_scene_view`](commands/capture.md#capture_scene_view) | Render the Scene View to a PNG (base64). |
| [`capture_editor_element`](commands/capture.md#capture_editor_element) | Capture a UI Toolkit element from an EditorWindow (6000.7+). |
| [`capture_runtime_element`](commands/capture.md#capture_runtime_element) | Capture a UI Toolkit element from a runtime panel (6000.7+). |
### Build, compilation & test commands
| Command | Description |
|---------|-------------|
| [`build`](commands/build-and-compilation.md#build) | Async Player build (poll `build_status`). |
| [`build_status`](commands/build-and-compilation.md#build_status) | Status / report of the current build. |
| [`switch_build_target`](commands/build-and-compilation.md#switch_build_target) | Switch the active build target (needs confirm). |
| [`switch_build_target_status`](commands/build-and-compilation.md#switch_build_target_status) | Status of the last target switch. |
| [`list_build_targets`](commands/build-and-compilation.md#list_build_targets) | List known build targets. |
| [`get_build_settings`](commands/build-and-compilation.md#get_build_settings) | Read build configuration. |
| [`set_build_settings`](commands/build-and-compilation.md#set_build_settings) | Set build configuration fields. |
| [`list_build_profiles`](commands/build-and-compilation.md#list_build_profiles) | List Build Profile assets (Unity 6). |
| [`recompile`](commands/build-and-compilation.md#recompile) | Force a script recompile (poll `recompile_status`). |
| [`recompile_status`](commands/build-and-compilation.md#recompile_status) | Status of the last recompile. |
| [`list_tests`](commands/build-and-compilation.md#list_tests) | List available tests without running. |
| [`run_tests`](commands/build-and-compilation.md#run_tests) | Run Unity tests with filters. |
| [`test_status`](commands/build-and-compilation.md#test_status) | Status of async test execution. |
| [`cancel_tests`](commands/build-and-compilation.md#cancel_tests) | Cancel running tests. |
### Project settings commands
| Command | Description |
|---------|-------------|
| [`get_audio_settings`](commands/project-settings.md#get_audio_settings) | Read Audio settings. |
| [`set_audio_settings`](commands/project-settings.md#set_audio_settings) | Change Audio settings (needs confirm). |
| [`get_graphics_settings`](commands/project-settings.md#get_graphics_settings) | Read Graphics settings. |
| [`set_graphics_settings`](commands/project-settings.md#set_graphics_settings) | Set the default render pipeline (needs confirm). |
| [`get_input_settings`](commands/project-settings.md#get_input_settings) | Read legacy Input Manager axes. |
| [`set_input_settings`](commands/project-settings.md#set_input_settings) | Tune a legacy input axis (needs confirm). |
| [`get_physics_settings`](commands/project-settings.md#get_physics_settings) | Read Physics settings. |
| [`set_physics_settings`](commands/project-settings.md#set_physics_settings) | Change Physics settings (needs confirm). |
| [`get_player_settings`](commands/project-settings.md#get_player_settings) | Read PlayerSettings. |
| [`set_player_settings`](commands/project-settings.md#set_player_settings) | Change PlayerSettings (needs confirm). |
| [`get_quality_settings`](commands/project-settings.md#get_quality_settings) | Read QualitySettings. |
| [`set_quality_settings`](commands/project-settings.md#set_quality_settings) | Change QualitySettings (needs confirm). |
| [`get_tags_layers`](commands/project-settings.md#get_tags_layers) | Read tags and layers. |
| [`set_tags_layers`](commands/project-settings.md#set_tags_layers) | Add / remove tags, name layers (needs confirm). |
| [`get_time_settings`](commands/project-settings.md#get_time_settings) | Read Time settings. |
| [`set_time_settings`](commands/project-settings.md#set_time_settings) | Change Time settings (needs confirm). |
### Package Manager commands
| Command | Description |
|---------|-------------|
| [`package_list`](commands/package-manager.md#package_list) | List packages by scope. |
| [`package_search`](commands/package-manager.md#package_search) | Search the registry. |
| [`package_add`](commands/package-manager.md#package_add) | Add a UPM package (needs confirm). |
| [`package_remove`](commands/package-manager.md#package_remove) | Remove a UPM package (needs confirm). |
| [`package_resolve`](commands/package-manager.md#package_resolve) | Resolve / refresh packages. |
| [`package_status`](commands/package-manager.md#package_status) | Status of the last package operation. |
### Editor lifecycle & observability commands
| Command | Description |
|---------|-------------|
| [`editor_play`](commands/editor-lifecycle-and-observability.md#editor_play) | Enter play mode. |
| [`editor_stop`](commands/editor-lifecycle-and-observability.md#editor_stop) | Exit play mode. |
| [`editor_pause`](commands/editor-lifecycle-and-observability.md#editor_pause) | Pause play mode. |
| [`editor_status`](commands/editor-lifecycle-and-observability.md#editor_status) | Detailed Editor status. |
| [`editor_focus`](commands/editor-lifecycle-and-observability.md#editor_focus) | Bring the Editor to the foreground. |
| [`menu`](commands/editor-lifecycle-and-observability.md#menu) | Execute (or list) Editor menu items. |
| [`screenshot`](commands/editor-lifecycle-and-observability.md#screenshot) | Capture Scene / Game view to a PNG file. |
| [`set_autotick`](commands/editor-lifecycle-and-observability.md#set_autotick) | Keep the editor ticking while unfocused. |
| [`get_console_logs`](commands/editor-lifecycle-and-observability.md#get_console_logs) | Read captured Editor console logs. |
| [`clear_console`](commands/editor-lifecycle-and-observability.md#clear_console) | Clear the console / log buffer. |
| [`get_performance_stats`](commands/editor-lifecycle-and-observability.md#get_performance_stats) | Read render / memory / frame stats. |
| [`get_authoring_root`](commands/editor-lifecycle-and-observability.md#get_authoring_root) | Get the authoring-root folder. |
| [`set_authoring_root`](commands/editor-lifecycle-and-observability.md#set_authoring_root) | Set the authoring-root folder. |
### Runtime commands
| Command | Description |
|---------|-------------|
| [`runtime_status`](commands/runtime.md#runtime_status) | Runtime application status. |
| [`quit`](commands/runtime.md#quit) | Quit the application. |
| [`set_target_framerate`](commands/runtime.md#set_target_framerate) | Set the target frame rate. |
| [`set_timescale`](commands/runtime.md#set_timescale) | Set the time scale. |
| [`simulate_key`](commands/runtime.md#simulate_key) | Simulate a keyboard event (Input System). |
| [`simulate_pointer`](commands/runtime.md#simulate_pointer) | Simulate a pointer event (Input System). |
| [`log`](commands/runtime.md#log) | Write a message to the Unity console. |
| [`console`](commands/runtime.md#console) | Read captured console output. |
| [`eval`](commands/runtime.md#eval) | Evaluate C# via Roslyn. |
| [`eval_file`](commands/runtime.md#eval_file) | Evaluate C# from a .cs file. |
| [`reload_file`](commands/runtime.md#reload_file) | Apply in-place [HotReload] edits from a file. |
| [`reload_file_override`](commands/runtime.md#reload_file_override) | Compile & apply override hot reload. |
| [`hotreload_status`](commands/runtime.md#hotreload_status) | Hot reload registry status. |
| [`cleanup_hotreload`](commands/runtime.md#cleanup_hotreload) | Clear old hot reload DLLs / registry. |
@@ -0,0 +1,60 @@
# Runtime connection & setup
How to run the Pipeline server inside a built Player so a client can drive it the same way it drives the Editor. The runtime server only exists in **development builds**, so setup is mostly about building correctly.
## The `RuntimePipelineManager` component
The runtime server is owned by a `RuntimePipelineManager` MonoBehaviour. Add it to a scene via the component menu:
> **Add Component → Pipeline → Runtime Pipeline Manager**
It is `[DisallowMultipleComponent]` and survives scene loads (`DontDestroyOnLoad`); only one instance should exist. Its `Update` pumps the server's dispatcher each frame (a Player has no `EditorApplication.update` to do this) and drives the listener watchdog.
### Inspector fields
| Field | Default | Meaning |
|-------|---------|---------|
| `enableInBuilds` | `false` | Master switch. The server only starts when this is `true`. **Off by default for safety.** |
| `autoStart` | `true` | Start the server automatically in `Start()` (requires `enableInBuilds`). |
| `port` | `0` | Listen port. `0` = auto-assign from `7900``7949`. |
| `requestTimeoutMs` | `30000` | Per-request timeout. |
| `enableAuditLogging` | `true` | Log remote requests for auditing. |
| `maxWorkItemsPerFrame` | `10` | Dispatcher work items processed per frame. |
If `autoStart` is off you can start/stop manually with `StartServer()` / `StopServer()`.
## Development-build gating
The runtime server, code evaluation, and hot reload are all gated behind a compile-time guard:
```csharp
#if UNITY_EDITOR || (UNITY_STANDALONE && DEBUG)
```
`DEBUG` is defined for **standalone Development Builds** only. In a non-development (release) build the compilation/eval/hot-reload code is compiled out entirely, so it cannot run — even if `enableInBuilds` is `true`. To use the runtime server in a Player you therefore need **both**:
1. A **Development Build** (defines `DEBUG`), built for a **standalone** target (Windows/macOS/Linux).
2. `enableInBuilds = true` on the `RuntimePipelineManager`.
## Step-by-step: enable in a dev build
1. Add a **Runtime Pipeline Manager** component to a GameObject in your startup scene (component menu *Pipeline → Runtime Pipeline Manager*).
2. Tick **`enableInBuilds`** on that component. Leave `autoStart` on and `port` at `0` (auto).
3. Open **File → Build Settings** and enable **Development Build** for a **Standalone** platform.
4. Build and run the Player.
5. On start, the manager creates a `RuntimePipelineServer`, which binds the first free port in `7900``7949` and writes the runtime descriptor `.unity-pipeline-runtime-port` (with `port` and `evalToken`).
6. Connect a client using that port and token.
## Security
The runtime server applies the same protections as the editor server (see [Connectivity](connectivity.md)):
- It binds the **IPv4 loopback** (`http://127.0.0.1:<port>/`, plus the `localhost` hostname), so it is reachable only from the same machine and never exposed on a routable interface. Clients should connect to `127.0.0.1` explicitly — see [Loopback-only binding](connectivity.md#loopback-only-binding) for why `localhost` can resolve to the IPv6 loopback (`::1`), which Unity's Mono `HttpListener` cannot serve.
- Every request must present `Authorization: Bearer <evalToken>`; the token is generated at startup and published in the runtime descriptor.
Because the server exposes code evaluation and hot reload, only enable it in development/QA builds — never in a production build without additional safeguards.
## See also
- [Connectivity](connectivity.md) — ports, descriptor file, and auth in detail.
- [Hot reload](hot-reload.md) — applying live code changes to a running Player.
@@ -0,0 +1,90 @@
# Safety & mutations
Mutating commands — asset writes, project-settings changes, package/build changes —
share two conventions so command authors and clients know what to expect: a `confirm`/`dry_run` gate
on destructive or overwriting operations, and Undo grouping via `AuthoringUndoScope`. Commands that
resolve caller-supplied asset paths confine them with `ProjectPaths` (see
[Creating authoring commands](authoring-commands.md)). The helpers live in `Editor/Authoring/`.
### The confirm / dry_run convention
Destructive or overwriting commands expose two boolean `[CliArg]`s — `confirm` and `dry_run` — and
gate their own mutation on them. There is no central dispatcher; each command applies the same simple
rules inline:
- **`dry_run == true`** → validate and describe the intended change, mutate nothing, return a preview.
This wins even if `confirm` is also true.
- **`confirm == false`** (and not a dry run) → refuse without mutating. Return the failure the way the
command reports its other errors — `throw new ArgumentException(...)` for the throwing style (e.g.
`delete_asset`, `clear_baked_lighting`), or a structured error object for commands that return
structured results (e.g. `build`, which returns `{ success = false, status = "error", message = "…" }`).
- **otherwise** (`confirm == true`, not a dry run) → perform the mutation. Group *scene/object*
mutations in an `AuthoringUndoScope` (see below). Asset/settings/package writes are **not** part of
Unity's Undo, so they run directly — say so in the command description ("Not undoable via Ctrl+Z.").
```csharp
[CliCommand("clear_baked_lighting", "Clear baked lightmap data for the open scene(s). Destructive: requires confirm=true (use dry_run to preview). Not undoable via Ctrl+Z.")]
public static object ClearBakedLighting(
[CliArg("confirm", "Apply the clear. Without it the call is refused.")] bool confirm = false,
[CliArg("dry_run", "Preview what would be cleared without clearing it.")] bool dryRun = false)
{
// …resolve the open scene(s)…
if (dryRun)
return new { status = "dry_run", wouldClear = true };
if (!confirm)
throw new ArgumentException("Refusing to clear baked lighting. Pass confirm=true to apply, or dry_run=true to preview.");
// Clearing baked GI is not part of Unity's Undo — no AuthoringUndoScope.
Lightmapping.Clear();
return new { cleared = true };
}
```
Purely additive, non-destructive commands (e.g. `create_folder`, `add_animator_parameter`)
do not take `confirm`/`dry_run`; they just perform the mutation directly.
### Undo grouping
Scene/object mutations are grouped with `AuthoringUndoScope` so a multi-step command reverts as a
single Ctrl+Z step. It increments Unity's current Undo group on construction and calls
`Undo.CollapseUndoOperations` on dispose, collapsing everything the body registers — via
`Undo.RecordObject`, `Undo.RegisterCreatedObjectUndo`, and similar — into one named step. The command
opts into Undo by calling those APIs inside the scope. See
[Creating authoring commands](authoring-commands.md) for the full pattern and the per-mutation `Undo`
API table.
> **Caveat.** Some operations are not part of Unity's Undo system. `AssetDatabase` operations, UPM
> package changes, and settings backed by native assets may not be undoable; for those the collapse is
> simply a no-op and Ctrl+Z will not revert the change. Don't rely on Undo to clean up such writes —
> validate up front and fail before writing.
### Path confinement
Commands that accept a caller-supplied asset path resolve it through `ProjectPaths.Resolve`, which
normalizes the path, rejects `..` traversal, and confines it to the configurable authoring root
(default `Assets`) so agent-supplied paths cannot escape the project. It returns a project-relative
path, or `null` with an `error` string when the path escapes the root.
```csharp
var normalized = ProjectPaths.Resolve(path, out var error);
if (normalized == null)
throw new ArgumentException(error);
// normalized is project-relative and guaranteed to live under the authoring root.
```
See [Creating authoring commands](authoring-commands.md) for the full path-handling rules and the
`set_authoring_root` / `get_authoring_root` commands that adjust the root.
### For command authors
To make a mutating command safe:
1. If the operation is destructive or overwrites existing content, add `confirm` and `dry_run` boolean
`[CliArg]`s and gate on them inline (preview on `dry_run`, refuse on `!confirm`).
2. Group scene/object mutations in `using (new AuthoringUndoScope("<operation>"))` and register Undo
operations inside it where the mutation is undoable.
3. Resolve any caller-supplied asset path through `ProjectPaths.Resolve` before touching the filesystem
— ideally during validation, so a bad path fails before anything is applied.
See [Creating commands](creating-commands.md) and [Creating authoring commands](authoring-commands.md).
@@ -0,0 +1,95 @@
# Tests architecture
How the package's tests exercise commands. There are two complementary styles — **ViaClient** (over real HTTP, end-to-end) and **CommandDirect** (calling the static command method straight) — backed by a small set of shared test helpers.
## Two test styles
### ViaClient — exercise the full HTTP path
Spin up an isolated `PipelineTestServer` and call `server.Execute(command, params)`. This goes over HTTP through the same routing, parameter coercion, and threading the real server uses — it tests the command *as a client sees it*.
```csharp
[Test]
public void SetTransform_ViaClient_ArrayParams_Apply()
{
var go = Track(new GameObject("Xform219_Arrays"));
using (var server = new PipelineTestServer())
{
var response = server.Execute("set_transform", new
{
target = new { instanceId = PipelineUtils.GetObjectId(go) },
position = new[] { 1f, 2f, 3f },
rotation = new[] { 0f, 90f, 0f },
scale = new[] { 2f, 2f, 2f }
});
Assert.IsTrue(response.IsSuccess, $"set_transform should succeed: {response.Error}");
Assert.AreEqual(new Vector3(1, 2, 3), go.transform.localPosition);
}
}
```
The test server is isolated: it uses the **test editor port range `7850``7899`** and **writes no descriptor**, so it never disturbs the live editor server (which uses `7800``7849`). `Execute` pumps the server's own dispatcher while the HTTP call is in flight, so `MainThreadRequired` commands complete even from a plain `[Test]` that blocks the main thread — no deadlock.
### CommandDirect — call the static method directly
Call the command's static method with typed arguments. This is synchronous, with **no server, HTTP, or dispatcher** involved — fast and ideal for unit-testing command logic and parameter handling.
```csharp
[Test]
public void SetTransform_Direct_TypedArrays_Apply()
{
var go = Track(new GameObject("Xform219_Direct"));
GameObjectCommands.SetTransform(RefTo(go),
position: new[] { 1f, 2f, 3f },
rotation: new[] { 0f, 90f, 0f },
scale: new[] { 2f, 2f, 2f });
Assert.AreEqual(new Vector3(1, 2, 3), go.transform.localPosition);
Assert.AreEqual(new Vector3(2, 2, 2), go.transform.localScale);
}
```
Use **CommandDirect** to verify a command's behavior with strongly-typed inputs; use **ViaClient** to additionally verify wire-level concerns (JSON coercion, required-parameter validation, threading).
## Shared helpers
| Helper | Role |
|--------|------|
| `PipelineTestServer` | Disposable wrapper that starts an isolated `TestEditorPipelineServer`, wires up a `PipelineClient`, and exposes `Execute(command, parameters, timeoutMs = 30000)`. Pumps the server dispatcher during each call to avoid main-thread deadlock. |
| `TestEditorPipelineServer` | `EditorPipelineServer` subclass for tests. Overrides `WritesDescriptor => false`, `GetPortRange() => (7850, 7899)`, and `GetToken()` (from `SecurityTokenManager`) so it is fully isolated from the live server. |
| `PipelineClient` | Test-side HTTP client. Constructed from a URL+token or a server/manager instance. Key methods: `ExecuteCommandAsync` (`/api/exec`), `GetStatusAsync` (`/api/status`), `PostJsonAsync`. Returns a `PipelineResponse` (`IsSuccess`, `StatusCode`, `Error`, `JsonResponse`, `IsCommandSuccess`). |
| `EditorTestUtilities` | Async helpers for editor state, e.g. `WaitFor(Func<bool> condition, timeoutMs)` to poll a condition without busy-waiting. |
| `LiveServerGuard` | Assembly-level `ITestAction` that asserts the **live editor server survives the test run**. |
### `PipelineTestServer` setup
```csharp
public PipelineTestServer()
{
m_Server = new TestEditorPipelineServer();
m_Server.Start(); // auto-assigns a port in 7850-7899; writes no descriptor
m_Client = new PipelineClient($"http://localhost:{m_Server.Port}", SecurityTokenManager.GetOrCreateToken());
}
```
Wrap it in a `using` (it is disposable) so the isolated server is stopped at the end of the test.
### `LiveServerGuard`
Applied once at assembly scope (`[assembly: LiveServerGuard]`), it runs before and after **every** test in the editor suite. If a live editor server was advertising its descriptor before a test, the guard asserts afterwards that the test did not disturb it — the descriptor still exists, the port is unchanged, and the server is still listening:
```csharp
Assert.IsNotNull(after, $"'{test.Name}' deleted the live pipeline server descriptor");
Assert.AreEqual(m_Before.Port, after.Port, $"'{test.Name}' changed the port");
Assert.IsTrue(IsListening(after.Port, after.EvalToken), $"'{test.Name}' left the server not responding");
```
This is what makes it safe to "dogfood" — run the test suite against the very editor you are driving — without a test clobbering the live server. Tests that intentionally start/stop the live server are marked `[Explicit]` and must hand it back intact.
## See also
- [Creating commands](creating-commands.md) — the command API these tests exercise.
- [Connectivity](connectivity.md) — ports, descriptor, and auth (the test server deliberately skips the descriptor).