
의존성 없이 네이티브 macOS AI 워크스페이스를 구축한 이유
요약
의존성 없이 단일 Python 파일로 구성된 네이티브 macOS AI 워크스페이스 'JoeBro' 구축 사례를 소개합니다. Electron 기반 앱의 높은 리소스 점유와 클라우드 기반 앱의 데이터 보안 문제를 해결하기 위해 로컬 모델과 표준 라이브러리만을 활용했습니다.
핵심 포인트
- 제3자 패키지 없이 Python 표준 라이브러리만 사용하여 의존성 문제 해결
- Ollama와 통신하여 로컬 모델을 활용하는 경량 백엔드 구현
- Swift를 이용한 네이티브 macOS 앱과 단일 파일 백엔드의 결합
- Tailscale을 활용해 원격 서버(Raspberry Pi)에서도 백엔드 구동 가능
저는 한동안 이 작업을 개인 프로젝트로 진행해 왔으며, 이는 매우 유용하다는 것이 증명되었습니다. 이름은 JoeBro이며, 번들링된 백엔드를 갖춘 네이티브 macOS 앱입니다. 백엔드는 단 하나의 Python 파일로 구성되며, 표준 라이브러리(standard library)만 사용하고 제3자 패키지(third-party packages)는 전혀 사용하지 않습니다. 제가 시도했던 모든 AI 채팅 앱은 웹 앱을 감싸는 Electron 셸이거나, 제 데이터를 소유하는 클라우드 구독 서비스였습니다. Electron 앱은 RAM을 엄청나게 잡아먹으며 프롬프트를 특정 서버로 전송합니다. 클라우드 기반 앱은 단순히 데이터를 자신들의 서버에 보관합니다. 저는 제 Mac에서 실행되고, 로컬 모델(local models)을 사용하며(또는 더 저렴한 클라우드 옵션을 사용하며), 실제로 네이티브 앱처럼 느껴지는 무언가를 원했습니다. 그래서 JoeBro를 만들었습니다.
백엔드: 단 하나의 Python 파일, 제로 의존성 (Zero Dependencies)
전체 백엔드는 단일 파일입니다. pip install도, venv도, node_modules도, requirements.txt도 없습니다. HTTP 서버를 열고 사용자의 기기에서 실행 중인 Ollama와 통신합니다.
다음은 핵심 루프입니다. 그 외의 모든 것은 라우팅(routing)과 도구 디스패치(tool dispatch)일 뿐입니다:
class JoeBroHandler(BaseHTTPRequestHandler):
def do_POST(self):
body = json.loads(self.rfile.read(int(self.headers['Content-Length'])))
...
이것이 전부입니다. 하나의 파일, 하나의 포트, 하나의 실행 프로세스. 저장소(repo)를 클론하고 python3 joe.py를 실행하면 백엔드가 준비됩니다. 엔드포인트(endpoint)가 설정되면 Ollama로부터 사용 가능한 모델을 자동으로 찾아냅니다. 도구 호출(tool calls)을 대부분의 로컬 모델이 이해할 수 있는 OpenAI 호환 스키마(OpenAI-compatible schema)로 포맷팅합니다. 스트리밍 응답(streaming responses)과 사고 토큰(thinking tokens)도 처리합니다.
사람들이 단일 파일 백엔드를 보고 왜 모듈로 분리하지 않았는지 물을 것이라는 점을 알고 있습니다. 이것이 왜 중요한지에 대한 이유는 다음과 같습니다.
의존성이 없다는 것은 Python 버전을 두고 싸울 필요가 없음을 의미합니다. 깨진 pip 설치를 디버깅할 필요도 없습니다. 동기화가 어긋나는 requirements.txt를 관리할 필요도 없습니다. 단 500줄의 코드를 실행하기 위해 가상 환경 (venv)을 설정할 필요도 없습니다. 백엔드는 Python 3가 설치된 어떤 머신에서도 동작하며, 그것으로 끝입니다. 제 Mac에서 실행하거나, Raspberry Pi로 복사하거나, 헤드리스 (headless) 서버에 던져 놓아도 그냥 작동합니다. 또한 의존성이 없는 읽기 쉬운 단일 파일이기 때문에, 오후 한나절이면 전체를 검토 (audit)할 수 있습니다. 여러분도 그렇게 해보시길 권장합니다.
Swift 앱은 JoeBro를 열 때 백엔드 프로세스를 자동으로 실행합니다. 이는 .app 내부에 번들링되어 실행 시 자식 프로세스 (child process)로 생성되고, 종료 시 함께 종료됩니다. 이 프로세스는 127.0.0.1:8765에 바인딩되며 네트워크에 절대 노출되지 않습니다. 사용자는 이를 전혀 신경 쓸 필요가 없습니다.
하지만 프론트엔드가 완전히 다른 곳에서 실행 중인 백엔드를 가리키도록 설정할 수도 있습니다. 저는 노트북을 계속 켜둘 필요 없이 언제든 작업을 실행할 수 있도록, Tailscale을 통해 Raspberry Pi 5에서 백엔드를 호스팅합니다. 앱을 열고 서버 주소를 입력하기만 하면, 노트북 배터리를 소모하지 않고도 동일한 모든 기능을 사용할 수 있습니다. 저렴한 VPS나 집에 있는 오래된 컴퓨터로도 똑같이 할 수 있습니다.
원한다면 클라우드 모델을 사용할 수도 있습니다. 설정 패널에는 모든 OpenAI 호환 API 키를 위한 필드가 있습니다. DeepSeek 키, Groq 키, 또는 로컬 모델을 넣으세요. 앱은 상관하지 않습니다. 여러분이 지정하는 어떤 백엔드와도 통신합니다.
프론트엔드: Swift + WebKit을 이용한 네이티브 macOS
React 없음. Electron 없음. 번들러 (bundler) 없음. 오직 Xcode뿐입니다.
프론트엔드는 Swift와 WebKit으로 구축된 네이티브 macOS 앱입니다. 이것이 실제로는 무엇을 의미하는지 설명하겠습니다:
- 메모리 사용량이 Electron보다 훨씬 낮습니다. ChatGPT Electron 클라이언트는 채팅창 하나를 보여주는 데만 500MB 이상을 소비할 수 있습니다. JoeBro는 약 60MB 수준을 유지합니다.
- 진정한 Mac 앱처럼 느껴집니다. 네이티브 메뉴(Native menus), 네이티브 창 관리(Native window management), 네이티브 키보드 단축키(Native keyboard shortcuts)를 지원합니다. Cmd+W는 창을 닫고, Cmd+,는 설정(SF symbols 포함)을 엽니다. 브라우저 엔진과 싸울 필요가 없기 때문에 즉각적으로 반응합니다.
- 큰 화면에서의 3단 레이아웃. 중앙에는 채팅이, 왼쪽에는 대화 목록이 위치합니다. 오른쪽에는 에이전트와 함께 문서나 코드로 직접 작업하거나, 단순히 PDF를 읽을 수 있는 에디터가 있습니다.
- JoeBro를 사용하면 거의 모든 파일 형식을 편집할 수 있으며, HTML과 SVG는 뷰 모드(view mode)에서 사이드바에 직접 렌더링될 수 있습니다.
- 심도 있는 테마 설정(Deep theming). 전체 UI는 사용자가 선택한 어떤 배경화면 위에도 놓일 수 있는 적응형 글래스 인터페이스(adaptive glass interface)입니다. 어떤 이미지를 넣더라도 패널은 그 위의 반투명한 유리처럼 변합니다. 사이드바 하단에는 유리의 투명도를 조절할 수 있는 ◐ 버튼이 있습니다. 더 단순한 것을 선호한다면 내장된 솔리드 컬러(solid colour) 테마도 있습니다. 강조 색상(accent colour)은 시스템을 따르므로 항상 일관된 느낌을 줍니다.
WebView는 메시지 버블, 인라인 코드 포맷팅(inline code formatting), 마크다운 렌더링(markdown rendering)이 포함된 깔끔한 채팅 인터페이스를 렌더링합니다. Swift 레이어는 창 관리, 파일 대화 상자, 설정 패널, 그리고 Python 백엔드와의 통신과 같은 모든 네이티브 작업을 처리합니다.
개발자뿐만 아니라 모두를 위해 구축되었습니다
대부분의 AI 도구는 당신이 무엇을 하고 있는지 이미 알고 있다고 가정합니다. API, 토큰(tokens), 속도 제한(rate limits), 엔드포인트 URL(endpoint URLs), 환경 변수(environment variables) 같은 것들 말이죠. 이는 매우 지치는 일입니다.
JoeBro는 반대로 작동합니다. 모델을 다운로드하고, 드롭다운 메뉴에서 선택한 뒤, 타이핑을 시작하면 됩니다. 에이전트 도구(agent tools)는 그저 토글(toggles)일 뿐입니다. MCP가 무엇의 약자인지 알 필요도 없습니다. 설정 파일(config file)을 편집할 필요도 없습니다. 스위치를 켜기만 하면 모델이 파일을 읽거나, 이메일을 확인하거나, 웹을 검색할 수 있습니다. 권한 시스템(permission system)이 나머지를 처리합니다.
기술적인 사용자라면, 이 앱은 사용자의 방해를 하지도 않습니다. 원격 서버(remote server)를 지정하세요. API 키를 붙여넣으세요. 커스텀 모델(custom model)을 실행하세요. 스크립트를 작성하고 싶다면 전체 로컬 API(local API)가 127.0.0.1:8765에서 작동합니다. 양방향으로 유연하게 대응합니다.
저는 기술적이지 않은 제 친구들이 무언가를 고쳐달라고 저에게 전화하지 않고도 로컬 AI를 사용할 수 있도록 이 앱을 만들었습니다. 그냥 작동합니다.
개인정보 보호 관점 (The Privacy Angle)
이것이 JoeBro가 존재하는 이유 전체입니다.
이 앱은 100% 오프라인입니다. 텔레메트리(telemetry), 계정, 클라우드가 없습니다. 모델을 다운로드한 후에는 인터넷 연결조차 필요하지 않습니다. API 키도 필요 없습니다. 누구에게도 신용카드를 제공할 필요가 없습니다. 모든 모델은 Ollama를 통해 사용자의 하드웨어에서 실행됩니다. 어떤 데이터도 기기를 떠나지 않습니다. 사용자의 프롬프트(prompts), 파일, 대화는 모두 로컬에 머뭅니다. 사용자의 데이터는 하나의 SQLite 파일일 뿐입니다. cp 명령어로 백업하세요. 이더넷 케이블을 뽑아도 JoeBro는 똑같이 작동합니다.
현재 OpenAI나 Anthropic 같은 기업들은 비용이 급증함에 따라 고객들을 사용량 기반 요금제(pay-per-use pricing)로 몰아가고 있습니다. 모든 쿼리(query)마다 비용이 발생합니다. 모든 기능이 구독(subscription) 뒤에 숨겨져 있습니다. JoeBro는 스마트하고 프라이빗한 선택지입니다. 독점적인 프런티어 앱(frontier apps)들과 동일한 기능을 제공하며, 곧 더 많은 기능을 제공할 것입니다. 모두 로컬이며, 모두 당신의 것이고, 사용량 측정기(meter)는 돌아가지 않습니다.
에이전트 시스템 (The Agent System)
LLM(대규모 언어 모델)은 강력하지만, 대다수의 사람들, 특히 기술적이지 않은 업무를 수행하는 사람들은 ChatGPT나 Claude에서 복사/붙여넣기를 하는 수준을 절대 벗어나지 못합니다. JoeBro에는 모델이 실제로 무언가를 수행하기 위해 도구(tools)를 사용할 수 있게 해주는 에이전트 모드(agent mode)가 있습니다.
메시지 박스 아래의 토글을 에이전트 모드로 전환하면 모델은 다음과 같은 일을 할 수 있습니다:
- 파일 읽기 및 쓰기 (Read and write files): 연결된 프로젝트 폴더 내에서 파일을 읽고 쓸 수 있습니다. .md, .docx를 비롯해 생각할 수 있는 거의 모든 파일 형식에서 에이전트와 함께 직접 작업할 수 있습니다.
- 터미널 명령 실행 (Run terminal commands): 터미널 토글을 활성화하면 모델이 Python 스크립트를 실행하거나, 디스크 공간을 확인하거나, 로그를 grep으로 검색할 수 있습니다. 실행 결과는 대화창으로 다시 전달됩니다.
- 웹 검색 (Search the web): 최신 정보를 위해 웹을 검색합니다.
- 심층 조사 수행 (Run deep research): 어떤 주제에 대해서든 심층 조사를 수행합니다. 모델은 단순히 빠른 검색 결과만을 보여주는 것이 아니라, 여러 소스에서 정보를 가져와 전체 보고서를 합성합니다.
- 이메일 관리 (Manage your email): IMAP을 사용하여 이메일을 관리합니다. 이메일 목록 확인, 읽기, 보내기, 보관 및 삭제가 가능합니다.
- 캘린더 관리 (Manage your calendar): 이벤트 생성(macOS 캘린더 통합 또는 CalDAV를 통해 직접 수행)을 통해 캘린더를 관리합니다.
- 기억 저장 및 회상 (Save and recall memories): 사용자에 대한 정보를 저장하여, 여러 대화에 걸쳐 사용자의 선호도를 기억합니다.
- 예약된 작업 실행 (Run scheduled tasks): 일일 이메일 요약이나 기술 및 기억에 대한 주간 감사와 같은 예약된 작업을 실행합니다.
토큰 사용량을 경제적으로 관리하고자 하는 분들을 위해 사고/속도(thinking/fast) 토글도 제공됩니다.
각 기능에는 권한 수준이 있습니다. 세션을 샌드박스(sandbox, 안전함, 쓰기 불가), 읽기 전용(read-only, 보기만 가능), 또는 전체 액세스(full access, 모든 작업 허용)로 설정할 수 있습니다. 터미널 명령을 실행하려면 전체 액세스 권한과 터미널 토글이 켜져 있어야 합니다. 이러한 작업들에 대해 승인이 필요한지 여부 또한 설정에서 토글할 수 있습니다.
또한 이 앱에는 도구를 전혀 사용할 수 없는 채팅 모드(chat mode)가 있습니다. 모델은 단순히 대화만 하며, 간단한 글쓰기 도움 등을 받기에 완벽합니다.
두뇌: 사용자가 제어하는 기술, 작업 및 기억
JoeBro는 시간이 지남에 따라 사용자로부터 학습하지만, 모델이 알고 있는 모든 것에 대한 완전한 제어권은 사용자에게 있습니다. 전용 탭이 있어 사용자의 기준에 따라 모든 기술(skill), 작업(task), 기억(memory)을 확인, 추가, 편집 및 삭제할 수 있습니다.
**Memories (기억)**는 당신에 관한 사실들입니다. 당신의 선호도, 설정, 그리고 대화 전반에 걸쳐 모델이 기억해주길 바란다고 당신이 말한 것들이 여기에 해당합니다. 당신은 원할 때마다 수동으로 이를 추가하거나, 모델이 자율적으로 새로운 기억을 추가하도록 할 수 있습니다. 어떤 방식이든, 당신은 전체 목록을 확인하고, 잘못된 것은 편집하며, 유용하지 않은 것은 삭제할 수 있습니다.
**Skills (기술)**는 모델에게 특정 작업(task)을 처리하는 방법을 가르치는 재사용 가능한 지침입니다. 이는 단순한 프롬프트(prompt)일 수도 있고, 다단계 워크플로 (workflow)일 수도 있습니다. 모델은 처음에는 낮은 신뢰도로 당신과의 대화로부터 기술을 자동 학습하므로, 당신이 실제로 사용할 때만 기술로 정착됩니다. 하지만 당신은 직접 처음부터 기술을 작성하거나, 기존 기술을 편집하고, 필요 없는 것을 삭제하거나, 표준 형식의 기술을 .md 파일로 업로드할 수도 있습니다.
**Tasks (작업)**는 타이머에 따라 실행되는 예약된 동작입니다. 일일 이메일 요약, 주간 기술 감사(skill audit), 월간 정리 등이 이에 해당합니다. 당신이 일정을 설정하고, 실행할 항목을 선택하며, 원할 때 언제든 이를 끌 수 있습니다.
기본적으로 신뢰도가 낮은 기술과 사용되지 않는 기억을 정리하는 주간 감사 작업이 포함되어 있습니다. 당신이 실제로 사용하는 것은 남고, 무시하는 것은 정리됩니다. 하지만 당신이 이를 확인하고 변경할 수 없는 상태에서는 아무 일도 일어나지 않습니다.
Settings (설정): 깔끔하고 미니멀한 구성
설정 패널(Cmd+,)은 네 가지 섹션으로 구성됩니다:
- Models (모델) — 대화할 로컬 모델을 선택합니다. JoeBro는 Ollama가 내려받은 모든 것을 자동으로 찾아냅니다. 엔드포인트(endpoint)를 입력하거나 설정을 구성할 필요가 없습니다. 클라우드 모델을 위한 API 키를 붙여넣을 수도 있습니다.
- Appearance (외관) — 배경이나 색상 테마를 변경합니다.
- Link email and calendar (이메일 및 캘린더 연결) — IMAP을 통해 이메일을 연결하고, macOS(원클릭) 또는 설정에서 CalDAV를 통해 직접 캘린더를 연결합니다.
- Updates (업데이트) — JoeBro는 Sparkle을 통해 자동으로 업데이트될 수 있습니다.
이것이 전부입니다. 계정 설정도, 구독 페이지도, 텔레메트리 (telemetry) 동의 양식도 없습니다.
Call to Action (참여 유도)
JoeBro는 무료이며, 오픈 소스이고, GPLv3 라이선스를 따릅니다. 전체 프로젝트가 오픈 상태로 유지되므로 포크 (fork)된 프로젝트들도 오픈 상태를 유지합니다. 만약 이것이 당신의 취향에 맞는다면:
GitHub에서 저장소(repo)에 Star를 눌러주세요: github.com/joexk1/JoeBro
플러그 앤 플레이 (plug and play) 경험을 위해 v1.0 .dmg 파일을 다운로드하고 클라우드 API (cloud API)를 연결하세요.
또는 저장소를 클론 (clone)하고, Xcode 프로젝트를 열어 빌드 (Build)를 누르세요. 그것으로 끝입니다. 가져올 컨테이너 (containers)도, 컴포즈 파일 (compose file)도, 포트 포워딩 (port forwarding)도, 리버스 프록시 (reverse proxy)도 필요 없습니다. Xcode와 Ollama만 있으면 됩니다. 그게 전부입니다.
이슈 (issue)를 생성하거나 토론 (discussion)을 시작해 주세요. 이것은 처음으로 세상에 공개되는 것입니다. 질문에 기꺼이 답변해 드리겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기