영상을 보는 눈을 달아주는 /watch 스킬/watch 하면, yt-dlp로 영상을 내려받고 → ffmpeg로 장면 프레임을 뽑고 → 자막 또는 Whisper로 타임스탬프 대본을 만들어 Claude에게 "화면(이미지) + 대사(대본)"를 통째로 넘긴다. 그러면 Claude가 마치 영상을 본 사람처럼 "30초 지점에서 뭐가 잘못됐어?" 같은 질문에 시각·청각 근거를 들어 답한다.
놀라운 점은 이 전부가 서드파티 라이브러리 0개, 순수 파이썬 표준 라이브러리로 짜였다는 것 — LLM에게 새 감각기관을 붙이는 실전 설계의 교과서다.
(저장소: bradautomates/claude-video · 제작 Bradley Bonanno · v0.2.0 · MIT · TrendShift 이번 주 Weekly #10)
/watchclaude-video는 "LLM에게 영상을 입력으로 넣어주는" Claude Code 플러그인/Agent Skill이다. 원래 Claude 같은 모델은 이미지는 볼 수 있어도 동영상은 직접 못 본다. 이 스킬은 그 벽을 우회한다 — 영상을 "여러 장의 사진(프레임) + 시간표가 붙은 대본(transcript)"으로 변환해, Claude가 원래 잘 다루는 "이미지 읽기 + 텍스트 이해"로 문제를 바꿔치기한다.
사용법은 슬래시 명령 한 줄이다. /watch <URL 또는 파일경로> [질문] 을 입력하면, 뒤에서 파이썬 스크립트가 다운로드→프레임 추출→대본 생성을 자동으로 처리하고, 그 결과를 Claude가 받아 "영상을 실제로 본 것처럼" 대답한다. 코드는 100% 파이썬 표준 라이브러리로만 쓰여 있어 pip install이 필요 없다(대신 ffmpeg·yt-dlp 같은 시스템 도구는 있어야 한다).
Claude는 사진과 글은 잘 읽지만 동영상 파일은 못 여는 친구와 같다. 그 친구에게 영상 내용을 물어보려면? 영상을 대신 재생해서 중요한 장면을 사진으로 캡처하고, 대사를 시간과 함께 받아쓴 다음, "여기 사진 20장이랑 대본이야, 이거 보고 질문에 답해줘"라고 건네면 된다.
claude-video가 하는 일이 정확히 이것이다. 영상 자체를 AI에게 던지는 게 아니라, AI가 이미 잘 다루는 형태(이미지 + 타임스탬프 텍스트)로 번역해서 넘긴다. 그래서 "영상 이해"라는 어려운 문제가 "사진 여러 장 보기"라는 이미 풀린 문제로 바뀐다.
SKILL.md라는 설명서 + 실제로 실행할 스크립트로 구성된다. claude-video의 경우 SKILL.md가 "영상을 보려면 이 파이썬 스크립트를 이렇게 호출하라"고 Claude에게 지시하는 사용설명서 역할을 한다.[01:23] …)와 함께 받아쓴 대본이다. 이 둘이 Claude에게 넘어가는 "영상의 요약본"이 된다.2026년의 AI 코딩 에이전트는 텍스트·이미지·PDF까지 척척 다루지만, 동영상 앞에서는 여전히 장님이다. "이 버그 재현 영상 좀 봐줘", "이 강의에서 그 부분이 몇 분이야?", "이 화면 녹화에서 UI가 언제 깨져?" 같은 일상적 요청을 처리 못 한다. claude-video는 이 정확한 빈틈을, 새 모델이나 거창한 인프라 없이 기존 도구를 영리하게 엮어 메운다. (TrendShift의 굵은 숫자는 별 개수가 아니라 사회적 언급 모멘텀 점수다.)
진짜 영상 이해 모델(video LLM)을 쓰려면 무겁고 비싸고 특별한 API가 필요하다. claude-video는 "영상을 프레임+대본으로 쪼개면, 지금 있는 Claude로도 충분하다"는 통찰로 그 전부를 우회한다. 프레임은 Claude의 이미지 읽기로, 대사는 텍스트로 처리 — 이미 있는 능력의 재조합만으로 새 기능을 만들어냈다. "없는 능력을 만드는" 게 아니라 "있는 능력으로 문제를 번역"하는 접근이 개발자들에게 신선하게 받아들여졌다.
파이썬 서드파티 패키지가 단 하나도 없다. Groq/OpenAI SDK조차 안 쓰고 표준 라이브러리 urllib로 직접 API를 호출한다. 덕분에 /plugin install watch@claude-video 한 줄이면 끝이고, 감사(audit)·이식도 쉽다. "당장 오늘 내 Claude Code에 붙여볼 수 있다"는 접근성이 확산을 도왔다.
영상을 프레임으로 다 넘기면 Claude의 컨텍스트(그리고 비용)가 폭발한다. claude-video는 이를 알고 프레임 수를 "예산"으로 관리한다 — 길이별로 목표 프레임 수를 정하고, 장면 전환만 잡고, 비슷한 프레임은 지우고, 최대 개수로 clamp한다. 4가지 상세 모드(transcript/efficient/balanced/token-burner)로 "정확도 ↔ 토큰 비용"을 사용자가 고를 수 있게 한 점이 실용적이다.
공개 영상에 자막(캡션)이 있으면 API 키 없이 무료로 대본을 얻는다(yt-dlp가 자막만 받아옴). 자막이 없을 때만 Whisper API로 폴백한다. 게다가 Claude Code 전용이 아니라 npx skills add 한 줄로 Codex·Cursor·Copilot·Gemini CLI 등 50여 개 하네스에 꽂힌다. 특정 생태계에 묶이지 않는 이식성이 트렌딩에 유리하게 작용했다.
claude-video의 스택을 이해하는 열쇠는 "파이썬 코드는 '지휘자'일 뿐, 무거운 일은 외부 프로그램이 한다"는 점이다. 파이썬은 순수 표준 라이브러리만 쓰며, 실제 영상 다운로드·프레임 추출·음성 인식은 시스템에 설치된 바이너리나 클라우드 API에 위임한다. 3개 계층으로 나눠 보자.
| 구성 | 역할 |
|---|---|
| Python 3 (stdlib only) | 전체 파이프라인을 지휘. subprocess로 바이너리 호출, urllib로 API 호출, json·argparse로 입출력. 서드파티 패키지 0개 — requirements.txt·pyproject.toml조차 없다. |
| watch.py (393줄) | 진입점. 다운로드→프레임→대본 전 과정을 조율하고 마크다운 리포트를 출력. |
| frames.py (756줄) ★ | 가장 큰 파일. ffmpeg를 불러 프레임을 뽑고, 장면 검출·auto-fps·중복 제거를 담당하는 심장부. |
| whisper.py (480줄) | Groq/OpenAI 음성인식 API 클라이언트를 SDK 없이 urllib로 손수 구현. |
이 도구들이 없으면 스킬이 동작하지 않는다. 그래서 실행 전 setup.py --check가 먼저 PATH에 있는지 확인한다.
| 바이너리 | claude-video에서의 쓰임 |
|---|---|
| yt-dlp | 영상 다운로드 + 네이티브 자막(VTT) 추출 + 메타데이터(info.json). 유튜브를 비롯한 수천 개 사이트 지원. |
| ffmpeg | 프레임을 JPEG로 추출, 오디오를 mp3로 뽑기, 중복 판정용 16×16 썸네일 디코드, 25MB 초과 오디오 분할. |
| ffprobe | 영상의 길이·해상도·코덱·오디오 유무를 미리 조사(probe). 프레임 예산 계산의 입력값이 된다. |
공개 영상에 자막이 있으면 이 계층은 건너뛴다(무료). 자막이 없을 때만 오디오를 클라우드 Whisper로 올려 대본을 만든다.
Groq whisper-large-v3 | 기본 선호(더 싸고 빠름). GROQ_API_KEY 필요. 엔드포인트 api.groq.com/openai/v1/audio/transcriptions. |
OpenAI whisper-1 | 대체 백엔드. OPENAI_API_KEY 필요. --whisper openai로 전환. |
| 호출 방식 | SDK를 안 쓰고 urllib.request로 multipart/form-data를 손으로 조립해 업로드. 키는 ~/.config/watch/.env(권한 0600)에 보관. |
핵심은 자기완결적인 skills/watch/ 폴더 하나다. 이 폴더를 각 생태계의 매니페스트가 감싸 여러 도구로 배포된다: Claude Code 플러그인(.claude-plugin/), Codex/Cursor/Copilot/Gemini용 Agent Skills(.codex-plugin/·.agents/), claude.ai 웹용 .skill 번들. "한 번 짜서 여러 곳에" 배포하는 전형이다.
"서드파티 라이브러리 0개"는 파이썬 패키지 이야기다. 대신 시스템 바이너리(ffmpeg·yt-dlp)는 반드시 별도 설치해야 한다. macOS는 setup.py가 brew install ffmpeg yt-dlp를 대신 실행해주지만, Linux/Windows는 명령만 안내한다. "pip install 없이 된다"를 "아무 준비물도 없다"로 오해하면 ffmpeg not found 오류를 만난다.
claude-video의 아키텍처는 서버 구조가 아니라 영상 하나를 "Claude가 읽을 수 있는 것"으로 바꾸는 처리 파이프라인이다. watch.py가 다음 흐름을 조율한다. 핵심 설계 사상은 두 가지: ① 불필요한 작업을 최대한 건너뛴다(캡션 있으면 다운로드 스킵), ② 프레임 수 = 토큰 비용이라 예산 안에서만 뽑는다.
가장 배울 만한 대목이다. 스크립트는 이미지를 API로 보내지 않는다. 프레임을 로컬 임시폴더에 JPEG로 떨구고 파일 경로 목록만 텍스트로 출력한다. 그러면 Claude가 자신의 Read 툴(멀티모달)로 그 JPEG들을 열어 컨텍스트에 이미지로 넣는다. 즉 "영상→이미지 변환"은 스크립트가, "본다"는 행위는 Claude의 네이티브 이미지 읽기가 담당하는 깔끔한 분업이다. 스크립트는 이미지 업로드·인코딩을 신경 쓸 필요가 없어진다.
순진한 구현이라면 "초당 1프레임"처럼 고정 간격으로 뽑겠지만, 그러면 1시간 영상은 3600장이 되어 컨텍스트가 터진다. claude-video의 auto_fps()는 반대로 생각한다 — "이 길이 영상엔 프레임 몇 장이 적당한가"라는 예산을 먼저 정하고, 거기에 맞춰 샘플링 간격을 역산한다. fps는 항상 MAX_FPS = 2.0 이하로 clamp된다. LLM의 컨텍스트 비용을 1급 설계 제약으로 다루는 사고방식이다.
거의 모든 단계에 폴백(대안 경로)이 있다. 캡션 없으면 → Whisper. 장면검출로 프레임이 너무 적으면(정적 영상) → 균등 샘플링. 키프레임이 4장 미만이면 → 균등 샘플링. Groq 실패하면 → OpenAI. 오디오가 25MB 넘으면 → 시간 균등 청크로 쪼개 각각 업로드 후 타임스탬프를 이어붙임. 청크 일부가 실패해도 → 나머지로 진행(전부 실패할 때만 에러). 어느 한 곳이 막혀도 전체가 죽지 않게 설계된 "우아한 열화"의 교과서다.
비슷한 프레임(예: 말하는 사람이 가만히 있는 장면)을 여러 장 넘기면 토큰 낭비다. claude-video는 Pillow 같은 이미지 라이브러리 없이 이걸 해결한다. ffmpeg로 각 프레임을 16×16 흑백 썸네일로 디코드한 뒤, 순수 파이썬으로 픽셀 평균 절대차를 계산한다. "마지막으로 남긴 프레임"과 비교해 차이가 2.0 이하면 근접 중복으로 보고 버린다. 이렇게 "직전 keep 프레임 기준" 비교라서 천천히 바뀌는 페이드 장면도 놓치지 않는다. 무거운 도구 없이 지각적 중복 제거를 구현한 영리한 디테일이다.
skills/watch/ 하나가 본체 — 나머지는 여러 하네스로 배포하기 위한 포장지구조가 곧 메시지다. 실제 로직은 전부 skills/watch/scripts/의 파이썬 8개 파일에 있고, 루트의 .claude-plugin/·.codex-plugin/·.agents/는 같은 폴더를 여러 생태계로 배포하기 위한 얇은 포장지일 뿐이다. 특히 frames.py(756줄)와 whisper.py(480줄)가 기술적 깊이의 핵심이다. tests/가 외부 네트워크·유튜브 없이 ffmpeg로 합성 영상을 만들어 장면검출·중복제거를 결정론적으로 검증하는 점도 눈여겨볼 만하다.
이 저장소의 교육 가치는 크게 두 갈래다 — (A) 에이전트/스킬 엔지니어링(LLM의 능력을 어떻게 확장하나)과 (B) 실전 파이썬·미디어 처리(subprocess·ffmpeg·API를 견고하게 다루는 법). 기술별로 정리한다.
claude-video의 핵심 교훈은 "모델이 못하는 일을, 모델이 잘하는 일로 바꿔라"다. 영상 이해(어려움)를 이미지 읽기+텍스트 이해(쉬움)로 번역했다. 이 변환 발상은 다른 곳에도 응용된다 — PDF를 이미지로, 오디오를 대본으로, 웹페이지를 마크다운으로. "새 모델을 기다리지 말고, 지금 모델이 소화할 형태로 입력을 가공하라"는 사고법을 배운다.
download.py는 yt-dlp를 subprocess로 호출하며 실전 노하우가 가득하다: 인자에 --를 넣어 URL을 옵션과 분리(옵션 인젝션 방지), -로 시작하는 입력 거부, 그리고 성공 판정을 "종료코드"가 아니라 "결과 파일이 실제로 생겼나"로 한다(자막 다운로드가 429로 실패해도 영상만 있으면 성공). 외부 CLI를 코드에서 부릴 때 마주치는 현실 문제와 그 해법을 보여준다.
whisper.py는 groq/openai SDK를 쓰지 않고 urllib.request로 multipart/form-data body를 손으로 조립해 파일을 업로드한다. HTTP가 실제로 어떻게 파일을 실어 나르는지, boundary가 뭔지 밑바닥부터 이해하게 된다. 덤으로 Cloudflare WAF에 막히지 않으려 정직한 커스텀 User-Agent를 붙이는 실전 디테일(watch-skill/1.0 …)까지 배운다.
frames.py는 ffmpeg의 강력한 필터를 실전 활용한다: select='gt(scene,0.20)'로 장면 전환 검출, -skip_frame nokey로 I-프레임(키프레임)만 디코드해 ~40배 빠르게, scale 필터로 해상도·종횡비 clamp, showinfo로 각 프레임의 타임스탬프 복원. "영상에서 의미 있는 순간만 뽑는" 미디어 처리의 정석을 코드로 익힌다.
네트워크·외부 API를 다루는 코드가 갖춰야 할 견고성이 다 있다. 지수 백오프 재시도(429는 Retry-After 존중, 4xx는 즉시 포기), 크기 초과 시 청킹(25MB 넘는 오디오를 시간 균등 분할 후 재봉합), 부분 실패 허용(청크 일부 실패해도 진행). "해피 패스만 짜지 말고 실패를 설계하라"를 실물로 배운다.
tests/conftest.py는 유튜브나 API에 의존하지 않는다. ffmpeg로 "14색 하드컷 클립"·"단색 정적 클립"을 합성해 픽스처로 쓴다. 그래서 장면검출·키프레임·중복제거·폴백이 인터넷 없이 언제나 같은 결과로 검증된다. "외부 의존을 테스트에서 걷어내는" 방법의 좋은 사례다.
SKILL.md는 Claude Code 전용 변수(${CLAUDE_SKILL_DIR})에 의존하지 않고, 모델이 방금 읽은 SKILL.md의 위치를 기준으로 스크립트 경로를 잡는다. 덕분에 Codex·Cursor 어디서든 동작한다. git archive + .gitattributes export-ignore로 런타임 불필요 파일을 번들에서 빼는 것도 배포 노하우다.
| 항목 | 요구사항 |
|---|---|
| OS | macOS(brew 자동설치 지원) · Linux(apt/dnf + pipx) · Windows(winget + pip, 이때 python3 아닌 python 사용). 크로스플랫폼 명시 지원. |
| 필수 바이너리 | ffmpeg + ffprobe(ffmpeg 패키지에 포함), yt-dlp. Python 3(버전 핀 없음, 문맥상 3.8/3.9+). |
| GPU | 전혀 불필요. Whisper는 로컬 추론이 아니라 API 호출이라 GPU가 없어도 된다. 로컬 부하는 ffmpeg의 CPU 디코딩뿐. |
| 디스크 | 720p 상한 영상 + 프레임 JPEG + mp3(~분당 480KB)를 임시폴더에 잠깐 저장 후 삭제. 예) 49분 영상 다운로드 ≈ 76MB. |
| 네트워크 | 다운로드(yt-dlp)와, 자막 없을 때만 오디오를 Whisper API로 업로드. 영상 자체는 절대 업로드하지 않는다(오디오만). |
| API 키(선택) | GROQ_API_KEY(권장) 또는 OPENAI_API_KEY. 자막 있는 공개영상은 키 없이 무료. |
| 실행 환경 | 지원 하네스 하나 — Claude Code / Codex / Cursor / Copilot / Gemini CLI 등. claude.ai 웹은 "Code execution" 활성 필요(ffmpeg 셸아웃 때문). |
정리하면 "ffmpeg와 yt-dlp만 깔려 있으면, 캡션 있는 유튜브 영상은 API 키 없이 공짜로 분석"할 수 있다. 진입장벽이 낮은 이유다. 자막 없는 영상까지 다루려면 Groq 키(무료 티어로도 충분)만 하나 넣으면 된다.
ffmpeg·yt-dlp를 깔고 스킬을 설치한 뒤, 자막이 있는 강의 영상 URL에 /watch <URL> 이 영상의 핵심 3가지가 몇 분에 나와?를 시켜보자. Whisper 키 없이도 대본이 나오는지, Claude가 타임스탬프를 인용해 답하는지 확인 — 캡션 우선 경로가 체감된다.
같은 영상에 --detail transcript / efficient / balanced / token-burner를 각각 걸고, 프레임 수·소요 시간·토큰 사용량이 어떻게 달라지는지 표로 적어보자. "정확도 ↔ 비용" 트레이드오프를 숫자로 만나면, 왜 예산 관리가 중요한지 몸으로 안다.
frames.py의 SCENE_THRESHOLD = 0.20을 0.10이나 0.40으로 바꿔 프레임 수가 어떻게 변하는지 실험하자. 임계치를 낮추면 사소한 변화도 컷으로 잡히고, 높이면 큰 전환만 남는다. ffmpeg의 scene 검출이 실제로 어떻게 동작하는지 감이 잡힌다.
ffmpeg로 아무 영상의 프레임 몇 장을 16×16 흑백으로 뽑고, claude-video처럼 평균 절대차로 근접 중복을 걸러내는 미니 스크립트를 짜보자. 임계치를 바꿔가며 "몇 이하를 같다고 볼까"를 조율하면, 라이브러리 없는 지각적 해싱의 원리를 손에 넣는다.
claude-video의 구조를 본떠, LLM이 못 다루는 다른 입력을 변환하는 스킬을 설계해보자 — 예: "긴 오디오 팟캐스트 → 챕터별 요약 대본", "복잡한 스프레드시트 → 이미지 차트 + 표 텍스트". SKILL.md(지시서) + 변환 스크립트 + 사전점검(setup.py 흉내) 구조를 그대로 빌리면, "입력 번역으로 능력을 확장"하는 이 레포의 핵심 역량이 내 것이 된다.
| 주차 | 주제 | 핵심 질문 · 자료 |
|---|---|---|
| 1주차 | 스킬/에이전트 엔지니어링 | SKILL.md로 에이전트에게 절차를 어떻게 가르치나. 경로 독립성·멀티 하네스 배포. → SKILL.md·AGENTS.md 정독 + Claude Code/Codex 스킬 문서. |
| 2주차 | 미디어 처리 (ffmpeg) | 필터 그래프, 장면검출(select=scene), 키프레임(-skip_frame nokey), 스케일·타임스탬프. → frames.py 정독 + ffmpeg 공식 필터 문서. |
| 3주차 | subprocess · HTTP 밑바닥 | 외부 CLI 안전 호출(인젝션 방지), urllib로 multipart 업로드, 재시도·백오프. → download.py·whisper.py 정독. |
| 4주차 | 견고성 · 테스트 설계 | 폴백 사슬, 청킹, 부분실패 허용, 네트워크 없는 결정론적 테스트. → transcribe.py·tests/conftest.py + 직접 픽스처 작성. |
먼저 watch.py를 위에서 아래로 읽어 전체 흐름(다운로드→프레임→대본→출력)을 머릿속에 그려라 — 이게 지도다. 그다음 가장 재밌는 frames.py의 한 상수(SCENE_THRESHOLD·MAX_FPS)를 바꿔 결과가 어떻게 달라지는지 실험하면, 각 설계 선택의 "왜"가 이해된다. 마지막으로 이 구조를 본떠 내가 원하는 다른 입력(오디오·문서·데이터)을 LLM용으로 번역하는 스킬을 만들어보면, 이 레포의 진짜 역량("입력을 가공해 능력을 확장")이 손에 남는다. 미디어 처리 경험이 없어도 좋다 — 이 레포는 ffmpeg의 어려운 기능을 딱 필요한 만큼만 쓰는 좋은 본보기다.
claude-video는 "AI 스킬" 물결의 한 갈래다. bradautomates의 다른 작업들처럼 "Claude에게 새 능력을 붙이는" 계열이고, 같은 트렌딩 목록의 Graphify-Labs/graphify·Egonex-AI/Understand-Anything은 "코드를 지식 그래프로 번역"해 에이전트에게 먹이는 사촌이다. 밑바닥 도구로 보면 yt-dlp(만능 다운로더)와 ffmpeg(미디어 스위스 army knife), Whisper(음성인식)가 이 스킬이 올라선 어깨다. 이들을 나란히 보면 "LLM에게 무엇을, 어떤 형태로 먹일 것인가"의 서로 다른 답이 보인다.
SKILL.md(지시서) + 실행 스크립트로 구성. claude-video는 "영상 보려면 이 파이썬을 이렇게 호출하라"를 SKILL.md에 적어둔다.select='gt(scene,0.20)' 필터로 구현. 덕분에 "말하는 사람이 가만있는" 지루한 구간을 건너뛰고 의미 있는 프레임만 뽑는다.-skip_frame nokey로 키프레임만 디코드하면 전체를 풀지 않아 ~40배 빠르다(efficient 모드).transcribe.py가 "이전 줄의 확장이면 병합"하는 규칙으로 이를 정리한다.urllib로 이 body를 손수 조립해 오디오를 Whisper API로 올린다. "파일 업로드가 실제로 어떻게 동작하나"를 밑바닥부터 보여준다.config.py가 모드별 프레임 상한을 정한다.| 구분 | 링크 / 위치 |
|---|---|
| GitHub 저장소 | github.com/bradautomates/claude-video |
| TrendShift | trendshift.io/repositories/30967 |
| 설치 (Claude Code) | /plugin marketplace add bradautomates/claude-video → /plugin install watch@claude-video |
| 설치 (Codex/Cursor/기타) | npx skills add bradautomates/claude-video -g |
| 핵심 파일 | skills/watch/scripts/watch.py (진입점 393줄) |
| 핵심 파일 | skills/watch/scripts/frames.py (프레임 엔진 756줄 · auto-fps·장면검출·중복제거) |
| 핵심 파일 | skills/watch/scripts/whisper.py (stdlib Whisper 클라이언트 480줄) |
| 계약서 | skills/watch/SKILL.md (Claude 호출 규약 · 경로 독립성) |
| 이웃 프로젝트 | Graphify-Labs/graphify · Egonex-AI/Understand-Anything · yt-dlp · ffmpeg · openai/whisper |
| 연관 개념 | Agent Skill · 멀티모달 · 프레임 예산 · 장면검출 · STT/Whisper · graceful degradation |