unity-control-protocol · v0.6.3 · 2026-09-11 · sha256 90e53b62955e231c

unity-control-protocol v0.6.3A

Immutable. This exact content is served forever at /api/v1/blob/90e53b62955e231c.

---
name: unity-control-protocol
description: >-
  Programmatic control of the Unity Editor from the terminal via the `ucp` CLI.
  Automate scenes, GameObjects, components, assets, materials, prefabs, build
  pipelines, UI Toolkit UXML/USS, settings, tests, packages, selective `.unitypackage` import, debugging and profiling
  over a WebSocket/JSON-RPC 2.0
  bridge. Use when the user asks to inspect, create, modify, or automate anything
  inside a Unity project without opening the Editor UI.
compatibility: Requires the `ucp` CLI (install via npm, cargo, or binary) and the UCP Bridge package installed in the target Unity project. Unity 2021.3+ required.
metadata:
  author: mflRevan
  version: '0.6.3'
  homepage: https://github.com/mflRevan/unity-control-protocol
---

# Unity Control Protocol (UCP)

UCP is a cross-platform CLI + Unity Editor bridge. The CLI (`ucp`) sends commands over WebSocket to a bridge package running inside the Unity Editor, which executes them via JSON-RPC 2.0 and returns results. Every command supports `--json` for machine-readable output.

UCP and Unity expose a broad command surface. If you are unsure what is available in any area, prefer `ucp --help` and `ucp <command> --help` first to discover the current control surface before guessing.

## When to use this skill

- The user wants to inspect or modify GameObjects, components, materials, prefabs, or assets
- The user asks to enter/exit play mode, run tests, capture screenshots or recordings, or read logs
- The user needs to manage scenes, project settings, build pipelines, or scripting defines
- The user needs to browse/install Unity packages, manage scoped registries, or selectively import `.unitypackage` content
- The user wants to automate entire Unity Editor workflows
- The user wants to find all references to an asset, script, material, or prefab across the project
- The user wants to lint, inspect, populate, screenshot, or verify UI Toolkit UXML and USS

## When NOT to use this skill

- The user is writing C# game code without needing editor automation
- The user is working in a non-Unity project

## Setup & connection

Start here whenever bridge state is unknown:

```bash
ucp doctor
ucp open
ucp connect
ucp install
ucp bridge status
```

Use `ucp <command> --help` for flags such as `--project`, `--json`, `--unity`, `--timeout`, `--dialog-policy`, and bridge update controls.

`ucp connect` and other bridge-backed commands can auto-start Unity when the project and editor path are resolvable. If startup stalls on dialogs, use `--dialog-policy ...`. If you need machine-readable output, prefer `--json`.

## Core agent guidance

- Prefer direct workspace edits when you already have normal filesystem access always followed by `ucp compile`.
- Use `ucp files ...` as a sandboxed fallback for bridge-mediated project file I/O.
- Run `ucp scene snapshot` before object or prefab work to discover instance IDs.
- Treat instance IDs as short-lived handles; refresh them after compilation, reloads, package changes, scene loads, or test runs.
- For imported assets such as FBX, textures, and audio, prefer `ucp asset import-settings ...` over raw `.meta` file edits.
- `ucp files write` and `ucp files patch` automatically reimport edited Unity assets and `.meta` files under `Assets/` and `Packages/` unless you pass `--no-reimport`.
- Prefer `ucp packages add|remove` for normal Package Manager installs and `ucp packages dependency ...` for explicit manifest-driven local `file:` references.
- Prefer `cm` for normal Unity Version Control work; use `ucp vcs` only as a lightweight fallback.

## Editor state after every command

Every command that reaches the bridge ends with a dim `[editor] ...` line (and an `editor` object in `--json` envelopes): edit/play/paused mode, the active scene with `(dirty)`/`(untitled)`, the console's error and warning counts, plus `(+N errors from this command)` when your last command logged something. Read it. `COMPILE ERRORS`, `compiling`, `importing assets`, `prefab stage <path>`, or `MODAL "<title>"` in that line changes what you should do next: check `ucp compile` or `ucp logs tail --level error`, wait, or answer the dialog.

If a command fails immediately with `Unity is blocked by a modal dialog "<title>" [buttons]`, the editor's main thread is stuck on a prompt. Known Unity prompts are answered for you per `--dialog-policy`; anything else is left for you to decide:

```bash
ucp editor dialog                        # list open dialogs and their buttons
ucp editor dialog --answer "Don't Save"  # press one (case-insensitive, substring ok)
```

## Scene & editor basics

If unsure, inspect the full surface with `ucp scene --help` and `ucp editor --help`.

```bash
ucp scene snapshot --filter "Player"
ucp scene save # save active scene before loading another
ucp scene load Assets/Scenes/Level1.unity
ucp scene load Assets/Scenes/Lighting.unity --additive
ucp scene focus --id 46894 --axis 1 0 0

ucp editor status
ucp play
ucp stop
ucp compile
```

## Objects, assets, materials, and prefabs

Use `ucp object --help`, `ucp asset --help`, `ucp material --help`, and `ucp prefab --help` for the full command set.

```bash
ucp object get-fields --id 46894 --component Transform
ucp object set-property --id 46894 --component BoxCollider --property m_IsTrigger --value true

ucp asset search -t Material --max 10
ucp asset search -n '^SCN_[0-9]+$' --regex
ucp asset move "Assets/Legacy/Enemy.prefab" "Assets/Characters/Enemy.prefab"
ucp asset bulk-move --moves '[{"from":"Assets/Legacy/Enemy.mat","to":"Assets/Characters/Materials/Enemy.mat"}]' --dry-run
ucp asset import-settings write "Assets/Textures/HUD.png" --field m_IsReadable --value true
ucp asset reimport "Assets/Generated" --recursive

ucp material set-property --path "Assets/Materials/Agent.mat" --property _Metallic --value "0.5"
ucp prefab apply --id -136722
```

Object reference writes accept `instanceId`, asset `path`, or asset `guid`, and unresolved references fail explicitly.

Use `ucp asset move` / `bulk-move` for Unity-aware renames and folder cleanup instead of raw filesystem moves. That keeps `.meta` files and GUIDs intact so scenes, prefabs, build settings, and serialized object references continue to resolve.

## UI Toolkit authoring and verification

Use `ucp ui` on Unity 6+ to close the loop after editing UXML, USS, or a strict `.ucp-ui.json` scenario. Lint is the fast importer/schema pass; inspect reports bounded resolved layout and binding state; screenshot provides visual evidence; check runs all of them with cleanup.

```bash
ucp ui list --root Assets/UI
ucp ui lint Assets/UI/Inventory.ucp-ui.json --fail-on-warnings
ucp ui inspect Assets/UI/Inventory.ucp-ui.json --state populated --query '#cards' --json
ucp ui screenshot Assets/UI/Inventory.ucp-ui.json --state populated -o artifacts/inventory.png --force
ucp ui check Assets/UI/Inventory.ucp-ui.json --all-states --out-dir artifacts/ui --force --json
```

Use ordinary UXML `DataBinding` paths. Scenario data is JSON, and the harness adapts those paths to dictionary keys. Use `repeat` for small eager grids and harness-managed `list-view` collections for large virtualized lists. Width and height are an explicit pair; omit both to preserve a scenario viewport. Inspection, screenshot, and check briefly focus a transient Editor window and require a graphics device; lint also works headless.

## In-scene authoring & spatial workflows

For building and arranging scene content, use the dedicated transform/spatial/view commands rather
than raw serialized-property writes. See `ucp transform --help`, `ucp spatial --help`, `ucp view --help`.

```bash
# Create VISIBLE objects with --primitive. A plain `object create` makes an EMPTY object with no
# mesh (it will not render). --primitive is the only way to add a built-in mesh from the CLI.
ucp object create Floor --primitive Plane
ucp object create Crate --primitive Cube

# Author transforms directly (Euler degrees, world|local, --relative for offsets).
ucp transform move --id 1234 --to 3 0 0
ucp transform rotate --id 1234 --euler 0 45 0
ucp transform scale --id 1234 --uniform 2
ucp transform look-at --id 1234 --target 0 0 0       # or --target-id <id>

# Place objects on surfaces and reason about geometry.
ucp spatial ground --id 1234                          # drop onto the surface below
ucp spatial raycast --origin 0 10 0 --direction 0 -1 0
ucp spatial bounds --id 1234                          # world AABB (center/size/min/max)
ucp spatial nearest --point 0 0 0 --max 5

# See the scene. isolate/orbit render a single object so a vision model can read its 3D shape.
ucp view capture --target-id 1234 --max-edge 768 --output framed.png
ucp view isolate --id 1234 --output hero.png          # composite Front/Right/Back/Top grid
ucp view orbit --id 1234 --count 6 --output orbit.png
```

Objects are addressed by `--id` (from `ucp scene snapshot`), `--path` "Root/Child", or `--name`.
Prefer `--primitive` for cubes/spheres/etc.; `object instantiate` is only for prefab assets under
`Assets/`, not for built-in primitives.

## Packages, settings, build, logs, tests, profiler, and exec

Use `ucp packages --help`, `ucp settings --help`, `ucp build --help`, `ucp logs --help`, `ucp record --help`, `ucp run-tests --help`, `ucp profiler --help`, and `ucp exec --help` when you need the full surface.

```bash
ucp packages add com.unity.cinemachine
ucp packages dependency set com.company.tooling file:../tooling-package
ucp packages unitypackage inspect Downloads/EnvironmentPack.unitypackage

ucp settings player
ucp settings set-player --key runInBackground --value true
ucp settings set-lighting --key fog --value true

ucp build targets
ucp build start --output "Builds/Game.exe"

ucp logs --pattern "NullReference|Exception" --count 100
ucp run-tests --mode edit --filter "UCP.Bridge.Tests.ControllerSmokeTests.LogsTail_ReturnsRequestedBufferedCount"
ucp profiler summary --limit 5
ucp exec run SetupScene
ucp record capture --duration 5 --view game --output playtest.mp4
```

Prefer fully qualified test names when filtering, and use `--json` for structured log or test consumption.

For motion, timing, or transient-state inspection, prefer a short recording over many screenshots.
`ucp record capture` waits for a finalized file; `record start`/`stop` surrounds command sequences
that do not reload the domain; `exec run --record <path>` captures a script with lead/tail context.
Use `record arm --on
play-enter|play-exit|log:<regex>|signal:<name>` for event-driven clips, then inspect `record status`.
Defaults are a silent 960px-long-edge, aspect-preserving 15fps clip with no injected scene objects.
When the clip is for a model rather than a person, add `--slowdown <factor>`: multimodal models
sample a video at roughly one frame per second, so a short clip arrives as a handful of frames and
sub-second motion is invisible. `--slowdown` stretches playback only -- same captured frames, no
re-encode -- so a fixed-rate sampler gets several samples per gameplay second. `--view game` records
`Camera.main`, not the Game view's camera stack; use `--view scene` for a fixed vantage point that
does not follow the player.

## Reference search

Use `ucp references --help` for the full surface. Reference queries are read-only and do not require a running editor when native Rust indexing is available (Force Text + Visible Meta Files).

```bash
# Check native indexing compatibility
ucp references check

# Check outgoing references after a move/rename
ucp references check Assets/Prefabs

# Find all references to a material
ucp references find --asset "Assets/Materials/Agent.mat"

# Find by GUID
ucp references find --asset 933532a4fcc9baf4fa0491de14d08ed7

# Summary detail for minimal context bloat
ucp references find --asset "Assets/Scripts/PlayerController.cs" --detail summary

# JSON output for structured consumption
ucp references find --asset "Assets/Prefabs/Enemy.prefab" --json --detail normal

# Find string-based references Unity will not migrate automatically
ucp references find-strings --pattern "SCN_Menu"

# Force bridge fallback (requires running editor)
ucp references find --asset "Assets/Materials/Agent.mat" --approach bridge
```

Use `--detail summary` in general workflows to minimize context bloat — repetitive patterns (e.g., 200 MeshRenderers referencing one material) collapse to a single count line. Use `--detail verbose` only for small, targeted result sets.

Use `references check <path>` after refactors for fast missing-target verification, and `references find-strings` when custom string IDs or scene-path fields need manual migration help beyond GUID-safe asset moves.

## Version control (Plastic SCM / Unity VCS)

```bash
ucp vcs
```

Prefer the native `cm` CLI for Unity VCS when it's available. Use `ucp vcs` as a lightweight fallback that prints the currently available bridge-backed VCS commands and flags.

## Common workflows

### Spatial scene iteration loop

```bash
ucp scene snapshot --filter "Player"
ucp scene focus --id 46900 --axis 1 0 0
ucp screenshot --view scene --output before.png
ucp object get-fields --id 46900 --component Rigidbody
ucp object set-property --id 46900 --component Rigidbody --property m_Mass --value "2.5"
ucp screenshot --view scene --output after.png
```

Use this for scene-aware iteration, not just raw file editing. Snapshot gives live instance IDs, focus aligns the Scene view for repeatable screenshots, and property changes apply through Unity immediately.

### Build a scene object into a prefab workflow

```bash
ucp object create "EnemyRoot"
ucp object add-component --id -15774 --component Rigidbody
ucp object create "Visual" --parent -15774
ucp object add-component --id -15775 --component MeshRenderer
ucp prefab create --id -15774 --path "Assets/Prefabs/EnemyRoot.prefab"
ucp prefab apply --id -15774
```

Use this for bridge-native authoring loops: assemble hierarchy in-scene, attach components, then persist it as a prefab. Refresh IDs with `ucp scene snapshot` if compilation, reloads, or other editor events invalidate handles.

### Asset and importer iteration

```bash
# Preferred when you already have workspace access
<edit scripts/files locally>
ucp compile

# Fallback when you want bridge-mediated writes
ucp files write Assets/Scripts/EnemyAI.cs --content "..."

# Imported assets: update importer settings instead of hand-editing .meta
ucp asset import-settings write "Assets/Models/Enemy.fbx" --field m_GlobalScale --value 0.5
ucp asset reimport "Assets/Models/Enemy.fbx"
```

UCP is unique here because it can bridge Unity-aware apply steps: `ucp compile` handles recompilation after local edits, while `ucp files write` / `patch` automatically reimport eligible assets and `.meta` files unless you intentionally defer with `--no-reimport`.

### Package install and selective import iteration

```bash
ucp packages search com.unity.cinemachine
ucp packages add com.unity.cinemachine
ucp packages info com.unity.cinemachine

ucp packages registries add --name github --url https://npm.pkg.github.com --scope com.company
ucp packages dependency set com.company.tooling file:../tooling-package

ucp packages unitypackage inspect Downloads/EnvironmentPack.unitypackage
ucp packages unitypackage import Downloads/EnvironmentPack.unitypackage --select Assets/Environment/Trees
```

Use `packages add|remove` for normal UPM installs, `packages dependency ...` for explicit manifest references, and `packages unitypackage ...` when you need machine-friendly inspection plus selective import for archive-based content. Scoped registry adds may surface Unity's own security popup the first time a new registry is introduced.

### Playtest, logging, and failure triage

```bash
ucp compile
ucp play
ucp logs status
ucp logs --pattern "Exception|Error" --count 15
ucp stop
```

Use this loop for autonomous playtesting. If `ucp play` fails, fix compile or console-blocking errors first, then retry. Use logs for buffered inspection without needing to stream the entire editor log. `ucp logs status` returns curated/collapsed stats.

### Profiling and debugging

```bash
ucp profiler status
ucp profiler session start --mode play
ucp play
ucp profiler frames list --limit 1 --json
ucp profiler summary --limit 10
ucp profiler timeline --frame <fresh-frame> --thread 0 --limit 20
ucp profiler hierarchy --frame <fresh-frame> --thread 0 --limit 20
ucp profiler capture save --output ProfilerCaptures/session.json
ucp profiler session stop
ucp stop
```

Use profiler commands when debugging performance, spikes, or hot paths. Prefer grabbing a fresh frame id from `ucp profiler frames list` immediately before `timeline`, `hierarchy`, or `callstacks`, because live editor frame ids churn quickly. `summary` is intentionally bounded to recent frames by default, and `capture save --output *.json` exports a structured snapshot for agents/scripts without relying on unsupported live editor raw-binary logging.

### CI / validation pass

```bash
ucp connect || exit 1
ucp run-tests --mode edit
ucp build set-defines "CI;RELEASE"
ucp build start --output "Builds/Game.exe"
```

### Quick scene audit and debug snapshot

```bash
ucp scene snapshot --json > hierarchy.json
ucp logs --level error
ucp screenshot
```

This is a compact handoff workflow for agents: capture hierarchy state, inspect current errors, and grab a visual snapshot before deciding on the next action.