- Ghostty의 macOS 비방해형 자동 업데이트 알림 기능을 주로 AI 에이전틱 코딩 도구를 활용해 개발한 전 과정을 공개하며, 16개 세션에서 $15.98의 토큰 비용으로 약 8시간 만에 실제 배포 가능한 기능을 완성했음
- OpenAI 키노트 중 Ghostty 업데이트 프롬프트가 데모를 방해한 사건을 계기로, 작업을 중단시키지 않고 타이틀바나 창 하단에 작은 GUI 요소로 업데이트 상태를 표시하는 비모달 방식으로 전환 결정
- AI 시작 전 Sparkle 프레임워크의 커스텀 UI 프로토콜과 타이틀바 액세서리 컨트롤러를 활용한 대략적인 백엔드/프론트엔드 계획을 먼저 수립하고, AI를 프로토타입 도구로 활용
- UI 프로토타이핑, 버그 해결 실패 시 방향 전환, 반복적인 클린업 세션(문서화, 리팩토링)을 통해 향후 AI 세션의 성능 향상, 시뮬레이션 코드 생성 등 단계별 접근 방식 사용
- AI가 작업하는 동안 가족 아침 준비 등 다른 일을 할 수 있는 비동기적 작업 방식의 가치를 강조하며, 모든 AI 생성 코드는 철저한 수동 리뷰 후 배포하고 이해하지 못하는 코드는 배포하지 않는 원칙을 지킴
기능 개요
- 완성된 기능은 macOS에서 창을 가리지 않는 비방해형 업데이트 알림
- 창을 생성하거나 포커스를 가져가는 등 작업을 방해하지 않고 터미널 창 내에 업데이트 상태 표시
- OpenAI 키노트 도중 Ghostty 업데이트 프롬프트가 등장한 사건을 계기로 UX 개선 필요를 확인함
- 업데이트 알림을 비침입적으로 만들기로 결정
- 팝업 창 대신 사용자를 방해하지 않는 작은 비모달 GUI 요소를 어딘가에 표시하는 것으로 함
- 알림 표시 위치는 타이틀바 오른쪽을 기본으로 하되, 타이틀바 숨김 등 스타일에 따라 창 하단 오버레이등 대안 제공
- 개발 과정 전반에 AI 에이전트를 활용하되, 직접 수동 수정·폴리시·최종 리뷰를 병행하는 인간 주도형 보조 도구 전략을 채택
AI 사용 전 계획 수립
- AI 도구를 꺼내기 전에 먼저 대략적인 계획 수립
- Ghostty가 사용하는 Sparkle(매우 인기 있는 macOS 업데이트 프레임워크) 문서 조사
- Obj-C 프로토콜을 통한 커스텀 UI 지원 발견, 처음부터 많은 것을 재구현해야 하지만 가능
- 백엔드에 대한 대략적인 아이디어 확보 후 프론트엔드 구상
- 타이틀바에 작은 버튼을 임베드하는 막연한 아이디어
- macOS가 타이틀바 액세서리 컨트롤러를 통해 타이틀바에서 커스텀 UI 지원하는 것은 알고 있었지만 구체적인 모습과 느낌은 불확실
- 충분한 출발점 확보로 시작 가능
- AI는 매우 훌륭한 프로토타이퍼이므로 무엇을 모르는지 아는 것만으로도 시작하기에 충분
- 큰 그림에 대한 충분히 강한 감각 보유
첫 번째 세션: UI 프로토타이핑
-
첫 번째 에이전틱 코딩 세션의 시작 프롬프트
- SPUUserDriver를 커스터마이즈해 비침입적 업데이트 알림 및 설치 활성화 요청
- UI 작업만 수행하도록 제한
- SPUUserDriver가 요구하는 다양한 상태를 보여줄 수 있는 SwiftUI 뷰 생성 계획 요청
- macOS 창 타이틀바 오른쪽 상단에 표시하는 계획 수립 요청
- Oracle은? - Amp 전용 읽기 전용 서브 에이전트로, 더 느리고 비용이 높은 모델 사용, 일반적으로 사고에 더 뛰어남
- UI 프로토타입에 먼저 집중하기로 결정
- 에이전트에게 전체 기능을 구축하라고 보내지 않음
- 첫째, UI/UX가 어떤 모습이어야 할지 아직 모르므로 AI가 다른 변경 사항 중에서 이를 수행하도록 일관되게 기대할 수 없음
- 둘째, 작은 작업 덩어리가 검토, 이해, 반복하기 더 쉬움
- 계획만 작성하도록 요청하고 코드는 작성하지 않도록 지시
- 상대적으로 모호한 요청이므로 많은 작업(및 많은 토큰 소비)을 하기 전에 계획을 검토하는 것이 중요
- 팁: 에이전트와 포괄적인 계획을 대화식으로 만드는 것은 비자명한 작업의 중요한 첫 단계
- 일반적으로
spec.md같은 파일로 저장하고 향후 세션에서 "@spec.md를 참조하고 어떤 작업 수행" 요청 가능
- 에이전트가 충분히 동의할 만한 계획을 제시해 구현 진행 허용
- 생성한 UI는 방향성이 매우 좋았음
- 많은 폴리시 이슈(간격, 색상 등)가 있었지만 UI를 보고 원하는 것에 대한 영감의 불꽃 획득
- 팁: 영감을 얻기 위해 AI를 매우 자주 사용, 이 경우 생성한 UI 코드의 많은 부분(전부는 아님)을 유지했지만, 에이전트에 프롬프트를 주고 모든 것을 버리고 수동으로 다시 작업하는 경우도 매우 자주 발생
- 창작의 "제로 투 원" 단계가 매우 어렵고 시간이 많이 걸리며 AI는 뮤즈 역할을 훌륭히 수행
벽에 부딪힘
- 채팅 11~14에서 슬롭 존에 진입
- 에이전트가 생성한 코드에 심각한 버그가 있고 수정에 완전히 실패
- 나도 수정 방법을 모름
- 버그 수정을 위해 몇 번의 헤일메리 시도
- 에이전트가 해결하면 연구하고 배울 수 있음
- 실패해도 비용이 거의 들지 않음
- 에이전트가 해결했지만 이해하지 못하면 되돌림, 이해하지 못하는 코드는 배포하지 않음
- 실패하는 동안 탭을 전환해 문제를 검색하고 스스로 해결 시도
- 이 시점에서 뒤로 물러나 수행한 작업을 검토하고 자체 계획을 세워야 함을 인식
- 스스로 교육하고 비판적으로 사고할 시간
- AI는 더 이상 솔루션이 아니라 부채
클린업 세션
- 다음 몇 세션을 에이전트를 안내해 코드 정리에 소비
-
두 번째 세션: 더 나은 위치로 일부 메서드 이동
- 필 배경, 전경, 뱃지 함수를 UpdateAccessoryView.swift에서 UpdateViewModel.swift로 이동하고 더 일반화
-
세 번째 세션: 코드에 문서 추가
- UpdateBadge.swift의 문서 업데이트
- 팁: 문서 추가는 코드에 대한 자신의 이해를 재확인하고 이 코드를 읽고 수정할 수 있는 미래 에이전트 교육에 도움
- 에이전트는 자연어 설명과 코드를 모두 가질 때 훨씬 더 나은 성능 발휘
-
네 번째 세션: 뷰 모델을 앱 전역 위치로 이동
- 원래 작업이 창 범위에 배치했지만 업데이트 정보는 앱 범위이므로
- 이 과정에서 일반적으로 사소한 수동 변경도 함께 수행
-
클린업 단계의 중요성
- 효과적으로 정리하려면 코드에 대한 꽤 좋은 이해 필요, 따라서 AI가 작성한 코드를 맹목적으로 수용하지 않도록 강제
- 더 잘 구성되고 문서화된 코드는 향후 에이전틱 세션의 성능 향상에 도움
- 이를 농담 삼아 "안티-슬롭 세션" 이라고 부름
버그 직면
- 초기 세션에서 발견한 버그로 돌아갈 시간
- 에이전트가 이를 파악하도록 하기 위해 다시 몇 세션 소비
- 모호하게 시작해 접근 방법을 점점 더 구체적으로 만듦
- 첫 번째 모호한 세션: 표준 네이티브 탭의 경우 업데이트 액세서리 뷰가 보이지 않음, 창의 타이틀바에 계속 보이도록 해야 함 - 실패
- 두 번째 더 구체적: TerminalTabsTitlebarTahoe.swift 탭 바 제약 조건을 업데이트해 탭 바의 오른쪽 가장자리를 업데이트 액세서리 뷰의 왼쪽 가장자리에 정렬 - 실패
- 세 번째 다른 구체적 접근 시도: TitlebarTabsTahoeTerminalWindow.swift를 변경해 탭 바를 하단 액세서리 뷰가 아닌 상단 액세서리 뷰로 만들어 탭을 타이틀바에 넣는 것은 어떨까 - 실패
- 마지막 시도: 오른쪽 액세서리 뷰와 레이아웃이 TerminalWindow.swift의 업데이트 액세서리 뷰 설정과 충돌, 탭 바가 항상 업데이트 알림 왼쪽에 나타나도록 제한 가능한가 - 실패
- 이 전체 과정 동안 수동 연구와 인간의 노력으로 스스로 해결하려고도 시도
- 더 구체적인 프롬프트는 그 과정에서 배운 것을 기반
- 전반적으로 명확히 작동하지 않음
- 혼자서는 해결할 수 없다고 판단해 방향 전환 결정
- 문제가 있는 타이틀바 스타일의 경우 타이틀바가 아닌 창의 콘텐츠 뷰 위에 오버레이된 오른쪽 하단 모서리에 업데이트 알림 배치
- Ghostty에 타이틀바를 완전히 숨기는 구성이 있으므로 어쨌든 이를 지원해야 함
- 나중에 타이틀바 스타일 문제를 해결할 수 있더라도 이 다른 모드를 여전히 지원해야 함
-
다음 세션 은 이 계획으로 진행하며 매우 구체적인 프롬프트 사용
- Update 시스템을 보강해 TerminalView.swift에서 오버레이 접근 방식도 지원
- 업데이트 알림은 창 하단에 나타나야 하며 텍스트 위에 표시(따라서 터미널 뷰 크기 조정 없음)
- 모든 클릭 동작은 액세서리 뷰와 동일
- 정말 잘 수행, 나중에 많은 수동 폴리시 작업(이동, 이름 변경 등)을 했지만 핵심 작업은 견고
백엔드 시작
- UI가 충분히 좋다고 느껴짐
- 나중에 다루고 싶은 많은 폴리시 이슈를 메모했지만 주로 계획에 렌치를 던질 수 있는 미지의 미지수를 발견하기 위해 백엔드 작업으로 이동하고 싶었음
- 불완전한 함수와 다양한
TODO주석이 있는 스캐폴드 파일을 수동으로 생성. 새로운 세션 시작- UpdateDriver.swift 완성 요청, Sparkle 문서를 읽어 기능 이해
- 팁: AI는 빈칸 채우기나 나머지 올빼미 그리기에 매우 뛰어남
- 설명적인 함수 이름, 매개변수, todo 주석 등으로 스캐폴딩을 만드는 패턴은 매우 일반적이며 잘 작동
- 실제로 매우 나쁜 작업을 수행해 이 코드를 모두 버림
- 생성한 코드는 작동했지만 명백히 잘못된 접근 방식
- 많은 다른 관심사를 혼동했고 드라이버에 상태를 저장하는 방식이 명백히 잘못됨
- 수행한 작업을 연구했을 때 뷰 모델이 최적이 아닌 방식으로 구조화되어 있음을 깨달음
- AI(및 수동으로 작성하기로 선택한 경우 인간)에게 더 나은 프레임워크를 제공하기 위해 클린업 모드로 기어 전환
대대적인 재클린업
- 경험상 UI 프론트엔드와 비즈니스 로직 백엔드의 깔끔함은 종종 중간의 뷰 모델 품질에 의해 결정
- 뷰 모델을 수동으로 재구성하는 데 시간 소비
- 옵셔널이 많은 구조체가 아닌 태그된 유니온으로 전환, 일부 타입 이름 변경, 이동
- 경험상 중간에 이 작은 수동 작업이 향후 프론트엔드와 백엔드 모두의 세션에서 에이전트를 성공으로 이끌 것임을 알고 있었음
- 재구조화를 완료한 후 첫 번째로 한 일은 에이전트에게 다시 한 번 올빼미를 완성하도록 요청
- 이번에는 변경 사항을 검사하고 종속 코드를 새 스타일로 업데이트하고 이전 코드 제거
- 일련의 마라톤 클린업 세션 계속
- 추가 데드 코드 제거 요청
- 직접 빌드를 깨뜨린 후 회의 참석 중 에이전트에게 수정하도록 요청
- 팁: "엉망으로 만들었으니 내 실수를 고쳐주세요"는 에이전트에 대한 또 다른 빈번한 사용 사례
- 일부 뷰에서 리팩토링 시작
- 추가 클린업 작업
시뮬레이션
- 첫 번째 UI 세션에서 에이전트에게 실제 업데이트 확인 없이 UI를 실제로 볼 수 있도록 데모 코드 생성 요청
- 업데이트 플로우에는 여러 시나리오가 있으며 이 시점까지 해피 패스만 테스트
-
다음 세션 에서 시뮬레이션 코드를 전용 파일로 추출하고 에이전트에게 더 많은 시나리오 생성 요청
- AppDelegate.swift의 업데이트 시뮬레이션 코드를 Features/Update의 전용 파일로 추출
- 여러 시뮬레이션 시나리오(해피 패스, 찾을 수 없음, 오류 등) 포함하여 다양한 데모를 쉽게 시도할 수 있도록
- 팁: 에이전트는 테스트 및 시뮬레이션 생성에 뛰어남
- 여기서 생성한 시뮬레이션 코드는 솔직히 꽤 끔찍하지만 작동하며 릴리스 바이너리의 일부가 아니므로 품질은 중요하지 않음
- 세션에서 볼 수 있는 기본 사항을 넘어 정리조차 하지 않음
- 다양한 시뮬레이션을 실행하고 여러 UX 개선 사항 발견
마지막 마일
- 이 시점에서 작동하는 백엔드와 프론트엔드가 있었고 모두 연결 필요
-
다음 세션 에서 에이전트에게 프롬프트
- Sparkle의 SPUStandardUpdaterController.m과 동일하지만 업데이터 타입용 UpdateController 클래스 생성
- 약간의 왔다 갔다와 수동 폴리시가 필요했지만 도달
- 그런 다음 사소한 개선 사항 추가
- 앱캐스트가 있는 업데이트 가능 상태의 경우 SUAppcastItem을 살펴보고 설정된 경우 다른 관련 메타데이터 표시
- 예를 들어 크기에 대한 콘텐츠 길이
다른 것?
- 에이전트에 대한 마지막 프롬프트는 항상 놓친 것이 무엇인지 묻는 것
- 코드를 수동으로 직접 작성했든 아니든 관계없이 이 작업 수행
- Features/Update 기능에서 만들 수 있는 다른 개선 사항이 있는가, 코드 작성 금지, Oracle 컨설팅, 단위 테스트를 더 추가할 수 있는 코드 부분 고려
- 실제 문제를 강조했으므로 구현하도록 요청
- 나중에 선택적 커밋에서 쉽게 정리할 수 있으므로 수행할 특정 사항을 묻는 것보다 "모두 수행"하도록 에이전트에게 말하는 것이 더 쉽다는 것을 발견
- 이 세션의 재미있는 점은 에이전트가 정말 미친 토끼굴로 들어가기 시작해서 멈추라고 개입
- "멈춰 멈춰 멈춰. 모든 메인 액터 항목 취소"
- 또한 더 나은 방법이 있는데 다소 형편없이 수행한 것을 발견
- 오류 메시지의 경우 자르는 대신 SwiftUI 표준 방법이 있지 않나, 전체 메시지를 볼 수 있는 추가 UI 요소 추가 필요
비용과 시간
- 작업은 총 16개의 별도 세션으로 Amp에서 $15.98의 토큰 지출
- 일반적으로 비싸거나 저렴한지 추측하지는 않겠지만 개인적으로 이 기능에 소비한 2일 동안 커피숍에서 그 이상을 지출
- 이 기능에 소비한 총 실제 시간은 약 8시간으로 추정
- 처음과 마지막 커밋이 3일에 걸쳐 있지만 하루에 약 4시간만 컴퓨터 작업
- 이 기능에만 모든 시간을 소비한 것은 아님
- 예를 들어 Ghostty 업데이트 배포, ThePrimeagen에 1시간 게스트 출연, Zoo의 연례 전사 행사에서 게스트 프레젠테이션 제공 등을 이 기능을 작업하는 동안 수행
- 집에 유아가 있어서 "컴퓨터 시간"이 매우 예정되어 있고 매우 제한적
- 따라서 8시간 추정치가 후한 편
- 인터넷의 많은 사람들이 AI가 더 빠르게 작업할 수 있게 하는지 여부에 대해 논쟁함
- 이 경우 모두 직접 했다면보다 더 빠르게 배포했다고 생각
- 특히 사소한 SwiftUI 스타일링 반복이 개인적으로 너무 지루하고 시간이 많이 걸리며 AI는 그것을 너무 잘하기 때문
-
더 빠른/더 느린 논쟁보다 가장 좋아하는 것: AI가 다른 일을 하러 떠나는 동안 나를 위해 일할 수 있음
- 가족을 위해 아침 식사를 만드는 동안 클린업 세션 중 하나의 사진 촬영
- "요리하는 동안 코딩하고 싶지 않다" 또는 "더 존재하라" 같은 모든 종류의 무시가 있음
- 그렇게 하고 싶다면 괜찮음, 내 경우 이 특정 예에서 집에서 처음 일어난 사람이고 다른 모든 사람이 여전히 자고 있는 동안 아침 식사 준비
- 깨어 있는 모든 순간 이렇게 하지는 않음
- 결론: 나에게 효과가 있음
- 당신을 설득하려는 것이 전혀 아님
- 어떤 AI 회사와도 재정적으로 연관되어 있지 않음
- AI 도구로 많은 성공을 거두고 이에 대해 이야기하기를 좋아하는 사람으로서 사람들이 항상 예제를 공유해 달라고 요청
- 그것이 여기서 하고 있는 일
결론
- 기능이 아름답고 훌륭하게 작동하며 최종 수동 검토 후 병합
- "최종 수동 검토"는 매우 매우 매우 중요, 철저한 수동 검토 없이 AI가 작성한 코드를 배포하지 말 것
- Ghostty 사용자 중 tip 릴리스를 사용하는 경우 현재 사용 가능
- 태그된 릴리스를 사용하는 경우 Ghostty 1.3에서 사용 가능
- 나는 에이전틱 코딩 세션을 공개적으로 공유하는 것의 중요성에 대한 노골적인 옹호자임
- 이유 중 하나는 이러한 도구를 효과적으로 사용하는 방법에 대해 다른 사람들을 교육하는 믿을 수 없을 정도로 강력한 방법이기 때문
- 이 포스트가 이를 보여주는 데 도움이 되기를 희망