
Claude Code로 매일 아침 GitHub 순회하기 ― 유용한 OSS와 스킬 자동 채점
요약
Claude Code를 활용하여 매일 아침 GitHub의 유용한 OSS와 스킬을 자동으로 탐색하고 채점하는 'github-scout.sh' 스크립트 제작기를 소개합니다. 비용 최적화를 위해 크롤링과 채점 단계를 분리하고, 안전한 스킬만 자동 활성화하는 파이프라인 설계를 다룹니다.
핵심 포인트
- Claude Code를 이용한 GitHub OSS 자동 탐색 및 채점 자동화
- 비용 고정을 위해 크롤링(무료)과 채점(Claude API) 단계 분리
- 안전한 스킬과 리뷰가 필요한 대상을 구분하는 기계적 판정 설계
- GitHub Search API를 활용한 3개 레인 기반의 검색 전략
지난번 「Claude Code를 무인으로 자율 개선시키기」에서 아침 브리핑(Morning Brief)의 골격을 만들었다. 이번에는 그 브리핑 생성 작업에 편승하는 형태로, GitHub을 매일 아침 순회하며 유용한 OSS와 스킬을 자동 채점하고, 대응이 필요한 것만 데스크톱 브리핑에 삽입하는 github-scout.sh를 만든 이야기를 쓰고자 한다.
설계 포인트는 세 가지다. 크롤링(gh 사용, 무료)과 채점(claude -p 사용, MAX 할당량)을 분리하여 비용을 고정하는 것. 스킬의 안전성을 파일 구성으로 기계적 판정하여 자동 활성화할지, 리뷰가 필요한 격리 대상으로 분류할지 결정하는 것. 채점 실패 시에는 seen 장부에 기록하지 않고 다음 날 아침의 자동 재시도에 맡기는 것이다.
고민: GitHub을 「우연에 의존하여」 바라보고 있었다
Claude Code 스킬 중에는 커뮤니티에서 제작된 것도 GitHub에 널려 있다. 취업 트래커나 Chrome 확장 프로그램의 참고용 OSS도 마찬가지다. 하지만 「마음 내킬 때 수동 검색」하는 방식으로는 재현성이 없다. 매번 똑같은 인기 리포지토리(Repository)만 걸리고, 지난주에 발견한 OSS를 다음 주에는 잊어버린다.
유용한 스킬을 놓친 채 스스로 같은 것을 다시 작성하는 낭비가 얼마나 많았는지 셀 수 없을 정도다. 아침 브리핑이 오는 메커니즘은 이미 존재한다. 거기에 GitHub 발견 사항을 자동으로 삽입하는 것이 최단 경로의 해결책이었다.
전체 설계: 4단계 파이프라인
스크립트의 헤더 주석에 그대로 적혀 있다.
# CRAWL(gh=무료) -> DEDUP(shell) -> ENRICH(gh contents) -> SCORE+ROUTE+INGEST(claude -p=MAX 할당량) -> LEDGER
비용이 발생하는 것은 채점 단계뿐이다. 후보 수에 상한을 둠으로써 채점에 사용되는 토큰(Token) 소비를 고정하고 있다.
MAX_CANDIDATES=30 # claude에게 전달할 상위 건수 (비용 고정화)
MAX_ENRICH=8 # SKILL.md 내용을 가져올 skill 후보의 상한
TIMEOUT_SEC=600
출력 위치는 ~/.claude/ 하위 디렉토리뿐이다. Vault(iCloud 동기화·TCC 보호 영역)에는 직접 쓰지 않는다. 이는 autopilot과 마찬가지로 「보호 구역 외의 자신의 도구 저장소만 건드린다」는 설계 원칙이며, 스크립트 주석에도 명시되어 있다.
# 출력:
# - 브리핑 삽입용: ~/.claude/logs/github-scout-latest.md
# - 안전 스킬(md만 존재/read 권한): ~/.claude/skills/auto/<name>/ 에 자동 활성화
...
1. CRAWL: 3개 레인으로 그물을 치다
gh search repos를 용도별 3개 레인으로 실행한다. 레인은 후속 단계의 분류에 그대로 사용된다.
# A: Claude Code 스킬/플러그인 (본진)
run_search skill "A1 topic:claude-code" --topic claude-code --sort stars --order desc --limit 25
run_search skill "A2 claude code skills" "claude code skills" --sort stars --order desc --limit 20
...
각 run_search는 실패하더라도 커버리지(Coverage)에 ❌를 기록하고 계속 진행한다. 모든 소스가 성공하지 않더라도 멈추지 않는다. 속도 제한(Rate Limit) 대책으로 각 검색 후에 sleep 1을 넣었다 (GitHub Search API: 30 req/min).
run_search 함수는 레인 라벨이 붙은 JSONL을 raw.jsonl에 추가하는 구조로 되어 있다.
run_search() {
local lane="$1"; shift; local label="$1"; shift
local json
...
2. DEDUP: seen 장부와 기존 스킬로 제외
~/.claude/scout/seen.tsv (리포지토리 fullName·채점일)로 과거에 채점된 항목을 걸러내고, auto/ 하위의 기존 스킬 이름으로도 약한 중복 검출을 수행한다.
SEEN_SET="$WORK/seen.set"
cut -f1 "$SEEN" 2>/dev/null | sort -u > "$SEEN_SET"
"$JQ" -s -c 'unique_by(.name) | sort_by(-.stars) | .[]' "$RAW" 2>/dev/null \
...
unique_by(.name) | sort_by(-.stars)
를 사용하여 중복을 제거한 뒤, stars(별점) 내림차순으로 정렬하고 차분을 구한다. 상위 MAX_CANDIDATES=30개로 압축하는 시점에서 비용 상한이 확정된다.
3. ENRICH: 스킬 후보만 SKILL.md를 가져오기
채점의 질을 높이기 위해, lane=skill인 항목 중 상위 MAX_ENRICH=8개에 대해서만 루트의 SKILL.md 내용과 파일 목록을 가져온다. 그 외에는 메타 정보(stars/desc/언어)만으로 채점하게 한다.
if [ "$lane" = "skill" ] && [ "$enr_count" -lt "$MAX_ENRICH" ]; then
enr_count=$((enr_count+1))
skillmd=$("$GH" api "repos/$name/contents/SKILL.md" \
...
여기서 설정한 has_script 플래그가 후속 단계의 안전성 판정에 사용된다.
4. SCORE + ROUTE: claude -p에 채점과 실제 파일 조작을 위임하기
ENRICH된 후보들을 모아 프롬프트(Prompt)에 전달하고, ★1-5 채점과 파일 조작을 동시에 지시한다. 분류는 3가지 경로로 나뉜다.
A) 스킬 자동 도입 (lane=skill, skillmd 있음, ★4 이상)
프롬프트의 안전성 판정 규칙이 그대로 로직이 된다.
안전성 판정:
- allowed-tools가 없거나, Read/Grep/Glob/WebFetch/WebSearch만 있음 → 【안전】
- has_script=true이거나, allowed-tools에 Bash/Write/Edit 등이 포함됨 → 【검토 필요】
...
B) OSS/프로젝트 후보 (lane=project 또는 skill 중 skillmd가 비어 있음, ★4 이상)
~/.claude/scout/watchlist.md에 추가하기만 한다. 형식은 - [name](url) ★N — 30자 이내의 이유(DATE)이다. clone(복제)은 하지 않는다.
C) 트렌드 (lane=trend, ★3 이상)
브리프(Brief)에 한 줄 추가할 뿐이다. 파일 조작은 없다.
브리프에 삽입되는 섹션은 다음과 같은 구성이 된다.
## 🔭 GitHub Scout (2026-06-17)
### ⚡ 자동으로 도입된 스킬
- foo-skill ★4 — 무엇을 할 수 있는지 1줄 (활성화됨)
...
5. 아침 브리프에 합류하기
scout는 독립된 launchd 작업으로 구성하지 않았다. vault-auto-ingest.sh의 브리프 생성(step 2.5) 직후인 step 2.55로 호출된다.
# vault-auto-ingest.sh 발췌 (step 2.55)
# 2.55 GitHub Scout 순회 → 발견/대응 필요 항목을 브리프에 삽입. scout 본체는 ~/.claude(보호 대상 외)에만 기록함.
run_to 900 bash "$HOME/.claude/scripts/github-scout.sh" >> "$LOG" 2>&1 \
...
실패하더라도 || echo "...(계속)"를 통해 다음 단계로 진행한다. 브리프 생성 전체가 중단되지 않도록 하기 위함이다.
신선도 체크(-nt "$START_STAMP")를 통해 오래된 파일이 잘못 추가되는 것을 방지한다. vault-auto-ingest.sh는 4:55 / 8:15 / 10:15 / 12:15의 여러 슬롯에서 실행되지만, 성공 후에는 DONE_MARKER를 통해 이후 슬롯을 즉시 return하므로, scout를 포함한 브리프 전체가 한 번 성공하면 중복 실행되지 않는다.
6. 실패 내성: seen 장부에 기록하지 않는 것이 재시도의 핵심
채점 단계에서 어떤 일이 발생하는지를 제어하는 것이 SCORE_OK 플래그와 SESSION_LIMIT 검출이다.
# Claude MAX 한도 초과(session limit)를 전용 검출
SESSION_LIMIT=0
if [ "$rc" -ne 0 ] && grep -qi "session limit" "$RUN_OUT" 2>/dev/null; then
...
채점 결과의 내용이 부실한 경우(- 행이 1건 미만)에는 SCORE_OK=0으로 설정하여 3단계 폴백 (fallback)에 진입한다.
CONTENT_LINES=$(grep -cE '^- ' "$OUT" 2>/dev/null); CONTENT_LINES=${CONTENT_LINES:-0}
# ※ grep -c는 0건이어도 「0」을 출력하고 exit 1 → `|| echo 0`은 0\n0을 생성하여 정수 비교를 망가뜨리는 footgun(실수하기 쉬운 코드). 붙이지 않는다.
if [ "${CONTENT_LINES:-0}" -lt 1 ]; then
...
마지막 LEDGER 단계에서, 채점에 성공했을 때만 seen.tsv에 기록한다.
if [ "${SCORE_OK:-1}" -eq 1 ]; then
while IFS= read -r line; do
nm=$(echo "$line" | "$JQ" -r '.name')
...
SESSION_LIMIT으로 인해 리셋까지 시간이 많이 남은 경우도 SCORE_OK=0과 마찬가지로 커밋하지 않는다. 다음 날 아침 순회 시 동일한 후보가 자동으로 다시 부상한다.
커버리지 표: 누락을 명시하기
브리프(brief) 끝부분의 <details>에 소스별 커버리지 표가 붙는다.
<details><summary>scout 커버리지</summary>
| 소스 | 상태 | 건수 |
|---|---|---|
...
CLAUDE.md의 「Multi-source Coverage」 방침에 따라, 실패한 소스를 숨기지 않고 ❌로 표시한다. 「채점 30」이 MAX_CANDIDATES의 캡(cap)이 작동하고 있다는 증거이며, 비용이 고정되어 있음을 읽을 수 있다.
빠졌던 함정들
- 전체 단어 AND 검색으로 검색 결과 0건 → 핵심 단어 + 언어 + stars 하한선으로 완화. B계열 쿼리는 실측을 통해 조정했다 (주석에
v2: 2026-06-10 실측 조정이라고 적혀 있음) - launchd의 최소 PATH 문제 → autopilot과 동일한 대책: nvm의 node, Homebrew, local의 bin을 전부 export.
gh/jq를 찾을 수 없음
→gh search에--created/--updated를 쿼리 문자열로 섞으면 무시되므로,gh search repos의 네이티브 플래그인--created ">$D90"로 전달한다 (C계열은 이것이 필요함) - claude OUT이 35바이트의 헤더만 포함하는 경우 →
-s체크를 통과하는grep -cE '^- '를 사용하여 후보 행 수를 판정하도록 했다 (2026-06-11 새벽 소켓 장애 이후 구현)
→grep -c가 0건일 때 exit 1을 반환하므로, 여기에|| echo 0을 붙이면0\n0이 되어 정수 비교가 망가진다. 스크립트 주석에 "footgun. 붙이지 말 것"이라고 명시해 두었다. - 스크립트 포함 스킬을 프론트매터(frontmatter)만 보고 판단하면 안전해 보임 → 파일 목록의
has_script플래그로 보완 - SESSION_LIMIT을 에러와 동일하게 취급하면 🚨 알람이 오보로 발생함 → 전용 플래그로 분기하여 「한도 대기 중」과 「채점 버그」를 별도 메시지로 분리
요약
- 크롤링(
gh, 무료)과 채점(claude -p, MAX 한도)을 분리하고,MAX_CANDIDATES=30으로 비용을 고정한다. - 3개 레인(A 스킬/BOSS/C 트렌드) × 다중 쿼리로 그물을 펼치고,
seen.tsv를 통해 다음 날의 재부상을 방지한다. - 스크립트 포함 스킬은
.incoming/에 격리하고, Read 권한만 있는 것들만auto/에 즉시 활성화한다. - launchd의 작업으로 독립시키지 않고, 아침 브리프 생성의 step 2.55로서 병행시킨다.
- 채점 실패 시에는 3단계 폴백 + seen 미커밋을 통해 다음 날 아침에 자동 재시도한다.
- 커버리지 표를 통해 누락을 숨기지 않는다.
이 시리즈를 통해 만들어 온 파츠들(4층 기억 / 자기 증식 스킬 / 컨텍스트 축소 / launchd / autopilot / 장기 기억)이 여기서 하나로 연결되었다. GitHub 탐색 결과가 브리프(brief)에 반영되고, 좋은 스킬은 다음 날부터 자동으로 사용할 수 있게 된다. 환경이 "읽으며 성장하는" 루프가 하나로 이어졌다.
다음 회차에서는 GitHub Scout나 autopilot을 안심하고 실행하기 위해 밑바탕에서 확인해야 할 수치 ―― Claude Code의 비용과 플랜 할당량을 상시 시각화하는 statusline 구현에 대해 작성하겠습니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기