UNICLI(1)

NAME

UniCliA CLI tool to control Unity Editor - enabling both humans and AI agents to run compilations, tests, and editor…

SYNOPSIS

$brew install unicli

INFO

166 stars
12 forks
0 views

DESCRIPTION

A CLI tool to control Unity Editor - enabling both humans and AI agents to run compilations, tests, and editor commands from the terminal.

README

UniCli

GitHub Release License: MIT

A command-line interface for controlling Unity Editor from the terminal. UniCli lets you compile scripts, run tests, manage packages, inspect GameObjects, and more — all without leaving your terminal.

Designed to work with AI coding agents such as Claude Code, UniCli gives AI the ability to interact with Unity Editor directly through structured CLI commands with JSON output.

  • 80+ built-in commands: compile, test, build, inspect GameObjects, manage scenes/prefabs/packages, and more
  • Dynamic C# execution: run arbitrary C# code in Unity via unicli eval
  • Extensible: add custom commands with a single C# class
  • AI-agent ready: structured JSON output, Claude Code plugin, and Agent Skills support
  • Cross-platform: NativeAOT binaries for macOS (arm64/x64) and Windows (x64)

Table of Contents

Getting Started

UniCli requires two components: the CLI (unicli) installed on your machine, and the Unity Package (com.yucchiy.unicli-server) installed in your Unity project. Both must be set up for UniCli to work.

Requirements

  • Unity 2022.3 or later
  • macOS (arm64 / x64) or Windows (x64)

CLI

Homebrew (macOS):

brew tap yucchiy/tap
brew install unicli

Scoop (Windows):

scoop bucket add unicli https://github.com/yucchiy/scoop-bucket
scoop install unicli

Manual: Download the latest binary from the Releases page and place it in your PATH.

Unity Package

The UniCli package must be installed in your Unity project. You can install it using the CLI:

unicli install

Or add it manually via Unity Package Manager using the git URL:

https://github.com/yucchiy/UniCli.git?path=src/UniCli.Unity/Packages/com.yucchiy.unicli-server

Quick Usage

Open your Unity project in the Editor, then run unicli from the Unity project directory (or any subdirectory). UniCli automatically detects the project by looking for an Assets folder in the current directory and its ancestors.

# Verify connection
unicli check

List all available commands

unicli commands

Compile scripts

unicli exec Compile

Run EditMode tests

unicli exec TestRunner.RunEditMode

Execute arbitrary C# code (--json for JSON output)

unicli eval 'return Application.unityVersion;' --json

CLI Usage

The unicli binary provides the following subcommands:

SubcommandDescription
checkCheck package installation and Unity Editor connection
installInstall the UniCli package into a Unity project
execExecute a command on the Unity Editor
evalCompile and execute C# code dynamically in the Unity Editor
commandsList all available commands
statusShow connection status and project info
completionsGenerate shell completion scripts (bash / zsh / fish)
unicli check             # verify installation and editor connection
unicli install           # install the Unity package
unicli commands          # list all available commands
unicli eval '<code>'     # compile and execute C# code dynamically
unicli status            # show connection details
unicli completions bash  # generate shell completions

Add --json to check, commands, or status for machine-readable JSON output.

Project Discovery

By default, unicli searches the current directory and its ancestors for a Unity project (a directory containing an Assets folder). If you run unicli from outside a Unity project, or want to target a specific project, set the UNICLI_PROJECT environment variable:

# Run from anywhere by specifying the project path
UNICLI_PROJECT=/path/to/my/unity-project unicli exec Compile --json

Useful when the current directory is not inside the Unity project

UNICLI_PROJECT=src/UniCli.Unity unicli commands --json

Executing Commands

Use unicli exec <command> to run commands on the Unity Editor.

Parameter syntax

Parameters can be passed as --key value flags (recommended) or as a raw JSON string:

# --key value syntax (recommended)
unicli exec GameObject.Find --name "Main Camera"
unicli exec TestRunner.RunEditMode --testNameFilter MyTest

Raw JSON syntax

unicli exec GameObject.Find '{"name":"Main Camera"}'

Boolean flags can be passed without a value:

unicli exec GameObject.Find --includeInactive

Array parameters can be passed by repeating the same flag:

unicli exec BuildPlayer.Build --locationPathName "Builds/Test.app" --options Development --options ConnectWithProfiler
unicli exec BuildPlayer.Compile --target iOS --extraScriptingDefines MY_DEFINE --extraScriptingDefines ANOTHER_DEFINE

Common options

These options can be combined with any exec command:

OptionDescription
--jsonOutput in JSON format
--timeoutSet command timeout in milliseconds
--no-focusDon't bring Unity Editor to front
--helpShow command parameters and nested type details

By default, when the server is not responding (e.g., after an assembly reload), the CLI automatically brings Unity Editor to the foreground using a PID file (Library/UniCli/server.pid) and restores focus to the original application once the command completes. Use --no-focus to disable this behavior, or set the UNICLI_FOCUS environment variable to 0 or false to disable it globally.

Examples

# Compile scripts (--json for JSON output, --timeout to set deadline)
unicli exec Compile --json
unicli exec Compile --timeout 30000

Build the player

unicli exec BuildPlayer.Build --locationPathName "Builds/Test.app" unicli exec BuildPlayer.Build --locationPathName "Builds/Test.app" --options Development --target Android

Run tests

unicli exec TestRunner.RunEditMode unicli exec TestRunner.RunEditMode --testNameFilter MyTest --stackTraceLines 3 unicli exec TestRunner.RunEditMode --resultFilter all

Find and inspect GameObjects

unicli exec GameObject.Find --name "Main Camera" unicli exec GameObject.GetHierarchy unicli exec GameObject.GetComponents --instanceId 1234

Create and modify GameObjects

unicli exec GameObject.Create --name "Enemy" unicli exec GameObject.SetTransform --path "Enemy" --position 1,2,3 --rotation 0,90,0 unicli exec GameObject.AddComponent --path "Enemy" --typeName BoxCollider

Scene operations

unicli exec Scene.Open --path "Assets/Scenes/Level1.unity" unicli exec Scene.Save --all

Set component properties

unicli exec Component.SetProperty --componentInstanceId 1234 --propertyPath "m_IsKinematic" --value "true"

Console logs

unicli exec Console.GetLog --logType "Warning,Error"

Show command parameters and usage

unicli exec GameObject.Find --help

Inspect nested request/response types

unicli exec <command> --help shows top-level fields and, when available, nested type details. For machine-readable schemas, use unicli commands --json: each field includes a children array.

# Human-friendly schema (includes nested type details)
unicli exec AssetDatabase.Find --help

Machine-readable schema (fields include "children")

unicli commands --json

See Built-in Commands for the full list of available commands.

Dynamic Code Execution (Eval)

unicli eval compiles and executes arbitrary C# code in the Unity Editor context using AssemblyBuilder. Code has full access to Unity APIs (UnityEngine, UnityEditor) as well as any packages and libraries referenced by the project.

unicli eval '<code>' [--json] [--declarations '<decl>'] [--timeout <ms>]
OptionDescription
--jsonOutput in JSON format
--declarationsAdditional type declarations (classes, structs, enums)
--timeoutTimeout in milliseconds

For multi-line code, use shell heredocs:

unicli eval "$(cat <<'EOF'
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
var objects = GameObject.FindObjectsOfType<GameObject>(true);
return $"{scene.name}: {objects.Length} objects";
EOF
)" --json

The result is returned as raw JSON. If the return type is [Serializable], it is serialized with JsonUtility. UnityEngine.Object types use EditorJsonUtility. Primitives and strings are returned directly. Code that doesn't return a value (void operations) returns null.

Use --declarations to define custom types for structured return values:

unicli eval "$(cat <<'EOF'
var stats = new SceneStats();
stats.sceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
stats.objectCount = GameObject.FindObjectsOfType<GameObject>().Length;
return stats;
EOF
)" --declarations "$(cat <<'EOF'
[System.Serializable]
public class SceneStats
{
    public string sceneName;
    public int objectCount;
}
EOF
)" --json

Eval code supports async/await and receives a cancellationToken variable (System.Threading.CancellationToken) that is cancelled when the client disconnects.

Use it for cooperative cancellation of long-running operations:

# Wait asynchronously with cancellation support
unicli eval 'await Task.Delay(5000, cancellationToken); return "done";' --json

Custom Commands

You can extend UniCli by adding custom commands in your Unity project. Commands are auto-discovered — no manual registration required.

Inherit from CommandHandler<TRequest, TResponse> and define [Serializable] request/response types:

using System;
using System.Threading;
using System.Threading.Tasks;
using UniCli.Protocol;
using UniCli.Server.Editor.Handlers;

public sealed class GreetHandler : CommandHandler<GreetRequest, GreetResponse> { public override string CommandName => "MyApp.Greet"; public override string Description => "Returns a greeting message";

protected override ValueTask&lt;GreetResponse&gt; ExecuteAsync(GreetRequest request, CancellationToken cancellationToken)
{
    return new ValueTask&lt;GreetResponse&gt;(new GreetResponse
    {
        message = $&quot;Hello, {request.name}!&quot;
    });
}

}

[Serializable] public class GreetRequest { public string name; }

[Serializable] public class GreetResponse { public string message; }

Once the handler is placed anywhere in your Unity project, it becomes immediately available:

unicli exec MyApp.Greet --name "World"

For naming conventions (when to use concept-based names like Scene.* vs API-direct names like AssetDatabase.*), see doc/command-naming-guidelines.md.

For commands that require no input or produce no output, use Unit as the type parameter:

public sealed class PingHandler : CommandHandler<Unit, PingResponse>
{
    public override string CommandName => "MyApp.Ping";
    public override string Description => "Health check";
protected override ValueTask&lt;PingResponse&gt; ExecuteAsync(Unit request, CancellationToken cancellationToken)
{
    return new ValueTask&lt;PingResponse&gt;(new PingResponse { ok = true });
}

}

Text formatting

Override TryWriteFormatted to provide human-readable output (used when --json is not specified):

protected override bool TryWriteFormatted(GreetResponse response, bool success, IFormatWriter writer)
{
    writer.WriteLine(response.message);
    return true;
}

With this override, the output changes depending on whether --json is used:

$ unicli exec MyApp.Greet --name "World"
Hello, World!

$ unicli exec MyApp.Greet --name "World" --json {"message":"Hello, World!"}

Async handlers and cancellation

All command handlers receive a CancellationToken that is cancelled when the client disconnects (e.g., Ctrl+C). For long-running async operations, pass the token through to ensure prompt cancellation:

using System.Threading;
using System.Threading.Tasks;
using UniCli.Server.Editor;
using UniCli.Server.Editor.Handlers;

public sealed class LongRunningHandler : CommandHandler<MyRequest, MyResponse> { public override string CommandName => "MyApp.LongTask"; public override string Description => "A long-running async operation";

protected override async ValueTask&lt;MyResponse&gt; ExecuteAsync(MyRequest request, CancellationToken cancellationToken)
{
    var tcs = new TaskCompletionSource&lt;string&gt;();

    // Start an async Unity operation
    SomeAsyncUnityApi.Start(result =&gt; tcs.SetResult(result));

    // Use WithCancellation to abort the wait if the client disconnects
    var result = await tcs.Task.WithCancellation(cancellationToken);

    return new MyResponse { value = result };
}

}

The WithCancellation extension method (on Task / Task<T>) races the task against the cancellation token. If the client disconnects, the await throws OperationCanceledException and the server immediately becomes available for the next command.

For synchronous handlers that complete instantly, the cancellationToken parameter can be ignored.

Error handling

Throw CommandFailedException to report failures while still returning structured data:

if (hasErrors)
    throw new CommandFailedException("Validation failed", response);

Built-in Commands

The following commands are built in. Run unicli commands to see this list from the terminal, or unicli exec <command> --help to see parameters for any command. For a full reference with parameter and response details, see doc/commands.md.

Core

CommandDescription
CompileCompile scripts and return results
EvalCompile and execute C# code dynamically

Console

CommandDescription
Console.GetLogGet console log entries (supports comma-separated logType filter, e.g. "Warning,Error")
Console.ClearClear console

PlayMode

CommandDescription
PlayMode.EnterEnter play mode
PlayMode.ExitExit play mode
PlayMode.PauseToggle pause
PlayMode.StatusGet the current play mode state

TestRunner

CommandDescription
TestRunner.RunEditModeRun EditMode tests (resultFilter: "failures" (default), "all", "none")
TestRunner.RunPlayModeRun PlayMode tests (resultFilter: "failures" (default), "all", "none")

Build

CommandDescription
BuildPlayer.BuildBuild the player
BuildPlayer.CompileCompile player scripts for a build target
BuildTarget.GetActiveGet the active build target and target group
BuildTarget.SwitchSwitch the active build target
BuildProfile.ListList all build profiles (Unity 6+)
BuildProfile.GetActiveGet the active build profile (Unity 6+)
BuildProfile.SetActiveSet the active build profile (Unity 6+)
BuildProfile.InspectInspect a build profile's details (Unity 6+)

GameObject / Component

CommandDescription
GameObject.FindFind GameObjects
GameObject.CreateCreate a new GameObject
GameObject.CreatePrimitiveCreate a primitive GameObject
GameObject.GetComponentsGet components
GameObject.SetActiveSet active state
GameObject.GetHierarchyGet scene hierarchy
GameObject.AddComponentAdd a component
GameObject.RemoveComponentRemove a component
GameObject.DestroyDestroy a GameObject
GameObject.SetTransformSet local transform
GameObject.DuplicateDuplicate a GameObject
GameObject.RenameRename a GameObject
GameObject.SetParentChange parent or move to root
Component.SetPropertySet a component property (supports ObjectReference via guid:, instanceId:, asset path)

Scene

CommandDescription
Scene.ListList all loaded scenes
Scene.GetActiveGet the active scene
Scene.SetActiveSet the active scene
Scene.OpenOpen a scene by asset path
Scene.CloseClose a loaded scene
Scene.SaveSave a scene or all open scenes
Scene.NewCreate a new scene

Asset

CommandDescription
AssetDatabase.FindSearch assets
AssetDatabase.ImportImport an asset
AssetDatabase.GetPathGet asset path by GUID
AssetDatabase.DeleteDelete an asset
Prefab.GetStatusGet prefab instance status
Prefab.InstantiateInstantiate a prefab into scene
Prefab.SaveSave GameObject as prefab
Prefab.ApplyApply prefab overrides
Prefab.UnpackUnpack a prefab instance
Material.CreateCreate a new material asset
Material.InspectRead all properties of a material (auto-generated)
Material.SetColorSet a color property on a material
Material.GetColorGet a color property from a material
Material.SetFloatSet a float property on a material
Material.GetFloatGet a float property from a material

Animation

CommandDescription
AnimatorController.CreateCreate a new .controller asset
AnimatorController.InspectInspect layers, parameters, states
AnimatorController.AddParameterAdd a parameter
AnimatorController.RemoveParameterRemove a parameter
AnimatorController.AddStateAdd a state to a layer
AnimatorController.AddTransitionAdd a transition between states
AnimatorController.AddTransitionConditionAdd a condition to a transition
Animator.InspectInspect Animator component
Animator.SetControllerAssign an AnimatorController
Animator.SetParameterSet a parameter value (PlayMode)
Animator.PlayPlay a state immediately (PlayMode)
Animator.CrossFadeCross-fade to a state (PlayMode)

PackageManager

CommandDescription
PackageManager.ListList packages
PackageManager.AddAdd a package
PackageManager.RemoveRemove a package
PackageManager.SearchSearch registry
PackageManager.GetInfoGet package details
PackageManager.UpdateUpdate a package

Project / Settings

CommandDescription
Project.InspectGet project info
PlayerSettings.InspectGet all PlayerSettings values (auto-generated)
EditorSettings.InspectGet all EditorSettings values (auto-generated)
EditorUserBuildSettings.InspectGet all EditorUserBuildSettings values (auto-generated)

AssemblyDefinition

CommandDescription
AssemblyDefinition.ListList assembly definitions
AssemblyDefinition.GetGet assembly definition
AssemblyDefinition.CreateCreate assembly definition
AssemblyDefinition.AddReferenceAdd asmdef reference
AssemblyDefinition.RemoveReferenceRemove asmdef reference

Selection / Window / Menu

CommandDescription
Selection.GetGet the current editor selection
Selection.SetAssetSelect an asset by path
Selection.SetAssetsSelect multiple assets by paths
Selection.SetGameObjectSelect a GameObject by path
Selection.SetGameObjectsSelect multiple GameObjects by paths
Window.ListList all available EditorWindow types
Window.OpenOpen an EditorWindow by type name
Window.FocusFocus an already-open EditorWindow
Window.CreateCreate a new EditorWindow instance
Menu.ListList menu items
Menu.ExecuteExecute a menu item

Utility

CommandDescription
Type.ListList types derived from a base type
Type.InspectInspect nested types of a given type

Connection / Remote

CommandDescription
Connection.ListList available connection targets
Connection.ConnectConnect to a target by ID, IP, or device ID
Connection.StatusGet current connection status
Remote.ListList debug commands on connected player
Remote.InvokeInvoke a debug command on connected player

Profiler

CommandDescription
Profiler.InspectGet profiler status and memory statistics
Profiler.StartRecordingStart profiler recording
Profiler.StopRecordingStop profiler recording
Profiler.SaveProfileSave profiler data to a .raw file
Profiler.LoadProfileLoad profiler data from a .raw file
Profiler.GetFrameDataGet CPU profiler sample data for a specific frame
Profiler.TakeSnapshotTake a memory snapshot (.snap file)
Profiler.AnalyzeFramesAnalyze recorded frames and return aggregate statistics
Profiler.FindSpikesFind frames exceeding frame time or GC allocation thresholds

Screenshot / Recorder

CommandDescription
Screenshot.CaptureCapture Game View screenshot as PNG (requires Play Mode)
Recorder.StartRecordingStart recording Game View as video (requires Play Mode)
Recorder.StopRecordingStop the current video recording
Recorder.StatusGet the current recording status

Module

CommandDescription
Module.ListList all available modules and their enabled status
Module.EnableEnable a module and reload the command dispatcher
Module.DisableDisable a module and reload the command dispatcher

Optional: Search

CommandDescription
SearchSearch Unity project using Unity Search API

Optional: NuGet

Requires NuGetForUnity.

CommandDescription
NuGet.ListList all installed NuGet packages
NuGet.InstallInstall a NuGet package
NuGet.UninstallUninstall a NuGet package
NuGet.RestoreRestore all NuGet packages
NuGet.ListSourcesList all configured package sources
NuGet.AddSourceAdd a NuGet package source
NuGet.RemoveSourceRemove a NuGet package source

Optional: BuildMagic

Requires BuildMagic (jp.co.cyberagent.buildmagic).

CommandDescription
BuildMagic.ListList all BuildMagic build schemes
BuildMagic.InspectInspect a build scheme's configurations
BuildMagic.ApplyApply a build scheme

Settings Inspect commands (PlayerSettings.Inspect, EditorSettings.Inspect, etc.) are auto-generated via a Roslyn Source Generator, so the available properties always match your exact Unity version. To modify settings, use unicli eval:

unicli eval 'PlayerSettings.companyName = "MyCompany";' --json

Module Management

UniCli groups optional commands into modules that can be toggled on or off per project. Core commands (Compile, Eval, Console, PlayMode, Menu, Build, TestRunner, Settings, etc.) are always available and cannot be disabled.

The following modules are available:

ModuleDescription
SceneScene operations
GameObjectGameObject and Component operations
AssetsAssetDatabase, Prefab, Material operations
ProfilerProfiler operations
AnimationAnimator and AnimatorController operations
RemoteRemote debug and Connection operations
RecorderVideo recording operations (requires com.unity.recorder)
SearchUnity Search API operations
NuGetNuGet package management (requires NuGetForUnity)
BuildMagicBuildMagic build scheme operations (requires jp.co.cyberagent.buildmagic)

All modules are enabled by default. To disable a module, use the CLI or the Unity settings UI (Edit > Project Settings > UniCli):

# List all modules and their enabled status
unicli exec Module.List --json

Enable a module

unicli exec Module.Enable '{"name":"Search"}' --json

Disable a module

unicli exec Module.Disable '{"name":"Profiler"}' --json

Module settings are saved in ProjectSettings/UniCliSettings.asset.

unicli commands --json includes builtIn and module fields for each command, so you can programmatically identify whether a command is built-in or user-defined and which module it belongs to.

Architecture

UniCli consists of two components:

  • CLI (unicli) — A NativeAOT-compiled binary that you run from the terminal
  • Unity Package (com.yucchiy.unicli-server) — An Editor plugin that receives and executes commands inside Unity

Architecture

┌──────────┐  Named Pipe     ┌────────────────┐  PlayerConnection  ┌────────────────┐
│  unicli  │◄───────────────►│  Unity Editor  │◄──────────────────►│     Device     │
│  (CLI)   │ Length-prefixed │  (Server)      │ Chunked messages   │  (Dev Build)   │
│          │ JSON messages   │                │                    │                │
└──────────┘                 └────────────────┘                    └────────────────┘

CLI ↔ Editor (Named Pipe): The CLI and Unity Editor communicate over a named pipe. The pipe name is derived from a SHA256 hash of the project's Assets path, so each project gets its own connection. Messages use a length-prefixed JSON framing protocol with a handshake (magic bytes UCLI + protocol version). The server plugin initializes via [InitializeOnLoad], creates a background listener on the named pipe, and enqueues incoming commands to a ConcurrentQueue. Commands are dequeued and executed on Unity's main thread every frame via EditorApplication.update.

Editor ↔ Device (PlayerConnection): For remote debugging, the Editor relays commands to a running Development Build via Unity's PlayerConnection. The runtime module (UniCli.Remote) auto-initializes a RuntimeDebugReceiver on the device, which discovers debug commands via reflection and registers message handlers. Responses are split into 16 KB chunks to work around PlayerConnection's undocumented message size limits. The Editor's RemoteBridge reassembles chunks and returns the complete response to the CLI.

Remote Commands

UniCli can invoke debug commands on a running Development Build via Unity's PlayerConnection. This lets you inspect runtime state, query performance stats, and execute custom debug operations on a connected device — all from the terminal.

Communication path: CLI → Unity Editor (Named Pipe) → Device (PlayerConnection)

Prerequisites

  1. Define symbol — Add UNICLI_REMOTE to your project's Scripting Define Symbols (Player Settings → Other Settings).
    • The remote module's asmdef has two define constraints: UNICLI_REMOTE || UNITY_EDITOR and DEVELOPMENT_BUILD || UNITY_EDITOR.
    • In the Editor, both constraints are satisfied automatically — no additional setup needed for development.
    • In player builds, UNICLI_REMOTE must be defined and the build must be a Development Build for the module to be included.
    • This means release builds and builds without UNICLI_REMOTE will never contain the remote module code.
  2. Development Build — Build with the "Development Build" and "Autoconnect Profiler" options enabled to allow PlayerConnection communication.
  3. Connect — Use Connection.Connect to connect the Editor to the running player before sending remote commands.

Editor-side commands

CommandDescription
Remote.ListList all debug commands registered on the connected player
Remote.InvokeInvoke a debug command on the connected player
# List debug commands on connected runtime player
unicli exec Remote.List

Invoke a debug command

unicli exec Remote.Invoke '{"command":"Debug.Stats"}'

Invoke with parameters

unicli exec Remote.Invoke '{"command":"Debug.GetPlayerPref","data":"{&quot;key&quot;:&quot;HighScore&quot;,&quot;type&quot;:&quot;int&quot;}"}'

Specify a particular player (when multiple are connected)

unicli exec Remote.Invoke '{"command":"Debug.SystemInfo","playerId":1}'

Built-in debug commands

The following debug commands are included in the package and available on any Development Build with UNICLI_REMOTE defined:

CommandDescription
Debug.SystemInfoDevice model, OS, CPU, GPU, memory, battery, screen, quality settings
Debug.StatsFPS, frame time, memory usage, GC collection counts, scene/object counts
Debug.GetLogsRecent log entries from a ring buffer (supports limit and type filter)
Debug.GetHierarchyActive scene hierarchy tree with depth, active state, component names
Debug.FindGameObjectsSubstring search across all GameObjects (including inactive)
Debug.GetScenesAll loaded scenes with name, path, build index, root count
Debug.GetPlayerPrefRead a PlayerPrefs value by key (string, int, or float)

Creating custom debug commands

Inherit from DebugCommand<TRequest, TResponse> and override CommandName / Description. Commands are auto-discovered at runtime via reflection.

using System;
using UniCli.Remote;
using UnityEngine;

public sealed class ToggleHitboxesCommand : DebugCommand<ToggleHitboxesCommand.Request, ToggleHitboxesCommand.Response> { public override string CommandName => "Debug.ToggleHitboxes"; public override string Description => "Toggle hitbox visualization";

protected override Response ExecuteCommand(Request request)
{
    HitboxVisualizer.Enabled = request.enabled;
    return new Response { enabled = HitboxVisualizer.Enabled };
}

[Serializable]
public class Request
{
    public bool enabled;
}

[Serializable]
public class Response
{
    public bool enabled;
}

}

Use Unit as the type parameter when no input or output is needed:

public sealed class ResetStateCommand : DebugCommand<Unit, Unit>
{
    public override string CommandName => "Debug.ResetState";
    public override string Description => "Reset game state";
protected override Unit ExecuteCommand(Unit request)
{
    GameManager.ResetAll();
    return Unit.Value;
}

}

Key points:

  • Request/Response types must be [Serializable] with public fields (required by JsonUtility)
  • The base class uses [RequireDerived] to protect all subclasses from Managed Stripping automatically
  • Commands run synchronously on the main thread
  • Override CommandName (by convention Debug.*) and optionally Description
  • Place custom commands anywhere in your project — they are discovered automatically via reflection at startup

AI Agent Integration

Claude Code Plugin

UniCli provides a Claude Code plugin via the marketplace. This plugin gives Claude Code the ability to interact with Unity Editor — compiling scripts, running tests, inspecting GameObjects, managing packages, and more — as part of its coding workflow.

With the plugin installed, Claude Code can:

  • Compile & verify — catch compilation errors immediately after code changes
  • Run tests — execute EditMode / PlayMode tests and read results
  • Inspect the scene — find GameObjects, check components, and navigate the hierarchy
  • Manage packages — add, remove, and search Unity packages
  • Discover commands — automatically find all available commands, including project-specific custom commands

The plugin also handles server package setup: if the com.yucchiy.unicli-server package is not yet installed in the Unity project, Claude Code will run unicli install to set it up automatically.

Install the plugin

The UniCli CLI must be installed beforehand. See Getting Started — CLI above.

# 1. Add the UniCli marketplace
/plugin marketplace add yucchiy/UniCli

2. Install the plugin

/plugin install unicli@unicli

Agent Skills / Codex

UniCli's skill definition follows the Agent Skills specification, making it compatible with multiple AI coding agents:

  • Codex (OpenAI): Automatically detected via .agents/skills/unity-development/
  • Claude Code: Installed as a plugin via .claude-plugin/
  • Other agents: Any tool that supports the Agent Skills spec can load the skill from .agents/skills/

Install via Codex $skill-installer

If you're using Codex, install the UniCli skill directly from this repository:

$skill-installer install https://github.com/yucchiy/UniCli/tree/main/.agents/skills/unity-development

Once installed, Codex automatically detects the skill and gains the ability to interact with Unity Editor.

Manual setup for other projects

To use UniCli's skill in another project, copy the skill directory:

mkdir -p .agents/skills
cp -R /path/to/UniCli/.agents/skills/unity-development .agents/skills/unity-development

License

MIT

SEE ALSO

clihub3/7/2026UNICLI(1)