TRENDSHIFT #10 딥다이브 · 2026-06-02

hermes-webui 딥다이브
— 빌드 도구 0개로 만든 "내 서버 위 AI 에이전트" 웹 UI

요즘 웹앱은 React·번들러·수백 개 의존성으로 시작합니다. 이 레포는 정반대예요. 프레임워크도, 번들러도, 빌드 단계도 없이 파이썬 표준 라이브러리(http.server)와 순수 바닐라 JS만으로, 내 서버에서 돌아가는 AI 에이전트 Hermes Agent를 브라우저·폰에서 조종하는 다크 테마 웹 UI를 만듭니다. CLI로 할 수 있는 거의 모든 것을 웹에서 그대로, SSH 터널이나 Tailscale로 안전하게. (저장소: nesquena/hermes-webui · Python + Vanilla JS · ★8.4k · TrendShift 10위 · MIT 라이선스)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

이 레포가 무엇을 하는 물건인가.

핵심 메시지

"이미 설치된 AI 에이전트(Hermes)에
브라우저라는 얼굴을 씌우는 얇은 껍데기.
두뇌는 에이전트, 이건 리모컨이다."

hermes-webui는 AI 모델이나 메모리·도구를 직접 갖고 있지 않습니다. 진짜 두뇌는 따로 설치하는 Hermes Agent(Nous Research)이고, 이 레포는 그 에이전트의 파이썬 모듈을 그대로 불러다(import) 화면에 띄우고 조종하는 웹 리모컨입니다. 그래서 의존성이 단 2개(pyyaml, cryptography)뿐이에요.

조금 더 풀어볼게요. Hermes Agent는 "내 서버에 상주하면서, 배운 것을 기억하고, 오래 켜둘수록 똑똑해지는" 자율 에이전트입니다. 원래는 터미널(CLI)이나 메신저로 쓰죠. 그런데 터미널은 폰에서 쓰기 불편하고, 도구 호출 결과나 파일을 눈으로 보기도 어렵습니다. hermes-webui는 바로 그 CLI 경험을 왼쪽 세션 · 가운데 채팅 · 오른쪽 파일 3분할 웹 화면으로 옮겨, "터미널로 하던 거의 모든 것"을 마우스와 손가락으로 하게 해줍니다.

흥미로운 점은 만든 방식입니다. 보통 이런 채팅 UI는 React 같은 프레임워크로 짓는데, 이 레포는 파이썬 표준 라이브러리 HTTP 서버 + 순수 자바스크립트만 씁니다. 빌드도, 번들러도 없어요. 덕분에 python3 bootstrap.py 한 줄이면 뜨고, 코드를 고치면 새로고침만 하면 바로 반영됩니다.

용어
자율 에이전트 (autonomous agent)
사람이 한 줄 한 줄 지시하지 않아도, 목표를 받으면 스스로 도구를 골라 쓰고(파일 읽기·쉘 실행·웹 검색 등) 여러 단계를 거쳐 일을 끝내는 AI. Hermes는 여기에 더해 기억(메모리)예약 작업(cron)을 갖춰, 껐다 켜도 맥락을 잃지 않고 사람이 자는 동안에도 일합니다.

2왜 주목받는가

트렌딩 이유 · 경쟁 도구 대비 강점 · 냉정하게 보기.

2026년 들어 "항상 켜져 있고, 내 서버에서 돌고, 기억을 가진" 자율 에이전트가 한 흐름을 이뤘습니다. Claude Code·Codex·OpenCode·OpenClaw가 대표적이죠. Hermes는 이 경쟁에서 "파이썬 생태계 + 완전 셀프호스팅 + 자동 기억"을 내세웁니다. hermes-webui는 그 에이전트에 폰에서도 쓰는 예쁜 웹 얼굴을 붙였다는 점에서 화제가 됐어요. README가 직접 정리한 비교는 이렇습니다.

능력Claude CodeCodex CLIOpenClawOpenCodeHermes
자동 영속 기억부분적부분적부분적
셀프호스팅 예약작업아니오아니오아니오
메신저 접근일부(프리뷰)아니오예(15+)아니오예(10+)
셀프호스팅 웹 UI아니오아니오대시보드만아니오
자기개선 스킬아니오아니오부분적아니오
제공자 무관(멀티 LLM)Claude 전용
오픈소스아니오예(MIT)예(MIT)예(MIT)

이 표에서 webui 입장의 진짜 매력은 마지막 줄들입니다. SSE 스트리밍(글자가 타이핑되듯 흐르는 응답), 도구 호출 카드(에이전트가 어떤 도구를 어떤 인자로 불렀는지 펼쳐 보기), 워크스페이스 파일 브라우저(에이전트가 만든 파일을 바로 미리보기·편집), 모바일 반응형(폰에서 햄버거 메뉴로 그대로) — 터미널로는 어려운 것들을 웹의 강점으로 풀어줍니다.

이 레포의 강점
급진적 단순함 — 빌드 0, 의존성 2

프레임워크·번들러·빌드 파이프라인이 없습니다. 서버는 파이썬 표준 라이브러리, 화면은 순수 JS. 무거운 ML 의존성은 전부 에이전트 쪽 venv에 있고, webui 자체는 pyyaml·cryptography 둘만 필요합니다. 읽기 쉽고, 띄우기 쉽고, 고치기 쉽습니다.

냉정하게 볼 점
README의 마케팅 ≠ 검증된 사실

README의 경쟁 비교표·"248명 기여자"·버전 v0.51 대 수천 PR 같은 서사는 저자 측 주장이라 그대로 믿기보다 코드로 확인하는 습관이 좋습니다. 다만 코드베이스 자체는 실재하고 규모가 큽니다 — ~700개 파일·~7,150개 테스트(작성 시점 2026-06-02 기준 488파일·5,303개, 이후 급성장), 명확한 모듈 분리, 보안 헤더·세션 복구 로직까지. 이 글은 "검증 가능한 아키텍처"에 초점을 둡니다.

3기술 스택 전체 지도

백엔드 · 프론트엔드 · 인프라를 떠받치는 도구들 한눈에.

이 프로젝트의 스택은 한마디로 "있을 건 다 있는데, 무거운 건 하나도 없다"입니다. 진짜 무게(LLM·머신러닝 라이브러리)는 옆집(Hermes Agent venv)에 다 떠넘기고, webui는 표준 라이브러리만으로 살림을 차렸어요. 레이어별로 봅시다.

백엔드 (Python)

레이어기술 / 도구역할
HTTP 서버파이썬 표준 http.server (ThreadingHTTPServer + BaseHTTPRequestHandler)웹 프레임워크 없이 요청을 받고 응답. 스레드당 연결 처리.
실시간 전송SSE (Server-Sent Events)LLM 토큰을 생성되는 즉시 한 글자씩 브라우저로 흘려보냄.
네트워크 튜닝HTTP/1.1 keep-alive · TCP_NODELAY · SO_KEEPALIVESSH 터널 같은 고지연 회선에서 지연·끊김 최소화.
인증cryptography — HMAC 서명 쿠키선택형 비밀번호. 위변조 불가능한 서명 쿠키(24h)로 로그인 유지.
설정/직렬화pyyaml · JSON · SQLite (state.db)config.yaml 읽기, 세션을 JSON 파일로 저장, 인덱스/통계는 SQLite.
에이전트 연동sys.path 주입 + Hermes 모듈 import별도 설치된 에이전트의 파이썬 코드를 직접 불러 같은 프로세스에서 실행.
외부 인터페이스MCP 서버 (mcp_server.py, mcp SDK, stdio)세션·프로젝트 관리를 다른 AI 에이전트가 쓸 수 있는 도구로 노출.
용어
SSE (Server-Sent Events, 서버 전송 이벤트)
서버가 브라우저에게 한 방향으로 계속 데이터를 밀어 보내는 웹 표준. 채팅 응답이 "타닥타닥" 타이핑되듯 나오는 게 이것입니다. WebSocket보다 단순하고(평범한 HTTP 연결 하나), 끊기면 브라우저가 알아서 다시 잇습니다. 라디오 방송처럼 서버가 계속 송출하고 브라우저는 듣기만 하는 구조예요.

프론트엔드 (바닐라 JS)

레이어기술 / 도구역할
UI 로직순수 JavaScript (모듈 9개, 합계 5만 줄+)React/Vue 없이 DOM을 직접 조작. ui.js(~13,500줄)·panels.js(~9,000줄) 등.
스트리밍 수신EventSource + fetch서버 SSE를 받아 토큰을 화면에 실시간 렌더(rAF로 부드럽게).
코드 하이라이트Prism.js (CDN)응답 속 코드 블록을 언어별로 색칠.
다이어그램Mermaid (CDN)플로우차트·시퀀스·간트를 채팅 안에서 그림으로 렌더.
음성 입력Web Speech API마이크 버튼 → 실시간 받아쓰기 → 작성칸에 추가.
보안SRI(무결성 해시) · CSPCDN 리소스를 해시로 고정, 콘텐츠 보안 정책으로 XSS 방어.
비유

"빌드 단계가 없다"는 게 왜 특별할까요? 보통 현대 웹앱은 요리 전에 밀키트 공장(번들러)을 돌려 수백 개 재료를 한 봉지로 압축·가공해야 손님상에 냅니다. 이 레포는 그 공정을 통째로 없앴어요. .js 파일을 <script>로 그냥 불러 쓰니, 파일 고치고 새로고침 = 끝. 대신 타입스크립트·트리셰이킹 같은 현대 편의는 포기합니다. 단순함과 편의의 맞교환이죠.

인프라 / 배포

레이어기술 / 도구역할
컨테이너Docker (python:3.12-slim) + uv경량 이미지에 uv로 빠른 의존성 설치. 비루트 사용자로 실행.
이미지 배포GHCR (amd64 + arm64 멀티아치)릴리스마다 사전 빌드 이미지 자동 게시.
오케스트레이션compose 3종 (단일/2-컨테이너/3-컨테이너)"webui+agent 한 통" ~ "agent·dashboard·webui 분리"까지 선택.
원격/모바일 접근SSH 터널 · Tailscale(WireGuard 메시 VPN)포트 개방 없이 폰·노트북에서 안전하게 접속.
운영ctl.sh(데몬 lifecycle) · /health 헬스체크start/stop/status/logs, 30초 간격 컨테이너 헬스체크.
테스트pytest (~7,150개 / ~700파일) + 네트워크 격리테스트는 외부 통신을 막아(hermetic) 빠르고 재현 가능하게.

4아키텍처 심화 분석

브라우저에서 친 한 마디가 LLM 응답으로 돌아오기까지.

먼저 숲(전체 그림)입니다. 핵심은 "server.py는 교통정리만, 진짜 일은 api/ 모듈이, 진짜 두뇌는 에이전트가"라는 3단 구조예요. 브라우저 ↔ 얇은 HTTP 껍데기 ↔ 두꺼운 api 로직 ↔ 같은 프로세스에 import된 Hermes 에이전트 ↔ LLM 제공자.

[ 브라우저: 바닐라 JS ] index.html + ui.js / messages.js / panels.js ... │ ▲ POST │ │ SSE 토큰 스트림 (EventSource) /api/ │ │ "타닥타닥" 응답 ▼ │ ┌─────────────────────────────────────────────┐ │ server.py — 얇은 라우팅 껍데기 (~684줄) │ │ ThreadingHTTPServer + Handler │ │ · do_GET/do_POST → check_auth() → 위임 │ │ · CSP 헤더, 프로파일 쿠키 컨텍스트 │ └───────────────┬─────────────────────────────┘ ▼ handle_get / handle_post (api/routes.py ~9.8k줄) ┌─────────────────────────────────────────────┐ │ api/ — 두꺼운 비즈니스 로직 (모듈 50개+) │ │ streaming.py run_agent + SSE 엔진 │ │ models.py 세션 CRUD + CLI 브리지 │ │ profiles.py 프로파일 전환·게이트웨이 │ │ workspace.py 파일 작업 + git 감지 │ │ auth.py config.py onboarding.py ... │ └───────────────┬─────────────────────────────┘ ▼ import (sys.path 주입) ┌─────────────────────────────────────────────┐ │ Hermes Agent (별도 설치) — 진짜 두뇌 │ │ 메모리 · 스킬 · cron · 도구 실행 · 모델 │ └───────────────┬─────────────────────────────┘ ▼ LLM 제공자 (OpenAI / Anthropic / DeepSeek ...) 상태 저장: ~/.hermes/webui/ (세션 JSON · settings · state.db)

이제 나무(흐름 한 줄기)를 따라가 봅시다. 사용자가 메시지를 보내 응답이 흐르기까지의 해피 패스입니다.

① 요청 진입 + 인증 — 모든 요청은 server.pyHandler로 들어옵니다. 쓰기 요청(POST/PUT/PATCH/DELETE)은 공통 래퍼 _handle_write를 거쳐 쿠키에서 프로파일을 꺼내고, 인증을 확인한 뒤 api/routes.py로 위임합니다. server.py 자체엔 비즈니스 로직이 거의 없어요.

def do_POST(self): self._handle_write(handle_post)

def _handle_write(self, route_func):
    cookie_profile = get_profile_cookie(self)
    if cookie_profile: set_request_profile(cookie_profile)  # 요청별 프로파일
    try:
        parsed = urlparse(self.path)
        if not check_auth(self, parsed): return        # 인증 미들웨어
        result = route_func(self, parsed)              # api/routes.py로 위임
        if result is False: return j(self, {'error':'not found'}, status=404)
    finally:
        clear_request_profile()

② 에이전트 실행 + 스트리밍 — 채팅이면 api/streaming.pyrun_agent가 import된 Hermes 에이전트를 돌립니다. 에이전트가 토큰·도구호출·추론을 내놓을 때마다 SSE 이벤트로 즉시 브라우저에 밀어 보내요. 사용자가 Stop을 누르면 취소 신호가 전달됩니다.

③ 브라우저 렌더 — 프론트의 messages.jsEventSource로 토큰을 받아, 화면을 requestAnimationFrame 주기로 부드럽게 갱신합니다. 도구 호출은 접고 펼치는 카드로, 코드는 Prism으로, 다이어그램은 Mermaid로 그려집니다.

기억해둘 핵심 설계 패턴 6가지

패턴 1 · 얇은 껍데기 + 두꺼운 코어

server.py는 라우팅·인증·헤더만 담당하고, 실제 로직은 전부 api/*.py로 분리. "진입점은 가볍게, 갈아끼우기 쉽게"라는 전형적인 관심사 분리.

패턴 2 · 에이전트를 "임포트"해서 조종

별도 REST API로 통신하지 않고, 에이전트 디렉터리를 sys.path에 넣어 그 파이썬 코드를 직접 import해 같은 프로세스에서 실행. 장점은 단순함, 단점은 구현 결합(README도 "안정적 API 경계가 아니다"라고 명시).

패턴 3 · SSE 스트리밍 엔진

토큰을 모았다 한 번에 주지 않고 생성 즉시 송출. SSH 터널이 깜빡여도 자동 재연결로 버팁니다. streaming.py가 4천 줄에 달하는 이유 — 취소·재연결·중복 방지 등 경계 케이스가 많아서.

패턴 4 · 요청별 프로파일 컨텍스트

쿠키에서 프로파일을 읽어 set_request_profile로 설정하고 finally에서 항상 clear. 한 서버가 여러 에이전트 설정(프로파일)을 깔끔히 분리해 다룹니다.

패턴 5 · 크래시 안전 세션 복구

서버 시작 시 이전 프로세스가 남긴 손상 세션을 .bak에서 자동 복원하고, 추가-전용 "turn journal"로 응답 도중 죽어도 대화를 잃지 않게 설계. 셀프호스팅 신뢰성의 핵심.

패턴 6 · 기본은 안전, 노출은 명시적

기본 바인딩은 127.0.0.1(외부 차단). 0.0.0.0으로 열면서 비밀번호가 없으면 시작 시 경고를 출력. CSP·보안 헤더·HMAC 쿠키·요청 본문 20MB 제한이 기본 장착.

5디렉토리 구조 해부

어느 파일이 무슨 일을 하는가.

hermes-webui/ ├── server.py 진입점 · 얇은 라우팅 껍데기 + 인증 미들웨어 (~684줄) ├── bootstrap.py 에이전트 탐지·설치·서버 기동·온보딩 (한 방 실행) ├── start.sh / ctl.sh 쉘 런처 / 데몬 lifecycle(start·stop·status·logs) ├── start.ps1 (실험적) Windows PowerShell 런처 ├── mcp_server.py 세션·프로젝트 관리를 MCP 도구로 노출 (stdio) ├── requirements.txt 의존성 단 2개: pyyaml, cryptography ├── api/ ★ 비즈니스 로직 전부 여기 (모듈 50개+, 주요 12개만 아래 나열) │ ├── routes.py 모든 GET/POST 핸들러 (~9.8k줄) — 가장 큰 파일 │ ├── streaming.py SSE 엔진 · run_agent · 취소 지원 (~4.4k줄) │ ├── config.py 탐지·전역설정·모델감지·리로드 (~4.1k줄) │ ├── models.py 세션 모델 + CRUD + CLI 세션 브리지 (~1.9k줄) │ ├── profiles.py 프로파일 상태 · hermes CLI 래퍼 (~1.1k줄) │ ├── onboarding.py 첫 실행 마법사 · OAuth 제공자 (~1.0k줄) │ ├── workspace.py 파일 작업 · 워크스페이스 · git 감지 (~810줄) │ ├── auth.py 선택형 비밀번호 · 서명 쿠키 (~366줄) │ ├── helpers.py HTTP 헬퍼 · 보안 헤더 (~302줄) │ ├── upload.py 멀티파트 파서 · 파일 업로드 (~284줄) │ ├── updates.py 자체 업데이트 확인 · 릴리스 노트 (~545줄) │ └── state_sync.py /insights 동기화 (~118줄) ├── static/ ★ 프론트엔드 (빌드 없음) │ ├── index.html HTML 템플릿 (~1.3k줄) │ ├── style.css 전체 CSS · 모바일 반응형 · 테마 (~3.8k줄) │ ├── ui.js DOM 헬퍼 · 마크다운 · 도구카드 (~13,500줄) │ ├── panels.js cron · 스킬 · 메모리 · 프로파일 · 설정 (~9,000줄) │ ├── sessions.js 세션 CRUD · 검색 · 복구 (~3.5k줄) │ ├── messages.js send() · SSE 핸들러 · 라이브 스트리밍 (~2.3k줄) │ ├── commands.js 슬래시 명령 자동완성 (~1.3k줄) │ ├── boot.js 모바일 내비 · 음성입력 · 부팅 IIFE (~1.6k줄) │ └── workspace.js 파일 미리보기 · git 배지 (~369줄) ├── tests/ pytest — ~700파일 · ~7,150테스트 (네트워크 격리) ├── docs/ docker·onboarding·troubleshooting·rfcs ... ├── Dockerfile python:3.12-slim + uv, 비루트 실행, /health ├── docker-compose.yml 단일 컨테이너 (agent in-process) ├── docker-compose.two-container.yml / .three-container.yml └── ARCHITECTURE.md / ROADMAP.md / TESTING.md / THEMES.md / CHANGELOG.md

구조의 메시지는 분명합니다. 화면(static)과 로직(api)이 깔끔히 분리되고, 진입점(server.py)은 얇습니다. 큰 파일 순서(routes 9.8k → ui.js 7.2k → panels.js 6.5k → streaming 4.4k → config 4.1k)만 봐도 "라우팅·UI·실시간 스트리밍"이 이 앱의 무게 중심임을 읽을 수 있어요. 상태는 레포 밖 ~/.hermes/webui/에 두어, 코드를 업데이트해도 내 세션·설정이 날아가지 않습니다.

6학습 포인트 (기술별)

이 레포에서 실제로 뽑아 배울 것 + 곧바로 해볼 실습 아이디어.

① 프레임워크 없이 만드는 HTTP 서버

가장 큰 배움입니다. 다들 Flask·FastAPI부터 배우지만, 그 밑에 깔린 표준 라이브러리 http.server를 직접 다뤄보면 "프레임워크가 대신 해주던 일"이 보입니다. 이 레포는 ThreadingHTTPServer로 연결마다 스레드를 띄우고, BaseHTTPRequestHandler를 상속해 do_GET/do_POST를 직접 구현하며, HTTP/1.1 keep-alive와 TCP_NODELAY·SO_KEEPALIVE 소켓 옵션까지 손으로 켭니다.

용어
keep-alive · TCP_NODELAY
keep-alive는 한 번 연 TCP 연결을 여러 요청에 재사용해 매번 악수(handshake)하는 비용을 아끼는 것. 고지연(SSH 터널) 회선에서 큰 차이를 냅니다. TCP_NODELAY는 작은 패킷을 모았다 보내는 Nagle 알고리즘을 꺼서, 작은 응답이 즉시 나가게 합니다 — 채팅처럼 짧은 메시지가 잦을 때 체감 지연을 줄여요.
실습 아이디어

http.server만으로 "GET /health → {"ok":true}" 와 "POST /echo → 받은 JSON 그대로 반환"을 처리하는 30줄짜리 서버를 직접 작성해 보세요. 그다음 ThreadingHTTPServer로 바꿔 동시 요청을 견디게 만들어 보면 이 레포의 골격이 손에 잡힙니다.

② SSE로 LLM 토큰 스트리밍하기

ChatGPT식 "타닥타닥" 응답의 정체가 SSE입니다. 서버가 Content-Type: text/event-stream으로 응답을 열어두고 data: ...\n\n를 계속 흘려보내면, 브라우저의 EventSource가 받아 화면에 붙입니다. 끊겨도 자동 재연결이 표준 동작이라, 불안정한 터널에서도 견딥니다.

실습 아이디어

1초마다 현재 시각을 보내는 SSE 엔드포인트를 만들고, 브라우저에서 new EventSource('/clock')로 받아 화면에 찍어 보세요. 그다음 "단어 리스트를 0.2초 간격으로 하나씩" 보내 가짜 LLM 스트리밍을 흉내 내면 이 레포의 핵심 UX가 재현됩니다.

③ 빌드 없는 바닐라 JS 프론트엔드

5만 줄이 넘는 프론트를 React 없이 운영한다는 건 흥미로운 사례 연구입니다. 장점은 빌드 0·즉시 반영·디버깅 단순함, 대가는 타입 안정성·컴포넌트 재사용·상태관리의 부재입니다. ui.js가 어떻게 DOM 헬퍼와 마크다운 렌더러를 직접 굴리는지 보면 "프레임워크가 왜 등장했는지"를 거꾸로 이해하게 됩니다.

실습 아이디어

프레임워크 없이 fetch + DOM 조작만으로 미니 채팅창(입력→전송→말풍선 추가)을 만들어 보세요. 메시지가 50개를 넘어가면 어떤 점이 불편해지는지 체감하면, 상태관리 라이브러리의 필요성이 자연스레 보입니다.

④ 셀프호스팅 & 안전한 원격 접근

"내 서버에서 돌리고 폰에서 본다"를 안전하게 하는 두 정석을 배웁니다. SSH 터널(ssh -N -L로 로컬 포트를 원격 loopback에 연결)과 Tailscale(WireGuard 기반 메시 VPN으로 포트 개방 없이 같은 사설망). 기본 바인딩을 loopback으로 두고, 외부 노출 시 비밀번호를 강제하는 "안전 우선" 운영 철학도 함께 익히게 됩니다.

용어
SSH 터널 (포트 포워딩)
암호화된 SSH 연결 안으로 임의의 포트를 통과시키는 기법. ssh -N -L 8787:127.0.0.1:8787 사용자@서버를 실행하면, 내 PC의 8787 포트로 들어온 트래픽이 서버의 8787로 안전하게 전달됩니다. 서버 포트를 인터넷에 열지 않고도 나만 접근하는 비밀 통로를 만드는 셈이에요.
실습 아이디어

아무 로컬 웹서버(예: python3 -m http.server 8000)를 띄운 뒤, 다른 기기에서 SSH 터널로만 접속해 보세요. 포트를 직접 열었을 때와의 보안 차이를 비교하면 "왜 기본이 loopback인지"가 납득됩니다.

⑤ MCP 서버 만들기 + 보안 기초

mcp_server.py는 "내 앱의 기능을 다른 AI가 호출하는 도구로 노출"하는 MCP 서버의 깔끔한 예제입니다. Tool 정의 + 핸들러 매핑 + stdio 서버라는 표준 골격을 100% 보여줘요. 더불어 HMAC 서명 쿠키·CSP·입력 검증(색상 정규식, 길이 제한) 같은 실전 보안 패턴도 함께 읽을 수 있습니다.

실습 아이디어

mcp 파이썬 SDK로 "list_notes / create_note" 두 도구만 가진 MCP 서버를 만들어 보세요. 그다음 색상·길이 검증을 추가하고, HMAC으로 서명한 쿠키를 발급·검증하는 미니 로그인을 붙이면 이 레포의 보안 골격을 압축 체험할 수 있습니다.

7하드웨어 / 시스템 요구사항

webui 자체는 가볍다 — 무거운 건 에이전트와 모델 쪽.

중요한 구분: hermes-webui 자체는 거의 자원을 안 먹습니다. 표준 라이브러리 HTTP 서버일 뿐이니까요. 실제 비용·부하는 ① 옆에서 도는 Hermes Agent와 ② 그 에이전트가 호출하는 LLM(클라우드 API 또는 로컬 모델)에서 발생합니다.

항목요구/권장
운영체제Linux · macOS · WSL2 — 네이티브 Windows 부트스트랩은 미지원
런타임Python 3.12 (Docker 이미지 기준), 에이전트 venv 필요
기본 포트8787 (기본 바인딩 127.0.0.1 = loopback only)
webui 메모리/디스크매우 가벼움 — 무거운 ML 의존성은 에이전트 venv에 분리
실제 부하원Hermes Agent + LLM 추론(클라우드 API 비용 또는 로컬 GPU)
모바일 실측 사례커뮤니티 보고: ARM64 안드로이드(Redmi Note 13 Pro)에서 Debian VM(AVF) 기준 로컬 풋프린트 약 1.7GB, 클라우드 추론 사용
컨테이너Docker(amd64/arm64 사전 이미지) 또는 로컬 빌드. Podman은 4+ 권장
자주 겪는 함정
Docker bind-mount UID/GID 불일치

호스트의 ~/.hermes를 컨테이너에 마운트할 때 사용자 ID가 안 맞으면 PermissionError가 납니다. 특히 macOS는 UID가 501부터 시작(리눅스 1000)이라, echo "UID=$(id -u)" >> .env로 맞춰줘야 해요. 컨테이너가 마운트된 볼륨에서 UID/GID를 자동 감지하도록 설계돼 있지만, 비표준 환경에선 직접 지정이 필요합니다.

8직접 해볼 수 있는 실습 과제

난이도별로 손을 움직여 보는 5단계.

난이도 ★ · 입문

1. Docker로 5분 만에 띄우고 SSH 터널로 접속

레포를 클론하고 cp .env.docker.example .envdocker compose up -d. 브라우저에서 localhost:8787 확인. 그다음 다른 기기에서 ssh -N -L 8787:127.0.0.1:8787 사용자@서버로 터널을 뚫어 접속해 봅니다. 목표: 기본 바인딩이 왜 loopback인지 체감.

난이도 ★ · 입문

2. /health 엔드포인트 따라 만들기

표준 http.serverGET /health에 JSON을 응답하는 서버를 작성하고, curl http://127.0.0.1:8787/health로 확인. 이 레포의 Handler.do_GET이 어떻게 경로를 분기하는지 비교해 보세요.

난이도 ★★ · 중급

3. 표준 라이브러리만으로 미니 SSE 채팅

서버: text/event-stream으로 단어를 0.2초 간격 송출. 클라이언트: EventSource로 받아 말풍선에 이어 붙이기. 중간에 연결을 끊었다 다시 살려 자동 재연결을 확인. 목표: 이 레포 핵심 UX(스트리밍+재연결)의 미니 복제.

난이도 ★★ · 중급

4. HMAC 서명 쿠키 로그인 구현

cryptography(또는 hmac 표준 모듈)로 "비밀번호 검증 → 서명 쿠키 발급 → 이후 요청에서 서명 검증"을 만들어 보세요. 위조 쿠키를 넣어보고 거부되는지 확인. 목표: api/auth.py가 하는 일의 본질 이해.

난이도 ★★★ · 고급

5. 나만의 MCP 도구 추가 + 폰 접속

mcp_server.py 패턴을 본떠 새 Tool(예: "현재 세션 개수 세기")을 정의하고 핸들러를 연결. 그다음 Tailscale을 깔아 서버·폰을 같은 사설망에 넣고, HERMES_WEBUI_HOST=0.0.0.0 HERMES_WEBUI_PASSWORD=비밀로 띄워 폰 브라우저에서 접속해 봅니다. 목표: 확장(MCP)과 안전한 원격 접근을 동시에 경험.

9관련 기술 심화 학습 로드맵

이 레포를 제대로 소화하기 위한 4주 학습 계획.

주차주제할 것 / 참고
1주차HTTP의 바닥과 표준 라이브러리 서버Python http.server 문서 · BaseHTTPRequestHandler·ThreadingHTTPServer 실습 · 실습 1·2 · server.py 정독
2주차SSE 스트리밍 + 바닐라 JS 프론트MDN "Server-Sent Events"·EventSource · 실습 3 · messages.js / ui.js 흐름 따라가기
3주차셀프호스팅 · Docker · 네트워킹 보안SSH 포트포워딩 · Tailscale/WireGuard 개념 · Docker UID/GID · 실습 1·4 · Dockerfile·compose 비교
4주차MCP + 에이전트 통합 · 보안 마무리MCP 명세 · mcp 파이썬 SDK · HMAC/CSP · 실습 5 · mcp_server.py·auth.py 정독
학습 순서의 비유

이 로드맵은 "집을 안에서 바깥으로 넓혀 가는" 순서입니다. 1주차에 방(HTTP 서버) 한 칸을 짓고, 2주차에 그 방에 창문(스트리밍 UI)을 달고, 3주차에 안전한 현관문·담장(셀프호스팅·네트워크 보안)을 세운 뒤, 4주차에 외부 손님(다른 AI 에이전트)을 들이는 초인종(MCP)을 답니다. 순서를 지키면 각 단계가 다음 단계의 토대가 됩니다.

10핵심 키워드 사전

본문에 나온 용어 빠른 참조.

용어의미
Hermes AgentNous Research의 자율 에이전트. 서버에 상주하며 기억·예약작업·도구실행을 수행. 이 webui의 진짜 두뇌.
http.server파이썬 표준 라이브러리의 HTTP 서버 모듈. 프레임워크 없이 웹서버를 만드는 토대.
BaseHTTPRequestHandler요청을 처리하는 표준 핸들러 클래스. 상속해 do_GET/do_POST를 구현한다.
ThreadingHTTPServer연결마다 스레드를 띄워 동시 요청을 처리하는 표준 서버 클래스.
keep-alive한 TCP 연결을 여러 요청에 재사용해 핸드셰이크 비용을 아끼는 HTTP/1.1 기능.
TCP_NODELAY작은 패킷을 모으는 Nagle 알고리즘을 꺼 즉시 전송. 짧은 메시지 지연 감소.
SSEServer-Sent Events. 서버가 브라우저로 한 방향 데이터를 계속 밀어 보내는 표준. 채팅 스트리밍의 정체.
EventSource브라우저에서 SSE를 받는 자바스크립트 API. 끊기면 자동 재연결.
바닐라 JS프레임워크 없이 순수 자바스크립트만 쓰는 것. 빌드 단계가 필요 없다.
번들러여러 JS/CSS를 하나로 합치고 최적화하는 도구(webpack 등). 이 레포는 안 쓴다.
HMAC비밀키 기반 메시지 인증 코드. 쿠키를 서명해 위변조를 막는다.
CSPContent Security Policy. 허용된 출처의 스크립트/리소스만 실행시켜 XSS를 막는 브라우저 보안 정책.
SRISubresource Integrity. CDN 리소스를 해시로 고정해 변조된 파일 로드를 차단.
MCPModel Context Protocol. 앱 기능을 AI 에이전트가 호출하는 표준 도구로 노출하는 규약.
SSH 터널암호화된 SSH 연결로 포트를 전달(포워딩). 포트 개방 없이 원격 접속.
Tailscale / WireGuard제로설정 메시 VPN(WireGuard 기반). 기기들을 같은 사설망에 넣어 안전 접속.
uvRust로 만든 초고속 파이썬 패키지 설치·관리 도구. Dockerfile에서 사용.
GHCRGitHub Container Registry. 빌드된 Docker 이미지를 게시·배포하는 곳.
프로파일 (profile)에이전트 설정(모델·스킬·메모리) 묶음. 서버 재시작 없이 전환 가능.
워크스페이스 (workspace)에이전트가 파일을 읽고 쓰는 작업 폴더. webui에서 트리·미리보기로 본다.
cron (예약 작업)정해진 시각에 자동 실행되는 작업. 오프라인에도 돌아 결과를 메신저로 전달.

11참고 링크