일주일 만에 Slack TUI를 만들었습니다
요약
작성자는 느린 데스크톱 앱 환경에 대한 불만을 느끼고, 텍스트 처리에 최적화된 터미널(Terminal) 환경에서 Slack 클라이언트를 재구현하는 프로젝트를 시작했습니다. 이 과정에서 Go 언어와 charm.land 라이브러리들(Bubbletea, lipgloss 등)을 활용하여 빠르고 반응성이 좋은 TUI (Text User Interface) 기반의 Slack 클라이언트 'slk'를 개발할 수 있었습니다. 특히 Kitty 터미널의 그래픽 프로토콜 덕분에 아바타나 이미지를 실제 픽셀로 렌더링하는 것이 가능해져, 기존의 단순한 ASCII 근사치를 넘어선 완성도 높은 사용자 경험을 구현했습니다.
핵심 포인트
- 느린 데스크톱 앱 대신 빠르고 반응성이 좋은 TUI 환경에서 Slack 클라이언트를 구축함.
- Go 언어와 charm.land 라이브러리(Bubbletea, lipgloss)를 사용하여 휴대 가능하고 안정적인 TUI 애플리케이션을 개발함.
- Kitty 터미널의 그래픽 프로토콜 덕분에 아바타 및 이미지를 실제 픽셀로 렌더링하여 높은 시각적 완성도를 달성함.
- WebSocket을 이용한 실시간 메시징, 여러 워크스페이스 관리, Vim 스타일 모달 편집 등 Slack 핵심 기능을 TUI 환경에 성공적으로 구현함.
제 컴퓨터에서 Slack이 제대로 작동하지 않는 날이 있었습니다. :wave:를 입력하면 자동 완성되는 데 2초나 걸렸습니다. 이모지 하나 자동 완성하는 데 2초라니요! 팬은 돌아가고 있었고, 앱 전체가 느릿느릿하게 느껴졌습니다. 저는 Slack을 거의 쉬지 않고 실행해 둡니다. 대부분의 사람들이 그렇듯이 말이죠. 이모지 드롭다운이 느릿느릿 움직이는 것을 지켜보는 내내 저는 이런 생각을 했습니다. '이건 그냥 텍스트일 뿐인데.' 터미널 (Terminal)은 텍스트 처리에 탁월합니다. 제가 매일 의존하는 도구들인 vim, btop, tig, k9s는 사용하는 즐거움이 있습니다. 그것들은 믿을 수 없을 정도로 빠르고 반응성이 좋습니다. 살아있는 것처럼 느껴지죠. 반면, 제가 하루 종일 머물러야 하고 모든 대화가 이루어지는 앱은 제 컴퓨터에서 가장 느린 프로그램입니다. 또한 엄청나게 거대합니다. 메모리와 디스크를 엄청나게 차지하는 번들링된 Electron 앱이죠. Slack은 그저 텍스트일 뿐입니다. 터미널은 텍스트에 강합니다. 그런데 왜 저는 그것을 읽기 위해 1.5GB의 Chromium을 실행하고 있는 걸까요? TUI Slack 클라이언트들은 다 어디에 있는 걸까요? 누군가 이미 만들었을 것이라고 생각했습니다. Slack은 12년이나 되었습니다. TUI 생태계는 이미 수년 전부터 성숙해 있었습니다. 두 영역의 교차점은 명확해 보였습니다. 하지만 존재하지 않았습니다. 정말로 말이죠. 몇몇 프로젝트가 있었지만, 대부분 방치되었거나 아주 기본적인 기능만 갖추고 있었습니다. 일상적으로 사용할 만한 것은 없었습니다. 진짜 Slack 클라이언트처럼 느껴지는 것도 없었습니다. 이 간극은 이상했습니다. 솔직한 답변은, TUI Slack 클라이언트를 다듬는 작업이 아마 한 사람의 1년 치 가치가 없었을 것이라는 점입니다. Slack은 대부분의 사람들에게 대략적으로 잘 작동합니다. 데스크톱 앱은 비대하지만 기능적입니다. 진짜 대체제를 만드는 비용은 높았고 대상 관객은 적었습니다. 그래서 아무도 하지 않았습니다. 세상에 만들어지지 않은 앱들은 더 이상 수요 때문에 막히는 것이 아닙니다. 누군가가 그 갈증을 해소할 만큼 충분히 관심을 갖느냐에 따라 결정됩니다. 만약 제가 만든다면 어떨까요? 그래서 저는 시도해 보기로 했습니다. 2026년의 TUI 라이브러리들이 괜찮은 Slack 경험을 제공할 수 있을까요? 많은 미지수가 있었습니다. 실시간 메시징 (Real-time messaging), 스레드 (Threads), 멀티 워크스페이스 (Multi-workspace). 1995년의 IRC 클라이언트처럼 느껴지지 않는 세련됨. 이미지와 아바타(이미 터미널에서 가능하다는 것은 알고 있었지만 어떻게 작동하는지, 혹은 Slack TUI에서 제대로 버텨줄지는 몰랐던 것들).
그 질문들에 대해 하나씩 해결해 나가는 과정에서 얻은 답은 '예'인 것 같았습니다. TUI 생태계는 정말 좋은 상태에 있습니다. AI 코딩 TUI인 Opencode가 이미 그 증거였습니다. 저는 그것을 매일 사용합니다. 모달(Modals), 스피너(spinners), 모션(motion)까지, 아주 잘 구성되어 있습니다. 초기에 스택(stack)을 결정하는 동안, 저는 단 하나의 휴대 가능한 바이너리(portable binary)로 결정하고 싶었습니다. 사용자에게 Node나 Python, Ruby 또는 그 어떤 런타임(runtime)을 설치하라고 요구하고 싶지 않았습니다. 그냥 작동하는 단일 다운로드 파일을 원했습니다. 그것은 Go를 의미했습니다. 다음 질문은 Go에서 사용할 수 있는 TUI 라이브러리가 무엇인가였습니다. 저는 charm.land를 발견했습니다. 이 라이브러리 제품군은 정말 즐거움 그 자체입니다. Bubbletea는 아키텍처(architecture)를 처리하고, lipgloss는 스타일링(styling)을 처리합니다. V2 릴리스는 레이아웃(layouts)도 처리했는데, 이는 엄청난 양의 커스텀 코드 없이도 완성도 높게 느껴지도록 만드는 핵심이었습니다. 이미지와 아바타는 Slack UX의 핵심 부분입니다. 그래서 저는 그 부분에 대해 무언가를 해결해야 한다는 것을 알고 있었습니다. Kitty의 그래픽 프로토콜(graphics protocol)은 이름 그대로의 역할을 수행하며, 제 테스트 결과 제 사용 사례에 실행 가능하다는 것을 보여주었습니다. 이 모든 것이 완료된 후, 저는 에이전트(agents)가 타이핑의 대부분을 하게 하여 제가 얼마나 빨리 진행할 수 있는지 확인해 보기로 했습니다. 제가 시작한 빌드는 가장 걱정했던 부분인 이미지부터였습니다. Kitty 그래픽 프로토콜은 터미널이 단순히 하프 블록(half-blocks)이나 Sixel이 아닌, 실제 픽셀 이미지(true-pixel images)를 렌더링할 수 있는 방법을 제공합니다. Kitty 또는 Ghostty 터미널에서 slk는 실제 Slack 아바타와 이미지를 보여줍니다. 그것들은 블록 형태의 ASCII 근사치가 아니라 진짜 아바타처럼 보입니다. 이 순간 slk는 반쪽짜리 장난감처럼 느껴지는 것을 멈췄습니다. 이 포스트의 스크린샷이 지금과 같은 모습인 이유는 아바타와 이미지가 실제로 터미널에서 렌더링되기 때문입니다. 만약 Kitty가 아닌 터미널에서 slk를 사용하려고 하면, 대신 ASCII 근사치를 보게 될 것입니다. slk의 메인 뷰입니다. 아바타는 ASCII 근사치가 아니라 Kitty 그래픽 프로토콜을 통해 렌더링되는 실제 픽셀 데이터입니다. 나머지 작업은 덜 놀랍지만 더 만족스러웠습니다. WebSocket을 통한 실시간 메시지, 수정, 삭제, 반응(reactions), 그리고 타이핑 표시(typing indicators). 여러 워크스페이스(workspaces)가 왼쪽 레일(left rail)의 실시간 읽지 않음 배지와 함께 병렬로 연결된 상태를 유지합니다.
1부터 9까지의 키를 눌러 워크스페이스(workspaces) 사이를 이동할 수 있습니다. Vim 스타일의 모달 편집 (modal editing), 퍼지 채널 검색 (Fuzzy channel finder)을 지원합니다. 스레드 (Threads)는 사이드 패널에 표시되며, 스레드가 어느 채널에서 시작되었는지 항상 잊어버리는 저를 위해 워크스페이스 전체 스레드 보기 (workspace-wide threads view) 기능도 포함했습니다. 스레드 사이드 패널입니다. 워크스페이스 전체 스레드 보기는 키 한 번만 누르면 바로 나타납니다. 35개의 테마가 포함되어 있으며 (Hot Dog Stand 테마도 포함되어 있습니다, 하하. 제가 좀 옛날 사람이거든요.), 실시간 테마 전환기 (live switcher)가 제공됩니다. 스마트 붙여넣기 (Smart paste)는 클립보드의 이미지, 파일 경로, 텍스트를 캡션과 함께 한 번에 처리합니다. Slack 네이티브 사이드바 섹션은 실시간으로 유지되거나, 글로브 (globs)를 사용하여 직접 구성할 수 있습니다. 실시간 테마 전환기 사용 중. slk에는 이와 같은 테마가 35개 포함되어 있습니다. 바이너리 (binary) 크기는 24MB입니다. 실시간 멀티 워크스페이스 세션은 아주 적은 양의 RAM만 사용합니다. 동일한 설정에서 공식 Slack 앱은 500MB에서 1.5GB까지 사용합니다. 대화 내용은 동일합니다. 생산성도 동일합니다. 이것은 장난감이 아닙니다. Linux와 Mac에서 사용하는 저의 데일리 드라이버 (daily driver)입니다. 몰입하여 개발한 일주일. 영감이 강렬하게 찾아왔습니다. 저는 수년 동안 Slack 때문에 짜증을 느껴왔습니다. 소프트웨어가 항상 곁에 있지만 결코 완벽하지 않을 때 쌓이는 그런 종류의 짜증 말입니다. 일단 slk를 쓰기 시작하자 멈출 수 없었습니다. 일주일 동안 굶주린 듯이 코딩했습니다. 그 7일 동안 제 인생의 그 어떤 주보다 더 많은 커밋 (commits)을 했습니다. 일주일간의 slk 커밋 기록. 거의 매일 커밋을 하는 저임에도 불구하고, 제 인생의 그 어떤 주보다 더 많은 양을 커밋했습니다. 개발 환경은 4개의 tmux 창이었고, 각 창에는 opencode가 실행 중이었으며, 에이전트 (agents)들이 병렬로 실행되는 git worktrees에서 돌아가고 있었습니다. 타이핑의 대부분은 에이전트들의 몫이었습니다. 결정은 저의 몫이었습니다. 에이전트들은 제가 일주일을 쏟고 싶지 않은 일들을 아주 잘 처리해주었습니다. Bubbletea 보일러플레이트 (boilerplate), lipgloss 스타일링, Slack의 내부 프로토콜 파싱 (parsing), 테마 시스템 같은 것들 말입니다. 전체를 하나로 묶어주는 반복적인 UI 플러밍 (plumbing) 작업들입니다. 저는 아키텍처 (architecture) 설계를 시작으로 중요한 부분들을 주도했습니다. 아키텍처가 결정된 후에는 그 위에 기능을 구현하는 문제였습니다. 그 후에는 도구가 단순히 기능적인 것을 넘어 살아있는 것처럼 느껴지게 만드는 수많은 작은 다듬기 (polish) 결정들이 이어졌습니다.
현실은 이런 방식으로 만드는 것이 마법처럼 느껴지며 미치도록 중독적이라는 것입니다. 에이전트(agents)들이 무언가 작동하는 것을 볼 때 개발자가 느끼는 희열을 대체한 것이 아닙니다. 오히려 그 희열을 거의 건강하지 못한 수준까지 끌어올렸습니다. 저는 일주일 동안 집착의 파도를 타고 있었고, 에이전트들은 그 추진력 (jet fuel)이었습니다. 대부분의 바이브 코딩 (vibe-coded) 프로젝트들이 장난감에 불과한 이유는 대부분의 사람들이 중간에 멈추기 때문입니다. slk는 개발자가 집착에 빠져 일주일 동안 네 개의 에이전트를 병렬로 가동했을 때 일어나는 결과물입니다. 기술은 코드를 작성하는 것이 아닙니다. 그것은 커뮤니케이션, 판단력, 그리고 집착이 찾아왔을 때 그것을 탈 준비가 되어 있는 상태입니다. ...하지만 slk는 쓰레기가 아닙니다. 바이브 코딩 (vibe-coded) 소프트웨어의 경계선은 그것이 쓰레기라는 점입니다. 신뢰할 수 없고, 누군가 조금만 밀어도 무너져 버립니다. 저는 지금 본업에서 바로 그 상황을 겪고 있습니다. 그렇게 말하는 사람들은 틀리지 않았습니다. 하지만 slk는 그렇지 않습니다. slk는 작동합니다. 그 이유는 에이전트 때문이 아닙니다. 그 이유는 제가 그들을 어떻게 몰아붙였느냐에 있습니다. 저는 시작 단계에서 아키텍처 (architecture)에 대해 에이전트들에게 깊이 있게 도전했습니다. 모든 변경 사항에 대해 단위 테스트 (unit tests)와 TDD (테스트 주도 개발)를 강조했습니다. 문서화 (documentation)와 가독성 (readability)을 강조했습니다. 저는 실제로 코드를 읽었습니다. 저는 에이전트가 제가 직접 쓰려고 노력했을 법한 코드, 즉 문서화가 잘 되어 있고, 잘 모듈화되어 있으며 (well-factored), 변경과 확장이 쉬운 코드를 생성하도록 요구했습니다. 'Uncle Bob'이 좋아하는 그 모든 것들 말입니다. 만약 에이전트가 그 기준을 충족하지 못하는 코드를 내놓으면, 그 코드는 그대로 두지 않았습니다. 대부분의 바이브 코딩 (vibe-coded) 프로젝트가 쓰레기인 이유는 대부분의 운영자들이 규율 (discipline)을 가져오지 않기 때문입니다. 에이전트는 타이피스트 (typist)일 뿐입니다. 당신은 여전히 아키텍트 (architect)입니다.
한번 사용해 보세요. 저는 저를 위해 slk를 만들었습니다. 그 사실은 변하지 않았습니다. 만약 당신이 터미널 (terminal)에서 살고 Slack에서 산다면, 이 도구가 당신의 삶에도 맞을 수 있습니다. 만약 그렇다면, 여기 있습니다: brew install gammons/tap/slk. 소스 코드는 Github에 있습니다. 일종의 마케팅 페이지도 있습니다. 위키 (wiki)에는 설정, 키 바인딩 (keybindings), 그리고 구성 (configuration) 방법이 있습니다. 무엇이 있고 무엇이 없는지 알고 싶다면 트레이드오프 (tradeoffs) 페이지를 먼저 읽어보세요. 여전히 완벽하지는 않습니다. 누락된 기능과 버그들이 있습니다. 하지만 이것은 오늘 바로 사용할 수 있는 실제 Slack 클라이언트입니다. slk는 기능이 완전히 구현된 (feature-complete) 상태는 아닙니다.
Huddles, 화면 공유 (screen sharing), 그리고 Slack 앱 기능은 포함되어 있지 않습니다. 하지만 저는 이것을 데일리 드라이버 (daily driver)로 사용하고 있습니다. PR (Pull Request)은 언제든 환영합니다. 버그 리포트 (Bug report)는 더욱 환영합니다. 제가 가장 의견을 듣고 싶은 사람들은 이것을 직접 사용해 보는 터미널 너드 (terminal nerds)들입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기