3-1. 빈 저장소에서 첫 글자까지 (6/3 ~ 6/12)

첫날에 뼈대를 다 세웠다

시작은 코드가 아니라 계획서 검토였다.

"문서 읽고 평가해줘, 내가 지금 구현하려고 이것저것 계획 세웠거든." — 2026-06-03

"수정해야되는 부분은 다 수정해주세요 수행전에 계획 엄청 명확하게 잡고 싶어요" — 2026-06-03

그리고 계획서를 고칠 때마다 같은 요청이 반복된다 — "또 한번 수정했는데 메인기준으로 적대적 관점으로 리뷰해줘요". 첫날에만 이 왕복이 여러 번 있었다.

clean-room 원칙도 첫날 질문에서 구체화됐다. 무엇을 근거로 삼고 무엇을 오라클로 쓸지가 쟁점이었다.

"공개명세는 어디서 참고해요? 공게명세도 레퍼런스에 당연히 있어야 하고 개발시 참고해야하는데" — 2026-06-03

"외부 오라클에 고스티는 없어요? 가능한 오라클 뭐뭐 있죠?" — 2026-06-03

"libvterm이 가장 표준에 가까운거예요??" — 2026-06-03

"tmux는 붙이면 어떤 이득이 있어?? 얜 고스티같은 터미널은 아니잖아" — 2026-06-03

6월 3일 하루에 들어간 것들이다.

  • Zig 개발환경 부트스트랩
  • 터미널 전략 노트, 구현 계획, 사전 계약 문서
  • 에이전트 규칙과 프로젝트 구조
  • 클린룸 터미널 코어 정책
  • 헤드리스 E2E 스캐폴드
  • 외부 oracle, @import 경계 검사, 포맷 게이트
  • 성능 예산 하네스와 스트레스 테스트 계층

코드보다 게이트가 먼저 섰다는 게 특징인데, 이것도 의도적이었다.

"구현전에 미리 가능한 테스트는 미리 붙이고 싶은데." — 2026-06-03

"그리고 구현파일에 테스트코드가 있는게 아니라 _test로 분리하거나 폴더로 분리하는건 어떻게 생각하나요? 고스티는 테스트코드 어떻게 작성..." — 2026-06-03

경계 검사기와 성능 예산이 첫날부터 CI에 걸려 있었기 때문에, 이후 두 달 반 동안 경계를 넘는 커밋이 조용히 들어오지 못했다. PR 규칙(템플릿·라벨·담당자)도 같은 날 정해졌다.

PTY: 읽는 쪽부터 계약으로

6월 4~5일에 터미널 호환성과 스키마 계약을 정리하고 PTY 리더를 세웠다.

  • macOS openpty 세션
  • PTY reader 생명주기 — bounded 큐, self-pipe wake, kqueue NOTE_EXIT
  • 종료 정책 HUP → TERM → KILL
  • runtime event pump와 surface runtime 라우팅
  • 헤드리스 PTY 데모

같은 시기에 셀 폭 모델과 폰트 렌더링 전략을 정리하면서, grapheme·ZWJ·ambiguous-width·faux bold 같은 어려운 항목은 미룬다고 명시했다. 나중에 6월 23일에 이 항목들을 정면으로 다시 연다.

CoreText → Metal

6월 6~7일은 렌더링에 집중한 이틀이다. 6일에는 Metal 스모크, CoreText 셰이핑 스모크, glyph texture·glyph text 스모크를 쌓고 appearance 색 해석과 프레임 probe, 스크린샷 캡처로 파이프라인을 실측했다. 7일에는 40커밋으로 파이프라인을 완성했다.

  • CoreText 셰이퍼·rasterizer·font adapter 경계 추출
  • DrawList를 CoreText로 셰이핑해 Metal로 렌더
  • shaped glyph record 어댑터, render frame이 glyph quad를 소유하는 구조
  • font identity registry와 제품 atlas 샘플링 검증

"셰이핑은 CoreText, 그리기는 Metal, 그 사이는 DrawList"라는 구조가 이때 굳었다. 이 시기 PR은 대부분 브랜치 하나에 슬라이스 하나였고, 머지 전에 /code-review max --fix를 브랜치에 직접 돌렸다 — 6월 5~7일 사흘 동안 이 명령이 30번 넘게 반복된다.

렌더링 품질은 눈으로 보고 잡았다. 첫 글자가 화면에 뜬 직후부터 이런 보고가 이어진다.

"mise 도 m i s e 처럼 보여요 폰트 렌더링 여전히 잘못되고 있는것 같은데 루트커즈 찾아봐주세요" — 2026-06-09

"벌어짐은 해결됐는데 크고 또렷하지 않음" — 2026-06-09

"맥북 내장 화면에 옴기면 scr:2.0 win:2.0 외장 모니터에 하면 1.0 1.0 떠요" — 2026-06-09

해결 방식도 일정하다 — "다른 터미널 해결책은 어떤거예요? 특히 고스티는 어떻게 하고 있는지?"(6/9), "고스티 직접 코드 보고 확인해보세요 레퍼런스에 있는데"(6/9). 레퍼런스는 답을 베끼는 곳이 아니라 "우리만 안 하고 있는 것"을 찾는 대조군으로 쓰였다.

화면이 살아나기 시작한다

날짜들어온 것
6/8Metal 렌더러 최적화, live PTY 수명주기 강화, 프레임 루프 계약 고정, macOS Swift 앱 호스트 경계 정의
6/9스크롤백 뷰포트, 리사이즈 시 랩 재계산, IPC 페이로드 확장
6/10IME 조합 Phase 1~2, 편집 중 커서 깜빡임 억제와 선택 영역 표시, OSC 8 하이퍼링크, PTY 논블로킹화·배치 큐
6/11이모지 렌더링, 터미널 모드 2027, 키 바인딩·기능 키, VT 준수 테스트
6/12Stage 8 멀티탭 분할 — 다중 탭 PTY, cmux식 세로 사이드바, OSC 133 시멘틱 프롬프트, SplitTree 기반 멀티 패널

6월 12일 하루에 들어간 PR만 40건이 넘는다. 탭·사이드바·OSC 133·SplitTree 네 축을 동시에 밀었다.

멀티탭의 모양은 cmux를 기준으로 잡았다.

"씨먹스는 왼쪽 사이드탭도 있고, 그 탭 하나하나당 또 일반적인 화면 나누는 탭을 열 수 있고 위치도 드래그 되는데요, 이런걸 원하..." — 2026-06-12

"그리고 스피릿 탭같은경우(패널로 지칭할게) 마우스 상단에 패널(탭) UI가 따로 있어서 드래그도 되고, X도 있고" — 2026-06-12

이 시기의 결정

  • PTY는 논블로킹으로. 마스터 fd를 논블로킹으로 두고 배치 큐로 받는다. 출력이 많은 명령에서 UI가 멈추지 않게 하는 토대다.
  • 탭은 cmux 정도로. 첫 문서의 "tmux 호환 대체물은 만들지 않는다"를 지키면서, 분할은 SplitTree로 일반화했다.
  • IME는 미루지 않는다. 한국어 입력을 쓰는 사람이 만드는 터미널이라, 조합 표시와 커서 처리를 초기에 넣었다. 이 축은 이후에도 계속 회귀 검사 대상이 된다.
  • 방어 코드를 기본값으로 두지 않는다. "방어코드는 정말 불가피할때만 나와 상의하고 진행해"(6/12). 실패를 삼키는 대신 계약을 명확히 하고 assert로 잡는 방향이다.
  • 아까우면 버린다. "기존 설계 아끼려하지말고 엎어야한다면 엎어서 진행하세요"(6/12), "장기적으로 기존 코드 갈아엎는게 유지시키는것보다 이득이라면 갈아엎어도 상관없어요"(6/13). 7~8월에 여러 축을 통째로 재설계하는 결정들이 이 원칙 위에서 나온다.
  • Swift는 최소한만. "스위프트 코드 최소화는 지키면서 하시는거죠?"(6/13), "그리고 문서 정책에도 쓰여있지 않았나요? 네이티브 의존성은 최대한 줄인다로"(6/9).