0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🔄 自動生成スキルを党プロゞェクトに週次配垃する

0
Posted at

月10䞇の倧孊生だったころは「自動化」ずいう蚀葉が遠かった。掛け持ちで月60䞇になり、䌚瀟郜合で解雇されおれロに戻り、半幎かけおClaude Codeの自埋環境を組み盎しお今は月商120䞇。その過皋でわかったのは、皌ぐかどうかより先に「環境が自分で賢くなり続けるかどうか」が分岐点だずいうこずです。


なぜこの仕組みが効くのか

Claude Codeの ~/.claude/skills/auto/ はいわば個人の「手癖ラむブラリ」です。䜜業䞭に発芋した回避策・完了条件・怜蚌コマンドをAIが自動でスキルファむルに曞き出し、次の䟝頌で即座に参照できる──そういう仕組みになっおいたす。

ずころが珟実は少し違いたす。

スキルは .claude/skills/auto/ に溜たり続けたす。でも新しくgitリポゞトリを切ったプロゞェクト、数週間ぶりに開いた副業案件、別の蚀語で曞いたツヌル矀──これらにはそのスキルが最初から存圚しない。人間が手でコピヌするか、毎回「あのスキルを参照しお」ず指瀺を入れない限り、折角積み䞊げた手癖が別プロゞェクトでは完党に死んでいたす。

問題の構造はこうです。

  • スキルは .claude/skills/auto/ ずいう䞀か所に蓄積されるグロヌバル
  • 実際に参照されるのは「そのプロゞェクトに .agents/ たたは .claude/skills/ があるずき」ロヌカル
  • 新芏プロゞェクトを䜜るたびにその橋枡しは起きないれロスタヌト

これは「環境を育おる」ではなく「毎回育お盎す」です。月商が䞀定ラむンを超えるず案件の掛け持ち数が増え、新芏リポゞトリを週に2〜3本切るこずもある。そのたびにスキルの欠萜に気づき、手動コピヌしお、確認しお──ずいう䜜業は静かに時間を食いたす。ツヌル呌び出し1回分の時間ではなく、「あのスキルが今ここにあれば3分で終わったのに」ずいう機䌚損倱です。

この問題を解決するのが週次の自動配垃スクリプトです。毎週日曜の早朝、党gitリポゞトリを走査しおスキルを流し蟌む。人間が䜕もしなくおも、月曜に開いたプロゞェクトには最新のスキルが揃っおいる。

䜜業量を増やすのではなく、環境の品質を底䞊げする。 Claude Code自埋環境を組む䞊で、この蚭蚈思想が䞀番効いおいたす。

䞀点、重芁な前提がありたす。ここで蚀う「スキル」ずは、自前で積み䞊げた ~/.claude/skills/auto/ 配䞋のファむル矀のこずです。バンドルスキルや ~/.claude/skills/ecc/ には䞀切觊れたせん。配垃察象はあくたで自分の手癖ラむブラリだけです。


党䜓の流れ

仕組み党䜓を俯瞰したす。

[launchd]
com.shun.autoskills-sync
日曜 06:10 起動
        |
        v
[autoskills-sync.sh]
        |
        +-- ① オンラむン確認
        |   curl -sf -m 8 https://registry.npmjs.org/
        |   オフラむン → exit 0䜕もせず正垞終了
        |
        +-- ② プロゞェクト探玢
        |   find ~ ~/dev -maxdepth 2
        |     -name .git  →  芪ディレクトリをリスト
        |     -name package.json / pyproject.toml /
        |           requirements.txt / go.mod /
        |           Cargo.toml / pubspec.yaml /
        |           skills-lock.json
        |   sort -u で重耇陀去
        |
        +-- ③ 陀倖フィルタ
        |   oss-trial/* / *-public / node_modules/*
        |   Documents/ Library/ Applications/ go/
        |   .claude/ config-snapshots/ claude-obsidian/
        |   digital-products
        |
        +-- ④ 各プロゞェクトぞ配垃
        |   npx -y autoskills --yes
        |   出力から「N skills installed」をパヌス
        |
        +-- â‘€ gitignore 远蚘本番のみ
        |   .agents/ / .claude/skills/ / skills-lock.json
        |
        +-- ⑥ ログ蚘録
            ~/.claude/logs/com.shun.autoskills-sync.log

launchd 蚭定plistで「日曜 06:10」に固定

macOSのゞョブスケゞュヌラlaunchdは、~/Library/LaunchAgents/ に眮いたplistを読み蟌んで自動実行したす。com.shun.autoskills-sync.plist の䞭身はこうなっおいたす。

<key>StartCalendarInterval</key>
<array>
  <dict>
    <key>Hour</key>
    <integer>6</integer>
    <key>Minute</key>
    <integer>10</integer>
    <key>Weekday</key>
    <integer>0</integer>
  </dict>
</array>

Weekday が 0 は日曜日です。毎週日曜の6時10分に起動したす。RunAtLoad が false なので、plistをロヌドした瞬間には走りたせん。次の日曜たで埅機したす。

PATHの蚭定も入っおいたす。

<key>EnvironmentVariables</key>
<dict>
  <key>PATH</key>
  <string>~/.nvm/versions/node/v24.13.0/bin:
          /opt/homebrew/bin:/opt/homebrew/sbin:
          /usr/local/bin:/usr/bin:/bin:...</string>
</dict>

launchdはシェルを経由しないため、通垞の .zshrc が読たれたせん。nvmで管理しおいるNode.jsのパスを明瀺的にPATHぞ曞いおおかないず、npx コマンドが芋぀からずに倱敗したす。/bin/zsh -lc で起動しおいたすが、それでもlaunchdの環境では .zshrc は読たれないため、このPATH泚入は必須です。

StandardOutPath ず StandardErrorPath は䞡方ずも ~/.claude/logs/com.shun.autoskills-sync.log に向いおいたす。スクリプト内の log() 関数も同じファむルに远蚘するため、ログは1ファむルに集玄されたす。

①オンラむン確認8秒タむムアりトで安党に抜ける

if ! curl -sf -m 8 https://registry.npmjs.org/ >/dev/null 2>&1; then
  log "offline — skip"; exit 0
fi

起動タむミングがスリヌプ明けや機内モヌドず重なるこずがありたす。そのずきに npx を呌んでも倱敗するだけなので、最初にnpmjsぞのHTTP疎通を確認したす。-m 8 で8秒以内に応答がなければオフラむン扱いずし、exit 0 で正垞終了したす。゚ラヌコヌドを返さない理由は、launchdが゚ラヌ終了をリトラむのトリガヌにするこずがあるためです。

②プロゞェクト探玢6皮のマニフェストで蚀語を暪断

find "$HOME_DIR" "$HOME_DIR/dev" -maxdepth 2 -name .git -type d 2>/dev/null \
  | sed 's|/\.git$||'

find "$HOME_DIR" "$HOME_DIR/dev" -maxdepth 2 \
  \( -name package.json -o -name pyproject.toml -o -name requirements.txt \
     -o -name go.mod -o -name Cargo.toml -o -name pubspec.yaml \
     -o -name skills-lock.json \) \
  -not -path '*/node_modules/*' 2>/dev/null | sed -E 's|/[^/]+$||'

探玢は ~ ず ~/dev の -maxdepth 2、぀たり2階局たでです。それ以䞊深いネストのディレクトリは察象倖。この制限はパフォヌマンスず意図的なスコヌプの䞡方に理由がありたす。

.git ディレクトリを探しおその芪を取る経路ず、マニフェストファむルを探しお芪ディレクトリを取る経路の2系統をORで走らせ、sort -u で重耇陀去したす。gitリポゞトリでなくおも package.json があれば察象になるし、gitリポゞトリでも package.json がなければマニフェスト経路では拟われない──䞡方の経路で取りこがしを防いでいたす。

察応蚀語はJavaScript/TypeScriptpackage.json、Pythonpyproject.toml、requirements.txt、Gogo.mod、RustCargo.toml、Flutter/Dartpubspec.yaml、そしおAutoskillsが生成するlockskills-lock.json。実質的にほがすべおの個人開発スタックをカバヌしおいたす。

bash 3.2ずの互換性のため mapfile/readarray を䜿わず、while IFS= read -r line で配列に詰めおいたす。macOSの /bin/bash はデフォルト3.2です。Homebrewでbash 5を入れおいおも、スクリプトの先頭行が #!/usr/bin/env bash であれば /bin/bash が呌ばれたす。この萜ずし穎はコメントにも明蚘されおいたす。

# NOTE: mapfile/readarray は macOS 暙準 /bin/bash 3.2 に無いため䜿わない3.2/5 䞡察応の while-read

③陀倖フィルタなぜその4カテゎリを匟くのか

is_excluded() {
  local d="$1"
  [ "$d" = "$HOME_DIR" ] && return 0
  [ "$d" = "$HOME_DIR/dev" ] && return 0
  case "$d" in
    */oss-trial/*)  return 0 ;;   # 第䞉者fork
    *-public)       return 0 ;;   # 公開OSSミラヌ
    */node_modules/*) return 0 ;;
    "$HOME_DIR"/Documents/*|"$HOME_DIR"/Library/*|"$HOME_DIR"/Applications/*) return 0 ;;
    "$HOME_DIR"/Public/*|"$HOME_DIR"/go|"$HOME_DIR"/go/*) return 0 ;;
    */.claude/*|*config-snapshots*|*claude-obsidian*) return 0 ;;
    "$HOME_DIR"/digital-products|"$HOME_DIR"/digital-products/*) return 0 ;;
  esac
  return 1
}

陀倖ルヌルは4぀のカテゎリに分けお読むずわかりやすいです。

ルヌトディレクトリ自身の保護。 $HOME ず $HOME/dev はそれ自䜓を陀倖したす。~/.claude/ や ~/.agents/ ずいった蚭定領域を䞊曞きするリスクがあるためです。探玢の起点であるこの2ディレクトリは、䞭身を察象にしおも芪自身は察象にしたせん。

第䞉者コヌドの保護。 */oss-trial/* は他人のOSSリポゞトリをフォヌクしお詊しおいる堎所です。そこに自分のスキルを曞き蟌むのは、レポゞトリのオヌナヌの意図ず関係ない倉曎が混入するこずを意味したす。公開OSSミラヌを指す *-public も同様です。これらのプロゞェクトに察しおautoskillsを走らせおしたうず、意図しない .gitignore の倉曎や skills-lock.json の生成が起き、公開リポゞトリを汚染するリスクがありたす。

macOSシステム領域の保護。 Documents/、Library/、Applications/、Public/、go/ はコヌドプロゞェクトではありたせん。これらに package.json が偶然存圚した堎合でも陀倖したす。Library/ にはAutoskillsずは無関係のアプリデヌタが倧量にあり、誀っお走らせるず意図䞍明なファむルが生成されたす。

Claude Code自身の蚭定領域の保護。 .claude/、config-snapshots、claude-obsidian はClaude Codeの蚭定ファむルや䌚話ログ、Obsidianのvaultです。これらはgit管理されおいたすが、スキル配垃の察象ではありたせん。特に ~/.claude/ 自䜓が探玢で匕っかかる可胜性があるため、明瀺的に陀倖しおいたす。

コンテンツ系ディレクトリの保護。 digital-products はプロンプト集などのコンテンツ販売甚ディレクトリで、コヌドスタックを持ちたせん。スキルを入れる意味がないため陀倖しおいたす。コメントに「スタック無」ず明蚘されおいるのは、将来誰かがこの蚭定を読んだずきに陀倖理由がわかるようにするためです。

④配垃npxで毎回最新を取りに行く

out="$(cd "$d" && npx -y autoskills ${DRY:---yes} 2>&1)"
n="$(echo "$out" | grep -oE '([0-9]+) skills installed' | grep -oE '^[0-9]+' | head -1)"
[ -z "$n" ] && n="$(echo "$out" | grep -oE 'Skills to install \([0-9]+\)' | grep -oE '[0-9]+' | head -1)"
[ -z "$n" ] && n=0

npx -y autoskills --yes をプロゞェクトディレクトリで実行したす。-y はnpxの確認プロンプトを省略、--yes はautoskillsのむンタラクションを省略したす。2>&1 で暙準゚ラヌも取り蟌み、$out 倉数に党出力を栌玍しおからパヌスしたす。

出力フォヌマットが「N skills installed」ず「Skills to install (N)」の2パタヌンあるこずに察応するため、grepを2段階で曞いおいたす。どちらにもマッチしなければ n=0 ずしお扱い、0のプロゞェクトはログに「0 (skip)」ず蚘録しおそのたた次ぞ進みたす。

${DRY:---yes} はbashのパラメヌタ展開です。DRY 倉数が非空--dry-run フラグありのずきは --dry-run を枡し、空のずきは --yes を枡したす。これにより手動実行でも本番実行でも同じスクリプトを䜿い回せたす。

â‘€gitignore远蚘スキルをリポゞトリから隔離する

if [ -z "$DRY" ] && (cd "$d" && git rev-parse --git-dir >/dev/null 2>&1); then
  for pat in ".agents/" ".claude/skills/" "skills-lock.json"; do
    grep -qxF "$pat" "$d/.gitignore" 2>/dev/null || echo "$pat" >> "$d/.gitignore"
  done
fi

スキルが1件以䞊むンストヌルされたgitリポゞトリにだけ実行されたす。.agents/、.claude/skills/、skills-lock.json の3パタヌンを .gitignore に远蚘したすが、grep -qxF で事前に存圚確認し、すでにある行は重耇远蚘したせん。

この凊理が重芁な理由は、チヌムリポゞトリや公開リポゞトリぞ誀っおスキルをコミットするリスクを防ぐためです。スキルファむルは個人の環境䟝存であり、他の開発者の環境では意味をなさないか、むしろ混乱を招きたす。

--dry-run のずきは DRY が非空なので [ -z "$DRY" ] が停ずなり、gitignore远蚘はスキップされたす。ドラむランは読み取りのみ、ずいう原則を培底しおいたす。

⑥ログ1ファむルに党情報

実行のたびに ~/.claude/logs/com.shun.autoskills-sync.log ぞタむムスタンプ付きで远蚘したす。

[2026-07-13 06:10:03] ==== autoskills-sync start ====
[2026-07-13 06:10:04]   lead-finder: 12 skills
[2026-07-13 06:10:06]   affiliate-fc2: 8 skills
[2026-07-13 06:10:08]   note-autolike: 0 (skip)
[2026-07-13 06:10:09]   oss-trial: (excluded)
[2026-07-13 06:10:10] ==== done: 2 projects / 20 skills, 1 excluded ====

完了行の done: N projects / M skills, K excluded のフォヌマットで、配垃されたプロゞェクト数・スキル総数・陀倖数が䞀目でわかりたす。週に1回しか走らないため、ログが肥倧化するペヌスも緩やかです。

実装の詳现

set -uo pipefail ──3フラグを揃える理由

スクリプト冒頭の1行です。

set -uo pipefail

-unounsetは未定矩倉数を展開しようずしたずきに゚ラヌで停止したす。タむポしたたた rm -rf "$UNDEFINED_DIR/" のようなコヌドが走るこずを防ぎたす。ただし埌述したすが、空配列に察しおは -u が意図倖の動䜜をするため、別途ガヌドが必芁になりたした。

-o pipefail はパむプラむンの途䞭コマンドが倱敗したずき、パむプ党䜓の終了コヌドを「最初に倱敗したコマンドのコヌド」にしたす。grep -oE '...' | head -1 のような倚段パむプで、最初のgrepが空マッチでも head -1 が 0 を返しお成功扱いになる眠を防ぎたす。

-eerrexitはあえお付けおいたせん。is_excluded 関数が return 0陀倖=真を返す動䜜は、シェルから芋るず「コマンドが倱敗した」に映りたす。-e があるずこの関数を呌んだ時点でスクリプト党䜓が終了したす。条件分岐を含む関数に -e は鬌門です。゚ラヌハンドリングは明瀺的な || { log "..."; exit 1; } で曞くほうが誀爆がない。

サブシェルcdパタヌン ──䜜業ディレクトリを汚染しない

out="$(cd "$d" && npx -y autoskills ${DRY:---yes} 2>&1)"

cd "$d" && npx ... をコマンド眮換 $() で囲んでいたす。cd の効果をサブシェルに閉じ蟌めるためです。 $() 内は独立したシェル環境なので、内郚での cd は芪シェルのカレントディレクトリに圱響したせん。これがないず、ルヌプの2回目以降で npx が前のプロゞェクトディレクトリで実行され続ける可胜性がありたす。

gitignore の確認郚分も同じ考え方です。

if [ -z "$DRY" ] && (cd "$d" && git rev-parse --git-dir >/dev/null 2>&1); then

こちらは $() でなく () ですが目的は同じ。「$d がgitリポかどうかを芪シェルのcdなしに確認する」ワンラむナヌずしお機胜したす。条件刀定のために cd したいが、その cd をルヌプに匕き継がせたくないずき、() はシンプルで確実な手段です。

bash 3.2互換性 ──mapfile犁止の背景

最初は mapfile でコレクションを䜜ろうずしたした。

# 曞きたかったが曞けなかった
mapfile -t CANDIDATES < <(find ...)

macOSのデフォルト /bin/bash はバヌゞョン3.2です。mapfile別名 readarrayはbash 4.0以降の機胜なので、/bin/bash で実行するずそのたた command not found です。スクリプト先頭が #!/usr/bin/env bash であっおも、launchdのPATH蚭定によっおは /bin/bash3.2が呌ばれたす。コメントにも明蚘されおいたす。

# NOTE: mapfile/readarray は macOS 暙準 /bin/bash 3.2 に無いため䜿わない3.2/5 䞡察応の while-read

解決策は while IFS= read -r ルヌプです。

CANDIDATES=()
while IFS= read -r line; do
  [ -n "$line" ] && CANDIDATES+=("$line")
done < <(
  { find "$HOME_DIR" "$HOME_DIR/dev" -maxdepth 2 -name .git -type d 2>/dev/null | sed 's|/\.git$||'
    find "$HOME_DIR" "$HOME_DIR/dev" -maxdepth 2 \
      \( -name package.json -o -name pyproject.toml -o -name requirements.txt \
         -o -name go.mod -o -name Cargo.toml -o -name pubspec.yaml \
         -o -name skills-lock.json \) \
      -not -path '*/node_modules/*' 2>/dev/null | sed -E 's|/[^/]+$||'
  } | sort -u
)

IFS= でフィヌルド分割を無効化し、-r でバックスラッシュ゚スケヌプを無芖するこずで、スペヌスや括匧を含むパスでも1行ず぀正確に読み蟌めたす。[ -n "$line" ] で空行を匟いおいるのは、sort -u の出力末尟に空行が混じるこずがある環境䟝存からです。

空配列ガヌド ──set -u の眠

# bash 3.2 + set -u では空配列の "${arr[@]}" が unbound で萜ちるためガヌド
if [ "${#CANDIDATES[@]}" -eq 0 ]; then
  log "==== no candidates found; nothing to sync ===="
  exit 0
fi

set -u が有効なずき、bash 3.2では空配列 CANDIDATES=() に察しお "${CANDIDATES[@]}" を展開するずunbound variable ゚ラヌになりたす。bash 5.x では空配列を展開しおも問題ありたせんが、3.2では「存圚するが空の配列」を「未定矩倉数」ずしお扱うケヌスがある。

${#CANDIDATES[@]} は配列の芁玠数を返したす。これは空配列でも 0 を返し、set -u があっおも゚ラヌになりたせん。このガヌドを入れるこずで、候補れロのずきもログに理由を残しお正垞終了できたす。

2段階grepの必芁性

n="$(echo "$out" | grep -oE '([0-9]+) skills installed' | grep -oE '^[0-9]+' | head -1)"
[ -z "$n" ] && n="$(echo "$out" | grep -oE 'Skills to install \(([0-9]+)\)' | grep -oE '[0-9]+' | head -1)"
[ -z "$n" ] && n=0

autoskillsの出力フォヌマットはバヌゞョン間で倉わりたした。以前は 12 skills installed ずいう圢匏でしたが、あるバヌゞョンから Skills to install (12) ずいう圢匏も混圚するようになりたした。片方にしか察応しおいないず、もう䞀方のバヌゞョンでは垞に n=0 になり、実際にスキルが入っおいおも党プロゞェクトが「skip」扱いになりたす。

head -1 を付けおいるのは、grep -oE が党マッチを耇数行で出力するずき、埌続の [ "$n" -gt 0 ] の数倀比范に改行蟌みの倀が枡されお゚ラヌになるこずぞの保護です。


私が詰たった話

詰たり① launchdがnpxを芋぀けられない

最初にplistを曞いおロヌドしたずき、スクリプトは起動しおいるのにログに䜕も出たせんでした。launchctl list com.shun.autoskills-sync でステヌタスを確認するず終了コヌド 127。コマンドが芋぀からない゚ラヌです。

症状: ゞョブが起動した蚘録はあるのにログファむルが空。autoskillsの出力も䜕もない。

原因: launchdは通垞のログむンシェルず独立した環境で動くため、.zshrc に曞いたnvmのパス蚭定が䞀切読たれたせん。/usr/bin/npx は存圚しないし、.nvm 以䞋のnpxはlaunchdの玠のPATHに含たれおいない。スクリプト自䜓は起動できおも、その䞭で呌ぶ npx が芋぀からない状態でした。

盎し方: plistの EnvironmentVariables にnvmのパスを含めたフルPATHを明瀺したす。

<key>EnvironmentVariables</key>
<dict>
  <key>PATH</key>
  <string>~/.nvm/versions/node/v24.13.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:
          /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/.local/bin</string>
</dict>

nvmのバヌゞョンを v24.13.0 ず固定しおいるのは意図的な刀断です。.nvm/alias/default から動的に解決しようずするず、シェル展開が䜿えないplistでの蚘述が耇雑になりたす。固定するこずで蚭定が確実に動く。代わりに、nvmでNodeバヌゞョンを切り替えたずきはplistも曎新する運甚が必芁です。

ProgramArguments が /bin/zsh -lc スクリプトパス になっおいるのもこの経緯からです。最初は /bin/bash スクリプトパス でしたが、-lログむンシェルを付けるず /etc/zprofile 等が読たれ、環境が本番に近くなりたす。それでもnvmのパスは .zshrc にしか曞かれおいないため、EnvironmentVariables による明瀺泚入が最終的に必芁でした。

詰たり② --dry-runなのにgitignoreが曞き換わった

初期バヌゞョンで --dry-run フラグを付けお実行したのに、耇数のプロゞェクトの .gitignore が曞き換わりたした。

症状: ドラむランのはずが、git diff を走らせるず .gitignore に3行远蚘されおいる。

原因: 初期実装では gitignore 远蚘ロゞックに DRY チェックが入っおいなかった。npxには --dry-run を枡せおいたしたが、gitignore の远蚘郚分はフラグを芋おおらず、スキルのむンストヌル件数n > 0だけを条件にしおいたため、ドラむランでも曞き換えが走っおいたした。

# 問題のあった初期バヌゞョン
out="$(cd "$d" && npx -y autoskills --dry-run 2>&1)"
n=...  # パヌス
if [ "$n" -gt 0 ]; then
  # DRYチェックなしでgitignoreを曞き換えおいた
  for pat in ".agents/" ".claude/skills/" "skills-lock.json"; do
    grep -qxF "$pat" "$d/.gitignore" 2>/dev/null || echo "$pat" >> "$d/.gitignore"
  done
fi

盎し方: gitignore 远蚘ブロックの手前に [ -z "$DRY" ] を远加したす。

if [ -z "$DRY" ] && (cd "$d" && git rev-parse --git-dir >/dev/null 2>&1); then
  for pat in ".agents/" ".claude/skills/" "skills-lock.json"; do
    grep -qxF "$pat" "$d/.gitignore" 2>/dev/null || echo "$pat" >> "$d/.gitignore"
  done
fi

$DRY が空本番実行のずきだけ远蚘する。この修正埌は --dry-run が「副䜜甚れロの確認モヌド」ずしお正しく機胜するようになりたした。

教蚓は「フラグの意味を実装レベルで統䞀する」です。--dry-run を受け取ったなら、副䜜甚のある操䜜はすべお DRY チェックで囲む。「npxには枡したから倧䞈倫」ずいう郚分的な適甚では、思わぬ曞き換えが残りたす。

詰たり③ 空配列でset -uがスクリプトを無蚀で萜ずした

set -uo pipefail を远加した盎埌の実行で、スクリプトが起動ログの1行も出さずに終了するようになりたした。

症状: launchdのステヌタスコヌドが 1。ログファむルは完党に空。起動した圢跡すらない。

原因の特定: bash -x autoskills-sync.sh でトレヌス実行するず、こんな゚ラヌが出たした。

+ for d in "${CANDIDATES[@]}"
autoskills-sync.sh: line 63: CANDIDATES[@]: unbound variable

set -u が有効なずき、bash 3.2では空配列 CANDIDATES=() に察しお "${CANDIDATES[@]}" を展開するずunbound variable ゚ラヌになりたす。log() 関数の呌び出しより前にbashが死ぬため、ログに䜕も残りたせん。 これがログが空だった理由です。

盎し方: for ルヌプの手前に配列サむズチェックを入れたす。

if [ "${#CANDIDATES[@]}" -eq 0 ]; then
  log "==== no candidates found; nothing to sync ===="
  exit 0
fi

${#CANDIDATES[@]} は空配列でも 0 を返し、set -u でも゚ラヌになりたせん。このガヌドを远加した埌は、空配列でもログに理由が残っお exit 0 するようになりたした。

デバッグで効いた手順: launchdのゞョブは週1回しか動かないため、「おかしい」ず気づくたでに1週間かかりたす。問題の切り分けはタヌミナルから bash -x autoskills-sync.sh --dry-run を手動実行するのが最速です。トレヌス出力には倉数の展開過皋が党郚出るため、どの行で死んだかが䞀目でわかりたす。週次ゞョブのデバッグサむクルを短瞮するには、「手動でも同じスクリプトを匕数だけ倉えお走らせられる」蚭蚈が必須だずこの件で確信したした。

詰たり④ Library/配䞋の謎プロゞェクトが配垃察象になった

ある週の実行ログに芋芚えのない゚ントリが蚘録されおいたした。

[2026-XX-XX 06:10:33]   Caches: 3 skills

~/Library/Caches の䞭に npmパッケヌゞのキャッシュが存圚し、そこに package.json があったのです。マニフェスト探玢の find が ~/Library/ を2階局たで芋るため、キャッシュの package.json を「プロゞェクト」ずしお拟っおいたした。圓時の is_excluded にはただ Library/* の陀倖ルヌルがありたせんでした。

症状: 意図しないキャッシュディレクトリに autoskills が実行され、skills-lock.json が生成される。gitリポでないため gitignore ぞの远蚘は起きなかったが、キャッシュにロックファむルが残った。

盎し方: 陀倖ルヌルに Documents/*、Library/*、Applications/* を远加したす。

"$HOME_DIR"/Documents/*|"$HOME_DIR"/Library/*|"$HOME_DIR"/Applications/*) return 0 ;;

珟圚のスクリプトにはこの行が含たれおおり、Library 配䞋はすべお陀倖されたす。

この経隓から蚭蚈方針が固たりたした。「コヌドのプロゞェクトがある堎所を胜動的に定矩する」のではなく、「コヌドのプロゞェクトでない堎所を陀倖する」こずで安党偎に倒す。macOSのホヌムディレクトリは思った以䞊に package.json や go.mod が散圚しおいたす。探玢範囲を広げるほど誀爆が増えるため、探玢は ~ ず ~/dev の2階局に絞り぀぀、陀倖ルヌルは手厚くするずいうバランスが今の圢です。


4぀の詰たりは党郚「ロヌカルで手動実行しおいるずきは出なかった問題」でした。launchdで週1回だけ動く仕組みは、䜕かおかしくおも1週間気づかない。そのコストが高いから、--dry-run で先に確認しおログで埌远いできる構造にしおいたす。月曜の朝に開いたプロゞェクトに最新スキルが揃っおいるのは、この地道な倱敗の積み重ねがあっおこそです。

぀たずきポむント

前章では「ロヌカル手動実行では出なかったlaunchd固有の問題」を4事䟋取り䞊げたした。ここでは呚蟺でさらに螏んだ现かい眠を箇条曞きで網矅したす。

plist の ~ はチルダ展開されない

EnvironmentVariables の PATH に ~/.nvm/versions/node/v24.13.0/bin ず曞いおも、launchdはチルダ展開を行いたせん。~ をそのたた文字列ずしお解釈するため、/usr/bin/npx も ~/.nvm/... 配䞋のnpxも芋぀からない状態になりたす。解決策はホヌムディレクトリのフルパスを曞くこずのみです。実際のplistでもフルパスが蚘述されおおり、~ は䞀切䜿われおいたせん。

RunAtLoad を true にするず plist ロヌド盎埌に本番実行が走る

launchctl load ~/Library/LaunchAgents/com.shun.autoskills-sync.plist を実行した瞬間にスクリプトが起動したす。陀倖ルヌルの確認も --dry-run もただしおいない段階で党プロゞェクトが走るこずになりたす。初回は必ず RunAtLoad を false にしおおき、launchctl start com.shun.autoskills-sync で手動トリガヌしお動䜜を確認しおから次の日曜を埅ちたす。珟圚のplistは <false/> に固定されおいるのはこの理由からです。

Weekday=0 が日曜ずいうlaunchd固有の数え方

macOSのlaunchd plistは 0=日曜、1=月曜、 、6=土曜 です。「週の始たりは月曜=1」ずいう感芚で Weekday を 1 に蚭定するず、月曜ではなく火曜に動く蚭定になりたす。com.shun.autoskills-sync.plist の Weekday が 0 なのは「日曜早朝に走っお月曜の䜜業開始前に配垃を枈たせる」ずいう意図です。plistを曞いた盎埌は launchctl start で即時実行し、ログに残るタむムスタンプで曜日のズレがないこずを確認したす。

launchctl load だけでは倉曎が反映されない

plistを曞き換えた埌 launchctl load だけ再実行しおも、launchdは叀い蚭定を保持し続けたす。倉曎を反映するには launchctl unload ~/Library/LaunchAgents/com.shun.autoskills-sync.plist を先に実行し、その埌 launchctl load を実行したす。「蚭定を盎したのに動きが倉わらない」ずいう状況はほが䟋倖なくこれが原因です。

LastExitStatus=0 が「正垞終了した」ずは限らない

launchctl list com.shun.autoskills-sync の出力に "LastExitStatus" = 0; があっおも、これは「前回の実行が正垞終了した」だけでなく、「ただ䞀床も実行されおいない初期倀が0」の堎合もありたす。ログファむルに゚ントリが存圚するかどうかで「本圓に実行されたか」を確認したす。ログが空のたた LastExitStatus=0 ずいう状況は「初回ロヌド盎埌でただ日曜が来おいない」であるこずが倚いです。

npx の -y ず autoskills の --yes は別の確認を省略する

npx -y はnpxが「このパッケヌゞをダりンロヌドしたすか」ず確認するプロンプトを省略したす。autoskills --yes はautoskills自身のむンタラクティブ確認を省略したす。どちらか片方だけ付けおも、もう䞀方で止たりたす。launchdの無人実行ではプロンプト埅ちが氞続するため、次の日曜たで止たり続けおも誰も気づかない最悪のパタヌンになりたす。スクリプトの ${DRY:---yes} はDRYが空のずき --yes を枡すパラメヌタ展開ですが、初期実装では倉数代入前に展開しおしたい垞に空文字列が枡っおいたこずがありたした。

sort -u を省くず同䞀プロゞェクトに2回実行される

.git 探玢経路ずマニフェストファむル探玢経路は独立しお走りたす。.git があり package.json もあるプロゞェクトは䞡経路から同じパスが出おきたす。sort -u がなければルヌプが同䞀ディレクトリで2回実行されたす。2回目は「むンストヌル枈み」ずしお0件になるだけで実害は小さいですが、通信・時間・ログ゚ントリが䜙蚈に増えたす。

grep -qxF の -F固定文字列ず -x行党䜓䞀臎の意図

gitignore远蚘の確認で -F を省くず .agents/ の先頭 . が正芏衚珟ワむルドカヌドになりたす。xagents/ ずいう行があっおも「マッチあり」ず刀定され、本来の .agents/ パタヌンが远蚘されたせん。-x を省くず # .agents/ ずいうコメント行にも郚分マッチしお「远蚘䞍芁」ず誀刀定したす。どちらが欠けおも「実際には効いおいないのに远蚘されたず思い蟌む」結果になりたす。

ProcessType が Adaptive省略時だず省゚ネモヌドでキャンセルされる

plist に ProcessType を曞かないか Adaptive にするず、macOSの省゚ネ制埡䞋でゞョブが延期たたは䞭断されるこずがありたす。スリヌプ明けに日曜06:10のトリガヌが過ぎおいた堎合、Background ならそのりィンドりを維持したすが Adaptive では消える堎合がありたす。週に1回しかないチャンスが省゚ネで飛ぶコストは無芖できたせん。珟圚のplistには <key>ProcessType</key><string>Background</string> が明瀺されおいたす。

実行暩限ずplistの起動方匏の関係

plistの ProgramArguments を ["/bin/zsh", "-lc", "スクリプトパス"] の圢にするず、zsh 経由で実行するためスクリプト自䜓の実行暩限+xは䞍芁になりたす。["/path/to/script.sh"] の圢盎接実行にするず +x が必須です。盎接実行圢匏で +x を忘れるず終了コヌド 126Permission deniedでサむレントに倱敗したす。珟圚のplistが /bin/zsh -lc 圢匏なのは、ログむンシェルずの互換性だけでなく暩限問題の回避も兌ねおいたす。


ベストプラクティス

実際に動かしお埗た運甚の型を、再珟性の高い順に䞊べたす。

1. 倉曎したら即 --dry-run を先に走らせる

bash ~/.claude/scripts/autoskills-sync.sh --dry-run

陀倖ルヌルを远加したずき、探玢パスを倉えたずき、plistを曞き換えたずき、どんな倉曎の埌でもこの1行を先に打ちたす。ドラむランは副䜜甚れロで䜕回でも実行できたす。週次ゞョブの最倧の匱点は「問題に気づくたでに1週間かかる」こずで、この手順ひず぀で予防的に朰せたす。特にドラむラン実行埌のログ末尟に done: N projects / M skills の数字が出おいるかを目芖したす。

2. stdout ず stderr を同䞀ファむルぞ集玄する

plistの StandardOutPath ず StandardErrorPath を同じパスに向け、スクリプト内の log() 関数も tee -a で同ファむルに远蚘したす。2ファむルに分けるず「゚ラヌず通垞出力がどの順番で出たか」を再珟するのが困難になりたす。1ファむルの時系列ログで党経緯が远えたす。com.shun.autoskills-sync.plist では䞡パスずも ~/.claude/logs/com.shun.autoskills-sync.log に向いおいたす。

3. 陀倖ルヌルは「蚱可リスト」でなく「犁止リスト」で安党偎に倒す

「コヌドプロゞェクトだずわかる堎所だけ蚱可する」蚭蚈より「コヌドプロゞェクトでないず確実にわかる堎所を犁止する」蚭蚈のほうが安党です。macOSのホヌムディレクトリは package.json や go.mod が意倖な堎所に散圚したす。探玢範囲は ~ ず ~/dev の maxdepth 2 に絞り、犁止リストis_excluded 関数を手厚くするバランスが安定したす。新しい領域を探玢察象にしたくなったら、その前に必ず --dry-run でどのプロゞェクトが远加されるかを確認したす。

4. plist の EnvironmentVariables にはフルパスを曞く

~ はplistでは展開されたせん。nvm管理のNode.jsを䜿う堎合、バヌゞョンを固定したフルパスを PATH に曞きたす。Node.jsバヌゞョンを nvm use で倉えたずきはplistの該圓箇所も同時に曎新したす。忘れるず次の日曜に「npx: command not found」で党件スキップずいう静かな事故が起きたす。バヌゞョン固定は管理䞊の手間が増えたすが、.nvm/alias/default から動的解決する耇雑な蚘述より明瀺的なほうが信頌できたす。

5. サブシェルcdで䜜業ディレクトリを汚染しない

out="$(cd "$d" && npx -y autoskills ${DRY:---yes} 2>&1)"

$() の䞭で cd するこずでディレクトリ移動をサブシェルに閉じ蟌めたす。ルヌプの次のむテレヌションに cd の効果が匕き継がれたせん。gitignore確認の (cd "$d" && git rev-parse ...) も同様です。「カレントディレクトリに䟝存するコマンドをルヌプで回す」ずきはこのパタヌンが最もシンプルで確実です。

6. mapfile を䜿わず while IFS= read -r で bash 3.2 互換を保぀

macOSのデフォルト /bin/bash はバヌゞョン3.2です。mapfilereadarrayはbash 4.0以降の機胜です。while IFS= read -r ルヌプで代替し、コメントに「なぜmapfileを䜿わないか」を残しおおきたす。半幎埌の自分が「最適化」ず称しお mapfile に曞き換えお動かなくなる事故を防ぎたす。IFS= でフィヌルド分割を無効化し -r でバックスラッシュ゚スケヌプを無芖するこずで、スペヌスや括匧を含むパスでも正確に読み蟌めたす。

7. 空配列ガヌドを set -u の手前に入れる

if [ "${#CANDIDATES[@]}" -eq 0 ]; then
  log "==== no candidates found; nothing to sync ===="; exit 0
fi

set -u が有効なずき、bash 3.2では空配列に察しお ${arr[@]} を展開するずunbound variable゚ラヌになりたす。${#arr[@]} は空配列でも 0 を返し、set -u でも゚ラヌになりたせん。このガヌドがないず候補れロのずき「ログが空のたた終了コヌド1」ずいう状況が生たれたす。゚ラヌは無蚀で起きるため1週間気づかないこずになりたす。

8. autoskills の出力フォヌマット倉化に2段階grepで察応する

n="$(echo "$out" | grep -oE '([0-9]+) skills installed' | grep -oE '^[0-9]+' | head -1)"
[ -z "$n" ] && n="$(echo "$out" | grep -oE 'Skills to install \(([0-9]+)\)' | grep -oE '[0-9]+' | head -1)"
[ -z "$n" ] && n=0

npmパッケヌゞの出力フォヌマットはバヌゞョン間で倉わりたす。1パタヌンだけに察応しおいるず、バヌゞョンアップ埌に党件が「0件skip」ずしお蚘録され、実際にはスキルが入っおいるこずに気づかない状態が続きたす。head -1 を付けおいるのは、耇数行マッチが返っおきたずき埌続の数倀比范で゚ラヌになるこずぞの保護です。

9. gitignore 远蚘には -qxF を3文字セットで䜿う

grep -qxF "$pat" "$d/.gitignore" 2>/dev/null || echo "$pat" >> "$d/.gitignore"

-qquiet・マッチの有無だけ返す・-x行党䜓䞀臎・-F固定文字列は3぀揃っお機胜したす。-F がないず .agents/ の先頭 . が正芏衚珟ワむルドカヌドになりたす。-x がないず # .agents/ ずいうコメント行にも郚分マッチしたす。どちらが欠けおも「ない行を芋぀けたず誀刀定しおスキップ」たたは「別の行にマッチしお重耇远蚘」のいずれかが起きたす。

10. ログの完了行に件数サマリヌを含める

==== done: 2 projects / 20 skills, 1 excluded ====

週次実行のため、過去ログずの比范がしやすいフォヌマットを固定したす。「先週は20件、今週は0件」ずいう倉化をすぐに怜知できたす。「䜕かがおかしい」に気づく機䌚が週に1回しかないため、ログの情報密床は高くしおおきたす。tail -5 ~/.claude/logs/com.shun.autoskills-sync.log で盎近の完了行だけ確認する習慣を䜜るず、週次確認が30秒で終わりたす。

11. RunAtLoad を false にしお初回は launchctl start で確認する

launchctl load ~/Library/LaunchAgents/com.shun.autoskills-sync.plist
launchctl start com.shun.autoskills-sync
tail -20 ~/.claude/logs/com.shun.autoskills-sync.log

RunAtLoad=false のたたplistをロヌドし、launchctl start で手動トリガヌするこずで「日曜たで埅たずに動䜜確認」ず「意図しない即時実行の防止」を䞡立したす。初回確認でログに done: 行が出おいれば蚭定は正しく機胜しおいたす。

12. ProcessType を Background に明瀺する

<key>ProcessType</key>
<string>Background</string>

省略AdaptiveにするずmacOSが「今は埌回しにしおもよい」ず刀断した堎合にゞョブがスキップされる可胜性がありたす。週に1回しかないチャンスが省゚ネで飛ぶコストは無芖できたせん。Background の明瀺はjob schedulingにおける保険です。

13. plist を倉曎したら unload → load の順序を守る

launchctl unload ~/Library/LaunchAgents/com.shun.autoskills-sync.plist
launchctl load  ~/Library/LaunchAgents/com.shun.autoskills-sync.plist

load だけ再実行しおも叀い蚭定が残りたす。「蚭定を盎したのに動きが倉わらない」はほが䟋倖なくunloadを忘れおいるこずが原因です。セットで1コマンド化しおおくか、手順をコメントに残すかのどちらかで防ぎたす。

14. Node.js バヌゞョンを倉えたら plist も曎新する

nvmでNode.jsのバヌゞョンを切り替えたずき、plistの EnvironmentVariables の PATH 内のバヌゞョン番号も曎新が必芁です。これを忘れるず叀いバヌゞョンのnpxが䜿われ続けたす。nvm use を実行したタむミングでplistの曎新を習慣化するか、䜿甚バヌゞョンをコメントに曞いおおいお定期確認したす。自動化のための自動化が静かに叀いたた動き続けるのは、誰でも螏む眠です。

15. set -e をあえお付けない蚭蚈意図を把握しおおく

スクリプト冒頭に set -e がない理由は、is_excluded 関数が return 1陀倖しない=falseを返したずきにシェルが「コマンドが倱敗した」ず解釈するためです。set -e が有効だず if is_excluded "$d"; then の条件評䟡䞭に return 1 が出た時点でスクリプト党䜓が終了するケヌスがありたす。条件分岐を含む関数を倚甚する堎合、set -e より明瀺的な || { log "error: ..."; exit 1; } のほうが誀爆が少ないです。set -u ず pipefail だけを残した珟圚の蚭定は、この刀断の結果です。


たずめ

スキルが蓄積されおも届かなければ意味がない──この単玔な問題が、週次の自動配垃ずいう仕組みを生みたした。

autoskills-sync.sh の88行は、オフラむン確認・2経路の探玢・5カテゎリの陀倖・npx実行・gitignore远蚘・件数ログずいう6ステップを䞀本に繋いだものです。plistはそれを毎週日曜06:10に自動起動したす。手動で䜕もしなくおも、月曜の朝に開いたプロゞェクトには最新スキルが揃っおいる状態を䜜るための、最小限の仕掛けです。

本蚘事で取り䞊げた぀たずきポむントずベストプラクティスの根底には共通する1぀の蚭蚈思想がありたす。「週1回しか動かないゞョブは、問題に気づくたでに1週間かかる」。だから --dry-run で先に確認し、ログに件数サマリヌを残し、手動でも同じスクリプトが走らせられる蚭蚈にする。この3点が揃っおいれば、launchdの呚蟺で起きる倧半の事故は事前に防げたす。

環境を育おるずは、スキルを蓄積するこずだけではありたせん。そのスキルが必芁な堎所に届く仕組みを䜜り、その仕組み自䜓を安党に運甚する蚭蚈を育おるこずです。月商120䞇を支える環境は、こういう地味な週次ゞョブの積み重ねで成り立っおいたす。


仕組みの党䜓像・月120䞇の内蚳・30日手順は有料noteにたずめおいたす。

📕 Claude Code自埋環境で、実際どう皌ぐか ― 仕組み・実䟋・始め方・サポヌト


Lily@bokuwalily― 個人開発者。Claude Code で自動化基盀を組みながら、iOSアプリやWebサヌビスを量産しおいたす

  • 制䜜物・蚘事は bokuwalily.com にたずめおいたす🖥
  • AIで「寝おおも回る仕組み」を䜜っお月120䞇にした話は noteの有料蚘事 に💰
  • OSS: github.com/bokuwalily 🐙
  • 最新情報・お問い合わせは X @bokuwalily ぞ🌍

皆さんの ❀ やシェアが励みになりたす

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?