
Claude Code를 무시하지 않기 위해 메뉴 막대에 게를 넣었습니다
요약
Claude Code 사용 시 발생하는 사용자 응답 지연 문제를 해결하기 위해 macOS 메뉴 막대 앱인 MenubarCC를 소개합니다. 애니메이션 게 캐릭터를 통해 AI 세션의 실시간 상태를 시각적으로 전달하여 개발 효율을 높입니다.
핵심 포인트
- Claude Code 세션의 상태를 실시간으로 모니터링하는 MenubarCC 개발
- 게 애니메이션을 통해 작업 중, 대기 중, 루프 발생, 유휴 상태 구분
- 사용자가 AI의 질문에 즉각 응답하도록 유도하여 병목 현상 방지
- 세션별 프로젝트 폴더 및 상태 유지 시간 확인 가능
Claude Code를 진지하게 사용한다면, 아마 세션 하나만 실행하지는 않을 것입니다. 아마 세 개 정도는 실행하고 있을 겁니다. 한 터미널에서는 리팩터링 (refactor) 작업을 묵묵히 수행하고 있고, 다른 터미널에서는 버그 조사를 하고 있으며, 세 번째에서는 문서 작업을 하고 있을지도 모릅니다. 에이전트 (agents)들은 괜찮습니다. 그들은 인내심이 있고, 병렬적으로 작동하며, 절대 불평하지 않습니다.
병목 현상 (bottleneck)은 바로 당신입니다.
어느 시점에 그 세션 중 하나가 작업을 마치고 질문을 던집니다. "테스트도 업데이트할까요?"라고 말이죠. 그러고는 그냥... 거기 가만히 있습니다. 조용히 말이죠. 다른 네 개의 창 뒤에 숨어서요. 20분 뒤에 탭을 전환해 보면, 당신이 비용을 지불하고 있는 비싼 AI 동료가 커피가 식기 전부터 예/아니오 답변을 기다리고 있었다는 사실을 깨닫게 됩니다. 이를 하루에 몇 세션씩 곱해본다면, 파이프라인 (pipeline)에서 가장 느린 구성 요소는 바로 당신입니다.
저는 병목 현상이 되는 것에 지쳐서 MenubarCC를 만들었습니다. Clawd라는 이름의 애니메이션 픽셀 아트 게가 모든 Claude Code 세션의 실시간 상태를 한눈에 보여주는 작은 macOS 메뉴 막대 앱입니다. RunCat을 생각하면 쉽습니다. 다만 CPU가 바쁘다고 알려주는 대신, AI가 당신을 필요로 할 때 알려줍니다.
하나의 게, 네 가지 상태
Clawd는 정확히 네 가지 애니메이션을 가지고 있으며, 각 애니메이션은 모든 세션의 종합적인 상태에 매핑됩니다.
- 걷기 (Walking) — Claude가 작업 중입니다. 그냥 두세요. 다른 일을 하러 가셔도 됩니다.
- 튀어 오르기 (Bouncing) — 세션이 완료되어 당신의 입력을 기다리고 있습니다. 이것이 가장 중요한 상태이므로 다른 모든 것보다 우선순위가 높습니다.
- 맥동 (Pulsing) — 세션이 설정된 임계값(5~60분) 동안 진전 없이 계속 바쁜 상태입니다. 무언가 루프 (loop)에 빠졌거나 명령에서 멈춰 있을 가능성이 큽니다.
- 정지 (Static) — 모든 것이 유휴 (idle) 상태입니다. 평화롭습니다.
우선순위 순서는 의도적입니다: 대기 (waiting) > 정지 (stuck) > 활성 (active) > 유휴 (idle). 게가 걷고 있다면 "모든 것이 정상"임을 의미하며, 게가 튀어 오르고 있다면 "현재 로봇의 작업을 방해하고 있음"을 의미합니다. 며칠 지나면 반사적으로 반응하게 됩니다. 주변 시야에 튀어 오르는 모습이 보이면, 질문에 답하러 가고, 그러면 게는 다시 걷기 시작합니다.
게를 클릭하면 상태별(STUCK, ACTIVE, WAITING, IDLE)로 그룹화된 모든 세션 목록이 메뉴로 나타나며, 각 세션에는 프로젝트 폴더와 해당 상태로 유지된 시간이 표시됩니다:
메뉴 막대를 보고 있지 않더라도, MenubarCC는 프로젝트 이름을 헤드라인으로 하는 macOS 네이티브 배너 알림을 띄웁니다 — "MenubarCC: 응답 완료", "dotfiles: 권한 요청" 등 — 따라서 아무것도 열지 않고도 어느 세션이 당신을 원하는지 알 수 있습니다. 소리와 배너는 별도로 설정할 수 있으며, 이벤트 유형별로 사용자 정의 사운드(mp3/wav/m4a 등 무엇이든)를 지정할 수 있습니다. 제 권한 요청은 "딩" 소리가 나고, 응답이 완료되면 "팝" 소리가 납니다. 유치해 보일 수 있지만 효과적입니다.
설치 (Install)
Homebrew:
brew tap ksterx/tap && brew install --cask menubarcc
또는 릴리스 페이지에서 DMG를 다운로드하여 Applications 폴더로 드래그하세요. 처음 실행할 때 앱이 Claude Code 훅 (hook) 설치를 제안합니다. 클릭 한 번으로 설치하고, 나중에 원하면 클릭 한 번으로 삭제할 수 있습니다. 요구 사항: macOS 13 이상, Apple Silicon.
이 앱은 Developer ID 서명이 되어 있고 Apple의 공증 (notarized)을 받았으므로, "확인되지 않은 개발자" 관련 절차를 거칠 필요가 없습니다. MIT 라이선스이며 전체 코드는 GitHub에 공개되어 있습니다.
작동 원리 (How it works)
마법이나 클라우드는 없습니다. 세 가지 구성 요소가 작동합니다:
- Claude Code hooks. Claude Code는 세션 시작, 종료, 알림, 권한 요청과 같은 라이프사이클 이벤트(lifecycle events) 발생 시 실행되는 훅(hooks) 시스템을 가지고 있습니다. MenubarCC는 사용자의 훅 설정(hook config)에 작은 Python 브릿지 스크립트를 설치하여 "이 세션은 입력을 기다리는 중"이라는 플래그(flag)와 이벤트 메타데이터(metadata)를 기록합니다.
- Local state files. 세션 상태는
~/.claude/sessions/디렉토리 아래의 JSON 파일에 저장됩니다. 앱은 10초마다 이 파일들을 폴링(poll)하며, 상태(status) + 대기 플래그(waiting flag) + 경과 시간(elapsed time)을 통해 각 세션의 상태를 도출합니다. 이것이 전체 "프로토콜(protocol)"입니다: 디스크 상의 파일들 말이죠. - A native Swift/AppKit app. Electron도, Python 런타임(runtime)도, 프레임워크(frameworks)도 없습니다. 게 애니메이션 프레임은 단일 PNG로부터 CoreGraphics를 사용하여 런타임에 생성됩니다. 다운로드 크기는 약 150 KB로, 대부분의 파비콘(favicon)이 사용하는 node_modules보다 작습니다.
모든 것은 사용자의 기기에 머뭅니다. 앱이 수행하는 유일한 네트워크 호출은 업데이트를 위해 GitHub 릴리스(releases)를 확인하는 것뿐입니다 (사람들에게 DMG를 다시 다운로드하라고 요청하는 것은 무례한 일이기에 내장된 자동 업데이트 기능이 있습니다).
전쟁 이야기: macOS 26이 내 Python 앱을 잡아먹었다
동료 개발자들이 보통 즐거워하는 부분입니다.
MenubarCC v1.x는 rumps를 기반으로 구축되고 py2app로 패키징된 Python 앱이었습니다. 아주 잘 작동했습니다 — macOS 26 Tahoe가 나오기 전까지는 말이죠.
Tahoe는 새로운 Liquid Glass 메뉴 막대를 탑재했고, 그와 함께 제 상태 항목(status item)은 단순히 렌더링(rendering)을 멈춰버렸습니다. 괜찮다고 생각했습니다. py2app/PyObjC 호환성 문제겠거니 하며 디버깅(debug)을 하려 했죠. 하지만 상황은 더 이상해졌습니다. macOS가 이제 **번들 ID(bundle ID)별로 NSStatusItem 위치를 캐싱(cache)**하게 되었고, 제 앱은 보이지 않는 슬롯에 캐싱되어 버린 것입니다. 렌더링 경로를 수정했음에도 아이콘은 계속 사라진 상태였습니다. 시스템이 제 상태 항목이 "있어야 할" 위치를 기억하고 있었는데, 그 위치가 하필이면 아무 데도 없는 곳이었던 것입니다. 환경설정(preferences)을 초기화해도 도움이 되지 않았습니다. 번들 ID 자체가 오염된 상태였습니다.
Python 코어 주변에 네이티브 Objective-C 런처 심(shim)을 구현해 보기도 했습니다. 점점 더 기괴한(cursed) 우회 방법들을 시도해 보았습니다. 결국 저는 명백한 사실을 받아들여야 했습니다. 세 개의 Python 패키징 접착제(glue) 층을 통해 새로운 OS와 싸우는 것은 승산이 없는 게임이었습니다. v2.0은 Swift와 AppKit을 사용하여 처음부터 다시 작성되었습니다. 기존 번들 ID(bundle ID)가 영구적으로 오염되었기 때문에 새로운 번들 ID를 사용했습니다.
재작성 과정은 이틀 정도 고통스러웠지만, 그 즉시 보상을 받았습니다. Python 버전은 전체 인터프리터를 끌고 다니는 약 30MB 크기의 앱 번들(app bundle)이었지만, Swift 버전은 150KB에 불과하며, 즉시 실행되고, 애니메이션이 부드러우며, 강령술(séance)을 통하는 대신 NSStatusItem과 일급 시민(first-class citizen)처럼 통신합니다. 만약 여러분이 네이티브가 아닌 스택으로 메뉴 막대 앱을 유지 관리하고 있다면, 이것을 Tahoe에 대한 친절한 경고로 받아들이십시오.
사용해 보기
MenubarCC는 무료이며 오픈 소스입니다:
brew tap ksterx/tap && brew install --cask menubarcc
만약 여러분이 여러 개의 Claude Code 세션을 실행하면서, 어떤 세션이 30분 동안이나 여러분을 기다리고 있는 것을 발견한 적이 있다면, Clawd에게 메뉴 막대의 자리를 내어주세요. 별(Star)은 감사히 받겠으며, 이슈(issue)는 언제든 환영합니다. 기능 요청, 버그 보고, 또는 게(crab) 애니메이션 프레임 레이트에 대한 강한 의견 모두 환영합니다.
이 글은 저의 Zenn에 올린 원문 일본어 기사를 영어로 각색한 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기