앞의 두 글에 들어간 데모 스크린샷 아홉 장은 에디터 창을 한 번도 클릭하지 않고 찍었습니다. 터미널에서 프로젝트를 열고, 씬을 바꾸고, 재생하고, 게임 뷰를 PNG로 저장하는 일을 전부 명령으로 했습니다. 그 도구가 Unity CLI입니다. 이 글은 Unity CLI가 무엇이고 어디까지 할 수 있는지를, 어젯밤에 실제로 쓴 명령을 따라가며 정리한 것입니다.
무엇인가
Unity CLI는 Unity Hub가 하는 일을 터미널에서 하게 해 주는 명령줄 도구입니다. 에디터 버전을 설치하고, 프로젝트를 만들고 열고, 빌드와 테스트를 배치로 돌립니다. 여기까지는 Hub의 터미널판입니다.
다른 점은 그다음입니다. 프로젝트에 Pipeline이라는 패키지를 넣으면, 이미 열려 있는 에디터가 작은 서버가 되어 터미널의 명령을 받습니다. 게임오브젝트를 만들고, 씬을 열고, 재생하고, 스크린샷을 찍고, 심지어 C# 한 줄을 에디터 안에서 실행합니다. 그리고 그 명령들을 MCP 서버로도 내보내서 AI 에이전트가 같은 것을 할 수 있게 합니다. 2026년 9월 기준 버전은 1.0.0-beta.9, 아직 베타입니다.
설치는 한 줄입니다.
1
2
3
curl -fsSL https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.sh | UNITY_CLI_CHANNEL=beta bash
unity --version # 1.0.0-beta.9
unity doctor # 로그인, 설치된 에디터, 최근 오류를 한 번에
모든 명령은 --format json을 받습니다. 사람이 읽는 표 대신 기계가 읽는 JSON을 내보내니, 스크립트나 에이전트가 결과를 파싱해 다음 명령을 정할 수 있습니다. 이 한 가지가 Hub와 CLI를 가르는 차이입니다.
첫 층: 에디터와 프로젝트
1
2
3
4
5
unity editors --installed # 이 기기의 에디터 목록
unity releases --stream lts # 설치할 수 있는 LTS 버전
unity install 6000.4.10f1 --module android --yes --accept-eula
unity projects create MyTwin --path ~/UnityProjects --editor-version lts --template com.unity.template.3d
unity open ~/UnityProjects/MyTwin # 프로젝트가 요구하는 버전으로 열기
어젯밤 기기에는 6000.3, 6000.4, 6000.5 세 버전이 있었고, 교재 프로젝트는 6000.4.10f1을 요구했습니다. unity open에 버전을 붙이면 맞는 에디터로 열어 주고, 없으면 설치를 제안합니다. 여러 버전을 오가며 가르치는 사람에게는 이것만으로도 쓸 이유가 됩니다.
프로젝트를 만들 때 Git 저장소를 함께 만들어 첫 커밋까지 밀어 주는 옵션도 있습니다. 토큰은 표준 입력으로만 받아서 셸 기록에 남지 않게 합니다.
둘째 층: 배치로 돌리기
1
2
3
unity test ~/UnityProjects/MyTwin --mode EditMode --report-format junit --output results.xml
unity build ~/UnityProjects/MyTwin --target StandaloneOSX --execute-method Builder.Build
unity run ~/UnityProjects/MyTwin -- -executeMethod Tools.Export -logFile out.log
셋 다 에디터를 배치 모드로 띄워 일을 시키고 종료합니다. 배치 모드 플래그는 CLI가 알아서 붙이고, 테스트 결과는 GitHub Actions가 그대로 읽는 JUnit 형식으로 씁니다. 실패하면 종료 코드 6, 인증 문제면 3. CI에서 분기할 수 있게 코드가 정해져 있습니다.
교육에서 이 층이 쓸모 있는 자리는 채점입니다. 수강생 프로젝트 스무 개에 같은 에디트모드 테스트를 돌려 통과 여부를 표로 받는 일이 명령 하나의 반복이 됩니다.
셋째 층: 열려 있는 에디터에 말하기
여기가 이 도구의 본론입니다. 에디터가 터미널의 명령을 받으려면 프로젝트에 Pipeline 패키지가 들어 있어야 합니다. 넣는 방법은 두 가지입니다.
새 프로젝트라면 Hub에서 만들 때 끝납니다. 새 프로젝트 화면 오른쪽에 Use Unity CLI 체크박스가 있고, 이것을 켜고 만들면 Pipeline 패키지와 설정이 프로젝트에 미리 들어갑니다. 에디터를 열자마자 unity status에 잡히고 명령을 받습니다.
이미 있는 프로젝트나 체크하지 않고 만든 프로젝트는 따로 세팅해야 합니다. 어젯밤 교재 프로젝트가 이 경우였고, 명령 한 줄로 패키지를 넣었습니다.
1
2
3
unity pipeline install --project-path ~/UnityProjects/TP_GPUComputeShader # 체크 안 한 프로젝트는 이 한 줄
unity open ~/UnityProjects/TP_GPUComputeShader --editor-version 6000.4.10f1
unity status --format json # state 가 "ready" 가 되면 명령을 받을 준비
pipeline install은 프로젝트의 Packages/manifest.json에 com.unity.pipeline을 추가합니다. 에디터가 열려 있었다면 패키지를 가져오느라 한 번 리로드되고, 그다음부터 연결됩니다.
status는 이 기기에서 열려 있는 에디터를 전부 보여 줍니다. 어젯밤에는 다른 프로젝트 두 개가 이미 열려 있어서 셋이 나왔고, 그래서 이후 모든 명령에 --project-path를 붙여 어느 에디터에 말하는지 지정했습니다.
에디터가 받는 명령은 에디터가 정합니다. unity command를 인자 없이 부르면 목록이 옵니다. 어젯밤 교재 프로젝트는 151개를 내놨습니다. 씬 열기, 재생, 게임오브젝트 만들기, 계층 구조 읽기, 스크린샷, 애니메이터 레이어 추가, 플레이어 설정 읽기와 쓰기. 그리고 eval. C# 코드를 문자열로 보내면 에디터 안에서 컴파일해 실행하고 반환값을 돌려줍니다.
1
2
3
4
unity command eval 'return UnityEngine.Application.unityVersion + " | "
+ UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name;' \
--project-path ~/UnityProjects/TP_GPUComputeShader --format json
# "6000.4.10f1 | Session3_WarehouseInstancing"
왕복은 0.2초에서 0.6초쯤입니다. 배치 모드로 에디터를 새로 띄우는 데 수십 초가 걸리는 것과 비교하면, 이미 켜져 있는 에디터에 말을 거는 쪽이 압도적으로 빠릅니다. 스크립트 리컴파일도, 도메인 리로드도 없습니다. 그래서 에이전트가 한 세션 안에서 수십 번 왕복하며 작업하는 것이 가능해집니다.
어젯밤 실제로 한 일
스크린샷 아홉 장을 찍은 흐름을 그대로 적습니다. 씬 하나마다 네 명령입니다.
1
2
3
4
5
6
7
8
P=~/UnityProjects/TP_GPUComputeShader
c() { unity command --project-path "$P" --format json --no-banner "$@"; }
c open_scene --path GPUInstancingResources/Scenes/Session2_PerInstanceDataAndPicking
c editor_play
# ... 잠시 기다린 뒤
c capture_game_view --source screen --width 1920 --height 1080 --save_path Screenshots/gi2_heatmap.png
c editor_stop
capture_game_view의 source=screen은 화면 위 UI까지 포함한 게임 뷰를 그대로 저장합니다. 기본값인 카메라 렌더는 오버레이 UI를 놓치기 때문에, 프레임 시간 패널이 보이는 사진을 원하면 screen을 써야 합니다.
여기서 함정을 하나 만났습니다. 재생 명령은 성공했는데 시뮬레이션 시간이 0에서 움직이지 않았습니다. 히트맵은 몇 초가 지나야 이상 값이 퍼지는데 첫 프레임만 찍힌 것입니다. 원인은 에디터 창이 다른 창 뒤에 있어서였습니다. 에디터는 포커스가 없으면 재생 루프를 거의 돌리지 않습니다. 해결은 프레임을 직접 밀어 주는 것이었습니다.
1
2
3
c eval 'for (int i = 0; i < 100; i++) UnityEditor.EditorApplication.Step();
return UnityEngine.Time.timeSinceLevelLoad;'
# 한 번에 100프레임, 고정 시간 0.02초니까 시뮬레이션 2초
이 명령을 열 번 부르면 시뮬레이션 20초가 흐르고, 그 뒤에 찍은 사진에는 이상 값이 붉게 솟아 있습니다. 창을 앞으로 가져오지 않고 해결할 수 있었던 것은 eval이 있어서입니다. 정해진 명령 목록에 없는 일도 C# 한 줄이면 됩니다.
작업이 끝나면 에디터를 닫습니다. 열려 있는 에디터는 라이선스 시트를 하나 물고 있습니다.
1
c eval 'UnityEditor.EditorApplication.Exit(0); return "bye";'
에이전트가 붙는 자리
같은 명령 151개는 MCP 서버로도 나갑니다.
1
unity mcp configure claude-code # AI 클라이언트 설정에 Unity MCP 서버를 등록
이렇게 하면 에이전트가 에디터의 명령 목록을 도구로 받아서, “이 씬을 열고 재생해서 5초 뒤 화면을 찍어라”를 사람의 손 없이 수행합니다. 어젯밤 스크린샷 작업은 정확히 그 형태였습니다. 사람은 어떤 사진이 필요한지 말했고, 명령을 고르고 순서를 짜고 함정을 우회한 것은 에이전트였습니다.
이 구조가 산업 교육에서 의미 있는 이유는 검증에 있습니다. 에이전트가 무엇을 만들었는지 사람이 눈으로 다 볼 수는 없습니다. 대신 테스트를 돌리고, 계층 구조를 읽고, 스크린샷을 찍어 숫자와 화면으로 확인합니다. 에이전트가 만들고 사람이 숫자로 검증한다는 원칙이 여기서는 도구로 구현되어 있습니다. KITECH 과정의 “MCP for Unity” 이틀은 이 흐름을 창고와 로봇 팔 프로젝트로 연습하는 시간입니다.
알아둘 것
- 베타입니다. 명령 이름과 옵션이 바뀔 수 있고, 저는
--format json으로 결과를 받아success필드로 분기하는 습관을 들였습니다. - 프로젝트에 컴파일 에러가 있으면 에디터가 세이프 모드로 뜨고 Pipeline 패키지가 로드되지 않아 연결이 안 됩니다.
unity pipeline list가 그 상태를 알려 줍니다. - 배치 모드로 직접 띄운 에디터는
status에 안 잡힙니다.unity command --project-path로 직접 확인해야 합니다. - 재생 중에는
open_scene이 거부됩니다. 먼저editor_stop. - 포커스 없는 에디터는 시간이 흐르지 않습니다. 위의
Step트릭. - 셸이 zsh라면 명령을 변수에 넣고
$C open_scene처럼 부르면 안 됩니다. 단어 분리가 안 됩니다. 함수로 감싸는 쪽이 안전합니다.
정리
Unity CLI는 Hub를 터미널로 옮긴 도구로 시작해서, 열려 있는 에디터를 원격으로 조작하는 도구가 됐습니다. 설치·프로젝트, 배치 빌드·테스트, 연결된 에디터 조작이라는 세 층 중에 셋째 층이 새롭고, 그 위에 MCP가 있어서 에이전트가 에디터를 직접 다룹니다. 어젯밤의 스크린샷 아홉 장이 그 증거입니다.
다음 글은 컴퓨트 셰이더와 인스턴싱을 잇는 글로 돌아갑니다. 그 글의 프로파일러 숫자도 같은 방법으로 뽑을 예정입니다.