고영민mandu05.com

둘러보기

  • 홈
  • 글
  • 프로젝트
  • 지식 그래프
  • 이력서
본문으로 건너뛰기
  1. 고영민
  2. /
  3. 글
고영민/글
© 2023-2026 Youngmin. All rights reserved.
rhdudals0505@naver.comGitHubLinkedIn
이 사이트는 Next.js로 만들었습니다.갱신 2026.09.26
글/프로젝트 · 해커톤 · 대회 · 사이드 프로젝트

[사이드 프로젝트] 에이전트의 2시간을 35초 영상으로 — sessionreel을 만들며 배운 것

2026-09-19·5분 읽기
Claude CodeOpen SourcePythonSide ProjectDeveloper Tools
← 이전 글 한화오션 2026 상반기 AX·AI개발(DT) 추가합격 회고 다음 글 →[사이드 프로젝트] 'Jev 호환'이라는 말에 스펙이 없어서 — jevcompat을 만들며 배운 것

댓글 불러오는 중…

← 글

목차

  • 어떻게 동작하나
  • 어려웠던 것 1: 영상이 거짓말을 하지 않게 하기
  • 어려웠던 것 2: 비밀값이 한 프레임도 새지 않게 하기
  • 기타 디테일
  • 마치며

에이전트에게 버그를 맡기면 두 시간 뒤에 결과가 나온다. 테스트는 통과했고 커밋도 올라갔다. 그런데 팀원이나 매니저에게 "이렇게 고쳤다"를 보여주려고 하면 막힌다. 보여줄 수 있는 게 30 MB짜리 세션 로그뿐이기 때문이다.

이미 세션을 보여주는 도구는 여럿 있다. claude-replay, mindwalk, claude-code-log, zoetrope 같은 것들이다. 전부 뷰어다. 보는 사람이 링크를 열고, 스크롤하고, 뒤져야 한다. 아무도 그렇게까지 하지 않는다.

그래서 반대로 만들었다. 사람이 찾아오게 하는 대신, 보내는 물건을 만든다. sessionreel은 세션 로그를 읽어서 30~60초짜리 mp4를 만든다.

text
1uvx sessionreel
sessionreel demo
  • GitHub: https://github.com/mandu5/sessionreel
  • PyPI: pip install sessionreel / uvx sessionreel
  • Claude Code 플러그인: /plugin marketplace add mandu5/sessionreel → /reel

어떻게 동작하나

Claude Code는 모든 세션을 ~/.claude/projects/<프로젝트>/<세션 id>.jsonl에 기록한다. 프롬프트, 에이전트의 말, 모든 도구 호출과 그 결과, 그리고 Edit 도구가 남기는 diff hunk까지 들어 있다. 영상에 필요한 재료가 이미 다 있다는 뜻이다.

파이프라인은 네 단계다.

  1. ingest — JSONL을 프롬프트/발화/도구 호출 다섯 종류의 이벤트로 정규화한다. 로그 형식은 문서화돼 있지 않고 버전마다 바뀌어서, 모르는 필드는 무시하고 깨진 줄은 세서 건너뛴다.
  2. redact — 비밀값을 지운다. (아래에서 자세히)
  3. story — 로그에서 이야기를 찾는다. 뼈대는 실패 → 수정 → 통과다. 같은 검사 명령이 실패했다가, 그 사이에 파일이 바뀌고, 다시 통과한 구간을 찾는다.
  4. render — Pillow로 프레임을 한 장씩 그리고, raw RGB를 ffmpeg에 파이프로 넘겨 H.264로 인코딩한다. 브라우저도 Node도 없다. 35초 영상이 M1 Pro에서 약 30초에 렌더된다.

어려웠던 것 1: 영상이 거짓말을 하지 않게 하기

"LLM한테 로그 주고 요약 영상 만들어달라고 하면 되지 않나?" 처음엔 나도 그렇게 생각했다. 하지만 사람들이 X에 올릴 영상이라면, 한 장면이라도 사실과 다르면 끝이다. 그래서 스토리 엔진은 결정적으로(deterministic) 만들고, 자막은 전부 로그의 숫자로만 만든다.

그런데 결정적이라고 정직한 건 아니었다. 독립 리뷰어 에이전트를 붙여서 실제 세션 29개에 돌려보니, 이런 것들이 나왔다.

  • 다른 명령끼리 짝지어진 실패→통과. ruff check A.py의 실패와 ruff format B.py의 성공이 한 쌍으로 묶여 "고쳤다"가 됐다. 전체 테스트 5개 실패 뒤에 -k empty로 좁혀서 1개 통과한 걸 "5 failed → 1 passed"라고 보여주기도 했다. → 같은 검사, 같은 선택자(경로, -k, -m)일 때만 짝을 짓고, 통과한 쪽이 범위를 좁혔다면 짝으로 인정하지 않는다.
  • 결론이 없는 걸 결론으로 읽기. 백그라운드로 보낸 테스트("Command running in background")가 "통과"로, 사용자가 거절한 도구 호출이 "실패"로 잡혔다. → "실패가 안 보임"과 "통과함"은 다르다. 통과 신호(N passed, All checks passed 등)가 있을 때만 통과로 본다.
  • 가짜 "Shipped". heredoc 안의 파이썬 스크립트에 git commit이라는 문자열이 있거나, grep "git push"를 실행해도 "배포"가 떴다. git push --dry-run도 배포가 됐다. → 셸 명령을 세그먼트로 쪼개고, heredoc 본문은 데이터로 취급해 버리고, 세그먼트의 시작에서만 판정한다. 로컬 커밋만 했다면 "Shipped"가 아니라 "Committed"라고 쓴다.
  • "수정"이라는 과장. 실패와 통과 사이에 바뀐 파일이 전부 "수정"은 아니다. 문서 파일이 "Fix in SUBMISSION.md"로 나오는 걸 보고 규칙을 바꿨다. → 실패 출력이 파일 이름을 가리킬 때만 "Fix in"이라고 쓰고, 나머지는 "Changed"로 쓴다.

이 문제들은 합성 테스트 데이터로는 한 번도 안 보였고, 실제 로그에서만 드러났다. 합성 데이터로 짠 테스트가 다 초록불이어도, 진짜 입력을 돌려보기 전까지는 믿으면 안 된다는 걸 다시 배웠다.

어려웠던 것 2: 비밀값이 한 프레임도 새지 않게 하기

세션 로그에는 온갖 게 다 들어 있다. .env를 읽은 기록, 커밋 메시지 속 이메일, 터미널에 찍힌 토큰. 가리기(redaction)는 스토리보드가 만들어지기 전, 파싱된 세션 전체에 적용된다. 이후 단계는 원문을 아예 보지 못한다.

그래도 리뷰에서 구멍이 나왔다.

  • diff는 한 줄씩 가렸기 때문에, 여러 줄에 걸친 개인 키는 첫 줄만 지워지고 본문이 그대로 남았다. → hunk 전체를 한 문자열로 가린 뒤 다시 나눈다.
  • 홈 경로(/Users/이름)만 지우고 있었는데, Claude Code의 프로젝트 폴더명(-Users-이름-...), 대소문자가 다른 경로, 이름@맥북이름 ~ % 같은 셸 프롬프트로 사용자명과 호스트명이 그대로 남았다. 호스트명에 다른 사람 이름이 들어 있는 경우도 있었다.
  • {"api_key": "..."}처럼 따옴표가 붙은 JSON 키, mysql -p비번, curl -u 아이디:비번 같은 형태는 패턴에서 빠져 있었다.
  • 사람이나 에이전트가 스토리보드 JSON을 수정한 뒤 렌더하면, 그 사이에 들어간 문자열은 검사하지 않았다. → 렌더 직전에 모든 문자열을 한 번 더 가리고, 자막에 들어간 숫자가 그 장면 데이터에 없으면 경고한다.

반대 방향의 실수도 있었다. auth를 비밀 단어로 잡았더니 author: 이름에서 이름이 지워졌고, Co-Authored-By:가 망가졌다. 과하게 지우면 영상을 못 읽게 되고, 덜 지우면 키가 X에 올라간다. 결국 실제 세션 29개를 전부 돌려서, 화면에 남는 비밀이 0건이 되고 과잉 삭제로 확인된 사례(긴 파일명, LaTeX의 \if@…, 에이전트 id의 @)를 규칙에서 빼낼 때까지 다듬었다. 그래도 패턴 기반이라 완벽할 수는 없다. README에도 적었듯이, 올리기 전에 한 번은 꼭 봐야 한다.

재밌는 후일담도 하나 있다. 저장소를 공개하자마자 GitGuardian에서 "비밀값 8개 감지" 메일이 왔다. 가리기 테스트에 넣어둔 가짜 키들(abcdefgh…, AWS 공식 예제 키)이었다. 비밀값 탐지 도구를 테스트하려면 비밀값처럼 생긴 문자열이 필요하고, 그건 다른 탐지 도구 눈에도 비밀값이다. 지금은 테스트 문자열을 실행 시점에 조립하도록 바꿨다.

기타 디테일

  • 여러 작업이 섞인 긴 세션에서는 한 에피소드만 보여준다. 수정으로 이어진 요청부터 다음 요청 전까지다. 안 그러면 버그 수정 영상이 전혀 다른 작업의 요약으로 끝난다.
  • 작업 시간은 15분 넘게 비는 구간을 뺀 활성 시간이다. 한 세션을 며칠에 걸쳐 이어 쓰면 "1535시간"이 찍히는 걸 보고 바꿨다.
  • 한글은 Pretendard, 이모지는 Noto Emoji로 글자 단위 폴백을 한다. 한국어 프롬프트도 그대로 나오고, --lang ko로 자막도 한국어로 바꿀 수 있다.
  • 세로 영상(--format tall)과 OS 음성 내레이션(--voice, macOS say)도 된다. 클라우드 TTS는 쓰지 않는다.
  • Claude Code 플러그인으로 쓰면, 작업을 한 에이전트가 자기 맥락으로 자막을 다듬는다. 다만 장면 데이터에 없는 숫자를 쓰면 렌더러가 경고한다.

마치며

이 프로젝트를 하면서 가장 크게 남은 건 기술보다 태도였다. 도구가 사용자를 대신해 무언가를 말하는 순간, 그 말은 증거가 뒷받침하는 만큼만 해야 한다. 테스트 통과 수, "고쳤다"는 표현, "배포했다"는 표현 모두 그렇다.

146개의 테스트와 macOS·Ubuntu × Python 3.10·3.13 CI가 돌고 있고, 다음 버전에서는 Codex 세션 로그도 지원할 계획이다. 써보고 이상한 장면이 나오면 이슈로 알려주면 좋겠다.

  • GitHub: https://github.com/mandu5/sessionreel