터미널 안에만 살던 대화 기록을 웹으로 꺼냈다. 어느 기기에서든 지난 세션을 검색해 다시 잇고, 폰에서 새 세션을 원격으로 켠다. 집에 켜 둔 컴퓨터 한 대면 된다.
데이터는 왼쪽에서 오른쪽으로만 흐른다.
Claude Code가 대화 한 턴 한 턴을 기록 파일(JSONL)로 자동 저장. 모든 것의 출발점.
순찰 스크립트가 새로 바뀐 기록만 골라 사람이 읽는 웹페이지로 변환.
작은 파이썬 웹 서버가 변환된 페이지를 내보냄. 죽으면 OS가 자동으로 되살림.
사설망(Tailscale)으로 내 모든 기기에서 같은 주소로 접속. 주력은 폰.
이 시스템의 데이터 규칙은 이 한 줄이 전부다.
Claude Code가 스스로 남기는 표준 기록(~/.claude/projects/ 아래, 세션당 한 파일).
나는 이 파일을 직접 만들지도, 고치지도 않는다. 백업 대상도 이것뿐이다.
세션별 대화 페이지, 목록, 검색 화면, 분리 저장된 첨부 이미지. 전부 원본에서 기계적으로 다시 만들 수 있는 파생물이라, 통째로 지워도 1분 뒤 되살아난다.
· 목록 페이지가 마음에 안 들어도 그 파일을 손으로 고치지 않는다. 어차피 1분 뒤 재생성되며 수정이 사라진다. 바꾸려면 변환기의 템플릿(코드)을 고친다.
· 백업은 원본만 챙긴다. 사본까지 백업하면 용량만 몇 배가 되는데, 어차피 다시 만들 수 있는 것들이다.
· 사고가 나면 원본이 멀쩡한지부터 본다. 멀쩡하면 나머지는 전부 복구 가능한 문제다.
cron(정해진 주기마다 명령을 자동 실행하는 OS 기본 기능)이 1분에 한 번 변환기를 깨운다. 깨어난 변환기가 하는 일은 세 가지다.
매번 전체를 다시 만들지 않는다. 이미 변환된 세션은 건너뛰고 새로 바뀐 기록만 처리하기 때문에 1분 주기를 버틴다.
첨부 사진을 페이지 안에 박지 않고 별도 폴더로 빼서 링크한다. 사진 많은 세션 하나가 4.4MB → 0.4MB로 가벼워졌다.
답변 생성 중에 내가 보낸 입력(대기열 메시지)은 기록에서 누락되기 쉽다. 변환 단계에서 따로 찾아내 페이지에 살려 둔다.
처음엔 턴이 끝나는 이벤트(hook)에 변환을 걸었다. 그런데 "끝났다"는 신호가 "기록이 디스크에 다 써졌다"는 보장은 아니었다. 변환기가 반쪽짜리 기록을 읽는 일이 실제로 났다. 이벤트에서 떼어내 1분 주기 순찰로 바꾸자 사라졌다. 즉시성을 1분 내주고 정합성을 산 거래였다.
변환된 페이지를 내보내는 건 상시 켜 둔 데스크탑에서 24시간 떠 있는 한 파일짜리 파이썬 웹 서버다. 꺼지면 OS의 서비스 관리자가 알아서 되살린다(KeepAlive).
서버는 한 대뿐이고, 다른 기기는 Tailscale(내 기기들끼리만 직접 연결되는 개인 VPN)이 부여한 사설 IP로 직접 붙는다. 프록시도, 공개 인터넷 배포도 없다.
접속 주소가 사설망 안에만 존재해 공개 인터넷에서는 닿지 않고, 구간 암호화는 Tailscale(WireGuard)이 이미 해 준다. 그래서 인증서·도메인·로그인 관리를 통째로 생략하고 평문 HTTP로 두었다. 개인 도구에서 이만한 유지비 절감이 드물다. 대신 실제 IP나 포트 같은 배포 좌표는 이 문서에 적지 않는다.
보기만 하는 건 아니다. 화면 아래 입력칸에 글이나 이미지를 넣으면 집의 데스크탑에서 새 Claude Code 세션이 켜진다. 밖에서 제일 많이 쓰는 기능이다.
매일 들여다보지 않아도 되도록 감시, 백업, 배포에 안전장치를 하나씩 달았다.
변환 순찰이 돌 때마다 외부 하트비트 서비스(healthchecks.io)에 신호를 보낸다. 신호가 끊기면 바깥에서 알림이 온다. 죽은 시스템은 자기 부고를 못 보내니까. 저장 폴더가 지나치게 커져도 경고가 온다.
원본 기록 전체를 압축해 클라우드 드라이브에 저장하고, 최근 몇 주 치만 남기고 자동 회전한다. 사본(페이지·이미지)은 뺐다. 2절의 규칙대로 언제든 다시 만들 수 있어서다.
변환기 코드를 고치면 전체 재생성을 한 번 돌리고, 서버 프로세스를 확실히 종료한 뒤 재시작한다. 재시작했다고 믿었는데 옛 프로세스가 계속 살아 있던 함정을 한 번 밟았다.
브라우저로 보는 대시보드를 그대로 본뜬 정지 화면이다. 세션 제목과 시간, 숫자는 전부 가상이고 버튼은 눌리지 않는다.
| 대화 | ID | 조작 | 마지막 대화 ▼ | 시작 | 종료 | 지속 | 메시지 |
|---|---|---|---|---|---|---|---|
| 세션 시작 중… | ······· | 방금 | — | — | — | — | |
| 신규 가입 폼 유효성 검사 버그 수정 | a3f1c0d9 | 방금 | 2026-06-09 14:24 | 2026-06-09 14:32 | 8분 | 23 | |
| 주간 매출 리포트 자동 집계 스크립트 작성 | 7b29e8a4 | 12분 전 | 2026-06-09 14:05 | 2026-06-09 14:21 | 16분 | 88 | |
| 고객 문의 자동 분류 프롬프트 튜닝 | c5d70f12 | 1시간 전 | 2026-06-09 13:02 | 2026-06-09 13:40 | 38분 | 142 | |
| 이미지 업로드 용량 제한 버그 추적 | e1846b3a | 어제 | 2026-06-08 21:10 | 2026-06-08 22:14 | 1시간 4분 | 64 | |
| 위키 전체 검색 기능 추가 | 90ab2fd7 | 2일 전 | 2026-06-07 10:48 | 2026-06-07 12:03 | 1시간 15분 | 117 | |
| 배포 파이프라인 캐시 정리 + 회의록 요약 템플릿 | 2f6c9e05 | 3일 전 | 2026-06-06 09:15 | 2026-06-06 09:46 | 31분 | 9 |
다른 시스템에 옮겨 심는다면 스크립트가 아니라 이쪽이다.
손으로 고치는 건 원본과 그걸 만드는 코드뿐. 파생물을 지워도 되는 것으로 유지하면 백업과 복구, 실험이 전부 싸진다. 백업 대상도 원본 하나로 줄어든다.
쓰기 완료를 보장하지 않는 이벤트에 후속 처리를 걸면 경합이 난다. 짧은 주기 순찰(폴링)이 더 단순하고 안전했다. 즉시성을 조금 내주는 대신.
자기 상태를 자기에게 보고시키면 죽는 순간 보고도 같이 죽는다. 신호가 멈추면 알림이 오도록 방향을 뒤집어 외부에서 지켜보게 했다.
공개 배포 없이 내 모든 기기에서 접속이 된다. 인증·도메인·인증서 관리가 통째로 사라지고, 외부에 노출되는 면적은 0이다.
모바일은 긴 대기를 못 견딘다. 요청에는 즉시 "접수됨"을 돌려주고 실행은 뒤에서 한다. 재전송으로 생기는 중복 요청도 서버 쪽에서 걸러 줘야 한다.
github.com/sidoyu/claude-session-dashboard에 있다.