# Unity CLI v1.0.0-beta.12

### Changed

- `unity status` no longer tells you to install the Pipeline package when you just did. If you install it while the project's Editor is already open, the Editor doesn't load it until its window regains focus. Until then, `status` now says that an Editor has the project open and the package is in its manifest but not loaded yet, and asks you to wait if it's still opening or otherwise switch to the Editor window, instead of reporting that no Editor was found. The machine error code for that case is `STATUS_PIPELINE_LOAD_PENDING`, with the same exit code as before. It applies to the project containing the current directory, or the one `--project-path` names. The message also points to `unity pipeline list` in case the Editor is in Safe Mode and can't load the package.

- `unity releases`, `unity projects list`, `unity context list`, `unity auth list`, `unity modules list`, `unity list` and `unity doctor` now end their `--format ndjson` output with a `{"type":"result"}` line, as `unity editors` already does, so a script can tell a complete listing from a cut-off one. The rows before it are unchanged, and the last line's `data.count` is the number of rows. If you read every line as a row, skip the line whose `type` is `result`. An empty listing now prints that one line instead of nothing, and `--quiet` still prints it. `unity releases` puts its "use `--skip` to see more" hint in that line's `warnings`, as its json output already did.

- `unity assets export` now signs the `.unitypackage` it writes when the project uses Unity 6.6 or later, the same way the Editor's own Export Package window does. It signs for your organization: pass `--cloud-org <id-or-name>`, set `UNITY_CLOUD_ORG`, or rely on the default set with `unity cloud org set-default`. Signing needs you to be signed in, and if the CLI can't sign, the export fails before the Editor starts and tells you what to fix. Pass `--no-sign` to export an unsigned package. JSON and NDJSON results include `signed` and `signingOrganizationId`. Projects on Editors older than 6.6 export unsigned packages, as before.

- On Windows, a runtime that a plugin needs (for example the Python a tool uses) now installs under `%LOCALAPPDATA%` instead of your roaming profile, so a domain roaming profile no longer copies it at every sign-in and sign-out. A runtime installed by an earlier version moves across the next time you install, upgrade, remove or run that plugin, and it keeps working until then. The licensing client and plugins themselves stay where they are, and macOS and Linux are unchanged.

- `unity command` with no command name now lists the Editor's command TAGS instead of every command it has. A connected Editor answers with around fifty tags and the number of commands under each, which fits on one screen; `unity command --tag <tag>` then lists that tag's commands, and the count on a tag's row is exactly how many that will be. The old behavior dumped 160-odd commands in one go, which was unusable as a starting point for a person and expensive for an agent. To get the full catalog back, ask for it: `unity command --detail full` (or `--detail compact`) lists every command as before, so a script that piped `unity command --format json` into a catalog needs that flag added. The tags come from the Editor, not from the CLI — a package that adds commands and tags is reflected without a CLI update. The tag index needs `com.unity.pipeline` 0.8.0-exp.1; an Editor running anything older gets the full listing it would have given before, unchanged and without comment, so nothing that works today stops working. Asking for the tag index by name against such an Editor — `unity command --tags` — reports that the package is too old and names the version to upgrade to, because handing back the whole catalog would be answering a different question.

- A partial `--editor-version` that matches several installed patches now runs the newest one instead of refusing. `unity run --editor-version 6.6` with both `6000.6.0f1` and `6000.6.1f1` installed used to be an error; naming a line is a reasonable way to ask for an editor, and the two candidates differed only by a patch you had already said you did not care about. This applies to the commands that take `--editor-version` and resolve it without asking you anything: `run`, `test`, `build`, `vcs conflicts resolve` and `vcs merge-setup`. `assets import` and `assets export` share the same resolver but have no `--editor-version` of their own — they read the version from the project's own `ProjectVersion.txt`, which normally names a complete version, so they change only for a project file that names a line. `open` and `projects open` are deliberately unchanged: they show you a picker, and replacing a question with a silent choice is a different decision. An **official** release always wins over a newer prerelease, so an installed `6000.6.1a1` does not shadow `6000.6.0f1`; a prerelease is chosen only when no official patch is installed, matching what `--editor-version latest` already does. A patch built for the architecture you asked for also wins over a newer one that was not, so on an Apple silicon machine with `2022.9.20f1` for arm64 and `2022.9.21f1` for Intel installed, `--editor-version 2022.9` runs the arm64 `20f1` rather than putting a newer Intel build under Rosetta — and `--architecture` is never overridden by the choice of patch. When no installed patch of the line matches the architecture and you didn't pass `--architecture`, the newest is used; when you did pass it, the CLI reports the ambiguity as before rather than running an editor for a different architecture. A match must line up on a version component, which is what stops `2022.3.1` from quietly running `2022.3.11f1`: `2022.3.1` still reports the ambiguity rather than guessing, while `6000.6.1` resolves to `6000.6.1f1` over `6000.6.10f1` because a channel letter ends the component and a digit does not. An exact version you spell out is never reinterpreted, so `2023.2.0f1` with both `2023.2.0f1c1` and `2023.2.0f1c2` installed still asks you to choose, `--allow-install` still receives the version you typed, and nothing that succeeded before now fails — the only outcome that changes is an error becoming a resolution.

- `unity open` and `unity projects open` now print a success document under `--format json` and `--format ndjson`, with the project path, the resolved Editor version and location, and the launched process id, instead of writing nothing on a healthy launch. If a script or agent relied on empty stdout to mean success, check `success` (or the exit code) instead.

- `unity editors`, `unity editors upgrade --check` and `unity templates list` now end their `--format ndjson` output with a `{"type":"result"}` line, like every other ndjson command, so a script can tell a complete listing from a cut-off one. The rows before it are unchanged, and the last line's `data.count` is the number of rows. If you read every line as a row, skip the line whose `type` is `result`. An empty listing now prints that one line instead of nothing, and `--quiet` still prints it.

- The CI workflows `unity ci init` writes now install the CLI with the plain `install.sh` command, without setting `UNITY_CLI_CHANNEL=beta`. Until a stable release ships, the installer gets the latest beta on its own.

- `unity changelog` now downloads the running version's release notes instead of reading a copy built into the CLI, so corrected notes appear without an update. It needs a network connection.

- Version options that look up a release now accept `latest` and a leading `v`, as in `v1.0.0`: `unity self-update --target`, `unity changelog --target`, `unity plugin changelog --version`, `unity hub install --hub-version`, and `unity pipeline install --package-version`.

- `unity command <name>` now waits while the Editor is briefly unavailable, such as right after `editor_play` or during a script reload, and runs the command once the Editor is ready, within the command's `--timeout`. It only resends a command the Editor rejected without running it. If the Editor stays unavailable, the error says whether it was busy or refusing connections.

- `unity --help` now describes what the CLI can do: install an Editor, create a project without the GUI, drive a running Editor, play and capture the game, and build it. It used to just say “CLI for Unity”.

- `unity projects new --help` now says it never links to Unity Cloud, matching what it actually does. `unity projects create` still asks, and links by default.

- `unity mcp configure claude-code` now checks whether a Claude Code plugin you have enabled already provides an MCP server that runs `unity mcp` for the same project. If one does, it warns and skips its own `claude mcp add` registration unless you confirm or pass `--yes`, so you don't end up with two copies of the same server. This matches how `unity skill install claude-code` handles a plugin that already provides the skill.

- `unity bug --area` now accepts `licensing`, for issues about licensing or signing in. On a terminal, "Licensing or signing in" now appears as a choice when the reporter answers the area question. The `pipeline-package` and `editor` choices are also reworded, to "The connection to the Editor or the Pipeline package" and "The Unity Editor or your project", so the wording matches how Unity's support team triages reports. `--area` is still optional and never blocks a report.

- `unity plugin install ugs` and `unity plugin upgrade` now install version 2.0.0 of the Unity Gaming Services CLI, which `unity ugs` runs.

- The CLI now uses Unity Licensing Client 1.19.0-rc.3. A client it downloaded under an earlier version is replaced the next time a `unity license` command or an Editor launch needs it.

- The first-run analytics consent prompt now uses its reviewed wording. It asks about sharing usage analytics, offers “Yes, share” and “No, don’t share”, and explains the anonymous usage count once, in a note above the choices. Long lines in the prompt now wrap between words.

### Added

- `unity projects create --with-pipeline` adds the Pipeline package (`com.unity.pipeline`) to the new project, so an AI agent can drive the Editor as soon as it opens, without a separate `unity pipeline install`. The project is still created when the package can't be added (an editor older than Unity 6, or the registry is unreachable): you get a warning and exit code 0. In an AI-agent session, `projects create` without the flag prints a hint pointing at it.

- `unity status --format json` shows whether a game in Play mode is actually running. While the Editor is in Play mode, each instance row carries `frameCount` and `playerLoopTicking`, passed through from the Editor. `playerLoopTicking: false` outside a pause means the player loop is frozen, which can happen in an unfocused Editor even though the Editor still reports Play mode. Both fields are omitted in Edit Mode and for Editors whose `com.unity.pipeline` doesn't report them yet, so existing output is unchanged.

- `unity install`, `unity install-modules` and `unity projects require` accept `--no-wait` and `--wait-timeout <seconds>` for when the Hub or another CLI is already installing. By default they still wait until that install finishes. `--no-wait` fails straight away when the lock is already held, before that item is downloaded, and `--wait-timeout` fails once it has waited that many seconds in total. Either way the command exits `9` with the error code `INSTALL_LOCK_BUSY`, so a script can tell "try again later" apart from a failed install. The lock is taken per item, so an install that also adds modules can stop with exit `9` after the editor is in place; `completedUids` in the ndjson result lists what was installed, and `unity install-modules` finishes the rest.

- **Experimental, unsupported:** on a Linux arm64 host you can opt in to running the x86_64 Unity Editor under FEX-Emu by setting `UNITY_EXPERIMENTAL_FEX_EMU=1`. It takes effect only when FEX-Emu and an x86_64 RootFS are installed, and `unity doctor` reports whether they are. C# script compilation is known to crash under FEX-Emu (https://github.com/FEX-Emu/FEX/issues/5766), so don't rely on it for real development; every affected command warns you.

- A registry plugin's published version can now state the minimum version of a runtime it needs. `unity plugin install` and `unity plugin upgrade` check it after resolving the runtime, and hold the tool back with a clear message naming the runtime and the version required, plus `unity plugin upgrade <runtime>` to fix it, rather than installing or upgrading a tool next to a runtime it can't actually use. The check uses the minimum of the plugin version you keep or run, not a newer one that isn't being installed. `unity <tool>` refuses to run the same way. When the runtime's version can't be read, for example a copy found on your PATH, the plugin isn't blocked and a warning says the minimum wasn't checked. JSON and NDJSON rows carry the required version as a new `requiredRuntimeVersion` field (`null` when nothing is blocked), and TSV output adds it as a new column.

- `unity commands --grep <pattern>` searches the CLI's commands and its plugin catalog by keyword, so you can find the command for a task without paging through `--help`. It matches command names, descriptions, and options, and plugins whether or not they're installed; each result says whether it's a command or a plugin, and a plugin you haven't installed names the command that installs it. Matching is case-insensitive, and `--format json` gives the results as structured data.

- `unity plugin list` now shows a short description of what each plugin does, in every format (human, `--format json`, and `--format tsv`), whether or not it's installed. It's the easiest way for a script or an agent to learn what plugins exist and what they're for.

- `unity plugin install`, `unity plugin upgrade`, `unity plugin list` and `unity doctor` now say where each runtime a plugin uses came from: `machine` for a copy that was already on your computer, `package-manager` for one installed through Homebrew, winget, apt or dnf, and `managed` for the Unity CLI's own download. JSON and NDJSON rows carry it as a new `source` field (`null` for a tool), and TSV output adds it as a last column, so existing columns keep their positions. The `plugin list` table shows it once a runtime is installed.

- Running a not-installed catalog plugin's command now fails with the same clear message under `--format json` and `--format ndjson` as it already did in human output, wrapped in the usual error envelope under a stable code. A failed `unity plugin install`/`upgrade` download also now logs the actual reason, so `unity logs` shows what the on-screen message already tells you to look for.

- `unity skill disable <skill>` and `unity skill enable <skill>` turn an installed skill off and back on without uninstalling it, and `unity skill list` shows every tracked install with its state. Every installed skill's description is loaded into every session of the client that found it, whether or not the skill is ever used, so the cost is paid per skill *installed* rather than per skill useful on this project — and until now the only way to stop paying it was to delete the files by hand and edit the CLI's own install record, which the next `unity skill refresh` undid anyway. Disabling renames the skill's `SKILL.md` to `SKILL.md.disabled` and records the choice; because every supported client finds a skill by looking for `SKILL.md` in its directory, that single rename is what stops it loading, identically on all of them. The rest of the skill's files stay where they are, so enabling is a rename back rather than a reinstall. By default both verbs apply to every client that has the named skill — `--client <client>` narrows to one, and `--dry-run` previews. `unity skill refresh` skips a disabled skill and keeps tracking it, so a refresh never quietly switches one back on; `unity skill install <client>` does re-enable it and says so, since installing is an explicit request to have it active. `unity skill install --list` now reports such a client as `disabled` rather than as installed or out of date. An unknown skill name exits 2 listing the names that are installed.

- `unity pipeline cloud-build` and `unity pipeline automation` add twenty-four more read-only inventory commands across fourteen groups, extending the ten they shipped with. `cloud-build` gains `project get|stats` for the project already in scope, a `tooling` group with six lookups for what you can build with (`unity`, `xcode`, `visual-studio`, `os`, `platforms`, `machine-types` — every one has `list`, and `unity` and `os` also have `get`), and `targets groups`. `automation` gains `automations`, `bots`, `profiles` and `templates` with `list|get` each, `apps versions` and `pipelines versions` subgroups, and a `jobs stats` leaf reporting running and queued counts against the organization's concurrency limit. Everything is a read: nothing here triggers, cancels, or changes a remote resource, and none of it needs a running Editor.

  Each `tooling` lookup documents only its own filters, so a filter that works on a neighbouring lookup is an unknown option rather than one that gets ignored. Where an endpoint documents no pagination — all six `tooling` lookups, `targets groups`, and `profiles list` — `--page` and `--limit` are absent rather than accepted and ignored. `templates list`'s five filters (`--app-ids`, `--tags`, `--metadata`, `--system-metadata`, `--used-with`) are each repeatable. Note that `profiles list` takes `--app-id` and `templates list` takes `--app-ids`.

  Secret values are never printed. In `--format json` an automation's `secrets` keeps its key names so you can see which secrets it consumes, with every value as `***`; its table has no `secrets` column at all. A bot's `serviceAccountId` and `serviceAccountKeyId` are shown deliberately — they identify which service account and key a bot runs as, and neither can be used to authenticate. `tooling platforms list` keeps a property called `credentials`, which is an enum describing whether a platform needs signing credentials configured rather than a credential itself.

  Three response states stay distinguishable rather than collapsing into each other, on the two new single-array envelopes (`targets groups` and `profiles`) as on the existing `results` pages: a property the service omitted renders empty and stays omitted in machine output, an explicitly empty array renders empty and stays `[]`, and an explicit null, a non-array or a non-object entry fails the read with `AUTOMATION_INVALID_RESPONSE` and exit 6. On `profiles get` an omitted or empty array means not-found instead, because you asked for one profile by id.

  A `tooling` list shows only what you can actually use: versions the service marks hidden and machine types it marks not enabled are left out, in every format, and each list leads with its own identifying token, so the first column is always the one to copy. A `get` is not filtered, so `tooling unity get <version>` and `tooling os get <value>` still return a hidden version, with `hidden` shown, which is how you confirm a build target is pinned to a version that stopped being offered. Deprecated versions stay listed because they still work, and their row is painted yellow in a colour terminal, so piping or `--no-color` costs the highlight and no information. One thing to script defensively: a platform's `defaultVersion` can name a version that is not in its own filtered `versions` array, and it is left exactly as the service sent it.

- `unity projects create`, `unity projects link cloud`, `unity projects link vcs`, and `unity vcs setup` accept `--coppa <status>` to set the COPPA status of a Unity Cloud project they create: `not_compliant` (the default, unchanged), `compliant`, or `unspecified`. When a command creates a cloud project, its output now names the COPPA status it sent, and JSON and NDJSON results include `coppa`. Linking an existing cloud project never changes its COPPA setting, so `--coppa` can’t be combined with `--cloud-project` (or with `--no-cloud` on `projects create`), and a run that ends up creating no cloud project warns that `--coppa` was not applied.

- `UNITY_CLI_FTUE=1` turns on the agent first-session ("paved") mode. Every `--format json` envelope and ndjson result frame then carries `"paved": true`. `unity projects create` saves the choice in the new project's `UserSettings/UnityCliPaved.json`, so later commands in that project are marked without the variable. Output without the mode is unchanged.

- A passthrough tool (`unity uvcs`, `unity cm`, `unity ugs`, and any future curated tool) now gets `UNITY_CLI_INVOKED_AS` and `UNITY_CLI_CORE_VERSION` in its environment. `UNITY_CLI_INVOKED_AS` is the command you actually typed, for example `unity uvcs`, so a tool with more than one alias can show help and errors that match what you ran. `UNITY_CLI_CORE_VERSION` is the CLI's own version, so the tool can check compatibility without shelling out to ask.

- `--format json` and `--format ndjson` output can now carry a `notifications` array telling you when a newer `unity` CLI is available, so scripts and AI agents find out without running a check of their own. Each entry has a `code`, a readable `message`, and a `remediation` naming the command that updates you. The key is only present when there is something to report, at most once a day, and `UNITY_NO_UPDATE_CHECK` or `unity config update-check off` turns it off. The MCP server reports the same thing once per session.

- The CLI log now records every command you run, with its arguments, exit code, and duration, so `unity logs` and `unity bug` reports show what ran. Tokens, passwords, and credentialed URLs in arguments are redacted.

- `unity projects report` groups every registered project by the editor version its `ProjectVersion.txt` asks for, and flags a version that isn't installed and a version whose stream isn't LTS. It never installs, removes, or changes anything. It pairs with `unity projects require <path>` to install a missing version and `unity editors prune` to review installed editors nothing needs. Supports `--format json`, `ndjson`, and `tsv` alongside the default table.

- `unity status` and `unity pipeline list` now show Multiplayer Play Mode virtual players, named by player (for example "Player 2") under the project they belong to. In JSON and NDJSON output, both commands add `role`, `instanceName`, and `vpId`, and `unity pipeline list` also adds `ownerProjectPath`.

- `unity changelog --target <version>` shows the release notes for a specific version, for example before you update with `unity self-update --target`.

- `unity templates list --format json` now accepts `--brief`, which trims the output to the same name, display name, type, version, and status columns the table view already shows. Use it when all you need is a template id: the full JSON output can run into the hundreds of KB.

- `unity status --until-ready` waits until a matching Editor reports `ready` and then prints the usual status, so you don't have to poll it after `unity open` or while an Editor enters Play mode. It also waits for an Editor that hasn't started yet, and `--timeout <seconds>` (default 300) sets how long it waits before it exits `6` with the last state it saw.

- `unity setup claude` installs Unity's Claude Code plugin, with its Unity skills, in one step: it adds the plugin's marketplace and installs the plugin through the `claude` CLI, and reports the plugin's version, whether it loads in this session or the next, and where its skills can be read right away. It's safe to re-run, since an existing install is reported rather than reinstalled. `--dry-run` prints the two `claude` commands without running them. If `claude` isn't on your PATH, it fails with `CLAUDE_NOT_FOUND` and names the commands to run yourself.

- `unity projects info` now shows whether Developer Data diagnostics is on: the project's build-default setting and the file it came from, any build profile overrides, and the cloud link. `unity projects create` includes the same `diagnostics` block in its JSON and NDJSON result. A setting the CLI can't read shows as unknown, never as on or off.

- `unity build`'s JSON and NDJSON result now includes `outputPath`, the absolute path of the build output. It's `null` only when you build with `--execute-method` and no `--output-path`, since your own build method decides where the output goes.

- `unity vcs providers` now lists `cm`, the Unity Version Control client, with the same path, version, and state `unity plugin list --versions` reports. Inside a Unity Version Control workspace with no `cm` installed, it suggests `unity plugin install uvcs`.

- The installers (`install.sh` and `install.ps1`) now end with a line for AI agents that names the command to start with: `UNITY_CLI_FTUE=1 unity auth status --json`, or `$env:UNITY_CLI_FTUE=1; unity auth status --json` in PowerShell. `install.sh` also prints plain text, without color codes, when its output isn't a terminal or `NO_COLOR` is set.

- `unity bug` now asks which part of Unity the issue is in: the CLI itself, the Pipeline package (`com.unity.pipeline`) in the Editor, the Editor, or not sure. Until now a report said nothing about where the failure was, so an Editor or Pipeline package failure that happened to show up in CLI output was routed as a CLI bug. Scripts and CI pass it as `--area <cli|pipeline-package|editor|not-sure>`. It is optional and never holds a report back. On a terminal the question starts on "Not sure", so pressing Enter doesn't blame the CLI by accident. Off a terminal, including under `--non-interactive`, a report without `--area` is sent exactly as it was before, with no area. An unknown value is a usage error. The answer is sent with the report as an "Issue area:" line in the report text, which is what Unity's triage reads. When you answer the Editor or the Pipeline package, the question about including a copy of your project first explains why a copy helps for those issues; it still defaults to no, and nothing is shared unless you answer yes.

- `unity docs` now reaches Unity’s documentation platform as well as the Editor documentation: `--cli` for the Unity CLI, `--hub` for the Unity Hub, and `--cloud` for Unity Cloud. Those pages aren’t versioned by editor, so they take no `--editor-version`, and the four documentation selectors — including `--manual` — are mutually exclusive. Page names on the new sets are lowercase and hyphenated, and anything else falls back to a documentation search, the same way the Editor sections already work.

- `unity command --tags` asks for that same tag listing explicitly, and composes with the other listing filters: `unity command --tags --tag runtime` shows the tags within one subtree, `unity command --tags --query prefab` shows which tags have prefab-ish commands in them. It renders in every output format — a `tag`/`count` table under `--format tsv`, one object per tag under `--format ndjson`, and a `tags` array under `--format json`. It cannot be combined with `--detail`, which picks the same thing.

- `unity command --help` now ends with runnable examples — how to list the tags, how to list one tag's commands, how to run a command, and how to run one with arguments. `unity command` is the entry point to the Editor's whole command surface, and the help had no worked example of invoking anything through it.

- `unity bug --help` now points at `unity bug mcp`, a new way to add Unity’s Issue Tracker to an AI assistant so it can check for known issues before you file a report. It’s exactly `unity mcp configure --server issue-tracker`, so it takes the same client argument and the same `--list`, `--local`, `--yes`, and `--dry-run` flags. The interactive bug wizard also prints a one-line reminder about it before asking its own questions; it adds no new required question.

- `unity projects create --template` now accepts a local template as well as a registry name: a path to a `.tgz` archive, or to a directory holding a `package.json` with a `name` field. The archive or directory is validated (the archive is checked as a readable `tar` stream, and a directory's `package.json` must parse and declare a `name`) before it's handed to the Editor, with a clear error naming what's wrong. A directory template that also declares a minimum Unity version through the standard `unity` package.json field (`"MAJOR.MINOR"`) is checked against the editor version you resolved, so an incompatible template is rejected before the project scaffold starts rather than failing inside the Editor. The existing registry template-id flow is unchanged.

- `unity pipeline upgrade` now shows what's changing: alongside the resolved version, it prints that version's release summary, and when the upgrade spans more than one published version, it shows every version in between too, oldest first, so a change in a version you're skipping past is never silently missed. `unity pipeline install --force` shows the same summaries when it moves an already-installed project to a newer version. JSON and NDJSON output carry the summaries as a structured `summaries` array; TSV and `--quiet` are unchanged.

### Fixed

- On macOS, the CLI no longer removes Unity Hub’s keychain access to your shared sign-in when it saves a refreshed token. It now updates the saved sign-in instead of re-creating it.

- A path, version, or other value that contains a terminal control code such as `ESC[?25l` or `ESC[12~` no longer leaves that code's text, such as `[?25l` or `[12~`, in the CLI's output; the whole code is removed.

- Using the CLI no longer removes the Hub’s saved sign-in. Before, the first `unity` command after you signed in through the Hub could leave the Hub signed out at its next launch, or, on macOS, asking for keychain access again.

- `unity doctor --format json` no longer crashes on a Linux machine with a provisioned auth broker. The report's `authBroker.storeOwnerUid` field now shows the broker store's owning user id as a number, and stays `null` when it can't be read.

- `unity doctor --format tsv` no longer passes control characters from the values it reports straight to your terminal. In a path, an account name, an editor entry, a log line or a proxy setting, a tab, newline or carriage return now becomes a space and other control characters and terminal control sequences are removed, as the rest of the CLI's tables already do, so a value can't split a row into extra columns or add a row of its own. Color codes are kept, and ordinary values are unchanged.

- On macOS and Linux, the Editor sign-in helper that `unity open` starts, the auth broker, and the Unity Licensing Client no longer keep you from ejecting or unmounting the drive you ran `unity` from. They now run from the root directory instead of the folder you were in.

- On Linux, a browser that `unity` opens, for example for `unity auth login`, `unity docs` or a WebGL `unity build run`, no longer keeps you from unmounting or ejecting the drive you ran `unity` from while it stays open. The browser opener now runs from the root directory instead of the folder you were in.

- When `unity command <name>` fails, its error is printed once. It used to appear twice: once under `❌ Command '<name>' failed:` and again as a plain `Error:` line just before the `For more details:` hints. The exit code, the hints, the log record and `--format json` output are unchanged.

- A path, version, or other value that contains a truecolor color code written with colons (for example `ESC[38:2::255:0:0m`) no longer leaves that code's text, such as `[38:2::255:0:0m`, in the CLI's output; the whole code is removed, as the semicolon form already was.

- `unity projects require --format json` now writes exactly one JSON document to stdout when it installs the editor, as `unity install --format json` does. It used to print install progress lines ahead of the result, so a script that parsed stdout as JSON failed. Any install warnings now appear in the result's `warnings`, and `--format ndjson` keeps its progress lines.

- `unity projects upgrade`, `unity vcs git worktree add --install-editor`, and `unity build`, `unity run` and `unity test` with `--allow-install` no longer print install progress lines ahead of their `--format json` result when they install an editor first. Any install warnings now appear in the result's `warnings`, and `--format ndjson` keeps its progress lines.

- A failed `unity plugin install` or `unity plugin upgrade` no longer deletes the plugin you already had. If the new version can't be put in place, the previous one is restored and keeps working, and a read-only checksum file left by an earlier install no longer makes an upgraded plugin look out of date. `unity plugin remove` on a runtime now fails while a plugin that needs it is being installed, instead of deleting the runtime from under it.

- On Windows, `unity self-update` now reports when another program is holding the CLI's executable open, instead of saying the update was staged and then leaving the old version in place. It names the programs using the file when Windows can tell, and asks you to close them or restart your computer before running `unity self-update` again. Nothing is changed when this happens. An MSIX update that can't apply because another `unity` process is still running now names that process too, rather than saying the update applies the next time you run `unity`.

- `unity command` now removes the Editor's truecolor styling from a task name in its progress bar and in the `--format ndjson` progress messages, including the colon-separated form some tools write. That form used to pass through, which could cut the bar's label short or color the rest of the line, and left escape bytes in the ndjson `msg`.

- `unity command` now reports an Editor's argument error at once when the error's text happens to start with "Cannot connect to Unity Editor Pipeline server at". It used to read that answer as the Editor being unreachable and keep resending the command until `--timeout` ran out.

- `unity recompile` and `unity mcp` now treat that same kind of Editor argument error as an answer, not a lost connection. `unity recompile` exits with 6 (command failed) instead of 7 (network unreachable), and `unity mcp` returns the error at once instead of dropping its connection, waiting out a status poll, or sending a desktop screenshot in place of a failed capture.

- `unity install` and `unity install-modules` now wait while the Unity Hub or another `unity` command is installing on the same machine, instead of failing. The CLI prints “Waiting for another install to finish before continuing…” once, then continues on its own when the other install finishes, so two installers never write into one editor at the same time. Press Ctrl-C to stop waiting.

- A project command that changes your project list no longer replaces it when the list can't be read. The Unity CLI and Unity Hub share the project list, and a failed read (for example, a permission error, or Unity Hub holding the file) used to leave the CLI with an empty list, so adding, removing or pinning a project saved only that one change over every project you had. Now the command stops with an error that names the file and what went wrong, and your project list stays as it was. Listing your projects still works, and shows an empty list, when the list can't be read.

- A setting change no longer wipes your other settings when the shared settings file can't be read. The Unity CLI and Unity Hub share one settings file, and a failed read (for example, a permission error or another program holding the file) used to replace every setting in it, Unity Hub's included, with the one you were changing. Now the change is refused with an error that says why, and the file stays as it was. A damaged settings file is still replaced, but its contents are first saved to a `user-settings.json.corrupt-…` file next to it.

- A file the Unity CLI shares with Unity Hub is no longer wiped when it can't be read or lists the same name twice, including your settings, located Editors, hidden Editor folders, paused downloads, proxy settings, project defaults, and template settings. The change is refused with an error that says why, or skipped with a warning when the rest of the command already finished, and the file stays as it was. A damaged file is saved to a `<name>.json.corrupt-…` file next to it before it's replaced.

- `unity plugin list` fits its table to the terminal. A long path used to push every row past the terminal edge, so rows wrapped and blank lines appeared between them. Only the path column is shortened now, and the name, state, and version columns stay whole.

- `unity plugin upgrade` and `unity plugin changelog` no longer show internal notes in the one-line summary for the Unity Licensing Client, Unity Gaming Services CLI, Unity Version Control, and Pipeline package entries. The summaries now describe each version in plain language.

- `unity templates create --name` now accepts a name written only in a non-Latin script, such as Japanese or Cyrillic, instead of rejecting it for having no usable characters. The template is stored under a generated ASCII id, and `--display-name` stays what the template shows.

- On macOS, `unity modules list`, `unity editor module list`, `unity install-modules`, and `unity install --dry-run` now show download and install sizes in the same units as the Hub and Finder, where 1 GB is 1,000,000,000 bytes. They used to divide by 1024, so Android Build Support read 2.36 GB in the CLI and 2.53 GB in the Hub. The download progress bar of `unity install` and `unity install-modules` uses the same units, so it agrees with the install plan. The size text in their TSV, JSON, and NDJSON output changes the same way, and TSV is the default when you pipe or redirect the output. Fields that hold a byte count, such as `totalDownloadSize` in `unity install-modules --dry-run --format json`, are unchanged. Sizes on Windows and Linux are unchanged.

- The `notifications` array now reaches the `--format json` output of every command, matching `--format ndjson`. Many commands, including the `vcs`, `plugin`, `assets`, and most `projects` commands, left it out of their JSON. The `--watch` refreshes of `editors list` and `projects list` carry it too.

- A sign-in that actually succeeded is no longer reported as `KEYRING_WRITE_FAILED`. After writing your credential, the CLI reads it straight back to confirm it was really stored — a check that exists because some keyrings report a successful write and keep nothing. That read-back was allowed exactly one attempt, so a credential that was written correctly but not yet visible to an immediate read failed the whole sign-in, and the fix was to simply run `unity auth login` again. It is now retried briefly before being treated as a failure, which is enough to absorb the race: on Windows a secret is split across several Credential Manager entries plus an index entry, and a read landing mid-write can see an incomplete set. A keyring that genuinely did not store the value still fails, with the same message and the same diagnostics as before, and nothing is retried on the write itself. A credential that reads back correctly the first time — the normal case — waits for nothing.

- `unity doctor` now always reports the auth broker, on every platform. The section used to appear only on Linux, or on a machine that already had a sealed credential store — so on Windows and macOS a healthy broker, a broker that was refusing this program, and a broken build all produced the same report: no section at all. It now says whether the broker is running, whether it refused this program (which silently sends every command back to your operating system credential store), whether something is listening but not answering, whether it has stored anything or holds a signing key on disk yet, and — the question that prompted this — that signing in does not go through the broker in this version, so credentials are written to the operating system credential store and the broker seals one only once a command first needs a token. "Not created yet" is now stated rather than left blank, because a blank row reads as a broken build. `--format json` gains an `authBroker.runtime` object and `--format tsv` an `authBroker.state` row, so `authBroker` is now present in `--format json` on every machine, where it was previously omitted; `--format ndjson` renders the same localized rows the human report does, as it already does for the rest of this report. Checking costs at most two local connections — one to see whether anything is listening, one to ask a listener who it is — and never starts a broker, so `unity doctor` still cannot prompt, hang, or leave a background process behind.

- `unity projects link cloud` no longer fails with `ALREADY_LINKED` on a project whose Unity Cloud link was removed from `ProjectSettings/ProjectSettings.asset` but is still recorded in the Unity Hub project list, for example after unlinking the project in the Editor. The project now links, and both places get the new link.

- A download that gets cut off partway through now resumes instead of restarting from scratch. Before this fix, a connection dropping mid-download deleted the partial file and failed the whole operation, even though the file could have been resumed.

- `unity releases` no longer waits forever when the Unity release service accepts the connection and then stops responding. Each request now times out after 10 seconds, so the command succeeds or fails within about half a minute. A request that gets no response in time, a connection that drops before the service answers, and a server error are each retried twice. A response that stops partway through is reported without a retry. `unity editors list` and `unity editors default latest` also stop waiting for the release list after 10 seconds: `editors list` then shows your installed Editors only, and `editors default latest` resolves against the release list built into the CLI.

- `unity projects create --cloud`, `unity projects link cloud` and `unity projects link vcs --vcs uvcs` no longer report a Unity Cloud link that wasn’t saved. When the project’s `ProjectSettings/ProjectSettings.asset` can’t be updated (for example because it doesn’t exist yet, or has no Unity Cloud fields to update), the Editor and `unity projects info` see no link, yet the command used to say it linked. `projects create` now reports `cloudLinked: false` with a warning, `projects link cloud` fails with `PROJECTS_LINK_CLOUD_LOCAL_WRITE_FAILED` (exit 1), and `projects link vcs` warns and leaves `cloud` out of `linked`. JSON output adds a `cloudLinkError` object with the reason, and every message names the cloud project and the `unity projects link cloud --cloud-project <id>` command that saves the link without creating a second project.

- `unity projects add` on a case-sensitive volume no longer records a project whose path differs from an already registered project only by letter case as if it were that project. It used to copy the registered project’s path into the new registry row, so the next `projects` command that loaded the registry folded the two rows together and deleted one. Both rows are now written and kept under their own paths, and a row an earlier version wrote in that shape is repaired on the next load.

- On Windows, `unity self-update`, `unity self-update --rollback`, and `unity self-install` now complete while other `unity` processes are running, such as an MCP server started by an AI client or a `unity shell` session. Before, the update reported itself as staged and then silently kept the old version until every other `unity` process had exited. Processes already running keep the old version until they exit, and the CLI removes the old file afterwards.

- A mistyped command no longer reports success when you add `--help`. `unity project --help` printed the top-level help and exited 0 — output byte-identical to a bare `unity --help`, so the token you typed left no trace at all — while `unity project` on its own already printed `unknown command 'project' (Did you mean 'projects'?)` and exited 2. The help flag was outranking the error. That made a typo inside a script or a CI job pass silently, and it misled coding agents, which commonly append `--help` to check whether a command exists and were told that it did. An unknown command now reports itself with the same message and the same exit code whether or not `--help` is present, at every level: `unity bogus --help`, `unity projects bogus --help` and the `-h` spelling all behave like their bare forms. Help still wins wherever the unrecognized token is an argument rather than a command, so `unity install 6000.1.0f1 --help` and `unity projects add ./game --help` print their own command's help exactly as before. `unity help <unknown>` is unchanged and still prints the top-level help: naming `help` is an explicit request for discovery, not an attempt to run something.

- Interrupting `unity auth login` while it waits for you to sign in in the browser now always exits `130` for Ctrl-C and `143` for SIGTERM. If the signal arrived while the CLI was checking whether you'd finished signing in, it used to print `Sign-in failed: canceled` and exit `3`.

- `unity run`, `unity build run`, `unity test` and `unity assets import` now exit `130` when you stop them with Ctrl-C and `143` on SIGTERM. A plain `unity run` (without `--command`), `unity test` and `unity assets import` also stop the Editor they started, so a CI timeout that kills only the CLI no longer leaves that Editor running and holding the project, and an interrupted `unity test --retries` run starts no further attempt. `unity build run` used to exit `0` either way.

- The "multiple editors found" error now names the ambiguity it actually hit. Passing a partial `--editor-version` — `6.6` with both `6000.6.0f1` and `6000.6.1f1` installed — matched two editors and told you to `Pass --architecture to disambiguate`, which cannot work: those two candidates share an architecture, so the suggested flag had nothing to choose between and the only way forward was guessing that the full version would help. The message now distinguishes the two cases, and each one names its own options. Several *versions* matched lists them and asks for the exact version; one version installed for several *architectures* names `--architecture` **and the architectures you actually have installed**, so you no longer have to run `unity editors list` to find out which values that flag would accept. An install whose architecture can't be read — a partial or quarantined one — is left out of that list, because `--architecture` can't select it anyway. The version list puts official releases ahead of prereleases, so the entry you're most likely to copy is the one the CLI itself would pick. The two cases also carry distinct error codes in `--format json` and `ndjson` — `MULTIPLE_EDITOR_VERSIONS` and `MULTIPLE_EDITOR_ARCHITECTURES` — so a script can tell them apart without reading a message that's translated into ten languages. `unity projects create` and `unity projects new` hit the same case through their own code path and printed a separate, untranslated English sentence carrying the same wrong advice (`Multiple editors found matching the version … and no architecture was specified`) — they now share the classifier with `unity run`, `test`, `build`, `vcs conflicts resolve` and `vcs merge-setup`, so every one of them names the same axis and the message is translated in all ten languages. A third case is now separated out too: when several installs share a version but none of their architectures can be read — a partial or quarantined install — neither remedy applies, because the exact version does not separate them and `--architecture` has no value it could take. That case now asks you to repair the installs (`unity editors verify`, or a reinstall) and reports `MULTIPLE_EDITOR_ARCHITECTURES_UNREADABLE`.

- `logs/cli-log.json` now records what each run did, instead of repeating the same block of startup lines on every run. Those lines are now written only to `debug-log.json`, and the ones describing things the CLI never checked or did, such as a first-time-user check that always reported `firstTimeUser: true`, are removed.

- On Linux, `unity uninstall` and `unity editors prune --remove` no longer hide an editor version from your desktop's application menu when another install of that version remains, such as the other architecture. The menu entry now points at the remaining install.

- `unity logs` now shows the time each record was written, instead of the time you ran the command.

- When a command running in the Unity Editor fails with an error that mentions a refused connection, for example a web request inside the command, the CLI now shows the Editor's error. It used to report that it couldn't connect to the Editor and drop the Editor's message. The same now applies to `unity recompile`, which exits with code 6 instead of 7 and stops at the error instead of waiting until it times out, to the `unity command` listing, and to `unity mcp`, whose screenshot tools return the error instead of a desktop screenshot.

- `unity recompile` and `unity mcp` now also show the Editor's error when it mentions a reset or timed-out connection, or a server the command couldn't connect to, instead of treating the Editor as unreachable.

- `unity mcp`'s `capture_game_view` and `capture_scene_view` now fall back to a desktop screenshot when the Editor doesn't answer in time, as they already did when a dialog blocked the Editor. `unity recompile` now exits with code 7 instead of 6 when the Editor drops its recompile request or doesn't answer it in time, so a CI step can retry it.

- `unity command` no longer reports multiple candidate Editors for a project running Multiplayer Play Mode virtual players. It picks the main Editor; pass a clone's folder to `--project-path` to target the clone.

- On a machine where the auth broker protects your sign-in with a local key file, because no TPM, DPAPI, keyring, or Keychain is available, two first-time sign-ins running at once on a busy machine no longer fail to save your session. A first sign-in interrupted by a full disk also no longer leaves behind an empty key file that stops every later sign-in from being saved.

- On macOS, and on Linux machines with no machine ID, the auth broker no longer loses your first saved sign-in when two `unity` commands run at once. Before, the next command could ask you to sign in again.

- On Windows, when a program runs `unity` and captures its output, the capture no longer waits for the auth broker to exit. The broker could inherit a copy of the output pipe from that program and hold it open until it went idle, two minutes after the last command.

- On Windows, the background identity server that `unity open` starts now keeps accepting connections while it checks a new one, so requests to it no longer time out and get dropped. `unity close` now reliably lets it exit early once no Editor is using it, and a second `unity open --cloudEnvironment` reliably switches it to the new environment.

- On Windows, the background identity server that `unity open` starts now refuses a connection made through the network redirector (a `\\localhost\pipe\...` connection, as opposed to a direct local one), and grants access to its pipe only to the account that started it. Before, that network path reached the identity server exactly the way a genuinely local Editor does, and any other account on the machine could open the pipe directly. The Editor connects the same way it always has, so this changes nothing observable for the ordinary case.

- On Windows, the auth broker now keeps accepting connections while it checks a new one. Before, a command that reached it during that check could conclude that no broker was running, so `unity self-update`, and the Hub when it installs the CLI, could fail to replace the binary the broker runs from with "Access to the path is denied".

- On Windows, `unity self-update`, and the Hub when it installs the CLI, now also reach an auth broker that has only just started. Before, a broker still starting up could look as if none was running, so replacing the binary it runs from could fail with "Access to the path is denied".

- On Windows, capturing the output of `unity open` no longer waits until five minutes after the Editor closes, and capturing `unity build run` no longer waits for the player to close. A `unity license` command that starts the Unity Licensing Client no longer waits for the client to exit. The background processes `unity open` and `unity license` leave running also no longer lock the folder you ran the command in against renaming or deletion.

- On macOS and Linux, a `unity` command whose output is captured or piped no longer keeps its reader waiting after it finishes when the caller handed it an extra open descriptor, such as a shell’s `3>&1`. The Editor, the Unity Licensing Client, and the background processes the CLI starts no longer receive that descriptor. On Linux, capturing `unity build run`, `unity auth login`, or `unity docs` also no longer waits for the player or the browser to close.

- On Windows, saving a setting, for example with `unity config set`, no longer fails with "Access to the path is denied" when another program, such as the Hub, has the settings file open at the same moment.

- A failed command's entry in `cli-log.json` is now short and readable: it names the command, the error code, and the error message once, instead of repeating the message five times. When there's more to the failure than the message, such as the connection error behind "Unable to reach the Unity release service", the entry adds it as the cause. `unity logs` and `unity doctor` show these details next to each failure.

- `cli-log.json` now records a failure as a warning when it's your mistake or a setup problem, and as an error only when it could be a problem in the CLI itself. A mistyped `unity command` name, a missing parameter, an Editor version that isn't installed, and a signed-out session are now warnings wherever they happen. Exit codes don't change.

- `unity install lts` no longer picks a release Unity marked Supported just because its version number looks like an LTS one. It installs the newest release Unity marks LTS.

- `unity auth login --secret-from-stdin` no longer waits forever. If stdin is a terminal, it now stops right away and asks you to pipe the secret in. If the pipe feeding it is never closed, it stops after 30 seconds. It also refuses a secret longer than 1,048,576 characters, or one that's only whitespace, instead of trying to sign in with it. Each of these exits `2`, and no message includes the secret. Piping a secret and closing stdin, as in `printf '%s' "$SECRET" | unity auth login --client-id <id> --secret-from-stdin`, works as before.

- On Windows, the CLI stores your sign-in as a single Credential Manager entry shared with Unity Hub, which prevents occasional sign-outs when both refresh your session at the same time. An older multi-entry record converts on your next session refresh.

- In `cmd.exe` and other windows run by the classic Windows console, the CLI no longer prints raw escape codes such as `←[36m` instead of colors. This affected the release notes and the update prompt in `unity self-update`, and could affect any colored output. The CLI now turns on the console's color support when it starts, and leaves output uncolored if the console can't provide it. Release notes from `unity changelog`, `unity self-update`, `unity plugin changelog`, and `unity plugin upgrade` also respect `--no-color` and `NO_COLOR` now.

- On macOS and Linux, pressing Ctrl-C during a `unity license` command no longer also stops the Unity Licensing Client that command started. The client keeps running for the Editor and for later commands, as it does when the command finishes on its own.

- On Windows, `unity self-update` and `unity self-install` can now replace the CLI while its background auth broker, or the identity server `unity open` starts, is still running. They move the running copy aside and put the new one in its place without waiting for those processes to exit, and `unity self-update` reports success only after the new version is in place. If the file still can’t be replaced, the message now suggests checking antivirus software instead of asking you to close other `unity` processes.

- Installing an Editor or module no longer fails a size check on an installer that downloaded correctly. The release catalog lists each download’s size rounded down to a whole kilobyte, so a file whose real size wasn’t a multiple of 1,024 bytes was rejected.

### Security

- `unity collaboration jira server add`, `update`, and `test` now take `--key-from-stdin`, which reads the Jira API token from stdin so it doesn't show in the process list or in CI logs that echo commands. Pipe the token in, for example `printf '%s' "$JIRA_TOKEN" | unity collaboration jira server test --organization-id <id> --url <url> --username <name> --key-from-stdin`. `--key` still works, and its help now warns that its value is visible.

- The CLI's logs and crash reports now fully mask email addresses whose domain ends in an internationalized top-level domain, such as `.рф` (written `xn--p1ai`). Previously, the end of the domain was left in the clear next to the mask.

- `unity bug` now removes user names and passwords embedded in URLs from the logs it attaches, including debug logs. Before, a credentialed URL in a debug log record, or one whose host was an IP address or `localhost`, was uploaded as written.

- `unity bug` now also masks the OS account name embedded in the Unity auth broker's named pipe (`Unity-auth-broker-<account>`, with or without a CoCreate slot) in the log files it collects, matching the CLI's own log writer and the native Hub. Previously, a collected Editor or Licensing Client log that mentioned the broker's pipe path was uploaded with the account name in the clear.

- On macOS, installing a plugin's runtime component now verifies the code signature of every native library it extracts, not just its main executable. Before, an unsigned or tampered library deep in the install could pass installation and only fail the first time something tried to load it.

- `unity plugin` now refuses a plugin download URL that hides a `..` behind an encoded slash or backslash (such as `..%2F`), or that contains a control character (such as a tab or a line break), written out or percent-encoded (such as `%0c`), or a non-ASCII character, or a `..` or `.` padded with spaces (such as `..%20`). A plugin catalog naming such a URL, or repeating a JSON key, is treated as invalid, and the CLI falls back to its cached or built-in catalog. No published plugin uses these forms.

- A command run inside a piped `unity shell` session, or one driven with `unity shell --protocol ndjson`, can no longer read the lines meant for the shell. Before, `unity auth login --secret-from-stdin`, `--key-from-stdin`, and `--git-token-stdin` read from the same stdin as the shell, so the rest of a script could be sent to a server as the secret. Those commands now see an empty stdin in these sessions. `--secret-from-stdin` and `--key-from-stdin` report that no secret was supplied. `--git-token-stdin` resolves no token and falls through to the next credential source (`--git-token`, a provider token environment variable, or your credential helper), so the command still runs with a credential configured there. Either way, the shell keeps running the lines that follow. Pass the secret with `--client-secret`, `--key`, `--git-token`, or an environment variable instead, or run the command outside the shell with the secret piped to it. Interactive `unity shell` sessions are unchanged, and plugin commands (`unity-*` executables on your PATH) still share the shell’s stdin.

- The helper that sends crash reports no longer inherits your whole environment. It receives only the variables it needs, so a credential such as `UNITY_SERVICE_ACCOUNT_SECRET` no longer reaches it.
