블로그
프로토타입에서 제품으로: Tactic Remote의 개발 여정
8주 동안 13개의 마일스톤을 달성하여 Tactic Remote를 개념 증명 tmux 래퍼에서 프로덕션 준비된 원격 개발 도구로 만들었습니다. 그 여정의 전체 이야기입니다.
이 카테고리의 제품 및 엔지니어링 업데이트를 확인하세요.
카테고리 보기Tactic Remote는 2026년 1월 초의 질문에서 시작되었습니다: 실행 중인 Claude Code 세션을 휴대폰에서 확인할 수 있다면 어떨까? 그 질문은 한 주말 만에 프로토타입이 되었고, 2주 안에 사용 가능한 도구가 되었으며, 첫 번째 버전 번호가 매겨진 릴리스를 출시하기 전에 13개의 마일스톤이 완료되었습니다. 이것은 그 개발 궤적의 이야기입니다. 무엇을 만들었고, 무엇을 버렸으며, 고장 내지 않으면서 빠르게 출시하는 것에서 무엇을 배웠는지.
주말 프로토타입 (2026년 1월 초)
Tactic Remote의 첫 번째 버전은 대략 200줄의 코드였습니다. 셸 스크립트가 tmux 세션 안에서 Claude Code를 실행하고, Python Flask 서버가 tmux capture-pane을 실행하여 결과를 일반 텍스트로 반환하는 엔드포인트를 노출했으며, 기본적인 iOS 앱이 그 엔드포인트를 2초마다 폴링하여 결과를 고정폭 텍스트 뷰에 표시했습니다.
투박하고 느렸습니다. 폴링 모델은 모든 업데이트에 2초의 지연을 의미했습니다. 일반 텍스트 캡처는 모든 서식을 잃었습니다. 인증이 없어서 같은 Wi-Fi 네트워크의 누구나 터미널을 읽을 수 있었습니다. 하지만 개념은 증명되었습니다: 휴대폰 화면에서 AI 코딩 세션을 의미 있게 따라갈 수 있다는 것을.
그 프로토타입은 약 4일 동안 살아남았고, 그 후 재구축을 시작했습니다.
마일스톤 아키텍처
캘린더 스프린트 대신 마일스톤 기반 개발 모델을 채택했습니다. 각 마일스톤에는 특정 기술 목표, 완료 정의가 있었고 고정 기한은 없었습니다. 이를 통해 스프린트가 끝날 때가 아니라 준비가 되었을 때 출시할 수 있었습니다. 실제로 마일스톤의 평균 소요 기간은 4-5일이었지만, 2일만에 끝난 것도 있었고 거의 2주가 걸린 것도 있었습니다.
다음은 요약된 진행 과정입니다:
마일스톤 1-3: 기반 구축. Flask를 Swift 네이티브 임베디드 서버로 교체. HTTP 폴링 대신 WebSocket을 통한 실시간 스트리밍 확립. 토큰 기반 인증 구현. 마일스톤 3 완료 후, iPhone이 200ms 이내에 터미널 업데이트를 수신하고 무단 접근이 차단되는 작동하는 시스템이 갖춰졌습니다.
마일스톤 4-5: 세션 관리. 여러 동시 tmux 세션 지원. 세션 라이프사이클(생성, 모니터링, 유휴, 완료, 정리) 구축. 시작 시 기존 tmux 세션에 재연결하여 컴패니언 앱 재시작 시에도 세션 지속성 추가. 이 시점에서 Tactic Remote는 데모에서 실제 작업에 사용할 수 있는 것으로 변모했습니다.
마일스톤 6-7: 휴먼 인 더 루프. Claude Code의 hook 시스템과 통합하여 승인 요청 인터셉트. iOS에서 승인 UI 구축 — AI가 무엇을 하려는지 표시하고, 관련 컨텍스트를 보여주며, 승인/거부 액션 제공. 앱이 열려 있지 않아도 승인이 가능하도록 푸시 알림 추가. 이 두 마일스톤이 전환점이었습니다. 이전의 Tactic Remote는 터미널 뷰어였습니다. 이후에는 제어판이 되었습니다.
마일스톤 8-9: 연결 견고성. Wi-Fi에서 셀룰러로의 핸드오프 처리. 지수 백오프를 사용한 자동 재연결 구현. 연결 품질 표시기 추가. 수동 IP 및 토큰 입력을 없애는 QR 코드 빠른 연결 흐름 구축. 마일스톤 9는 가장 어려운 단일 마일스톤이었습니다. iOS의 네트워킹 엣지 케이스는 많고 문서화도 부족합니다.
마일스톤 10-11: Cloudflare Tunnel. cloudflared를 관리되는 자식 프로세스로 통합. 듀얼 모드 연결 아키텍처(로컬 및 터널) 구축. 터널 상태 모니터링, 자동 재시작, 우아한 폴백 처리. 터널 URL을 QR 코드 생성에 추가.
마일스톤 12-13: 프로덕션 준비. 현지화(7개 언어). Mac 잠자기 방지. 메뉴 바 UI 다듬기. 크래시 리포팅 및 진단. 유휴 시 메모리 사용량을 약 60 MB에서 25 MB 미만으로 줄이는 성능 최적화. 인증 및 전송 레이어의 최종 보안 감사.
핵심 기술 결정
개발 중 몇 가지 결정이 제품의 성격을 정의했습니다:
커스텀 PTY 관리가 아닌 tmux
마일스톤 1 기간에 이에 대해 광범위하게 논의했습니다. 커스텀 PTY 관리는 터미널 캡처에 대한 더 세밀한 제어를 제공하고 tmux 의존성을 제거할 수 있습니다. 하지만 세션 지속성, 터미널 에뮬레이션, 프로세스 라이프사이클 관리를 재구현해야 한다는 뜻이기도 합니다. tmux가 15년에 걸쳐 해결해 온 문제들입니다. 재구축하는 대신 그 기반 위에 서기로 했습니다.
Server-Sent Events가 아닌 WebSocket
실시간 스트리밍에는 두 프로토콜 모두 사용할 수 있습니다. WebSocket을 선택한 이유는 양방향 통신이 필요했기 때문입니다. iPhone은 터미널 출력만 받는 것이 아니라 명령과 승인을 Mac으로 다시 보냅니다. SSE는 상향 통신을 위한 별도 채널이 필요하여 복잡성이 증가합니다.
독립형 데몬이 아닌 임베디드 서버
독립형 데몬(launchd로 관리)은 macOS 아키텍처 관점에서 더 "올바른" 방법이었을 것입니다. 하지만 설치 복잡도가 두 배가 되고 "서버는 실행 중인데 앱은 실행 중이 아닌" 유형의 버그가 발생합니다. 서버를 메뉴 바 앱에 내장하면 설치할 것, 실행할 것, 종료할 것이 하나씩입니다.
OAuth/세션 기반 인증이 아닌 정적 토큰
Tactic Remote의 위협 모델은 단순합니다: 네트워크에서의 무단 접근을 방지하는 것. 키체인에 저장된 암호학적으로 안전한 256비트 토큰은 토큰 갱신, 세션 만료, 로그인 흐름의 복잡성 없이 이를 달성합니다. 사용자별 인증이 필요한 엔터프라이즈 사용 사례에는 외부 레이어로 Cloudflare Access를 권장합니다.
파일 시스템 감시가 아닌 tmux 폴링
PTY에 대한 파일 시스템 알림 API(kqueue/FSEvents)가 아닌 200ms 간격으로 tmux capture-pane을 폴링합니다. 우아하지 않게 들릴 수 있지만, tmux의 캡처 명령은 매우 빠르며(서브밀리초), 테스트에서 PTY 장치에 대한 파일 시스템 감시는 macOS 버전 간에 신뢰할 수 없는 것으로 판명되었습니다. 폴링 방식은 macOS 13, 14, 15에서 견고하게 작동하고 있습니다.
버린 것들
모든 것이 살아남은 것은 아닙니다. 주목할 만한 삭제 항목들:
웹 기반 클라이언트. 마일스톤 6에서 모든 브라우저에서 작동하는 반응형 웹 인터페이스를 구축했습니다. 작동했지만, 경험은 네이티브 앱보다 현저히 떨어졌습니다. 푸시 알림 없음, 백그라운드 재연결 없음, 승인 시 햅틱 피드백 없음. 네이티브 iOS 경험에 집중하기 위해 보류했습니다.
터미널 색상 및 서식. 초기 버전에서는 ANSI 컬러 코드를 보존하여 iPhone에서 렌더링하려고 했습니다. 렌더링이 일관되지 않았고 스트리밍 프로토콜에 상당한 복잡성을 추가했습니다. 픽셀 단위의 완벽한 터미널 에뮬레이션 대신 구조를 보존하는 단순화된 렌더링 모델로 전환했습니다. 완전한 ANSI 지원은 로드맵에 남아 있습니다.
자동 작업 제안. 최근 git 활동을 기반으로 Claude Code 작업을 제안하는 기능을 프로토타이핑했습니다. 기술적으로 흥미로웠지만 주제넘은 느낌이었습니다. 개발자는 무엇을 작업하고 싶은지 알고 있습니다. 베타 테스터가 보기 전에 제거했습니다.
버전 관리 전환
마일스톤 13 이후, 마일스톤 기반 추적에서 시맨틱 버전 관리로 전환했습니다. 첫 번째 버전 릴리스는 1.2.0이었습니다(1.0.0이 아닌 이유는 비공개 테스트 중 1.0과 1.1 번호가 매겨진 내부 빌드가 있었고 혼란을 피하고 싶었기 때문입니다).
이후의 진행: 1.2.0, 1.3.0, 1.4.0, 1.4.2, 1.5.0-beta.1. 각 버전은 변경 로그에 문서화된 명확한 사용자 대상 변경 사항에 대응합니다. 마일스톤 시스템은 빠른 프로토타이핑 중에 잘 작동했지만, 시맨틱 버전 관리는 업그레이드 위험을 평가해야 하는 사용자에게 더 명확하게 전달됩니다.
배운 것
가장 작은 유용한 것을 출시하라. 주말 프로토타입은 어떤 엔지니어링 기준으로도 부끄러운 수준이었지만, 유일하게 중요한 질문에 답했습니다: 휴대폰에서 Claude Code를 모니터링하는 것이 실제로 도움이 되는가? 그 이후의 모든 마일스톤은 "다음으로 가장 유용한 개선은 무엇인가?"에 대한 점진적인 답이었습니다.
네트워킹이 가장 어려운 부분이다. 연결 안정성에 제품의 다른 어떤 측면보다 더 많은 시간을 투자했습니다. Wi-Fi에서 셀룰러로의 핸드오프, 잠자기 후 WebSocket 재연결, Cloudflare Tunnel 상태 모니터링. 각각이 완전한 마일스톤을 소비했습니다. 실제 터미널 캡처와 세션 관리는 비교적 간단했습니다.
의존성은 지루해야 한다. tmux, cloudflared, 키체인, IOKit. Tactic Remote가 의존하는 기술들은 안정적이고 문서화가 잘 되어 있습니다. 더 새롭거나 참신한 것의 채택을 고려할 때마다, 기존의 지루한 옵션으로 충분한지 물었습니다. 대개 충분했습니다.
마일스톤 기반 개발은 소규모 팀에 적합하다. 스프린트 계획, 스탠드업, 속도 추적의 오버헤드 없이 더 빠르게 움직였습니다. 각 마일스톤에는 명확한 완료선이 있었고, 구현 중 배운 것을 바탕으로 실시간으로 범위를 조정할 수 있었습니다. 이 모델은 더 큰 팀 규모에서는 무너지지만, 초기 개발에는 적합했습니다.
타임라인 요약
| 기간 | 내용 |
|---|---|
| 2026년 1월 초 | 주말 프로토타입: 셸 스크립트 + Flask + 기본 iOS 앱 |
| 1월 6-20일 | 마일스톤 1-5: 기반, WebSocket, 세션 |
| 1월 20-29일 | 마일스톤 6-9: 승인, 푸시 알림, QR 연결 |
| 1월 29일 - 2월 10일 | 마일스톤 10-11: Cloudflare Tunnel 통합 |
| 2월 10-18일 | 마일스톤 12-13: 현지화, 다듬기, 보안 감사 |
| 2월 18일 이후 | 시맨틱 버전 관리: 1.2.0에서 1.5.0-beta.1까지 |
아이디어에서 오픈 베타까지 8주. 대충 만들어서가 아니라 범위를 가차 없이 줄이고 검증된 기반 위에 구축했기 때문입니다.
각 버전 릴리스에 대한 자세한 내용은 변경 로그를 참조하세요.