본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 06. 21. 09:08

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가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0