domains / software-engineering / unity-editor-cli-control / unity-cli

unity-cli

Skill card

combined

The two copies describe different, non-interchangeable procedures for the same skill name. The Unity-Technologies copy is the upstream CLI skill: it drives a running Editor via the Pipeline package, covers installation, global flags, and live command execution. The Besty0728 copy is a community 'advisory' wrapper that gates all CLI use behind a project-specific cli_config.json, treats the CLI as experimental/beta, and focuses on cold-starting the Editor and preflight checks. Neither copy contains the other's core authorization model or primary workflow, so crowning one would hide a real alternative.

Repositories

RepositoryPath
Unity-Technologies/skillsskills/unity-cli/SKILL.md
Besty0728/Unity-SkillsSkillsForUnity/unity-skills~/skills/unity-cli/SKILL.md

Other copies

RoleRepositoryPath
peerUnity-Technologies/skillsskills/unity-cli/SKILL.md
peerBesty0728/Unity-SkillsSkillsForUnity/unity-skills~/skills/unity-cli/SKILL.md

Combined skill

---
name: unity-cli
description: Controls the Unity Editor and projects from the command line, driving a running Editor to edit scenes and assets or run C#, or cold-starting the Editor when it is closed. Use when asked to install or manage Editors, licenses, or projects, set up version control, build, test, configure the Unity MCP server, or run any unity command.
allowed-tools:
  - Bash
---

# Unity CLI

**Always use the latest version of the Unity CLI unless you are told to use a specific version.** Newer releases regularly add commands and output fields these docs describe, so an outdated CLI fails in ways that read like the docs being wrong. Check with `unity self-update --check --format json`.

## Gate — read this first (community advisory variant)

Before using anything below, check the binding config:

```
<projectRoot>/Library/UnitySkills/cli_config.json
```

- File missing, unreadable, or `enabled: false` → **Unity CLI is OFF for this project. Ignore this module entirely.** Do not suggest installing the CLI unprompted; the user opts in via `Window > UnitySkills → AI Config → Unity CLI Setup…`.
- `enabled: true` → use `cliPath` as the executable (it may not be on your PATH). Respect the per-feature switches in `features`.

The global registry (`~/.unity_skills/registry.json`) also carries `cliBound` / `cliPath` per running instance — use it for **liveness checks only, never as authorization**: the ONLY thing that authorizes CLI use for a project is that project's own `cli_config.json`. Do not cold-start any project whose own config you have not read, even if it appears in the registry.

> Unity CLI is **experimental (beta)** and its command surface changes between releases. Before using a command whose semantics changed recently, read `<cliPath> --version` and `<cliPath> <command> --help` — **`--help` is always the final authority** for the binary on disk. If a command errors unexpectedly, run `<cliPath> doctor --format json` first and re-check `--help` before retrying. Never modify the server or config to work around a CLI quirk.

## Install the CLI (if not already installed)

First check if the CLI is available:

```bash
which unity && unity --version
```

If not found, install it:

**macOS / Linux**
```bash
curl -fsSL https://unity.com/install.sh | bash
```

**Windows (PowerShell)**
```powershell
irm https://unity.com/install.ps1 | iex
```

After installing, open a new shell so `unity` is on PATH, then verify with `unity --version`. If the install script fails or the binary is still not found, tell the user and stop; if the command itself fails with a permissions error or crash, the installation may be broken — suggest re-running the install script.

## Drive a running Unity Editor (if one is open)

**If a Unity Editor is open on this machine, this CLI can control it live** — create and modify GameObjects, edit scenes and assets, inspect the hierarchy, and run arbitrary C# — through the project's **Pipeline** package (`com.unity.pipeline`). This runs entirely on your local machine, in your own user account, against your own open Editor: it is not remote access and grants no privilege you don't already have at your own terminal. When an Editor is available, drive it instead of hand-editing scene or asset files.

```bash
unity status                    # confirm a connected Editor (look for state "ready")
unity command                   # list the commands the Editor exposes
unity command editor_play       # run one — e.g. enter Play mode
# Run arbitrary C# — e.g. add a GameObject named "Joe" — when the Editor exposes eval:
unity command eval 'new UnityEngine.GameObject("Joe");'
```

> **Verifying a running game, not just editing a scene?** Entering Play mode is setup, not proof: an unfocused Editor can freeze at frame 1 while `unity status` still reports it as playing, and a screenshot can render a frozen frame that looks alive. The ordered recipe for playing, confirming the game is actually advancing, capturing the view, reading the console, and tuning it live with `eval` is in [playmode-verification-loop.md](references/playmode-verification-loop.md).

### More than one Editor open? Pass `--project-path`

Every Editor-driving command takes `--project-path <path>`. **Pass it whenever more than one Editor may be running** — without it the CLI targets the Editor whose project contains the current directory, so the target follows the shell's cwd:

```bash
unity command editor_play --project-path /path/to/MyProject
```

A `unity status` instance's `project` field is what `--project-path` takes. For `unity command`/`list`/`job`/`mcp`, matching no running project fails with `AMBIGUOUS_EDITOR` and lists the candidates.

Requires the project's `com.unity.pipeline` package (Unity 6.0+) — add it once with `unity pipeline install`. Full details — launching a headless Editor to drive, `unity list` tool discovery, and authoring custom `[CliCommand]` tools — are in [integration-advanced.md](references/integration-advanced.md).

> **Can't connect / commands time out? Check for Safe Mode first.** When a project has C# compile errors, the Editor boots into **Safe Mode**, where the Pipeline package doesn't load — so `unity command`, `unity status`, `unity list`, and `unity recompile` can't connect at all. Don't fall back to blind file-editing: run `unity pipeline list` to confirm, then fix the compile errors and restart Unity.

> **Running as a sandboxed coding agent and `unity status` reports no instances?** A restrictive sandbox can hide an Editor that is genuinely running from this CLI's view of it — don't treat that alone as proof the Editor is down.

## Cold start / lifecycle (community advisory variant)

The one capability REST can never provide: starting the editor when it is not running.

```bash
<cliPath> status --format json          # any editor instances running?
<cliPath> open "<projectPath>" --args -unityskills-coldstart
```

**Always pass `--args -unityskills-coldstart`** when cold-starting: the UnitySkills plugin detects this marker at editor startup and force-starts the REST server for this session, even if the user's Auto-start preference is off. Without the marker you depend on the user's saved preference. The marker is consumed once per editor session — it never overrides a mid-session manual stop.

**Preflight — read-only, no feature switch needed.** `open` / `test` / `run` / `build` all resolve the editor from the project's `ProjectVersion.txt`. Before the first CLI launch of a session run these checks; none of them modifies the project:

```bash
<cliPath> editors -i --format json                       # all versions: is the bound editorVersion installed?
<cliPath> doctor --ci --format json                      # beta6+: exit 6 = definitive blocker, 7 = retryable
<cliPath> projects verify "<projectPath>" --format json  # beta6+: exit 6 = errors, 0 = clean or warnings only
```

- `doctor --ci` (from the project root) checks licence, the project's editor, disk space and Unity services; branch on `errors[].code` (`LICENSE_NONE`, `EDITOR_NOT_INSTALLED`, `DISK_SPACE_LOW`, `NETWORK_UNREACHABLE`): `6` → stop and report, `7` → retry a few times, then tell the user. Plain `doctor` always exits `0`. beta6–8 on macOS may hang on a keychain prompt — wrap it in a shell timeout.
- `projects verify` needs no Editor, licence or network and only detects: `META_MISSING` / `META_ORPHAN` / `GUID_DUPLICATE` / `CONFLICT_MARKERS` / `MANIFEST_INVALID` exit `6` — report, never hand-repair; warnings (`PATH_UNVERIFIABLE`, `EDITOR_VERSION_DRIFT` via `--expect-editor <version>`) exit `0` unless `--strict`.

If the editor is not installed, **stop and tell the user** — never run `install` or pass `--allow-install`.

After launching, poll the UnitySkills REST server until ready (first import/compile can take minutes):

```python
from unity_skills import wait_for_health
health = wait_for_health(timeout=600)   # polls /health on ports 8090-8100
```

beta9+: `open` exits `6` (`OPEN_EDITOR_EXITED`) when the Editor dies inside the CLI's short watch window — report it at once instead of waiting on `wait_for_health`. Only that window is covered: an Editor that quits later is never observed, and older binaries exit `0` regardless.

## Global flags

These work on every command:

| Flag | Description |
|---|---|
| `--format <fmt>` | Output format: `human` (default), `json`, `tsv`, `ndjson`, `github`. Also via `UNITY_FORMAT` env var. |
| `--json` | Global shorthand for `--format json`, accepted on every command. `--format` takes precedence when both are supplied. |
| `--no-banner` | Suppress the branded header — use in scripts |
| `--no-pager` | Turn off paging. Also via `UNITY_NO_PAGER` (presence-based — any value, including `0`, disables it). |
| `--non-interactive` | Disable all interactivity |