openchamber/openchamber · 제작 Bohdan Triapitsyn · 라이선스 MIT · 버전 1.17.0 · 프론트엔드=React 19 / 서버=Node·Express 5 / 데스크탑=Electron 41 / 모바일=Capacitor 8 · Bun 모노레포(패키지 5개) · 약 1,500개 소스 파일 · 최초 1.0.1(2025-12) → 1.17.0(2026-07), 8개월간 릴리스 127회 · OSSInsight 트렌딩 · 최신 커밋 2026-07-29)
OpenChamber는 OpenCode의 "얼굴이자 원격 조종석"이다. OpenCode는 Claude Code나 Codex처럼 터미널에서 도는 AI 코딩 에이전트인데, OpenChamber는 그것을 opencode serve로 띄워 감독하고(supervise), 그 앞에 그래픽 채팅·diff 뷰어·git 패널·통합 터미널을 붙인다. 핵심은 "에이전트를 다시 만들지 않고, 이미 검증된 에이전트에 인터페이스와 접근성만 더한다"는 분업이다.
설치는 두 갈래다. 데스크탑 앱(mac/Win/Linux)은 릴리스 바이너리를 받으면 되고 맞는 버전의 OpenCode CLI가 함께 번들된다. 서버/웹 모드는 curl … | bash로 CLI(openchamber)를 깔고 openchamber --ui-password …로 띄운 뒤 브라우저로 접속한다. Docker(docker compose up -d, 3000포트)도 지원한다.
OpenCode는 강력하지만 터미널이라는 엔진룸에서만 만질 수 있다. 대부분의 사람은 엔진룸에 들어가 렌치를 드는 대신, 편한 운전석과 계기판에서 차를 몰고 싶어 한다.
OpenChamber는 엔진을 새로 만들지 않는다. 대신 그 엔진에 운전석(GUI)·계기판(diff·git·터미널 뷰)·원격 시동(폰에서 접속)을 달아, 엔진룸을 몰라도 누구나 어디서나 몰 수 있게 한다.
2026년 트렌딩 목록을 보면 "코딩 에이전트 하니스(harness)"가 하나의 장르가 됐다. Claude Code·Codex·OpenCode 같은 에이전트를 더 잘 쓰게 해주는 껍데기·워크플로 도구가 쏟아진다. OpenChamber는 그중에서도 "UI + 원격 접속 + 멀티 디바이스"라는 실용 각도로 자리를 잡았다. 이유를 셋으로 정리하면:
기존 코딩 에이전트의 가장 큰 제약은 "내 개발 PC의 터미널 앞에 앉아 있어야 한다"는 점이다. OpenChamber는 같은 세션을 터미널 → 태블릿 → 폰 → 다시 터미널로 이어받게 만든다. 지하철에서 폰으로 에이전트가 낸 diff를 리뷰하고, 집에 와서 데스크탑으로 이어서 빌드하는 식이다. 이 "이동성"이 개발자들의 마음을 샀다.
클라우드 IDE와 달리 내 컴퓨터에서 도는 에이전트를 내가 소유하면서도 밖에서 접근할 수 있다. Cloudflare 터널로 URL을 만들고, E2E 암호화 릴레이 · 일회용 연결 토큰 · QR 온보딩 · WebAuthn 패스키로 보안을 건다. "코드를 남의 클라우드에 올리기 싫지만 폰에서도 쓰고 싶다"는 요구를 정면으로 푼다.
같은 React UI가 웹·PWA·Electron 데스크탑·Capacitor 모바일·VS Code 확장으로 배포된다. 8개월 만에 1.0 → 1.17, 릴리스 127회라는 속도, macOS 서명·공증, Windows NSIS, Linux AppImage(x64+arm64), 9개 언어 문서까지 — "장난감"이 아니라 실제 유지되는 제품이라는 신호가 강하다.
OpenCode·Claude Code 같은 순수 TUI는 강력하지만 터미널에 묶여 있다. Cursor·클라우드 IDE는 편하지만 남의 인프라·모델에 종속된다. OpenChamber는 "내 구독·내 머신으로 도는 에이전트"의 소유권은 지키면서, GUI의 편함과 멀티 디바이스 접근성을 더한다. stablyai/orca(멀티 에이전트 ADE)와 결이 비슷하지만, OpenChamber는 OpenCode 전용 래퍼로서 깊게 통합됐다는 점이 다르다.
이 저장소는 Bun 워크스페이스 모노레포(bun@1.3.14, Node ≥22)이며, packages/* 아래 5개 패키지로 나뉜다. 핵심은 "UI 한 벌(ui)을 여러 실행 껍데기(web·electron·mobile·vscode)가 공유"한다는 것이다.
@openchamber/ui (React 19)| 요소 | 무엇 / 왜 |
|---|---|
| 프레임워크 | React 19.1 + Zustand 5(도메인별 스토어 ~40개). React Compiler(babel-plugin-react-compiler) 켜짐 |
| 에디터·뷰 | CodeMirror 6(+Vim), Shiki(문법 하이라이트), @pierre/diffs, beautiful-mermaid, KaTeX, ghostty-web(터미널) |
| OpenCode 연동 | @opencode-ai/sdk 1.18.8 — 공식 SDK로 에이전트 API 호출 |
| 스타일 | Tailwind CSS v4 + shadcn/ui("new-york") + Radix/Base UI/HeroUI. 18종+ 테마 |
@openchamber/web (Node·Express)
npm에 배포되는 공개 패키지이자 openchamber CLI의 본체다. OpenCode를 띄우고 프록시하며, GUI에 필요한 자체 기능(git·github·터미널·터널·인증)을 얹는다.
| 구성물 | 역할 |
|---|---|
| HTTP/실시간 | Express 5 + ws 8(WebSocket) + http-proxy-middleware(OpenCode로 /api/* 포워딩) |
| git/github | simple-git + @octokit/rest — 인앱 스테이징·커밋·PR 생성 |
| 터미널 | bun-pty/node-pty — 통합 pty 터미널(디렉토리별 세션) |
| 원격/보안 | Cloudflare 터널 + E2E 릴레이 · jose(JWT) · @simplewebauthn/server(패스키) · web-push |
| 기타 | better-sqlite3(로컬 상태) · sherpa-onnx-node(음성/TTS) · openai(소형 모델) · PWA(vite-plugin-pwa) · Vitest |
| 패키지 | 역할 |
|---|---|
@openchamber/electron | Electron 41 데스크탑 셸. electron-builder(서명·공증) + electron-updater(자동 업데이트). 웹 서버를 메인 프로세스 안에서 직접 실행(사이드카 아님) |
@openchamber/mobile | Capacitor 8 iOS/Android 셸. QR 바코드 스캔·시큐어 스토리지·푸시 |
openchamber(vscode) | VS Code 확장(webview). Agent Manager·우클릭 액션. 자체 sseProxy로 런타임 브리지 |
packages/*로 묶어 함께 빌드·의존하게 하는 방식. UI를 여러 앱이 공유하기에 적합하다.
OpenChamber의 심장은 "UI가 부르는 API를 서버가 OpenCode로 프록시하되, GUI에만 필요한 기능은 서버가 직접 처리"하는 3계층 구조다. UI는 자기가 OpenCode에 직접 붙는지, 중간 서버를 거치는지 몰라도 되게 /api라는 하나의 주소만 바라본다.
lifecycle.js는 OpenCode 바이너리를 spawn으로 띄우고, 자식의 stdout에서 opencode server listening 줄을 파싱해 "이제 준비됐다"를 알아낸다. 그 뒤 계속 헬스 체크하며 죽으면 재시작한다. 포트 충돌 시 killProcessOnPort로 정리하고(OS별로 Windows는 taskkill, Unix는 kill/lsof), 포트가 풀릴 때까지 기다린다. "외부 프로세스를 안정적으로 다루는 법"의 교과서다.
발전기(OpenCode)를 돌보는 관리인(lifecycle)이라 생각하면 쉽다. 관리인은 발전기를 켜고(spawn), "위잉—" 하는 정상 가동음(stdout의 listening 줄)을 듣고 나서야 "전기 들어왔다"고 알린다. 이후에도 계속 소리를 들으며(헬스 체크) 멈추면 즉시 다시 켠다. 건물(UI)은 관리인만 믿고 전기를 쓰면 된다.
proxy.js는 http-proxy-middleware로 /api/*를 OpenCode로 넘기되, 준비완료 게이트(아직 안 떴으면 대기)와 디렉토리 정규화(directory= 쿼리·x-opencode-directory 헤더로 현재 프로젝트 경로 전달, realpath 캐시)를 얹는다. 실시간 이벤트는 realtime-proxy.js가 SSE와 WebSocket을 따로 프록시하며, 허용된 업스트림 WS 경로만 통과시키고 SSE에는 압축을 끈다(스트리밍이 끊기지 않도록).
같은 React UI가 웹·PWA·Electron·모바일·VS Code에서 돈다. 비결은 두 종류의 호출을 분리한 것이다. ① OpenCode 공식 API는 @opencode-ai/sdk로, ② OpenChamber 자체 기능은 RuntimeAPIs라는 간접 계층으로 부른다. 껍데기마다 이 간접 계층의 구현만 바꿔 끼우면(웹은 fetch, 데스크탑은 preload 브리지 window.__OPENCHAMBER_DESKTOP__, VS Code는 sseProxy) 나머지 UI 코드는 그대로다.
보통 Electron 앱은 백엔드를 별도 프로세스(사이드카)로 띄우지만, OpenChamber는 @openchamber/web 서버를 Electron 메인 프로세스 안에서 직접 import해 실행(startWebUiServer())한다. API 경로에서 프로세스 간 직렬화(IPC) 비용을 없애는 선택이다. 패키지된 빌드는 openchamber-ui:// 커스텀 프로토콜로 정적 자산을 서빙하고, 루프백 서버가 API 백엔드로 남는다.
이 저장소에는 AI/LLM 로직이 없다. 실제 추론·도구 실행은 별도 저장소인 OpenCode가 한다(레포 규칙에도 "../opencode를 수정하지 말라"고 못 박음).
따라서 여기서 배울 것은 모델 내부가 아니라 래퍼·프록시·멀티 런타임 아키텍처, 프로세스 생명주기 관리, 원격 접속(터널/릴레이/SSE/WS)이다. 이 점을 헷갈리면 "에이전트 코드를 찾다가" 시간을 버린다.
구조가 주는 교훈: "공유 UI(ui) ↔ 오케스트레이션 서버(web) ↔ 얇은 실행 껍데기들(electron·mobile·vscode)"이 폴더로 정확히 분리된다. 각 모듈은 자기 DOCUMENTATION.md를 갖도록 규칙으로 강제되고, 진입점·브리지는 얇게 두고 도메인 로직은 소유 모듈에 둔다. 실제 멀티플랫폼 제품이 코드를 어떻게 조직하는지 보여주는 좋은 예다.
lifecycle.js에서 spawn → stdout 파싱으로 준비완료 감지 → 헬스 체크 → 재시작 → 포트 정리까지의 전 과정을 실물로 볼 수 있다. "외부 서버를 자식 프로세스로 띄워 감독하는" 패턴은 데브툴·로컬 서버·CI 러너 어디서나 쓰인다.
제3자 HTTP+SSE+WS 서버를 http-proxy-middleware로 감싸고 자체 라우트를 덧붙이는 어댑터 패턴, 그리고 SSE에서 압축을 꺼야 하는 이유 같은 실전 함정을 배운다. 준비완료 게이트·헤더 포워딩·경로 정규화도 좋은 참고감.
웹·PWA·Electron·Capacitor·VS Code에서 같은 React UI를 재사용하는 설계. 공식 API는 SDK로, 자체 기능은 RuntimeAPIs라는 간접 계층으로 분리해 껍데기별 구현만 갈아끼우는 의존성 역전을 실제 규모로 관찰할 수 있다.
Cloudflare 터널 + E2E 암호화 릴레이 + 일회용 연결 토큰 + WebAuthn 패스키 + web-push. "내 머신의 서비스를 밖에서 안전하게 쓰게 하는" 실전 구성표다. jose(JWT)·인증 상태 머신·QR 온보딩까지 한 세트로 읽어볼 수 있다.
도메인별 Zustand 스토어 ~40개, 셀렉터 기반 구독, React Compiler 적용, 가상 스크롤(@tanstack/react-virtual+virtua), Vite manualChunks 벤더 분할 등 "1,000개 넘는 컴포넌트를 빠르게 유지하는" 기법이 실제로 담겨 있다.
| 항목 | 요구사항 |
|---|---|
| 데스크탑 앱 | mac(dmg/zip)·Windows(NSIS)·Linux(AppImage x64/arm64). 맞는 OpenCode CLI가 함께 번들됨. 자동 업데이트 지원 |
| CLI/웹 모드 | curl -fsSL …/install.sh | bash → openchamber --ui-password …. Node 22+ 필요 |
| Docker | docker compose up -d(3000포트). OPENCHAMBER_UI_PASSWORD 환경변수 필수 |
| 외부 OpenCode 연결 | OPENCODE_SKIP_START=true + OPENCODE_HOST/PORT로 이미 뜬 OpenCode 서버에 붙기 가능 |
| 원격 접속 | Cloudflare 터널(quick / managed-remote / managed-local 모드). 데스크탑은 SSH 원격 + 포트 포워딩도 지원 |
| VS Code | 마켓플레이스 fedaykindev.openchamber (VS Code ^1.85) |
· OpenChamber는 OpenCode가 있어야 의미가 있다(데스크탑은 번들, 그 외는 PATH의 opencode를 찾음). env-runtime이 설정 → 환경변수 → 번들 → PATH → 알려진 위치 순으로 바이너리를 탐색한다.
· 소스 ~1,500개, 릴리스가 매우 잦아(8개월 127회) 세부 UI·기능은 빠르게 바뀔 수 있다. 특정 화면 위치보다 아키텍처 원리 위주로 이해하는 게 안전하다.
OpenCode를 먼저 설치한 뒤 openchamber --ui-password …로 띄우고, 같은 와이파이의 폰 브라우저로 접속해보라. 그 다음 Cloudflare 터널(quick 모드)을 켜 외부에서도 접속되는지, QR 온보딩이 어떻게 동작하는지 관찰하라.
OpenChamber를 띄운 상태에서 opencode 자식 프로세스를 강제로 kill해보라. 로그를 보며 헬스 체크가 죽음을 감지하고 재시작하는지, 포트 정리가 어떻게 일어나는지 lifecycle.js와 대조하며 확인하라.
브라우저 개발자도구 Network 탭에서 /api/* 요청과 SSE(/api/event)·WebSocket 연결을 찾아, "UI → OpenChamber 서버 → OpenCode"로 어떻게 흘러가는지 그려보라. directory= 쿼리·x-opencode-directory 헤더가 어디 붙는지도 확인.
opencode serve를 직접 띄운 뒤 OPENCODE_SKIP_START=true + OPENCODE_HOST/PORT로 OpenChamber를 그 서버에 attach해보라. "managed(직접 spawn) vs external(붙기)" 두 모드의 차이(특히 도구 주입 유무)를 lifecycle.js에서 찾아 정리하라.
packages/ui/src/lib/opencode/client.ts(OpencodeService)와 RuntimeAPIs 간접 계층, 그리고 packages/electron/preload.mjs의 window.__OPENCHAMBER_DESKTOP__ 노출을 함께 읽어라. "같은 UI가 웹·데스크탑에서 어떻게 다른 백엔드를 부르는지"를 한 문단으로 요약하면 심화.
| 주차 | 주제 · 목표 |
|---|---|
| 1주차 Node 시스템 | child_process(spawn/exec)·프로세스 신호·포트 관리. lifecycle.js·env-runtime.js를 읽고 "외부 CLI 감독"을 직접 작은 예제로 재현 |
| 2주차 프록시 & 실시간 | Express 5·http-proxy-middleware·SSE·WebSocket(ws). proxy.js·realtime-proxy.js를 분석하고 미니 리버스 프록시 만들기 |
| 3주차 멀티플랫폼 셸 | Electron(메인/프리로드/IPC)·Capacitor·VS Code 웹뷰. "같은 웹앱을 데스크탑/모바일/확장으로 감싸는" 방법과 런타임 추상화 이해 |
| 4주차 보안 원격 접속 | Cloudflare 터널·E2E 릴레이·WebAuthn 패스키·JWT(jose)·web-push. "셀프호스트 서비스를 안전하게 외부 노출"하는 전체 그림 정리 |
/api/*를 OpenCode로 프록시하면서 인증·경로 정규화 같은 부가 처리를 얹는다.RuntimeAPIs) 뒤로 숨겨 UI 본체는 그대로 두는 설계.