이 레포가 무엇을 하는 물건인가.
DeepSeek 모델로 도는 코딩 에이전트(DeepSeek TUI)는 원래 까만 터미널 안에서만 쓸 수 있었습니다. DeepSeek-GUI는 그 에이전트를 그대로 데려와 창이 있는 데스크탑 앱 안에 앉힙니다. 무슨 파일을 고쳤는지 diff로 보여주고, 위험한 작업은 승인 버튼을 띄우고, 메신저로 걸려온 요청(전화)도 받아줍니다.
한 문장으로 줄이면 "DeepSeek 모델용 로컬 AI 에이전트 워크스페이스"입니다. 작업 디렉토리를 고르면 에이전트가 그 폴더의 코드를 읽고·수정하고·새 파일을 만들며, 사용자는 추론 과정·도구 호출·파일 변경을 실시간으로 지켜보다가 승인하거나 되돌립니다. README가 강조하듯 목표는 "채팅 껍데기를 또 만드는 것"이 아니라 진짜 프로젝트 작업에 꾸준히 투입할 수 있는 데스크탑 동료를 만드는 것입니다.
트렌딩 이유 · 경쟁 대비 장점.
2026년의 AI 코딩 도구 흐름은 "터미널 에이전트(Claude Code·Codex류)의 능력을 일반 사용자도 쓸 수 있는 형태로 포장하기"입니다. DeepSeek는 가성비 좋은 모델로 인기가 높지만 공식 데스크탑 워크벤치가 없었고, 이 빈자리를 커뮤니티가 채운 것이 바로 이 레포입니다. 스타 수(★34)에 비해 트렌딩 순위(일간 5위)가 압도적으로 높다는 건 SNS 언급량 기반의 TrendShift에서 지금 막 화제가 되기 시작한, 아주 초기 단계의 프로젝트라는 신호입니다.
| 비교 항목 | 일반 챗봇 GUI | DeepSeek-GUI |
|---|---|---|
| 작업 단위 | 질문 → 답변 텍스트 | 작업 지시 → 파일 수정·명령 실행·결과 리뷰 |
| 프로젝트 연결 | 코드 복사·붙여넣기 | 로컬 폴더를 워크스페이스로 직접 연결, Git 브랜치 선택 |
| 변경 관리 | 없음 (답변을 직접 반영) | 인라인 diff + 승인/거부 + 권한 모드(읽기 전용~전체 접근) |
| 백그라운드 일 | 창을 열어둬야 함 | Claw가 메신저 수신·정시 작업을 뒤에서 처리 |
TUI 에이전트는 "지금 뭘 고치고 있는지"가 텍스트 로그로만 흘러가 초보자가 따라가기 어렵습니다. 여러 프로젝트·여러 세션을 오가려면 터미널 창을 여러 개 띄워야 하고, Skill·MCP 같은 확장 설정은 JSON 파일을 손으로 편집해야 했습니다.
추론·도구 호출·파일 diff를 한 화면에 시각화하고, 워크스페이스 단위로 세션을 관리하며, Skill/MCP 설정을 GUI 폼으로 바꿨습니다. 거기에 메신저 연동(Claw)이라는 TUI에 없던 기능까지 얹어 "터미널의 상위 호환"을 노립니다.
또 하나의 차별점은 로컬 우선(local-first) 설계입니다. 설정·세션·로그가 전부 내 컴퓨터에 저장되고, 모델 호출은 내 DeepSeek API Key로 직접 나갑니다. 회사 코드를 다루는 개발자에게는 "내 데이터가 어디로 가는지 명확하다"는 점이 SaaS형 도구 대비 큰 장점입니다.
데스크탑 셸·UI·에이전트 런타임·연동까지 한눈에.
package.json을 열어보면 이 앱이 단순한 Electron 래퍼가 아니라는 게 드러납니다. UI(렌더러)·데스크탑 셸(메인)·에이전트 런타임(Kun)의 3개 레이어가 각자 다른 스택을 씁니다.
| 레이어 | 기술 / 버전 | 역할 |
|---|---|---|
| 데스크탑 셸 | Electron 34 + electron-vite 3 + electron-builder | 창·메뉴·파일시스템 접근. Vite로 메인/프리로드/렌더러를 한 번에 빌드. |
| 프론트엔드 | React 19 + Zustand 5 + Tailwind CSS 3 | 채팅 워크벤치 UI. 상태는 Zustand 스토어가 전담. |
| 에디터/표시 | CodeMirror 6 · shiki · streamdown · react-markdown | 마크다운 인라인 편집, 코드 하이라이트, 스트리밍 마크다운 렌더. |
| 에이전트 런타임 | Kun (레포 내 동봉, HTTP/SSE 서버) | 실제 에이전트 루프. 스레드·턴·승인·사용량을 JSONL로 영속화. |
| 데이터 | better-sqlite3 · electron-store · JSONL 로그 | 로컬 저장. 설정은 electron-store, 대화 이력은 append-only 로그. |
| 연동/확장 | MCP SDK · Lark(飞书) SDK · openclaw(위챗) · zod 4 | 외부 도구 연결(MCP), 메신저 브리지, IPC 데이터 검증. |
| 품질 | Vitest 4 · ESLint 10 · TypeScript 5.8 | 테스트 파일 98개(전체 TS 파일의 약 30%) — 개인 프로젝트 치고 이례적으로 촘촘. |
메시지 하나가 화면에서 에이전트까지 갔다 오는 길.
먼저 숲부터 봅니다. Electron 앱은 원래 메인 프로세스(Node.js, 시스템 접근 가능)와 렌더러 프로세스(브라우저 화면, 격리됨)로 나뉘는데, 이 레포는 거기에 Kun이라는 별도의 로컬 HTTP 서버(자식 프로세스)를 하나 더 둡니다. 에이전트 두뇌를 앱 본체에서 떼어낸 구조입니다.
이제 흐름 한 줄기를 끝까지 따라가 봅니다. "사용자가 채팅창에 작업을 입력하고 엔터를 친 순간"의 해피패스입니다(에러·재시도 분기는 생략).
① 입력은 렌더러의 FloatingComposer.tsx(입력창 컴포넌트)가 받아 chat-store(Zustand)의 액션을 호출합니다. ② 렌더러는 시스템 권한이 없으므로, preload가 노출한 window API의 runtimeRequest(path, method, body)를 부릅니다 — 이게 ③ 메인 프로세스의 IPC 핸들러(register-app-ipc-handlers.ts)에 도착하고, zod 스키마(app-ipc-schemas.ts)로 요청 모양이 올바른지 먼저 검증됩니다. ④ 메인은 이 요청을 Kun의 로컬 HTTP 서버 /v1/* 엔드포인트로 전달합니다. ⑤ Kun은 에이전트 루프를 돌며 모델을 호출하고, 파일 수정·명령 실행 같은 도구 호출과 승인 요청을 만들어냅니다. ⑥ 그 과정 전체가 SSE 이벤트로 역방향 스트리밍되어(runtime-sse-ipc.ts가 중계) 렌더러의 MessageTimeline.tsx에 추론·도구 호출·diff로 실시간 그려집니다.
레스토랑으로 치면 렌더러는 홀(손님 응대), 메인 프로세스는 지배인(주문 검수·전달), Kun은 주방(실제 조리)입니다. 손님(사용자)은 주방에 직접 못 들어가고, 주문서(IPC)는 지배인이 형식을 확인한 뒤 주방에 넘기며, 조리 과정은 오픈 키친(SSE 스트림)으로 훤히 보입니다.
src/main/runtime/kun-adapter.ts는 "실행 파일 찾기·기동·중지·주소 얻기"를 인터페이스로 묶어둡니다. 덕분에 내장 Kun 대신 사용자가 지정한 deepseek 실행 파일로도 갈아끼울 수 있습니다. 콘센트(어댑터)만 맞으면 어떤 엔진이든 꽂는 구조입니다.이 레포 특유의 "정상 모양새"도 짚어둘 가치가 있습니다: 거의 모든 모듈 옆에 같은 이름의 .test.ts가 붙어 있고(코로케이션), 메인↔렌더러가 공유하는 타입·설정 스키마는 전부 src/shared/에 모여 있습니다. 파일 이름만 봐도 "어느 프로세스의 코드인지"가 읽히는 컨벤션입니다.
어떤 폴더가 무슨 일을 하나.
| 폴더/파일 | 역할 |
|---|---|
src/main/kun-process.ts | 핵심 — Kun을 spawn하고 "KUN_READY" 신호·포트 회수·정지 유예까지 수명 전체를 관리. |
src/shared/app-settings*.ts | 설정의 단일 진실원. 버전드 스키마(V1) + 정규화 함수로 마이그레이션 안전성 확보. |
src/renderer/src/store/ | chat-store를 thread·claw·navigation·maintenance 등 액션 묶음별 파일로 분할한 Zustand 패턴. |
kun/ | 레포 안의 또 다른 레포. 자체 package.json·테스트를 가진 에이전트 런타임으로, GUI 없이도 이론상 단독 구동 가능. |
src/main/claw-schedule-mcp-server.ts | 정시 작업을 MCP 도구로 노출하는 작은 서버 — "에이전트가 스스로 예약을 거는" 통로. |
이 레포에서 배울 만한 것 + 어디를 보면 되는지.
렌더러에 Node 권한을 직접 주지 않고, preload에서 필요한 함수만 골라 노출하는 게 현대 Electron의 정석입니다. 이 레포는 한 발 더 나아가 IPC 요청을 zod로 검증하고, 심지어 renderer-csp.test.ts로 콘텐츠 보안 정책까지 테스트합니다. src/preload/index.ts → src/main/ipc/ 순서로 읽어보세요.
preload가 노출하는 API의 실제 모양은 이렇게 단순합니다(전체 코드에서 발췌, 복사해서 따라 칠 필요 없이 모양만 눈에 익히면 됩니다):
// src/preload/index.ts — 렌더러가 쓸 수 있는 함수를 '목록으로' 노출
const api = {
getSettings: () => ipcRenderer.invoke('settings:get'),
runtimeRequest: (path, method, body) =>
ipcRenderer.invoke('runtime:request', { path, method, body }),
runClawTask: (taskId) => ipcRenderer.invoke('claw:task:run', taskId),
}
// 화면(렌더러)은 이 목록에 있는 것만 호출 가능 — 시스템 전체엔 손 못 댐
kun-process.ts는 로컬 서버를 품은 앱이 풀어야 할 문제를 다 보여줍니다: 빈 포트 찾기, 기동 신호(KUN_READY 접두사 로그) 대기, 15초 타임아웃, 우아한 종료(5초 유예 후 강제 1초), 죽은 프로세스의 포트 회수. Ollama·로컬 LLM 서버를 품는 앱을 만들 계획이 있다면 이 파일 하나가 미니 교과서입니다.
채팅 앱의 스토어는 금방 1,000줄짜리 괴물이 됩니다. 이 레포는 chat-store-thread-actions.ts, chat-store-claw-actions.ts처럼 도메인별 액션 파일로 쪼개고 chat-store.ts에서 합칩니다. 각 파일에 짝꿍 테스트가 붙어 있어 리팩토링 내성도 좋습니다.
Kun README의 선언이 인상적입니다 — "토큰은 요구사항·코드·결정·결과에 쓰여야지, 반복되는 도구 스키마·폭주한 도구 출력·캐시될 수 있었던 접두사에 낭비되면 안 된다." 이를 위해 불변 프롬프트 접두사 + TTL/LRU 캐시 + 명시적 컨텍스트 압축을 루프 설계 단계부터 박아 넣었습니다. kun/src/loop/·cache/가 해당 코드입니다.
Lark SDK·위챗 shim·webhook/relay·정시 작업이 어떻게 하나의 "백그라운드 에이전트" 기능으로 묶이는지 claw-runtime.ts와 claw-schedule-mcp-server.ts에서 볼 수 있습니다. 사내 메신저 봇 + LLM을 연결하고 싶은 사람에게 실전 레퍼런스입니다.
돌리려면 무엇이 필요한가.
| 항목 | 요구사항 |
|---|---|
| 설치본 | macOS .dmg/.zip (Intel·Apple Silicon) · Windows .exe (NSIS, x64) |
| Linux | 예비 빌드 미제공 — 소스에서 npm run dist:linux. 내장 터미널이 node-pty 네이티브 모듈에 의존하므로 반드시 Linux 위에서 빌드(크로스 패키징 금지). |
| 소스 실행 | Node.js 20+ · npm install 후 npm run dev · 첫 설치 시 인터넷 필요 |
| API | DeepSeek API Key 필수 (platform.deepseek.com) · OpenAI 호환 서버로 Base URL 변경 가능 |
| 데이터 위치 | macOS ~/Library/Application Support/DeepSeek GUI · Windows %APPDATA%\DeepSeek GUI · 공용 설정 ~/.deepseek |
node-pty·better-sqlite3 같은 C++ 네이티브 모듈은 빌드한 OS·아키텍처에 묶입니다. macOS에서 Linux용 패키지를 만들면 설치는 되지만 터미널이 안 켜지는 식으로 조용히 망가집니다 — README가 "Linux는 Linux에서 빌드하라"고 못 박는 이유입니다.
난이도별로 손에 익히는 단계.
클론 → npm install → npm run dev. 첫 실행 시 빌드 스크립트가 kun/의 의존성을 따로 설치하는 과정(ensure-kun-install.cjs)을 터미널 로그에서 직접 확인해 보세요. "레포 안의 레포"가 어떻게 부트스트랩되는지 보입니다.
설정에서 Base URL을 Ollama·LM Studio 같은 로컬 OpenAI 호환 서버로 바꿔보세요. src/shared/openai-compat-url.ts가 URL을 어떻게 정규화하는지 읽고 나서 시도하면, 연결이 안 될 때 어디를 봐야 할지 감이 잡힙니다.
GUI의 Skill 관리 화면에서 새 Skill을 만들고, src/main/services/skill-service.ts가 그 파일을 어디에 저장해 Kun에 어떻게 전달하는지 추적해 보세요. "에이전트 확장이 결국 마크다운 파일 관리"라는 걸 체감하게 됩니다.
"현재 워크스페이스의 파일 개수 세기" 같은 간단한 기능을 preload → IPC 스키마(zod) → 메인 핸들러 → 렌더러 버튼까지 풀코스로 붙여보세요. Electron 보안 모델이 손에 붙는 가장 빠른 길입니다. 기존 workspace:pick-directory 채널을 본보기로.
설정에서 Claw를 켜고 "매일 아침 워크스페이스 요약" 같은 스케줄 작업을 만들어 보세요. 그 작업이 claw-schedule-mcp-server.ts를 거쳐 어떻게 MCP 도구로 실행되는지 로그로 따라가면, 백그라운드 에이전트 설계의 뼈대가 보입니다.
한 주씩 따라가는 계획.
| 주차 | 주제 | 학습 자료 |
|---|---|---|
| 1주차 | Electron 기본기 — 메인/렌더러/preload 3분할과 IPC | Electron 공식 튜토리얼 · 이 레포 src/preload/ |
| 2주차 | React 19 + Zustand — 스트리밍 UI와 스토어 분할 | src/renderer/src/store/ 정독 · Zustand 문서 |
| 3주차 | 에이전트 런타임 — SSE 스트리밍·도구 호출·승인 루프 | kun/src/loop/ · MCP 공식 문서 |
| 4주차 | 로컬 데이터 — JSONL 로그·better-sqlite3·electron-store | kun/src/domain/ · 실습 1~3 |
| 5주차 | 배포 — electron-builder·코드 서명·자동 업데이트 | scripts/ · electron-builder.config.cjs |
본문에 나온 용어 빠른 참조.
| 용어 | 의미 |
|---|---|
| TUI / GUI | 터미널 글자 화면 / 마우스로 쓰는 그래픽 화면. 같은 엔진의 다른 운전석. |
| Kun | 이 레포에 동봉된 로컬 에이전트 런타임. 장자(莊子)의 큰 물고기 '곤'에서 따온 이름으로, HTTP/SSE 서버 형태. |
| Claw | 채팅과 별개로 도는 백그라운드 에이전트. 메신저(Lark·위챗) 수신과 정시 작업 담당. |
| IPC | Inter-Process Communication, 프로세스 간 통신. Electron에서 화면↔본체가 대화하는 통로. |
| contextBridge | preload에서 렌더러로 "허용된 함수 목록"만 안전하게 노출하는 Electron API. |
| SSE | Server-Sent Events. 서버→클라이언트 단방향 실시간 스트림. 에이전트 중계 방송용. |
| MCP | Model Context Protocol. 에이전트에 외부 도구를 꽂는 표준 콘센트 규격. |
| JSONL | 한 줄에 JSON 하나씩 쌓는 파일 형식. 덧붙이기 전용 기록(볼펜 가계부)에 적합. |
| node-pty | 앱 안에 진짜 터미널을 띄워주는 네이티브 모듈. OS별로 따로 빌드해야 함. |
| electron-vite | 메인/preload/렌더러 3개 빌드를 Vite 하나로 묶어주는 빌드 도구. |
| NSIS | Windows 설치 마법사(.exe 인스톨러)를 만드는 오픈소스 시스템. |
| local-first | 데이터를 클라우드가 아닌 내 기기에 우선 저장하는 설계 철학. |