Show original
Enjoyed this article?
Use "Request tipping" to ask the author to set up tip receiving.

AI translation
― Automatically score useful OSS and skills
Enjoyed this article?
Use "Request tipping" to ask the author to set up tip receiving.
Last time in "Claude Codeを無人で自律改善させる" I built the skeleton of the morning brief. This time I created github-scout.sh by piggybacking on that brief generation job — crawling GitHub every morning to auto-score useful OSS and skills, then inserting only items requiring action into the desktop brief.
Three design points: separate crawling (gh, free) from scoring (claude -p, MAX tier) to lock in costs. Use file structure to machine-judge skill safety and route to either auto-enable or quarantine-for-review. On scoring failure, don't mark the seen ledger and leave retry to tomorrow's automation.
Community-made Claude Code skills are scattered across GitHub. Same with reference OSS for job trackers and Chrome extensions. But "manual search when I feel like it" isn't reproducible. I kept hitting the same popular repos, forgetting OSS I found last week by this week.
I can't count how much waste there was — useful skills I missed, then wrote myself from scratch. The morning brief system already exists. Automatically injecting GitHub discoveries into it was the shortest solution.
It's written right in the script header comment.
# CRAWL(gh=無料) -> DEDUP(shell) -> ENRICH(gh contents) -> SCORE+ROUTE+INGEST(claude -p=MAX枠) -> LEDGERCosts only happen in the scoring phase. Capping candidate count locks in token consumption.
MAX_CANDIDATES=30 # claude へ渡す上位件数(コスト固定化)
MAX_ENRICH=8 # SKILL.md 中身を取りに行く skill 候補の上限
TIMEOUT_SEC=600Output goes only under ~/.claude/. Never write directly to Vault (iCloud sync / TCC protected zone). This follows the same "touch only unprotected personal tool space" design principle as autopilot, explicitly noted in script comments.
# 出力:
# - ブリーフ差し込み用: ~/.claude/logs/github-scout-latest.md
# - 安全スキル(md のみ/read系権限): ~/.claude/skills/auto/<name>/ に自動有効化
# - Bash/script 同梱スキル: ~/.claude/skills/auto/.incoming/<name>/ に隔離 + 要対応フラグ
# - OSS/トレンド候補: ~/.claude/scout/watchlist.md に追記(clone しない)Run gh search repos across three purpose-specific lanes. Lanes feed directly into downstream routing.
# 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 skill "A3 claude agent skill" "claude agent skill SKILL.md" --sort updated --order desc --limit 20
# B: 自分の開発に直結する OSS(autofill / maps scraper / turso / resume builder / job tracker 等)
run_search project "B1 chrome autofill" "autofill" --language JavaScript --stars ">100" --sort stars --order desc --limit 12
run_search project "B3 turso" "turso" --language TypeScript --stars ">50" --sort updated --order desc --limit 12
run_search project "B5 job tracker" "job tracker" --stars ">30" --sort stars --order desc --limit 12
# ... B2/B4/B6/B7 略
# C: トレンド横断
run_search trend "C1 breakout 90d" --created ">$D90" --stars ">800" --sort stars --order desc --limit 20
run_search trend "C2 hot now" --updated ">$D3" --stars ">3000" --sort updated --order desc --limit 20Each run_search records ❌ on failure but keeps going. The whole thing doesn't stop if not all sources succeed. Rate limit protection: sleep 1 after each search (GitHub Search API: 30 req/min).
B-lane queries started with all terms AND'd across multiple topics, yielding 0 results repeatedly. The comment says "v2: 2026-06-10 real-world tuning" — I relaxed to core term + language + stars floor. Complex queries need trial-and-adjust.
The run_search function appends lane-labeled JSONL to raw.jsonl.
run_search() {
local lane="$1"; shift; local label="$1"; shift
local json
json=$("$GH" search repos "$@" --json fullName,description,stargazersCount,url,language,pushedAt,createdAt 2>>"$LOG")
if [ -n "$json" ] && echo "$json" | "$JQ" -e 'type=="array"' >/dev/null 2>&1; then
n=$(echo "$json" | "$JQ" 'length')
echo "$json" | "$JQ" -c --arg lane "$lane" '.[] | {lane:$lane, name:.fullName, ...}' >> "$RAW"
COVERAGE="${COVERAGE}\n| ${label} | ✅ | ${n} |"
else
COVERAGE="${COVERAGE}\n| ${label} | ❌ | 0 |"
fi
sleep 1
}~/.claude/scout/seen.tsv (repo fullName · scoring date) blocks already-scored items. Weak duplicate detection also runs against existing skill names under 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 \
| while IFS= read -r line; do
nm=$(echo "$line" | "$JQ" -r '.name')
grep -qxF "$nm" "$SEEN_SET" 2>/dev/null && continue
echo "$line" >> "$FRESH"
doneuniqueby(.name) | sortby(-.stars) dedupes, sorts by stars descending, then takes the diff. Capping at MAX_CANDIDATES=30 locks in the cost ceiling.
To improve scoring quality, fetch the root SKILL.md content and file list for only the top MAX_ENRICH=8 lane=skill items. Everything else scores on metadata alone (stars/desc/language).
if [ "$lane" = "skill" ] && [ "$enr_count" -lt "$MAX_ENRICH" ]; then
enr_count=$((enr_count+1))
skillmd=$("$GH" api "repos/$name/contents/SKILL.md" \
--jq '.content' 2>/dev/null | base64 -d 2>/dev/null | head -c 6000)
files=$("$GH" api "repos/$name/contents" \
--jq '.[].name' 2>/dev/null | tr '\n' ',' | head -c 500)
if echo "$files" | grep -qiE '\.sh,|\.js,|hooks,|scripts,|install|setup\.'; then
has_script="true"
fi
fiThe has_script flag set here feeds into downstream safety judgment.
Feed enriched candidates into the prompt, instructing both ★1-5 scoring and file operations simultaneously. Three routing paths.
A) Auto-ingest Skills (lane=skill, skillmd present, ★4+)
The prompt's safety rules become the logic directly.
安全判定:
- allowed-tools が無い、または Read/Grep/Glob/WebFetch/WebSearch のみ → 【安全】
- has_script=true、または allowed-tools に Bash/Write/Edit 等が含まれる → 【要レビュー】
- 【安全】: ~/.claude/skills/auto/<kebab名>/ を作り SKILL.md を書く。
先頭に provenance を必ず足す:
<!-- source: github-scout | repo: <name> | url: <url> | adopted: DATE -->
既存の auto/ に同名/酷似スキルがあればスキップ(重複禁止)。fork/mirror は取り込まない。
- 【要レビュー】: .incoming/<kebab名>/ に SKILL.md を置く(有効化しない)。
ブリーフの『要対応』に列挙。Skills written to auto/ auto-enable on next session startup. .incoming/ doesn't auto-enable. To enable, use /scout-promote <name> for review-then-promote. Scripts bundled (has_script=true) always get human review.
B) OSS/Project Candidates (lane=project or skill with empty skillmd, ★4+)
Just append to ~/.claude/scout/watchlist.md. Format is - [name](url) ★N — 30字以内の理由(DATE)。clone はしない。
C) トレンド(lane=trend、★3以上)
ブリーフに1行乗せるだけ。ファイル操作なし。
ブリーフに差し込まれるセクションはこの構成になる。
## 🔭 GitHub Scout (2026-06-17)
### ⚡ 自動で入れたスキル
- foo-skill ★4 — 何ができるか1行(有効化済み)
### ⚠️ 要対応(あなたの確認待ち)
- bar-skill ★5 — 何ができるか / なぜ要レビューか / 有効化するなら: /scout-promote bar-skill
### 💡 採用候補(OSS) — watchlist追記済み
- baz-repo ★4 — 刺さりどころ1行
### 📈 トレンド横断
- trending-repo ★3 — 何が新しいか1行scoutは独立したlaunchdジョブにしていない。vault-auto-ingest.sh — called as step 2.55 right after brief generation (step 2.5).
# 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 "[$(ts)] github-scout 失敗(継続)" >> "$LOG"
SCOUT_SEC="$HOME/.claude/logs/github-scout-latest.md"
BRIEF_SRC="$VAULT/wiki/today-brief.md"
if [ -s "$SCOUT_SEC" ] && [ "$SCOUT_SEC" -nt "$START_STAMP" ] && \
[ -s "$BRIEF_SRC" ] && [ "$BRIEF_SRC" -nt "$START_STAMP" ]; then
{ echo ""; echo "---"; echo ""; cat "$SCOUT_SEC"; } >> "$BRIEF_SRC"
fiEven on failure, || echo "...(continue)" advances to the next step. Never stops the whole brief generation.
Freshness check (-nt "$STARTSTAMP") prevents stale files from being mis-appended. vault-auto-ingest.sh fires at multiple slots (4:55 / 8:15 / 10:15 / 12:15), but after success, DONEMARKER returns immediately for later slots, so once scout + brief succeed, no duplicate runs.
What happens in the scoring phase is controlled by SCOREOK flag and SESSIONLIMIT detection.
# Claude MAX 枠切れ(session limit)を専用検出
SESSION_LIMIT=0
if [ "$rc" -ne 0 ] && grep -qi "session limit" "$RUN_OUT" 2>/dev/null; then
SESSION_LIMIT=1
# リセットまで <=8 分なら待って1回リトライ
if [ "$wait_s" -ge 0 ] && [ "$wait_s" -le 480 ]; then
log "session limit — ${wait_s}s 待って1回リトライ (reset=${RESET_STR:-?})"
sleep "$wait_s"
run_claude; rc=$?
else
log "session limit — reset 遠い/不明(${wait_s}s)。待たず seen 非commit で次回巡回に委ねる"
fi
fiIf scoring output is thin (fewer than 1 dash line), set SCORE_OK=0 and enter 3-tier 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
SCORE_OK=0
# 1段目: 今回クロールの TOP 候補(生データ)を jq で整形
FB_LIST=$(head -n 8 "$TOP" | "$JQ" -r \
'"- [\(.name // "?")](\(.url // "")) \((.stars // 0))⭐ [\(.lane // "?")] — \((.desc // "")[0:60])"')
# 2段目: TOP が空なら直近 watchlist の ★4/★5 を引く
# 3段目: それでも空なら明示的な失敗行(無言の空欄にしない)
fiIn the final LEDGER step, only mark seen.tsv on scoring success.
if [ "${SCORE_OK:-1}" -eq 1 ]; then
while IFS= read -r line; do
nm=$(echo "$line" | "$JQ" -r '.name')
printf '%s\t%s\n' "$nm" "$TODAY" >> "$SEEN"
done < "$TOP"
else
log "採点未成立(SCORE_OK=0) — seen 非commit。次回巡回で再採点させる。"
fiIf SESSIONLIMIT reset is far off, also SCOREOK=0 and don't commit. Tomorrow's crawl auto-resurfaces the same candidates.
The brief footer's <details> includes a per-source coverage table.
<details><summary>scout カバレッジ</summary>
| ソース | 状態 | 件数 |
|---|---|---|
| A1 topic:claude-code | ✅ | 25 |
| B1 chrome autofill | ✅ | 12 |
| C1 breakout 90d | ❌ | 0 |
...
_raw 234 → fresh 41 → 採点 30。seen累計 187。_
</details>Following CLAUDE.md's "Multi-source Coverage" principle, failed sources show as ❌, not hidden. "Scored 30" proves MAX_CANDIDATES cap is working — costs are locked in.
The pieces built in this series (4-layer memory / self-growing skills / context reduction / launchd / autopilot / long-term memory) come together here. GitHub discoveries land in the brief, good skills auto-enable by tomorrow. The environment has one continuous "read and grow" loop.
Next time: how context injection bloated as skills and briefs accumulated daily — **228KBから48KBに削ったコンテキスト監査**.
Lily (@bokuwalily) — Solo developer. Building automation foundations with Claude Code while shipping iOS apps and web services at scale.
◼︎ Apps I've made are collected at **ポートフォリオ**📱
◼︎ New releases and dev stories on X **@bokuwalily**🐦
◼︎ OSS: **github.com/bokuwalily**🐙
Your ❤️ and shares keep me going!
前回「Claude Codeを無人で自律改善させる」で朝ブリーフの骨格を作った。今回はそのブリーフ生成ジョブに相乗りさせる形で、GitHubを毎朝巡回して有用なOSSとスキルを自動採点し、要対応だけをデスクトップのブリーフに差し込む github-scout.sh を作った話を書く。
設計のポイントは3つ。クロール(gh、無料)と採点(claude -p、MAX枠)を分けてコストを固定化すること。スキルの安全性をファイル構成で機械判定して自動有効化か要レビュー隔離かに振り分けること。採点失敗時は seen 台帳に刻まず翌朝の自動リトライに委ねること。
Claude Codeスキルはコミュニティ製のものもGitHubに転がっている。就活トラッカーやChrome拡張の参考OSSも同様だ。ところが「気が向いたとき手動サーチ」では再現性がない。毎回同じ人気リポしか引っかからず、先週見つけたOSSを翌週には忘れる。
有用なスキルを見逃したまま自分で同じものを書き直す、という無駄がどれだけあったか数えられない。朝ブリーフが来る仕組みはすでにある。そこにGitHubの発見を自動で差し込むのが最短の解決だった。
スクリプトのヘッダコメントにそのまま書いてある。
# CRAWL(gh=無料) -> DEDUP(shell) -> ENRICH(gh contents) -> SCORE+ROUTE+INGEST(claude -p=MAX枠) -> LEDGERコストが発生するのは採点フェーズだけ。候補数に上限を設けることで採点のトークン消費を固定化している。
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>/ に自動有効化
# - Bash/script 同梱スキル: ~/.claude/skills/auto/.incoming/<name>/ に隔離 + 要対応フラグ
# - OSS/トレンド候補: ~/.claude/scout/watchlist.md に追記(clone しない)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 skill "A3 claude agent skill" "claude agent skill SKILL.md" --sort updated --order desc --limit 20
# B: 自分の開発に直結する OSS(autofill / maps scraper / turso / resume builder / job tracker 等)
run_search project "B1 chrome autofill" "autofill" --language JavaScript --stars ">100" --sort stars --order desc --limit 12
run_search project "B3 turso" "turso" --language TypeScript --stars ">50" --sort updated --order desc --limit 12
run_search project "B5 job tracker" "job tracker" --stars ">30" --sort stars --order desc --limit 12
# ... B2/B4/B6/B7 略
# C: トレンド横断
run_search trend "C1 breakout 90d" --created ">$D90" --stars ">800" --sort stars --order desc --limit 20
run_search trend "C2 hot now" --updated ">$D3" --stars ">3000" --sort updated --order desc --limit 20各 run_search は失敗してもカバレッジに ❌ を記録して続行する。全ソース成功しなくても止まらない。レート制限対策で各検索後に sleep 1 を入れている(GitHub Search API: 30 req/min)。
B系クエリは最初、全語ANDで複数トピックを重ねていたが0件が続出した。コメントに v2: 2026-06-10実測調整 とある通り、コア語+言語+stars下限に緩めた。複合クエリは試して調整するしかない。
run_search 関数はレーンラベルを付けた JSONL を raw.jsonl に追記する構造になっている。
run_search() {
local lane="$1"; shift; local label="$1"; shift
local json
json=$("$GH" search repos "$@" --json fullName,description,stargazersCount,url,language,pushedAt,createdAt 2>>"$LOG")
if [ -n "$json" ] && echo "$json" | "$JQ" -e 'type=="array"' >/dev/null 2>&1; then
n=$(echo "$json" | "$JQ" 'length')
echo "$json" | "$JQ" -c --arg lane "$lane" '.[] | {lane:$lane, name:.fullName, ...}' >> "$RAW"
COVERAGE="${COVERAGE}\n| ${label} | ✅ | ${n} |"
else
COVERAGE="${COVERAGE}\n| ${label} | ❌ | 0 |"
fi
sleep 1
}~/.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 \
| while IFS= read -r line; do
nm=$(echo "$line" | "$JQ" -r '.name')
grep -qxF "$nm" "$SEEN_SET" 2>/dev/null && continue
echo "$line" >> "$FRESH"
doneuniqueby(.name) | sortby(-.stars) で重複除去→stars降順に並べてから差分を取る。上位 MAX_CANDIDATES=30 に絞った時点でコスト上限が確定する。
採点の質を上げるため、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" \
--jq '.content' 2>/dev/null | base64 -d 2>/dev/null | head -c 6000)
files=$("$GH" api "repos/$name/contents" \
--jq '.[].name' 2>/dev/null | tr '\n' ',' | head -c 500)
if echo "$files" | grep -qiE '\.sh,|\.js,|hooks,|scripts,|install|setup\.'; then
has_script="true"
fi
fiここで立てた has_script フラグが後段の安全判定に使われる。
ENRICHedな候補をまとめてプロンプトに渡し、★1-5採点とファイル操作を同時に指示する。振り分けは3経路。
A) スキルの自動取り込み(lane=skill、skillmdあり、★4以上)
プロンプトの安全判定ルールがそのままロジックになっている。
安全判定:
- allowed-tools が無い、または Read/Grep/Glob/WebFetch/WebSearch のみ → 【安全】
- has_script=true、または allowed-tools に Bash/Write/Edit 等が含まれる → 【要レビュー】
- 【安全】: ~/.claude/skills/auto/<kebab名>/ を作り SKILL.md を書く。
先頭に provenance を必ず足す:
<!-- source: github-scout | repo: <name> | url: <url> | adopted: DATE -->
既存の auto/ に同名/酷似スキルがあればスキップ(重複禁止)。fork/mirror は取り込まない。
- 【要レビュー】: .incoming/<kebab名>/ に SKILL.md を置く(有効化しない)。
ブリーフの『要対応』に列挙。auto/ に書かれたスキルは次回セッション起動時に自動で有効化される。.incoming/ は有効化されない。有効化したければ /scout-promote <name> でレビュー後に昇格させる設計になっている。スクリプト同梱(has_script=true)は必ず人間がレビューする。
B) OSS/プロジェクト候補(lane=project または skill で skillmd空、★4以上)
~/.claude/scout/watchlist.md に追記するだけ。形式は - [name](url) ★N — 30字以内の理由(DATE)。clone はしない。
C) トレンド(lane=trend、★3以上)
ブリーフに1行乗せるだけ。ファイル操作なし。
ブリーフに差し込まれるセクションはこの構成になる。
## 🔭 GitHub Scout (2026-06-17)
### ⚡ 自動で入れたスキル
- foo-skill ★4 — 何ができるか1行(有効化済み)
### ⚠️ 要対応(あなたの確認待ち)
- bar-skill ★5 — 何ができるか / なぜ要レビューか / 有効化するなら: /scout-promote bar-skill
### 💡 採用候補(OSS) — watchlist追記済み
- baz-repo ★4 — 刺さりどころ1行
### 📈 トレンド横断
- trending-repo ★3 — 何が新しいか1行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 "[$(ts)] github-scout 失敗(継続)" >> "$LOG"
SCOUT_SEC="$HOME/.claude/logs/github-scout-latest.md"
BRIEF_SRC="$VAULT/wiki/today-brief.md"
if [ -s "$SCOUT_SEC" ] && [ "$SCOUT_SEC" -nt "$START_STAMP" ] && \
[ -s "$BRIEF_SRC" ] && [ "$BRIEF_SRC" -nt "$START_STAMP" ]; then
{ echo ""; echo "---"; echo ""; cat "$SCOUT_SEC"; } >> "$BRIEF_SRC"
fi失敗しても || echo "...(継続)" で次のステップに進む。ブリーフ生成全体を止めない。
鮮度チェック(-nt "$STARTSTAMP")で古いファイルが誤追記されるのを防いでいる。vault-auto-ingest.sh は 4:55 / 8:15 / 10:15 / 12:15 の複数スロットで発火するが、成功後は DONEMARKER で以降のスロットを即returnするため、scout含めブリーフ全体が一度成功すれば重複実行されない。
採点フェーズで何が起きるかを制御しているのが SCOREOK フラグと SESSIONLIMIT 検出。
# Claude MAX 枠切れ(session limit)を専用検出
SESSION_LIMIT=0
if [ "$rc" -ne 0 ] && grep -qi "session limit" "$RUN_OUT" 2>/dev/null; then
SESSION_LIMIT=1
# リセットまで <=8 分なら待って1回リトライ
if [ "$wait_s" -ge 0 ] && [ "$wait_s" -le 480 ]; then
log "session limit — ${wait_s}s 待って1回リトライ (reset=${RESET_STR:-?})"
sleep "$wait_s"
run_claude; rc=$?
else
log "session limit — reset 遠い/不明(${wait_s}s)。待たず seen 非commit で次回巡回に委ねる"
fi
fi採点結果の中身が薄い(- 行が1件未満)場合は SCORE_OK=0 にして3段フォールバックに入る。
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
SCORE_OK=0
# 1段目: 今回クロールの TOP 候補(生データ)を jq で整形
FB_LIST=$(head -n 8 "$TOP" | "$JQ" -r \
'"- [\(.name // "?")](\(.url // "")) \((.stars // 0))⭐ [\(.lane // "?")] — \((.desc // "")[0:60])"')
# 2段目: TOP が空なら直近 watchlist の ★4/★5 を引く
# 3段目: それでも空なら明示的な失敗行(無言の空欄にしない)
fi最後のLEDGERステップで、採点成功時だけ seen.tsv に刻む。
if [ "${SCORE_OK:-1}" -eq 1 ]; then
while IFS= read -r line; do
nm=$(echo "$line" | "$JQ" -r '.name')
printf '%s\t%s\n' "$nm" "$TODAY" >> "$SEEN"
done < "$TOP"
else
log "採点未成立(SCORE_OK=0) — seen 非commit。次回巡回で再採点させる。"
fiSESSIONLIMITでリセットが遠い場合も SCOREOK=0 と同じく非commit。翌朝の巡回で同じ候補が自動的に再浮上する。
ブリーフ末尾の <details> にソース別のカバレッジ表が付く。
<details><summary>scout カバレッジ</summary>
| ソース | 状態 | 件数 |
|---|---|---|
| A1 topic:claude-code | ✅ | 25 |
| B1 chrome autofill | ✅ | 12 |
| C1 breakout 90d | ❌ | 0 |
...
_raw 234 → fresh 41 → 採点 30。seen累計 187。_
</details>CLAUDE.mdの「Multi-source Coverage」方針に従い、失敗したソースを隠さず ❌ で出す。「採点 30」が MAX_CANDIDATES のcapが効いている証拠で、コストが固定されていることが読み取れる。
このシリーズで作ってきたパーツ(4層記憶 / 自己増殖スキル / コンテキスト削減 / launchd / autopilot / 長期記憶)がここで一つながりになった。GitHubの発見がブリーフに乗り、良いスキルは翌日から自動で使えるようになる。環境が「読んで育つ」ループが一本つながっている。
次回は、この毎朝積み上がるスキルとブリーフが増えるにつれてコンテキスト注入が肥大化した話 ―― **228KBから48KBに削ったコンテキスト監査**を書いた。
Lily(@bokuwalily)― 個人開発者。Claude Code で自動化基盤を組みながら、iOSアプリやWebサービスを量産しています
◼︎作ったアプリは **ポートフォリオ** にまとめています📱
◼︎新着・開発の裏側は X **@bokuwalily** で発信しています🐦
◼︎OSS: **github.com/bokuwalily**🐙
皆さんの ❤️ やシェアが励みになります!