원문 캡처 · github.com
원문 캡처 · github.com

Trellis는 창·탭·분할 화면을 관리하고, 명령줄 인터페이스(CLI)와 로컬 자동화 API, 선택형 MCP 서버를 제공하는 macOS용 네이티브 터미널이다. SSH 호스트 저장, 작업 공간 복원, 셸 통합 기능도 갖췄다.

주요 기능

Trellis는 왼쪽 사이드바에서 여러 창을 관리하고, 이름과 색상을 지정한 탭과 가로·세로 중첩 분할을 지원한다. 명령 출력 중인 탭에는 작업 표시 막대가 나타나며, 프로그램이 암호를 기다리거나 주의를 요청하면 Input 표시가 붙는다. 프로그램은 OSC 9, OSC 777, OSC 99를 이용해 데스크톱 알림을 보낼 수 있다. 셸 통합을 켜면 화면 밖에서 실행한 긴 명령이 끝났을 때도 알림을 받을 수 있으며, 이 알림 기능은 설정에서 끌 수 있다.

복원된 작업 공간은 세션을 멈춘 상태로 열린다. 입력한 내용은 다시 재생하지 않는다. 선택적으로 앱을 종료한 뒤에도 세션을 계속 실행하고 다음 실행 때 다시 연결할 수 있으며, 각 창의 스크롤백을 민감한 내용이 가려진 텍스트로 복원할 수도 있다. 두 옵션은 기본적으로 꺼져 있고, 설정의 Sessions에서 바꿀 수 있다.

터미널은 내장된 SwiftTerm을 기반으로 한다. 스크롤백 검색, 붙여넣기 전 안전 검토, 복사, Cmd 키를 누른 채 클릭해 링크를 여는 기능을 제공한다. 열 수 있는 링크는 http, https, mailto로 제한된다.

셸 통합은 zsh, bash, fish에서 현재 디렉터리와 각 명령의 종료 상태를 알려준다. 셸 설정 파일을 수정할 필요는 없다. 새 탭과 분할 화면은 현재 위치에서 열리고, 실패한 명령은 표시되며, ⌘↑와 ⌘↓로 프롬프트 사이를 이동할 수 있다. SSH에서는 원격 셸 자체의 통합 표시를 이용해 원격 디렉터리, 제목, 종료 상태를 보여준다. 이 기능은 표시만 하며 원격 컴퓨터에 무엇도 설치하지 않는다. 기본으로 켜져 있고 Settings → Sessions에서 끌 수 있다.

그 밖에 밝은 테마와 어두운 테마를 각각 설정하고 JSON 테마 라이브러리에서 미리 볼 수 있다. 메뉴 키보드 단축키를 다시 지정할 수 있으며, 저장 전에 충돌을 거부한다. Option 키를 Meta로 쓰는 설정과 접근성 레이블도 제공한다.

SSH 호스트는 File → Hosts…에서 저장할 수 있고, ~/.ssh/config의 별칭을 읽기 전용으로 찾아낸다. 연결은 /usr/bin/ssh를 사용하며 호스트 키 신뢰 절차를 우회하지 않는다. 호스트별 비밀번호 저장은 선택 사항이며, macOS 키체인에 보관하고 필요하면 Touch ID로 보호할 수 있다. 비밀번호는 ssh가 비밀번호를 요구할 때만 전달된다.

자동화 기능은 소유자만 사용할 수 있는 로컬 JSON-RPC 소켓을 제공한다. Settings → Automation에서 범위와 만료 시간이 설정된 권한을 만들 수 있다. API는 창, 탭, 패널, 세션, 입력, 출력 커서, 이벤트, 선언형 레이아웃, 테마, 모양 설정을 다룬다.

MCP 서버는 선택 기능이며 기본적으로 꺼져 있다. 켜면 같은 API를 HTTP 기반 MCP 도구로 노출해 Claude Code 같은 에이전트에서 사용할 수 있다. 자동화와 같은 권한 체계를 사용하며, 인터페이스와 포트는 Settings → Remote Control에서 설정한다. 자세한 내용은 MCP 문서에 있다.

작업 공간은 검토 단계를 거쳐 내보내고 가져올 수 있다(File → Export/Import Workspace…). Trellis는 원격 측정 데이터를 수집하지 않는다. 터미널 출력과 입력한 내용은 기록하거나 저장하지 않는다. Help → Export Diagnostics…에서는 허용 목록에 포함된 보고서를 미리 본 뒤 저장할 수 있다.

설치와 개발 실행

개발 환경은 macOS 14 Sonoma 이상과 Xcode 26이 필요하다. Xcode 26은 Swift 6.2와 swift format을 제공한다. xcode-select -p가 Command Line Tools를 가리키면 다음 명령으로 Xcode를 선택한다.

sh
sudo xcode-select -s /Applications/Xcode.app

Python 3는 최근 버전이면 되며 scripts/qualify.py와 실행기 테스트에만 필요하다. 앱 아이콘을 다시 만들 때는 선택적으로 librsvg가 필요하다. 설치하려면 다음을 실행한다.

sh
brew install librsvg

Apple Developer 계정, Homebrew 패키지, 패키지 관리자 초기 설정은 필요하지 않다. SwiftTerm이 ThirdParty/SwiftTerm에 포함돼 있어 swift build는 오프라인에서도 동작한다. 도구 체인은 다음 명령으로 확인할 수 있다.

sh
swift --version # Apple Swift version 6.2 or later
swift format --version

저장소를 받아 개발 버전을 실행하는 명령은 다음과 같다.

sh
git clone https://github.com/bearstouch/trellis.git
cd trellis
swift build
swift run Trellis --state-directory "$PWD/.build/dev-state"

--state-directory를 지정하면 개발 작업 공간과 테마를 실제 데이터 디렉터리인 ~/Library/Application Support/com.bearstouch.trellis/와 분리한다. Trellis를 개발할 때 이 옵션을 사용하라고 안내한다.

Xcode에서는 open Package.swift로 프로젝트를 열고, 앱 실행에는 Trellis, 테스트에는 Trellis-Package 스킴을 선택한다. --state-directory /abs/path 같은 실행 인수를 전달하려면 Product → Scheme → Edit Scheme… → Arguments에서 스킴을 수정한다. VS Code와 Cursor에서는 Swift 확장을 설치하면 된다. 확장은 Package.swift를 읽고 SourceKit-LSP를 사용한다.

자주 쓰는 빌드·테스트·포맷 명령은 다음과 같다.

sh
swift build # 빌드(새 경고가 없어야 함)
swift test # 전체 XCTest 테스트, 약 20초
swift test --filter TrellisUITests.TabManagementTests # 테스트 클래스 하나
swift format -i -r Sources Tests # 파일에 포맷 적용
swift format lint --strict -r Sources Tests # 린트: 아무것도 출력하지 않아야 함

커밋 전에 실행할 명령은 다음과 같다.

sh
swift format -i -r Sources Tests && swift format lint --strict -r Sources Tests && swift build && swift test

포맷은 저장소의 .swift-format 설정을 적용한 도구 체인의 swift format으로 처리한다. 들여쓰기는 4칸, 줄 너비는 220자다. 저장소는 SwiftLint나 SwiftFormat을 별도 의존성으로 사용하지 않는다.

앱 실행 방법에 따라 작업 공간과 동작이 달라진다.

  • swift run Trellis는 Application Support에 있는 실제 작업 공간을 사용한다.
  • swift run Trellis --state-directory /abs/path는 별도 작업 공간과 테마 라이브러리를 사용하며, 개발에 권장된다.
  • swift run Trellis --fixture는 고정 셸을 쓰는 격리된 데모 창을 열고, 자식 프로세스는 종료 코드 7로 끝난다. 창은 확인할 수 있도록 열린 채로 유지된다.
  • swift run Trellis --no-mcp는 설정의 Remote Control 값과 관계없이 해당 실행에서 MCP 서버를 시작하지 않는다. --fixture에는 이 옵션이 포함된다.
  • scripts/run-feasibility.sh는 .build/Trellis.app을 만들고 임시 서명과 검증을 마친 뒤 연다. 아이콘, Info.plist, 리소스를 포함한 실제 앱 번들이 필요할 때 사용한다.
  • scripts/run-feasibility.sh --build-only는 창을 열지 않고 같은 작업을 수행한다.

새 작업 공간은 로그인 셸로 시작한다. 실행 중인 세션을 닫을 때는 확인을 거치도록 Quit을 사용한다.

개발 빌드에서 CLI를 쓰려면 앱을 실행하고 Settings → Automation에서 권한을 만든다. 토큰은 한 번만 표시되므로 본인만 읽을 수 있는 파일에 저장해야 하며, 명령 인수로 전달하지 말아야 한다. 저장소에서는 예시로 .build/token.txt를 든다.

sh
swift run trellis-cli window list --token-stdin --json < .build/token.txt
swift run trellis-cli

첫 명령은 토큰을 표준 입력에서 받아 창 목록을 JSON으로 출력하고, 두 번째 명령은 사용 가능한 명령 대상을 출력한다. 패키지 앱에는 이 실행 파일이 trellis라는 이름으로 포함된다. 자세한 내용은 릴리스 안내와 docs/api에 있다.

저장소에는 실행기 회귀 테스트, 릴리스 적격성 확인, 렌더러 벤치마크, 패키징, 아이콘 생성 스크립트도 있다.

sh
python3 scripts/test-feasibility-launcher.py "$(swift build --configuration debug --show-bin-path)" # 창을 열지 않는 실행기 회귀 테스트
python3 scripts/qualify.py [--quick] [--renderer metal|coregraphics] # 약 5분, 격리된 앱 창을 엶
python3 scripts/bench-renderer.py [--quick] [--only NAMES] # 약 25분, Metal과 CoreGraphics 비교; 창을 보이는 상태로 둘 것
scripts/package-release.sh # Universal 2 앱과 DMG 생성(서명 정보가 없으면 임시 서명)
scripts/generate-app-icon.sh # Design/AppIcon/*.svg에서 아이콘 생성(rsvg-convert 필요)

릴리스와 데이터 관리

CI는 master 또는 develop을 대상으로 한 모든 풀 리퀘스트와 해당 브랜치로의 모든 푸시에서 실행된다. macos-26과 Xcode 26을 사용해 린트, 빌드, 전체 테스트, 실행기 회귀 테스트를 수행하며 프로젝트 소스에 새 경고가 없어야 한다. 설정은 ci.yml에 있다.

release.yml은 release/manifest.json과 일치하는 vX.Y.Z 태그를 푸시할 때 실행된다. 테스트와 Universal 2 DMG 패키징을 수행한 뒤, 해당 CHANGELOG.md 항목에서 가져온 노트와 함께 GitHub 릴리스를 게시한다. 서명 비밀 정보가 없으면 임시 서명된 시험판으로 게시한다. 사용하는 비밀 정보는 워크플로 파일 상단에 나열돼 있다. 수동 실행은 DMG를 워크플로 아티팩트로 만들지만 릴리스를 게시하지 않는다.

릴리스를 만들 때는 release/manifest.json을 올리고 CHANGELOG.md에 해당 절을 추가해 커밋한 뒤 다음 명령을 실행한다.

sh
git tag vX.Y.Z && git push --tags

사용자 데이터는 ~/Library/Application Support/com.bearstouch.trellis/에 저장된다. 파일은 소유자만 읽고 쓸 수 있으며 원자적으로 기록하고, 마지막으로 정상 확인된 백업을 보관한다. 새 버전의 데이터나 손상된 상태를 발견하면 복구 모드로 열고 기존 데이터를 덮어쓰지 않는다.

Trellis는 이전에 uTerm이라는 이름을 사용했다. 처음 실행하면 기존 uTerm 작업 공간과 테마 라이브러리를 새 디렉터리로 복사하며, 원본은 그대로 둔다. Trellis 데이터가 이미 있으면 기존 데이터를 우선한다. trellis-로 시작하는 테마 ID는 기본 제공 테마용으로 예약돼 있다. 기본 디렉터리로 이전할 때 이 접두사로 시작하는 사용자 테마 ID는 새 ID로 바꾸고 저장된 선택 사항도 함께 갱신한다. --state-directory로 전달한 경로는 그대로 사용한다. 해당 경로의 오래된 사용자 라이브러리에 trellis-로 시작하는 ID가 있으면 ID와 파일 이름, 저장된 선택 항목을 직접 바꿔야 한다.

로그인한 사용자마다 앱 인스턴스 하나만 실행된다. 앱을 다시 열면 직접 실행했거나 다른 상태 디렉터리를 지정했더라도 기존 창을 앞으로 가져온다. 앱을 종료하거나 충돌하면 인스턴스 잠금은 자동으로 해제된다.

설치 앱(com.bearstouch.trellis)과 개발 빌드는 서로 다른 앱 ID를 쓴다. 개발 빌드에는 swift run, 번들로 만들지 않은 릴리스 바이너리, scripts/run-feasibility.sh가 만드는 Trellis Dev 번들이 포함되며 모두 com.bearstouch.trellis.dev를 사용한다. 두 ID는 인스턴스 잠금, 활성화 알림, 상태 디렉터리, 제어 소켓이 각각 다르다. 개발 상태 디렉터리는 ~/Library/Application Support/com.bearstouch.trellis.dev/다. 따라서 설치된 Trellis와 개발 인스턴스를 동시에 실행할 수 있다. --state-directory를 지정하지 않으면 trellis CLI는 설치된 앱을 대상으로 한다.

모양과 렌더링

Settings → Appearance에는 편집기에서 영감을 받은 10개 테마 계열이 있으며 각 계열은 밝은 버전과 어두운 버전을 포함한다. 계열은 Modern, One, Monokai, Solarized, Nord, Dracula, GitHub, Tokyo, Gruvbox, Rose Pine이다. Trellis에 맞게 조정한 테마로 터미널과 앱 색상을 맞춘다. 밝은 팔레트와 어두운 팔레트를 따로 선택할 수 있고, 시스템 모양 설정에 따라 자동으로 전환할 수 있다. 기존 Trellis 기본 테마도 계속 사용할 수 있다.

터미널 글꼴 선택기는 Mac에 설치된 고정폭 글꼴을 보여주고 선택한 글꼴을 미리 보기한다. 선택 사항을 저장하려면 Appearance 설정을 적용한다.

터미널은 글꼴에 기능이 있을 때 글꼴 합자(예: 내장 JetBrains Mono), 컬러 이모지, 넓은 CJK 문자, 결합 문자를 셀 격자에 그린다. 굵게, 흐리게, 기울임, 밑줄(단일·이중·물결·점선·파선과 별도 색상), 취소선, 윗줄, 깜박임, 반전, 숨김 텍스트도 지원한다. Settings → Appearance에서 합자, 굵은 글꼴의 밝은 색상 사용, 굵은 글꼴, 기울임 글꼴, 깜박이는 텍스트를 각각 켜거나 끌 수 있다.

기본 CPU 렌더러인 CoreGraphics와 같은 텍스트 렌더링으로 GPU 기반 Metal 렌더링을 사용할 수 있다. Settings → Sessions → GPU rendering (Metal)에서 켠다. Metal을 사용할 수 없으면 Trellis가 CoreGraphics로 전환한다. 한 번의 실행에서 렌더러를 지정하려면 swift run Trellis --renderer coregraphics 또는 swift run Trellis --renderer metal을 사용한다. scripts/bench-renderer.py로 두 렌더러를 비교할 수 있다.

프로그램은 iTerm2 이미지 프로토콜로 이미지를 터미널 안에 표시할 수 있다. 따라서 imgcat, yazi, timg, chafa -f iterm을 iTerm2에서처럼 사용할 수 있다.

저장소와 문서

저장소는 도메인 로직, 터미널, UI, 제어 API와 MCP 서버 등을 별도 구성 요소로 나눈다. 구조와 규칙은 아키텍처 문서와 CONTRIBUTING.md에 설명돼 있다.

text
Sources/
  TrellisCore/       엔진에 종속되지 않는 도메인: WorkspaceStore, 명령 서비스, 영속성, 테마
  TrellisPOSIX/      PTY와 프로세스 그룹 실행을 위한 작은 C 타깃
  TrellisTerminal/   SwiftTerm 전용 코드(SwiftTerm을 가져오는 유일한 위치)
  TrellisUI/         SwiftUI/AppKit 뷰와 AppWorkspaceModel
  TrellisControl/    로컬 JSON-RPC 서버, 프레이밍, 인증을 거치는 핸들러
  TrellisMCP/        같은 인증기를 쓰는 선택형 MCP 서버(HTTP)
  TrellisApp/        앱 진입점, 메뉴, 실행 인수
  TrellisRelease/    릴리스 매니페스트 확인, CLI 링크 계획, 제거 허용 목록
  TrellisCLI/        trellis CLI 로직(TrellisCLIMain은 실행 파일)
Tests/               모듈별 XCTest 타깃 하나
ThirdParty/SwiftTerm 내장 SwiftTerm 1.20.0과 기록된 패치
 docs/                동작 계약, 아키텍처, API, 기여자 안내 문서
 docs/release/        패키징, 설치, 업그레이드, 제거 안내
Design/AppIcon/      아이콘 원본
scripts/             실행기, 적격성 확인, 패키징, 아이콘 도구

아키텍처는 창에서 탭, SplitNode 트리, 패널, 세션으로 이어진다. UI와 API의 모든 변경은 하나의 WorkspaceCommandService를 거친다. PTY 입출력은 메인 스레드 바깥에서 처리하고 뷰는 @MainActor에서 갱신한다.

docs/는 동작 계약과 기여자 안내를 담는다. 제품 개요, 아키텍처, 기능, 자동화 API와 CLI, 통합 기능, macOS 지원, 개발 규칙을 다룬다. 문서는 일반 Markdown이며 MkDocs Material용으로 구성돼 있다. 로컬 문서 사이트는 다음 명령으로 실행한다.

sh
python3 -m venv .venv-docs && .venv-docs/bin/pip install mkdocs-material
.venv-docs/bin/mkdocs serve # http://127.0.0.1:8000

웹사이트의 랜딩 페이지는 landing/에 있다. Railway용 Docker 이미지에서 nginx로 제공하는 정적 Vite 사이트다. 개발 서버는 다음처럼 실행한다.

sh
cd landing && npm install && npm run dev

문제 해결과 기여

swift format을 찾지 못하면 xcode-select -p가 Command Line Tools를 가리키는지 확인하고 Xcode 26으로 전환한다. 빌드에서 동시성 오류가 나면 도구 체인이 너무 오래된 것일 수 있다. 패키지는 Swift 6 언어 모드의 Swift 6.2를 요구한다. 앱이 실제 작업 공간을 열면 절대 경로를 지정해 별도 상태 디렉터리를 사용한다.

sh
swift run Trellis --state-directory /absolute/path

임시 서명한 .app을 다른 Mac으로 복사했을 때 Gatekeeper가 차단하는 것은 예상된 동작이다. 배포할 수 있는 빌드에는 Developer ID 서명과 공증이 필요하다.

기여를 환영한다. 작업 절차, 코드 스타일, 테스트 규칙, 보안 문제 신고 방법은 CONTRIBUTING.md에 있다. Trellis는 MIT License로 배포된다. 내장된 SwiftTerm도 MIT 라이선스를 따르며, 라이선스와 출처, 패치 내역은 ThirdParty/SwiftTerm에 기록돼 있다.