Claude Code로 개발하면서 나눈 대화들이 아깝다는 생각을 자주 했다. 어차피 공부하고 삽질한 내용인데 블로그에 정리하면 좋겠는데 매번 손으로 쓰기가 귀찮더라고.. 그래서 아예 파이프라인을 짜버리기로 했다.
어떤 걸 만들고 싶었냐면
Claude Code로 개발한 내용을 자동으로 블로그 포스팅으로 만들어주는 구조를 원했다. 근데 완전 자동화는 좀 무서웠다. AI가 알아서 올려버리면 이상한 글이 올라갈 수도 있으니까.. 그래서 AI가 초안을 뽑아주면 내가 검토하고 마음에 드는 것만 골라서 올리는 반자동 구조로 방향을 잡았다.
Claude Code 대화 로그 수집 (주 1회 자동) ↓ Claude API로 블로그 초안 생성 ↓ 블로그 DB에 draft 상태로 저장 ↓ 내가 /admin/drafts 페이지에서 검토 & 선택 ↓ 발제 버튼 → 블로그에 바로 발행!
수집 소스 고민
처음엔 claude.ai 웹에서 한 것도 다 가져오고 싶었는데 알고 보니 웹 대화는 Anthropic 서버에만 저장되고 공식 export API가 없었다.. 그래서 로컬에 저장되는 CLI랑 VS Code 플러그인 로그만 수집하기로 했다.
Claude Code CLI나 VS Code 플러그인으로 작업하면 ~/.claude/projects/ 경로에 JSONL 형태로 대화 기록이 자동 저장된다. 이걸 읽어서 이번 주 대화만 쏙 뽑아오는 게 수집 스크립트의 핵심이었다.
왜 별도 서버 배포 없이 기존 블로그에 붙였냐면
처음엔 이 파이프라인을 Vercel에 따로 배포해야 하나 싶었는데, 생각해보니 그럴 필요가 없었다.
관리 UI랑 발행 API는 기존 블로그(Next.js + Supabase)에 페이지랑 API 라우트 추가만 하면 되고, 로그 수집 스크립트는 어차피 내 맥북에서만 돌아야 하니까 로컬 crontab으로 처리하면 됐다.
[내 맥북] crontab 주 1회 자동 실행 → 로그 수집 + Claude API 요약 → 블로그 Supabase DB에 draft 저장
[기존 블로그 Vercel] → /admin/drafts 페이지 (새 페이지만 추가) → /api/drafts/publish (새 API만 추가)
새로 배포할 프로젝트가 없으니 훨씬 간단했다.
노션 연동도 추가
개발하다 보니 Claude Code 로그 말고 노션에 정리해둔 메모들도 가져오고 싶어졌다. 노션은 공식 API가 있어서 생각보다 쉽게 붙일 수 있었다.
노션 integration 발급 → 연결하고 싶은 페이지에 integration 연결 → 페이지 ID를 환경변수에 넣으면 끝. ChatGPT 웹처럼 export API가 없는 것과 달리 노션은 공식적으로 API를 잘 지원해줘서 마음에 들었다.
Supabase에 draft_posts 테이블 추가
기존 블로그 DB에 초안을 저장할 테이블이 필요했다. SQL Editor에서 테이블 하나 만들어줬다.
sql CREATE TABLE draft_posts ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, description TEXT, content TEXT NOT NULL, tags TEXT, source_project TEXT, status TEXT DEFAULT 'draft', created_at TIMESTAMPTZ DEFAULT NOW() );
심플하게 title, content, tags, 상태값 정도만 넣었다. 어차피 발행 전에 내가 수정할 수 있으니까 초안 단계에서 너무 복잡하게 만들 필요가 없었다.
/admin/drafts 페이지 구현
블로그에 초안 관리 페이지를 추가했다. 왼쪽에 초안 목록, 오른쪽에 제목/태그/내용 편집 가능한 에디터 형태로 만들었다.
처음에 왼쪽에서 다른 초안을 눌러도 오른쪽 내용이 안 바뀌는 버그가 있었는데, DraftDetail 컴포넌트에 key prop이 빠진 거였다. key가 없으면 React가 컴포넌트를 재사용해버려서 state가 초기화가 안 됐던 거였다.
말투 학습에서 템플릿 방식으로 전환
처음엔 내 Claude Code 대화 로그에서 말투 패턴을 자동으로 추출하는 기능을 넣었는데, 이게 매번 API를 추가로 호출해야 해서 낭비였다. 그리고 결과도 불안정했다.
그래서 아예 내가 직접 쓴 블로그 글을 분석해서 스타일 가이드를 상수로 박아두는 방식으로 바꿨다. 경험/회고 글은 ## 헤더에 1인칭 스토리텔링으로, 기술 학습 글은 > 블록쿼트로 동기 설명 후 # 헤더로 섹션 구분하는 포맷으로 정형화했다.
나중에 내 글쓰기 스타일이 바뀌면 summarize.ts의 템플릿 상수만 수정하면 되니까 오히려 더 유지보수하기 편해졌다.
트러블슈팅 — JSON 파싱 실패
파이프라인 돌리다가 계속 JSON 파싱 실패 에러가 났다. 디버그 로그를 추가해서 Claude 응답 원문을 찍어봤더니 content 안에 긴 마크다운이 들어가다가 중간에 잘리고 있었다.
원인은 max_tokens: 4000 설정이 블로그 본문 전체를 담기엔 너무 적었던 것. 값을 늘려주니까 바로 해결됐다. 생각보다 간단한 문제였는데 원문을 찍어보기 전까진 원인을 알 수가 없었다.
자동화 파이프라인에서 AI 응답이 잘리는 문제는 항상 토큰 제한을 먼저 의심해보자.
지금 구조 최종 정리
| 구성 요소 | 역할 |
|---|---|
collect.ts | ~/.claude/ JSONL 파싱, Notion API 수집 |
summarize.ts | Claude API로 요약 + 블로그 초안 생성 |
upload-drafts.ts | Supabase draft_posts 테이블에 저장 |
index.ts | 전체 파이프라인 실행 |
/admin/drafts | 초안 검토 & 편집 & 발행 UI |
crontab | 주 1회 로컬 자동 실행 |
앞으로
일단 파이프라인 자체는 동작하고 있다. 앞으로는 실제로 일주일 돌려보면서 생성되는 초안 퀄리티를 보고 프롬프트를 계속 다듬어볼 생각이다. ChatGPT export 파일도 파서를 추가하면 수동으로 가져올 수 있을 것 같아서 추후에 붙여볼 예정이다.