데스크톱 AI 비서용 컴패니언 아일랜드 구축하기: 승인 요청, 마스코트, 그리고 14px 웨이크 스트립
요약
데스크톱 AI 비서의 권한 요청 UI 문제를 해결하기 위해, 화면 상단에 고정되는 '컴패니언 아일랜드'를 설계했습니다. 이 아일랜드는 승인 상태 표시와 처리라는 단일 기능에 집중하며, 사용자가 방해받지 않으면서도 필요한 정보를 제공합니다. 또한, 14px의 미묘한 웨이크 스트립을 통해 주변적인 상호작용 경험을 구현하는 것이 핵심입니다.
핵심 포인트
- AI 비서의 권한 요청 UI가 메인 채팅 창에만 머무는 문제를 해결함.
- 컴패니언 아일랜드는 상태 표시와 승인 처리라는 단일 기능에 집중하여 범위를 제한함.
- 14px 웨이크 스트립은 주변적으로 알아챌 수 있게 설계된 미묘한 상호작용 요소임.
- 마스코트 디자인을 통해 사용자의 주의를 끌고, 승인 과정의 중요성을 시각화함.
저는 데스크톱 AI 비서를 만들고 있는데, 아무리 프롬프트 엔지니어링을 해도 해결되지 않는 권한 문제가 있습니다.
Ankita는 무언가 되돌릴 수 없는 행동(메시지 전송, 스크립트 실행, 브라우저 세션 열기 등)을 하기 전에 승인을 요청합니다. 이것이 올바른 동작입니다. 문제는 그 질문이 어디에 나타나느냐 하는 것입니다. 메인 채팅 창에서요. 앱을 최소화하거나 트레이로 숨기고 alt-tab으로 IDE로 전환하면, 승인 요청이 보이지 않는 창에 그대로 남아 당신을 기다리고, 에이전트는 그 요청을 기다리며 대기합니다. 누구도 잘못한 것은 없습니다. 하지만 아무 일도 일어나지 않습니다.
그래서 저는 컴패니언 아일랜드를 만들고 있습니다. 메인 창이 사라졌을 때만 존재하는, 화면 상단 가장자리에 고정된 작고 항상 위에 떠 있는 알약 형태의 UI입니다. 이는 비서가 다른 곳에 방해되지 않으면서도 유지할 수 있도록 허용된 유일한 UI 요소입니다.
세 가지 뷰, 하나의 규칙
이 아일랜드는 세 가지 뷰를 가지고 있으며, 크기는 느낌(vibes)이 아니라 의도적인 상수 값입니다:
- Petit tab (240×64): 축소된 상태. 항상 존재하는 비서의 작은 조각입니다.
- Home (368×64): 마스코트와 상태 표시줄이 있는 전체 카드입니다.
- Home expanded (368×232): 승인이 보류 중일 때 커지면서 목록을 보여줍니다.
또한, 화면 가장자리 바로 위에 탭을 배치하여 14픽셀 스트립만 보이게 하는 숨겨진 뷰도 있습니다. 14픽셀은 전체 제품의 핵심 가설입니다: 주변적으로 알아챌 만큼 충분하고, 깨워 클릭할 만큼 충분합니다. 마우스를 올리면 살짝 보이고; 클릭하면 메인 창이 다시 나타납니다.
이 모든 기하학적 구조는 의도적으로 Electron 임포트가 없는 모듈에 존재합니다. islandSizeFor(view, approvalCount) 함수는 모든 것을 알려진 프리셋으로 제한합니다. 코드의 주석에는 명확하게 적혀 있습니다:
승인 과정은 채팅 창을 벗어나다
제가 가장 자랑스러운 디자인 결정입니다. 이 아일랜드는 두 번째 채팅 창이 아닙니다. 에이전트와 대화할 수 있게 해주지도 않습니다. 오직 두 가지 일만 합니다. 상태를 보여주고, 승인을 처리하는 것입니다. 한 가지 기능에 집중하여 범위 확대를 막았습니다.
네, 마스코트가 있습니다
이 아일랜드에는 상태(대기, 작업 중, 생각 중), 이모트, 눈 모양, 커서 추적 기능을 가진 작은 동반자 마스코트가 상주합니다. 포인터를 향해 곁눈질하는 식입니다. 애니메이션 엔진은 Coucou의 오픈 소스 Mochi 엔진(MIT 라이선스)에서 가져와 사용했으며, Ankita 자신의 캐릭터로 재디자인하고 원래 사운드 큐는 추출하지 않고 남겨두었습니다. 상태 변화는 이징 함수가 적용된 트윈(tween)으로 구동되며, 엔진은 busy 플래그를 보고하여 렌더러에게 모든 것이 안정화되었는지 알려줍니다.
이런 기능을 수행하는 도구에 마스코트가 사치스러운 것일까요? 어쩌면 그럴지도 모릅니다. 하지만 이 아일랜드는 사용자가 그것을 보이게 두지 않으면 화면 공간을 차지할 자격이 없습니다. 그리고 무언가를 승인할 때 자신을 바라보는 작은 얼굴은 이상하리만큼 효과적입니다.
주변에서 배포되는 것들
이 아일랜드는 제가 동시에 마무리하고 있는 두 가지 미공개 변경 사항과 함께 탑재될 예정입니다:
- Keyless Composio 로그인. 이제 앱을 연결하는 것은 브라우저 OAuth 2.1 + PKCE 플로우를 실행합니다. 이는 공개 클라이언트로서의 동적 클라이언트 등록, 단일 사용
http://127.0.0.1:<포트>/callback루프백 리디렉션, S256 코드 교환을 거칩니다. 공개 URL도 없고, 도메인도 없고, 호스팅할 브로커도 없습니다. 토큰은 OS 볼트로 바로 전송되며, 그랜트 파일에는 그랜트 ID와 타임스탬프만 유지됩니다. 그리고COMPOSIO_API_KEY는 폐기(deprecation) 기간이 끝날 때까지 계속 작동합니다. 왜냐하면 화요일에 기존 설정을 깨뜨리는 것은 한 번 결정하는 것이기 때문입니다. - MCP 승인 단계. 예전의 신뢰 서버 우회 방식은 사라졌습니다. 모든 도구 호출은 네 가지 레벨의 게이트를 통해 해결됩니다 — 자동 허용(auto-allow), 한 번 질문, 항상 질문, 거부(deny) — 이 순서대로 고정되어 있습니다: 블랙리스트, 명시적 도구 규칙, 앱별 규칙, 잠긴 앱 기본값, 휴리스틱. 그리고 휴리스틱은 절대 거부할 수 없으며, 보호를 완화하는 호출은 자동 승인 상태에서 실행될 수 없습니다. 새벽 3시에 방치된 예약 작업이 스스로 질문을 중단할 권한을 조용히 부여할 수는 없습니다.
둘 다 현재 변경 로그의 '미출시(Unreleased)' 섹션에 있습니다. 이 아일랜드는 동일한 철학의 눈에 보이는 얼굴입니다: 비서가 잘 질문하고, 적게 질문하며, 결코 사용자를 방치하지 않아야 한다는 것입니다.
왜 알림이 아닌가
저는 승인을 위해 OS 알림을 띄우하는 것만 고려했습니다. 그것들은 무료이고, 네이티브이며, 저는 이미 능동적인 루프를 위한 코드 경로를 반쯤 구축해 놓은 상태였습니다. 하지만 측정하기 어려운 이유 때문에 그렇게 하지 않기로 결정했습니다: 알림은 지워야 하는 대기열(queue)입니다. 아일랜드는 흘끗 보고 지나가는 존재감(presence)입니다. 보류 중인 승인은 슬랙과 경쟁하는 방해가 아니라, 에이전트의 _상태_이며 상태는 지속적인 표면을 가질 자격이 있습니다. 14px 스트립은 주변 인식(ambient awareness)이 방해되는 알림보다 낫다고 제가 건 도박입니다.
아직 완성된 것은 아닙니다 — 이 글을 쓰는 동안 슬라이드 전환의 애니메이션 엣지 케이스를 여전히 디버깅하고 있습니다. 만약 여러분이 항상 최상단에 떠 있는 컴패니언, 플로팅 위젯 또는 눈에 보여야 하지만 방해되어서는 안 되는 무언가를 구축한 경험이 있다면, 무엇을 배웠는지 정말 듣고 싶습니다. 배경 존재감에 적절한 픽셀 양은 얼마일까요?
Ankita는 오픈 소스입니다: https://github.com/akyourowngames/A.N.K.I.T.A
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기