매일 아침, 어제의 내가 정리된 채로 나를 기다린다
Karpathy가 올해 초에 LLM으로 개인 위키를 만드는 패턴을 소개했다. 핵심은 간단하다. PDF든 회의록이든 채팅 로그든, 소스를 LLM한테 던지면 LLM이 위키 페이지를 만들고 크로스레퍼런스를 걸고 모순을 잡아준다. 사람이 직접 정리하면 귀찮아서 안 하는 걸 LLM이 대신 해주니까, 위키가 처음으로 죽지 않고 계속 자란다.
나도 이걸 직접 만들어서 쓰고 있다. 마크다운 파일 121개짜리 개인 위키가 하나 있고, 매일 거기서 일한다. 구조를 half-memex 매니페스토에 정리해뒀다.
이 글은 그 위키의 소스 중 하나를 자동화한 얘기다. Claude Code 세션 기록을 매일 밤 자동으로 위키에 흘려보내는 파이프라인.
어젯밤 Claude Code 세션 닫고 잤다. 아침에 일어나서 노트 폴더 열어봤더니 파일 몇 개가 바뀌어 있었다. 내가 건든 적 없는 파일들이다.
열어보니까 어제 내가 뭘 결정했고, 뭘 시도했다가 포기했고, 왜 그 길로 갔는지가 적혀있었다. 슬랙 멘션도 아니고 커밋 메시지도 아니고, 내가 Claude한테 실제로 한 말이 그대로 정리되어 있었다.
이걸 어디에 쓰냐면:
- 어제 디버깅하다가 놓친 가설 다시 찾을 때 거길 본다
- 한 달 전에 같은 버그 만났을 때 뭘 결정했는지 찾을 때 거길 본다
- 주간 리포트 쓸 때 거기서 흐름만 긁어온다
기억으로 쓰는 것보다 정확하고, 슬랙 뒤지는 것보다 빠르다.
노트 파일은 이렇게 생겼다. 어젯밤 세션 끝나고 자동으로 붙은 조각:
## 2026-04-07 D'CENT 앱 탐색
- biometric 화면이 캐러셀 애니메이션 때문에 black screen으로 찍힘
- 해결: accessibility tree로 우회, UI dump 대신 DOM 레벨로 읽기
- TRANSITIONS.md 갱신: `AuthPrompt → tap Cancel → PasswordEntry`
- 결정: L2(인터랙션)까진 끝. 다음 세션은 L3(실거래)로.
(auto-sync from session 9ad78433, 2026-04-07 23:12)이게 한 파일에만 붙는 게 아니라 관련 파일 여러 개에 조각조각 들어간다. 세션 하나 끝나면 관련 주제 페이지 몇 개가 같이 업데이트된다.
두 가지 전제. 이 글은 Claude Code CLI 매일 쓰는 사람한테 하는 얘기다. 웹 Claude만 쓰면 여기 나오는 파일 자체가 없다. 그리고 개인 노트(Obsidian이든 마크다운 폴더든 뭐든)를 이미 쓰고 있는 사람한테 하는 얘기다. 노트 시스템 없으면 여기서 읽는 거 멈추는 게 낫다.
어디에 뭐가 쌓이나
Claude Code는 세션을 전부 JSONL로 디스크에 쌓고 있다.
- 경로:
~/.claude/projects/{cwd-encoded}/{session_id}.jsonl - 구조: 세션 하나가 파일 하나. 턴 하나가 줄 하나
- 내용물: 사용자 메시지, 어시스턴트 응답, tool 호출, 파일 수정, Bash 명령. 전부 시간 순
지금 이 글 읽고 있는 사람도 ~/.claude/projects/ 열어보면 이미 몇 기가 쌓여있을 것이다. 하루 종일 Claude Code로 일하는 사람이면 이게 그날 뭘 했는지에 대한 가장 정확한 기록이다. 근데 평소엔 아무도 안 본다.
파이프라인
세션 끝나는 순간부터 노트에 반영되기까지 5단계다.
1. hook을 건다. ~/.claude/settings.json에 Stop이랑 SessionEnd 두 개를 건다. Stop은 Claude가 응답 끝낼 때마다 뜨고, SessionEnd는 세션 자체가 닫힐 때 뜬다. 둘 다 건 이유는 크래시로 끝나면 Stop이 안 뜨기 때문이다. 둘 다 async: true라서 메인 세션은 아무것도 못 느낀다.
"Stop": [{ "hooks": [{ "type": "command", "async": true, "timeout": 5,
"command": "~/.claude/hooks/memex-ingest.sh" }] }]2. 별도 인스턴스를 띄운다. hook 스크립트가 claude -p를 백그라운드로 하나 띄우고 바로 리턴한다. -p는 대화형이 아니라 한 번 실행하고 끝나는 모드다. nohup + disown으로 hook에서 프로세스를 떼어내서, 메인 세션은 이게 돌고 있는지도 모른다.
3. 규칙부터 읽게 만든다. 이게 좀 중요한 부분인데, LLM한테 그냥 "정리해줘"만 시키면 자기 마음대로 쓴다. 내가 정한 파일 형식이고 뭐고 다 무시한다. 그래서 프롬프트 첫 줄에 이걸 박아넣었다:
## 작업 시작 전 반드시 먼저 읽을 것
1. CLAUDE.md — 전체 구조
2. wiki/CLAUDE.md — 노트 그래프 규칙
3. app-memory/CLAUDE.md — 앱 조작 메모리 규칙
4. projects/CLAUDE.md — 프로젝트 레이어 규칙규칙을 프롬프트에 직접 복붙하는 것보다, 파일을 먼저 읽게 시키는 게 훨씬 효과적이었다. 파일을 읽으면 규칙이 주변 맥락이랑 같이 들어오기 때문인 것 같다.
4. 분류해서 붙인다. 백그라운드 인스턴스가 세션 JSONL을 읽고, 규칙에 맞춰서 관련 노트 파일에 조각을 갖다 붙인다.
5. 안전망을 깐다. hook이 안 뜨는 경우가 있다. 크래시, 네트워크 문제, 알 수 없는 이유. 그래서 ~/Library/LaunchAgents에 launchd 작업(macOS에서 cron 같은 거)을 하나 등록해뒀다. 30분마다 돌면서 최근 35분 내 수정된 JSONL을 전부 긁어온다.
find "$PROJECTS_DIR" -name "*.jsonl" -mmin -35 \
-not -path "*ObsidianVault*" | head -20여기서 -not -path "*ObsidianVault*"가 핵심이다. 노트 폴더 안에서 작업하던 세션을 빼야 한다. 안 빼면 ingest하다가 생긴 세션이 또 ingest되고, 무한 루프가 된다.
왜 이렇게 해야 하나
왜 별도 인스턴스인가. 메인 세션에서 ingest를 같이 돌리면 "코드 짜는 나"랑 "노트 정리하는 나"가 같은 컨텍스트에 섞인다. 서로 오염된다. 토큰 문제가 아니라 역할 분리 문제다.
왜 규칙 파일을 매번 읽게 하나. LLM은 자유 주면 자기 스타일로 쓴다. 매번 규칙 파일부터 읽게 만들어야 형식을 지킨다.
왜 launchd까지 붙이나. hook이 안 뜨는 세션이 꼭 생긴다. 30분마다 도는 sweep이 그걸 줍는다.
한계
- 민감 정보 필터가 없다. 세션 기록에 비밀번호, API 키, 내부 정보가 섞여 들어온다. 지금은 수동으로 확인하고 있다
- 긴 세션은 앞쪽이 날아간다. 하루 100턴 넘는 세션을 한 번에 넘기면 앞부분이 희석된다. 길면 잘라서 넘기는 게 낫다
- 자동이라고 정확하진 않다. 봇이 엉뚱한 파일에다 사실을 갖다 붙이는 일이 생긴다. 규칙 파일 4개 먼저 읽게 해서 많이 줄었는데, 0은 아니다
내일 아침에도
이 글을 쓰는 동안에도 hook이 돌고 있었다. 방금 끝난 세션을 읽고 "변경 없음"이라고 판단하고 지나갔다.
내일 아침에도 노트 파일 몇 개가 바뀌어 있을 것이다. 이 파이프라인은 더 큰 구조의 한 조각이다 — 전체는 half-memex에.