name: unity-development
description: >-
Use for Unity Editor automation through UniCli in projects where unicli is
available: running unicli exec/unicli eval, editing files under Assets/
or Packages/, compiling Unity code, running EditMode/PlayMode tests, and
creating or modifying GameObjects, scenes, prefabs, assets, packages, build
settings, project settings, or memory snapshots. Follow required safeguards such as
AssetDatabase.Import after file changes and Compile verification after C#
edits.
metadata:
version: "1.4.1"
UniCli — Unity Editor CLI
UniCli lets you interact with Unity Editor directly from the terminal.
The CLI (unicli) communicates with the Unity Editor over named pipes, so the Editor must be open with the com.yucchiy.unicli-server package installed.
RULES — Always Follow These
- After creating/modifying ANY file under
Assets/orPackages/: Rununicli exec AssetDatabase.Import --path "<path>" --jsonto generate.metafiles. Never create.metafiles manually — always let Unity generate them via this command. Unity requires.metafiles for every asset — skipping this causes missing references, broken imports, and compilation errors. This applies to all file types:.cs,.asmdef,.asset,.prefab, directories, etc. - After modifying C# code in the Unity project: Run
unicli exec Compile --jsonto verify compilation. - Always use
--jsonwhen parsing output programmatically. - If connection to Unity Editor fails: Retry 2–3 times, then ask the user to confirm Unity Editor is running with the project open.
- For platform-specific verification: Use
unicli exec BuildPlayer.Compile --target <platform> --jsonto catch platform-specific errors (missing#ifguards, unsupported APIs, etc.). - When running tests: Always use the default
--resultFilter failures(or--resultFilter nonefor summary-only) to keep output minimal. Only use--resultFilter allwhen you specifically need to inspect individual passed test details. This prevents large test suites from flooding context. Stack traces are omitted by default (--stackTraceLines 0); use--stackTraceLines 3when you need to diagnose a failure location. - When checking console logs: Use
Console.GetLogwith{"logType":"Warning,Error"}to filter out informational noise and focus on actionable issues. Stack traces are omitted by default; use{"logType":"Error","stackTraceLines":3}when debugging errors. - Discover commands dynamically: Use
unicli commands --jsonto list all available commands andunicli exec <command> --helpto see parameters for any command.--helpincludes nested type details when applicable, andcommands --jsonprovides nested schemas via each command'srequestTypeDetailsandresponseTypeDetails. Match nested type details bytypeId;typeandtypeNameare display labels and may not be unique. Do not rely on memorized command lists — the project may have custom commands. - Before scene-affecting operations: Run
unicli exec Editor.Status(without--json— the compact text summary is enough to check for dirty state and keeps output small) beforeTestRunner.RunPlayMode,BuildPlayer.Build,Scene.Open,Scene.New,Scene.Close,Menu.Execute, or entering Play Mode.TestRunner.RunPlayModeis the most common offender: the test runner creates a temporary test scene and swaps out the currently open scenes, so any unsaved scene changes at that moment can trigger a save prompt, abort the run, or leave the CLI waiting forever. If dirty scenes came from your own edits, save only the changes that should persist; revert or discard temporary probe changes when that is safer. If the dirty state may be from the user, do not save or discard it; ask the user how to proceed. - When commands hang or time out: Suspect a Unity Editor modal dialog such as a scene save prompt. Do not keep retrying blindly; ask the user to close or resolve the dialog, then retry.
Project Path
By default, unicli looks for a Unity project in the current working directory.
If the Unity project is in a subdirectory, set the UNICLI_PROJECT environment variable:
export UNICLI_PROJECT=path/to/unity/project
unicli exec Compile --json
Or prefix each command:
UNICLI_PROJECT=path/to/unity/project unicli exec Compile --json
Prerequisites
Before running commands, verify that the CLI is installed and the Editor is reachable:
unicli check
If unicli check reports that the server package is not installed, run unicli install to install it:
unicli install
If the server package version does not match the CLI version, run unicli install --update to update it:
unicli install --update
If the package is installed but the connection fails, make sure Unity Editor is open with the target project loaded. Retry a few times — the Editor may need a moment to start the server.
Executing Commands
Run commands with unicli exec <command>. Pass parameters as --key value flags or raw JSON. Use JSON for arrays and nested values:
unicli exec GameObject.Find '{"name":"Main Camera"}' --json
Boolean flags can be passed without a value:
unicli exec GameObject.Find --includeInactive --json
Array parameters can be passed by repeating the same flag:
unicli exec BuildPlayer.Build --locationPathName "Builds/Test.app" --options Development --options ConnectWithProfiler --json
Common options
--json— Output in JSON format (recommended for structured processing)--timeout <ms>— Set command timeout in milliseconds--no-focus— Don't bring Unity Editor to front--help— Show command parameters and nested type details
Key Workflows
Pre-flight before scene-affecting commands:
unicli exec Editor.Status
# Save only when the dirty scenes are your own intended persistent changes.
unicli exec Scene.Save '{"all":true}' --json
unicli exec TestRunner.RunPlayMode --json
Compile and run tests:
unicli exec Compile --json
unicli exec TestRunner.RunEditMode --json
unicli exec TestRunner.RunPlayMode --json
Inspect and modify settings:
unicli exec PlayerSettings.Inspect --json
unicli eval 'PlayerSettings.companyName = "MyCompany";' --json
Dynamic C# code execution (Eval):
unicli eval compiles and executes arbitrary C# code in the Unity Editor context. Use shell heredocs for multi-line code:
unicli eval 'return Application.unityVersion;' --json
unicli eval "$(cat <<'EOF'
var go = GameObject.Find("Main Camera");
return go.transform.position;
EOF
)" --json
Options:
--declarations '<code>'— Additional type declarations (classes, structs, enums) included outside the Execute method- The generated eval code receives a
cancellationTokenvariable for cooperative cancellation withasync/await
Running Custom Code
When built-in commands don't cover what you need, choose the right approach:
- One-shot tasks → Eval: Use
unicli evalfor ad-hoc operations, quick inspections, prototyping, and tasks that don't need to be reused. No files to create or compile — just pass the code directly. - Reusable project commands → CommandHandler: Use
CommandHandlerwhen the operation will be called repeatedly or is part of the project's workflow. This provides type-safe parameters, structured responses, and discoverability viaunicli commands.
Connect to a running player:
Connection.* commands manage the Unity Editor's PlayerConnection — used to connect to Development Builds running on devices or the local machine. This connection is required for remote debug commands and profiler data collection.
unicli exec Connection.List --json # List available targets
unicli exec Connection.Connect '{"id":-1}' --json # Connect by player ID
unicli exec Connection.Connect '{"ip":"192.168.1.100"}' --json # Connect by IP
unicli exec Connection.Connect '{"deviceId":"SERIAL"}' --json # Connect by device serial
unicli exec Connection.Status --json # Check connection status
Invoke remote debug commands on connected player:
Remote.* commands invoke debug commands on a connected Development Build. Requires: UNICLI_REMOTE scripting define symbol + Development Build with Autoconnect Profiler enabled.
unicli exec Remote.List --json
unicli exec Remote.Invoke '{"command":"Debug.Stats"}' --json
unicli exec Remote.Invoke '{"command":"Debug.GetPlayerPref","data":"{\"key\":\"HighScore\",\"type\":\"int\"}"}' --json
Built-in debug commands: Debug.SystemInfo, Debug.Stats, Debug.GetLogs, Debug.GetHierarchy, Debug.FindGameObjects, Debug.GetScenes, Debug.GetPlayerPref
Investigate a memory leak:
MemorySnapshot.* commands are available when the project has com.unity.memoryprofiler. Captures can come from MemorySnapshot.Capture, Profiler.TakeSnapshot, or the Memory Profiler window; commands read .snap paths or named loaded snapshots and keep heavy snapshot data out of the CLI response.
unicli exec MemorySnapshot.Capture '{"path":"MemoryCaptures/before.snap"}' --json
# Reproduce the suspected leak in Play Mode or a connected player.
unicli exec MemorySnapshot.Capture '{"path":"MemoryCaptures/after.snap"}' --json
unicli exec MemorySnapshot.Load '{"path":"MemoryCaptures/before.snap","name":"before"}' --json
unicli exec MemorySnapshot.Load '{"path":"MemoryCaptures/after.snap","name":"after"}' --json
unicli exec MemorySnapshot.AllOfMemory '{"snapshot":"after","baseSnapshot":"before","limit":20,"minSize":1048576,"minSizeDelta":1048576}' --json
unicli exec MemorySnapshot.AllOfMemory '{"snapshot":"after","includeBreakdownTree":true,"pathFilter":"Native/Unity Subsystems","pathDepth":1,"memoryMetric":"both"}' --json
unicli exec MemorySnapshot.Diff '{"baseSnapshot":"before","targetSnapshot":"after","scope":"native","minSizeDelta":1048576}' --json
unicli exec MemorySnapshot.TopObjects '{"snapshot":"after","typeFilter":"Texture2D","limit":20}' --json
unicli exec MemorySnapshot.TopObjects '{"snapshot":"after","scope":"managed","groupByType":true,"limit":20}' --json
unicli exec MemorySnapshot.Analyze '{"snapshot":"after","baseSnapshot":"before","limit":10}' --json
Useful MemorySnapshot commands:
MemorySnapshot.Capture— capture a.snapfile; optionalflagsareUnity.Profiling.Memory.CaptureFlagsnames.MemorySnapshot.List/MemorySnapshot.Load— list files, then pin a snapshot under a stablename/id.MemorySnapshot.Status/MemorySnapshot.Unload— inspect loaded/cached analyses, release one by id/name, or clear all cached entries.MemorySnapshot.Summary— category totals and metadata; usesnapshotorpath, omittedpathuses the latestMemoryCaptures/*.snap.MemorySnapshot.AllOfMemory— Memory Profiler All Of Memory style report; default is bounded type sections. UseincludeBreakdownTree/pathFilter/pathDepthfor All Of Memory tree paths, andmemoryMetric(allocated,resident,both) for tree sorting andminSize; type/object sections remain allocated-based.MemorySnapshot.TopObjects— largest native objects or native/managed type totals; usescope:"managed"for managed type aggregation.MemorySnapshot.Diff— native/managed type deltas; usebaseSnapshot/targetSnapshotor paths, omitted paths use latest and second latest snapshots.MemorySnapshot.Analyze— compact one-shot report combining summary, top types/objects, and optional diff.
Custom Command Handlers
The server auto-discovers all ICommandHandler implementations via TypeCache, so no manual registration is required.
Place custom handlers under Assets/Editor/UniCli/ with a dedicated asmdef:
# 1. Create asmdef and add reference to UniCli.Server.Editor
unicli exec AssemblyDefinition.Create --path "Assets/Editor/UniCli/MyProject.UniCli.Editor.asmdef" --name "MyProject.UniCli.Editor" --editorOnly --json
unicli exec AssemblyDefinition.AddReference --path "Assets/Editor/UniCli/MyProject.UniCli.Editor.asmdef" --reference "UniCli.Server.Editor" --json
# 2. Create handler script, then import and compile
unicli exec AssetDatabase.Import --path "Assets/Editor/UniCli" --json
unicli exec Compile --json
# 3. Verify registration and execute
unicli commands --json
unicli exec MyCategory.MyAction --targetName "test" --json
Handler implementation
using System.Threading;
using System.Threading.Tasks;
using UniCli.Protocol;
using UniCli.Server.Editor.Handlers;
namespace MyProject.UniCli.Editor.Handlers
{
[System.Serializable]
public class MyRequest
{
public string targetName = "";
}
[System.Serializable]
public class MyResponse
{
public string result;
}
public sealed class MyCustomHandler : CommandHandler<MyRequest, MyResponse>
{
public override string CommandName => "MyCategory.MyAction";
public override string Description => "Description shown in unicli commands";
protected override ValueTask<MyResponse> ExecuteAsync(MyRequest request, CancellationToken cancellationToken)
{
return new ValueTask<MyResponse>(new MyResponse
{
result = $"Processed {request.targetName}"
});
}
}
}
Key rules:
- Request/Response types must be
[Serializable]with public fields (not properties) — required byJsonUtility - Use
UnitasTRequestwhen no input is needed, or asTResponsewhen no output is needed - Throw
CommandFailedExceptionwith response data on failure - For async operations, use
TaskCompletionSource+awaitwithWithCancellation(cancellationToken)to wait for Unity callbacks - Constructor parameters are resolved from
ServiceRegistryfor dependency injection
Tips
- Run
unicli commands --jsonto discover all available commands, including project-specific custom commands. - Run
unicli exec <command> --helpto see parameters, types, defaults, and nested type details for any command. - Run
unicli commands --jsonto get machine-readable schemas; nested types are represented by each command'srequestTypeDetailsandresponseTypeDetails, andtypeIdis the stable key for matching them. - If a command times out, increase the timeout:
unicli exec Compile --timeout 60000.