A Terminal Protocol for Program Status (OSC 7501)
프로그램 상태를 알리는 터미널 프로토콜, OSC 7501
OSC 7501은 프로그램이 터미널에 작업 중, 사용자 입력 대기, 완료, 실패 같은 상태와 이유를 전달하는 새 이스케이프 시퀀스입니다. 화면이나 프로세스 정보를 읽어 상태를 추측하는 대신 프로그램이 PTY로 직접 알리며, 터미널은 알림이나 상태 아이콘 등 원하는 방식으로 표시할 수 있습니다.
- 주제
AI 요약
Mitchell Hashimoto는 프로그램이 터미널에 현재 상태를 알리는 표준 이스케이프 시퀀스 OSC 7501, Program Status Protocol을 제안합니다. 빌드와 배포처럼 오래 걸리는 작업은 물론 코딩 에이전트도 실행 중, 사용자 입력 대기, 완료 상태를 오갑니다. 사용자가 다른 일을 하는 동안 작업이 끝났거나 승인이 필요한 순간을 알아야 하지만, 기존 터미널 기능만으로는 진행과 대기, 완료를 한데 표현하기 어렵다는 문제의식에서 출발합니다.
기존 방식의 한계
일부 터미널과 도구는 포그라운드 프로세스 변화나 일정 시간 출력이 없는 상태를 감지합니다. 하지만 이런 방식은 프로그램이 실제로 무엇을 하는지 직접 알려주지 않습니다. 코딩 에이전트 여러 개의 상태를 한 화면에 모으는 도구도 화면 문구나 창 제목을 분석해 상태를 추정하거나, 도구별 별도 API를 사용합니다.
Herdr는 에이전트별 규칙으로 화면 상태를 판별하는 사례입니다. 예를 들어 Claude Code의 창 제목이 Braille 스피너 또는 반원 문자로 시작하면 작업 중으로 분류합니다. 글쓴이는 이를 비판하려는 것이 아니라, Claude Code 규칙이 3개월 동안 열 차례 바뀐 기록처럼 앱별 추정 규칙을 계속 관리해야 하는 부담을 지적합니다. 별도 소켓 API는 프로그램이 상태를 직접 알린다는 장점이 있지만, 각 프로그램이 각 인박스에 따로 연동해야 합니다. 로컬 소켓은 SSH나 컨테이너 환경에서도 연결을 별도로 마련해야 합니다.
OSC 7501의 상태와 형식
OSC 7501은 프로그램이 이미 사용하는 PTY로 상태를 보냅니다. 본문은 콜론으로 구분한 key=value 쌍이며, 필수 항목은 state입니다. 상태값은 idle(대기), working(실행 중), done(완료), blocked(사용자 조치 대기), error(실패)입니다. working에는 진행률을 넣을 수 있고, blocked에는 kind로 permission, question, auth 같은 대기 이유를 지정합니다.
선택 항목 app은 cargo나 claude-code처럼 기계가 읽을 프로그램 이름입니다. msg는 사람이 읽을 한 줄 메시지이며 Base64로 인코딩합니다. Terraform은 다음과 같이 승인을 기다리는 상황과 이유를 보낼 수 있습니다.
ESC ] 7501 ; state=blocked:kind=permission:app=terraform:msg=QXBwbHkgMyB0byBhZGQsIDEgdG8gY2hhbmdlLCAwIHRvIGRlc3Ryb3k/ ESC \\
여기서 메시지는 “Apply 3 to add, 1 to change, 0 to destroy?”입니다. 터미널이나 Terraform을 실행하는 다른 도구는 이 정보를 알림, 인박스, 상태 아이콘 등 원하는 형태로 보여줄 수 있습니다.
여러 작업을 동시에 수행하는 프로그램은 계층형 ID를 사용해 여러 상태를 보냅니다. 예를 들어 배포 전체는 실행 중이어도 us-east는 이미지 업로드를 40% 진행하고, eu-west는 프로덕션 배포 승인을 기다릴 수 있습니다. 각 작업 상태를 함께 기록하고, 상태를 지우는 방식도 명세에 포함합니다.
간단한 POSIX 셸 스크립트에서도 상태를 알릴 수 있습니다. 글에서는 상태와 메시지를 받아 OSC 시퀀스를 출력하는 status 함수를 제시하고, rsync 시작 때 working, 성공 때 done, 실패 때 error를 보내는 예를 듭니다. 별도 SDK나 소켓, 환경 변수, JSON 없이 printf와 Base64만으로 연동하는 방식입니다. 전체 명세에는 레코드 수명, 기능 감지, terminfo, 크기 제한, 보안도 포함합니다.
구현 현황
글쓴이는 명세를 libghostty와 Rex에 각각 구현했으며, Terraform, Claude Code, Codex, Homebrew에서도 플러그인이나 포크로 시험 구현했다고 밝힙니다. 각 구현은 열두 줄을 넘지 않았다고 합니다. 터미널 개발자들과 검토를 진행했으며, 다른 도구와 터미널의 구현도 제안합니다.
Lobsters 반응
- @tstack — JSON이 아니라는 점이 정말 답답합니다. 앞으로도 새 이스케이프 시퀀스가 계속 나올 텐데, 각각 다른 직렬화 형식을 쓰면 도입이 느려지고 버그가 생깁니다. JSON일 필요까지는 없지만, 사실상 널리 자리 잡았습니다. 명세에 나온 프로그램은 전부 이미 JSON을 다룹니다. Base64가 있는 셸 환경에는 jq도 있을 가능성이 큽니다. JSON 대신 직접 형식을 만들면 도구 개발자에게 무엇이 절약되나요? 연동 지옥에 장애물만 더 놓습니다.
- @mitchellh — 제가 명세를 썼으니 설명하겠습니다. 지난 몇 년간 터미널 명세 대부분을 구현해 봤습니다. 이 형식은 여러 앱이 이미 다양한 형태로 구현한 Kitty 프로토콜과 아주 비슷하게 의도적으로 골랐습니다. 익숙한 형식입니다. JSON을 쓰는 터미널 명세는 당장 하나도 떠오르지 않습니다. Ghostty에서는 Kitty 프로토콜용 도우미 코드를 재사용했습니다. 앱 개발 쪽에서도 이 형식은 printf로 쓰기 쉽고, 대부분의 경우 printf 호출이면 충분합니다. 터미널 관례, 적어도 현대적인 관례에 더 잘 맞습니다.
- @tstack — 저도 터미널 라이브러리 버그를 만나 수정하거나 우회하느라 많은 시간을 썼습니다. 최근에는 tmux의 팔레트 처리 문제를 디버깅했고, 시작할 때 터미널에 질의하는 데 오래 걸리는 점도 답답합니다. 색상과 기능을 하나씩 물어보는 방식은 느리고 처리도 많이 필요합니다. 앱과 터미널 사이 프로토콜이 지나치게 복잡하다는 공통점이 있습니다. JSON을 꺼낸 이유는 널리 쓰이고 지금은 충분히 빠르기 때문입니다. 잘 정의되고 구현된 직렬화 형식이 있으면 나머지가 쉬워집니다. 터미널 이스케이프 시퀀스는 각자 다른 형식으로 구현하는 악몽입니다. 예를 들어 명세는 콜론으로 key/value를 나누지만 iTerm은 세미콜론을 씁니다. OSC blah; /ST로 감싼 뒤 그 안에 제대로 된 직렬화 형식을 넣으면 문제가 줄어듭니다. 터미널 기능을 알아낼 때도 한 번 요청해 계층형 데이터를 받으면 더 빠르고 간단합니다. 그리고 printf로 쓰기 쉽다는 말은 맞지 않습니다. 명세의 ID에는 허용 문자가 제한돼 있는데 예시의 us-west, eu-west 같은 ID는 다른 프로그램에서 전달됩니다. 사용자들이 이를 검증하지 않고 printf에 넘길 가능성이 높아 오류를 유발하는 설계입니다. JSON이라면 대부분 JSON.stringify()를 써서 이런 문제가 없을 겁니다.
- @fuzzypixelz — 제대로 된 명세는 아니지만 kitty remote control은 요청과 응답에 DCS ESC P @ kitty-cmd <json> ESC \\ 형식을 씁니다. 널리 구현할 목적이 아니라 Kitty 전용이라는 점은 이해합니다. 그래도 창 목록처럼 크고 중첩된 응답에는 JSON이 맞는 사례로 보입니다.
- @geocar — iTerm의 상태 알림과 거의 같은 것처럼 보입니다.
- @kolja — 거의 늘 터미널에서 일하는 사람으로서 터미널의 ‘브라우저화’가 마음에 들지 않습니다. 데스크톱 세션과 상호작용하는 방법은 이미 있습니다. 터미널에 기능을 너무 많이 넣으면 프로그램을 실행해서 가능한 멋진 아이디어가 줄어들 수도 있습니다. 제 관심을 끌고 싶다면 notify-send, spd-say, curl ntfy.sh 같은 도구를 고르면 됩니다. 에이전트 하네스가 엄청나게 많아졌으니 호출해서 알리는 옵션을 넣으면 됩니다.
- @linkdd — 그래서 stdout과 stderr가 있는 것 아닌가요?
- @zie — termios의 STATUS와 비슷한가요? https://man.freebsd.org/cgi/man.cgi?query=termios&sektion=4&manpath=freebsd-release-ports
- @dgl — 출력이 멈췄을 때 무슨 일이 있는지 보려는 경우에는 STATUS가 더 낮은 수준에서 유용합니다. 이 제안은 사용자가 해당 터미널을 보고 있지 않을 때 제목, 탭, 알림이 전체 상태를 반영하려는 목적입니다.
- @thisalex — 그러니까 같은 정보를 다른 경로로 전달하는 셈인가요?
- @panekj — 이미 진행 상태 시퀀스 OSC 9;4가 있습니다. https://learn.microsoft.com/en-us/windows/terminal/tutorials/progress-bar-sequences
- @sdt — 명세에서 이 점을 직접 다룹니다. 기존 시퀀스는 문제의 일부만 해결합니다. OSC 9;4는 작업 중인지 아닌지를 표시하지만, 사용자를 기다리는 상태나 무엇을 하는지는 알리지 못합니다.
원문: Mitchell Hashimoto / 번역·요약: Trawling