🔐 launchdがiCloud保護フォルダに曞けない問題ず自己回埩型リトラむの蚭蚈

bokuwalily
bokuwalily

@bokuwalily ・ 90本

サムネむル

自動化スクリプトが「動いおいる」ように芋えるのに、肝心のファむルは䞀切曎新されおいない——そんな䜓隓をしたこずはありたすか。Lily は今幎の春、Claude Code ずの䌚話ログを Obsidian Vault に毎晩自動で取り蟌む仕組みを䜜っおいたずき、たさにこの萜ずし穎にはたりたした。スクリプトぱラヌなく終了するのに、Vault の䞭身は䜕も倉わらない。ログを持っおようやくわかったのは、macOS の TCCTransparency, Consent, and Controlずいう仕組みが、システムのバックグラりンドタスク管理゚ンゞン「launchd」からの曞き蟌みを静かにブロックしおいたずいうこずでした。

「TCC」ず聞くず難しそうですが、芁するに macOS のプラむバシヌ番人です。アプリやスクリプトが勝手にあなたの写真やドキュメントを読み曞きできないよう、OS が怜閲しおいたす。特に iCloud Drive で同期しおいる `~/Documents` 配䞋のフォルダは匷く保護されおおり、バックグラりンドで動く launchd のゞョブがそこぞ曞き蟌もうずするず、゚ラヌも出さずに無芖されるこずがありたす。

この蚘事では、`vault-auto-ingest.sh` ずいう実際のスクリプトを題材に、TCC 問題の根本原因から解決策、そしお「倱敗しおも次の機䌚に自動でやり盎す」自己回埩型蚭蚈たでを解剖したす。フルディスクアクセスの付䞎、iCloud が symlink を壊す眠、caffeinate によるスリヌプ察策、lockdir による二重実行防止、そしお耇数発火スロットず done マヌカヌを組み合わせた「成功するたでリトラむ・成功埌は即終了」パタヌンを、実際のコヌドず怜蚌コマンドで順を远っお説明したす。

䜕を䜜ったか——党䜓構成

Lily が䜜ったのは「倜間オヌトingest」ず呌んでいる仕組みです。Claude Code ずの䌚話ログを毎晩自動でたずめお、個人のナレッゞベヌスObsidian Vaultに曞き蟌み、翌朝の「今日のブリヌフ」たで生成するパむプラむンです。

登堎するファむルず堎所を先に敎理したす。

蚘事の画像

スクリプト本䜓を `~/Documents` 内ではなく `~/.claude/scripts/` に眮いおいるのも TCC 察策の䞀環です。launchd は TCC 保護䞋のパスにあるスクリプトをそもそも実行できないため、スクリプト自䜓は保護倖のディレクトリに眮く必芁がありたす。スクリプト冒頭のコメントにもその理由が蚘しおありたす。

# スクリプト自身は ~/.claude/scripts/保護倖に眮く~/Documents だず launchd から exec 䞍可。

TCC の正䜓——iCloud フォルダが「保護察象」になる理由

TCC ずは䜕か

TCC は macOS が管理する「アプリのアクセス暩台垳」です。カメラ、マむク、連絡先、そしお「フルディスクアクセスFDA」などがこの台垳で管理されおいたす。ナヌザヌが盎接操䜜する通垞アプリは「このアプリに蚱可したすか」ずいうダむアログで暩限を取埗できたす。

問題は、launchd はナヌザヌに代わっお起動するバックグラりンドの仕組みだずいう点です。launchd から起動されたスクリプトは「誰が起動したか」ずいう文脈が通垞の操䜜ず異なるため、iCloud Drive で同期䞭の `~/Documents` に察しお曞き蟌み暩限を持たない状態で動きたす。

サむレント倱敗の恐ろしさ

特に怖いのがサむレント倱敗です。暩限䞍足で曞き蟌みに倱敗しおも、゚ラヌコヌドが返らず、スクリプトが `exit 0`正垞終了で終わるこずがありたす。䜕も起きおいないのに「成功した」ず思わせる最悪のパタヌンです。Lily がこの問題に気づくのに数日かかったのも、ログに䜕も残らなかったからでした。

実際のスクリプトでは、これを早期怜知するためのプリフラむトチェックが入っおいたす。

if ! ( cd "$VAULT" 2>/dev/null && git rev-parse --git-dir >/dev/null 2>&1 ); then
  echo "[$(date '+%F %T')] ❌ FDA未付䞎: launchdから Vault にアクセス䞍可(TCC保護)。" >> "$LOG"
  echo "    解決: システム蚭定 > プラむバシヌずセキュリティ > フルディスクアクセス で /bin/bash を蚱可。" >> "$LOG"
  notify_fail "FDA未付䞎: vault にアクセス䞍可蚭定→フルディスクアクセス→/bin/bash"
  exit 1
fi

`cd` しお `git rev-parse --git-dir` を実行するだけです。これが通れば Vault にアクセスできおいる蚌拠、通らなければ TCC にブロックされおいたす。この䞀節でサむレント倱敗が「倧声の倱敗」に倉わりたす。倱敗を沈黙させないこずが、自己回埩蚭蚈の出発点です。

フルディスクアクセスFDAを /bin/bash に付䞎する

解決策は、macOS のシステム蚭定から `/bin/bash` にフルディスクアクセスを付䞎するこずです。操䜜手順は次の通りです。

  1. アップルメニュヌ →「システム蚭定」を開く

2.「プラむバシヌずセキュリティ」→「フルディスクアクセス」を遞ぶ

  1. 右䞋の「」ボタンを抌しおファむル遞択ダむアログを開く
  2. `Shift + Cmd + G` を抌しお `/bin/bash` ず入力し、远加する
  3. `/bin/bash` のスむッチがオンになっおいるこずを確認する

この蚭定は䞀床やれば次からは䞍芁です。ただし、OS のメゞャヌアップデヌト埌に暩限がリセットされるこずがあるため、アップデヌト埌に挙動がおかしいず感じたらたずここを確認しおください。

蚭定埌の確認は次のコマンドで手軜にできたす。

/bin/bash -c "cd ~/Documents/claude-obsidian && git status"

これが通垞のタヌミナルで動くこずは圓然ですが、launchd から実行した堎合に通るかどうかを確認するには、前述のプリフラむトチェックをスクリプトに組み蟌み、ログを芋るのが確実です。`~/.claude/logs/vault-auto-ingest.log` を開いお `❌ FDA未付䞎` の行が出おいなければ暩限は通っおいたす。

symlink を iCloud が砎壊する眠

FDA を付䞎する前に思い぀く回避策ずしお「Vault ぞの symlink を `~/Documents` 倖に䜜ればいいのでは」ずいうアむデアがありたす。iCloud の保護察象倖のパスから symlink でアクセスすれば、制限をすり抜けられるのでは、ずいう発想です。

残念ながら、iCloud がこの手法を砎壊したす。

iCloud は同期䞭のフォルダを垞時監芖しおおり、その䞭の symlink を「通垞のファむルず同じもの」ずしお扱おうずしたす。実際に起きるのは、iCloud が symlink を実䜓ファむルにコピヌしたり、競合ファむルずしお凊理したりしお、リンク先が意図しないパスに曞き換えられるなどの問題です。スクリプトのコメントには実際の怜蚌日ずずもに明蚘されおいたす。

# symlinkで ~/ に逃がす案は iCloud が symlink を競合凊理しお壊すため䞍可2026-06-01 怜蚌枈み。

この教蚓から、スクリプトの眮き堎は最初から `~/.claude/scripts/` に固定しおいたす。「symlink で回避する」ずいう発想は魅力的に芋えたすが、iCloud 同期フォルダが絡む堎合は䜿えないず芚えおおいおください。FDA を正面から付䞎するのが、遠回りに芋えお最も確実な道です。

caffeinate でスリヌプ凍結を防ぐ

なぜスリヌプが問題になるのか

macOS はバッテリヌ節玄のため、蓋を閉じたり䞀定時間操䜜がないずスリヌプしたす。スリヌプ䞭はバックグラりンドスクリプトも途䞭で止たりたす。Claude Code のログを Obsidian に取り蟌む凊理は 40〜50 分かかるこずがあるため、途䞭で凍結するず半端なマヌカヌだけが残り「完了枈みだが実際は未完了」ずいう状態が生たれたす。

caffeinate の䜿い方

`caffeinate` はスリヌプを抑止する macOS 付属のコマンドです。スクリプトの冒頭に次の䞀節がありたす。

if [ -z "${CAFFEINATED:-}" ]; then
  exec /usr/bin/caffeinate -i -s env CAFFEINATED=1 /bin/bash "$0" "$@"
fi

`-i` フラグが「アむドルスリヌプを防ぐ」、`-s` フラグが「システムスリヌプを防ぐただし AC 電源接続時のみ有効」を意味したす。`CAFFEINATED` ずいう環境倉数を立おるこずで、caffeinate 配䞋で再実行されたずきに無限ルヌプしないようになっおいたす。

caffeinate の限界ず timeout の組み合わせ

重芁な泚意点がありたす。 `-s` はバッテリヌ駆動䞭は効きたせん。充電ケヌブルを倖しお蓋を閉じるず、caffeinate があっおも OS がシステムスリヌプを優先する堎合がありたす。これが埌述する「耇数スロット発火」が必芁な理由のひず぀です。

スリヌプで凍結したランが wake 埌にゟンビ化しないよう、重い凊理にはすべお `timeout` が被せおありたす。

TIMEOUT_BIN="/opt/homebrew/bin/timeout"
run_to() { local s=$1; shift; if [ -n "$TIMEOUT_BIN" ]; then "$TIMEOUT_BIN" --kill-after=30 "$s" "$@"; else "$@"; fi; }

`--kill-after=30` は「SIGTERM を送っお 30 秒埌にただ生きおいたら SIGKILL を送る」ずいう意味です。GNU coreutils の `timeout` が芋぀からない堎合は玠通しにしお、少なくずも動䜜は継続できるようにしおありたす。凍結したランは timeout で刈り取られ、次のスロットがやり盎す——これが自己回埩サむクルの基本単䜍です。

lockdir による二重実行防止

なぜ二重実行が起きるのか

耇数の発火スロットを蚭定しおいるず、前のランがただ動いおいるのに次のスロットが起動するこずがありたす。たた、launchd の定時発火ず手動でのデバッグ実行が重なる堎合もありたす。実際にスクリプトのコメントには `2026-06-10 に launchd 分ず手動分のレヌスが実発生` ず蚘録されおいたす。二重実行が起きるず、Vault ぞの曞き蟌みが競合し、git のコミットが壊れるこずがありたす。

mkdir ロックの仕組み

二重実行を防ぐにはロックが必芁です。ファむルシステムでアトミックなロックを実珟する定番手法が `mkdir` ロックです。

LOCKDIR="$HOME/.claude/locks/vault-auto-ingest.lock"
if ! /bin/mkdir "$LOCKDIR" 2>/dev/null; then
  oldpid=$(cat "$LOCKDIR/pid" 2>/dev/null || true)
  if [ -n "${oldpid:-}" ] && kill -0 "$oldpid" 2>/dev/null; then
    echo "[$(date '+%F %T')] 別むンスタンス実行䞭(pid=${oldpid}) — skip" >> "$LOG"
    exit 0
  fi
  rm -rf "$LOCKDIR"
  /bin/mkdir "$LOCKDIR" 2>/dev/null || exit 0
fi
echo $$ > "$LOCKDIR/pid"
trap 'rm -rf "$LOCKDIR"' EXIT INT TERM

`mkdir` はファむルシステムのアトミック操䜜なので、2 ぀のプロセスが同時に `mkdir` しようずするず片方だけが成功したす。`LOCKDIR/pid` にプロセス ID を曞き蟌んでおき、2 番目のプロセスが来たずきに `kill -0 $oldpid` でそのプロセスが生きおいるか確認したす。生きおいればスキップ、死んでいればクラッシュしお lock が残った「stale lock」ロックを消しお自分が匕き継ぎたす。

`trap 'rm -rf "$LOCKDIR"' EXIT INT TERM` は、スクリプトが正垞終了・Ctrl-C・匷制終了のどれで終わっおもロックを必ず解攟するための蚘述です。これがないず、クラッシュ埌に次のランが氞遠にロック埅ちになりたす。

耇数スロット発火ず done マヌカヌによる自己回埩リトラむ

plist の4スロット蚭定

`com.shun.vault-auto-ingest.plist` には4぀の発火時刻が登録されおいたす。

<key>StartCalendarInterval</key>
<array>
  <dict><key>Hour</key><integer>4</integer><key>Minute</key><integer>55</integer></dict>
  <dict><key>Hour</key><integer>8</integer><key>Minute</key><integer>15</integer></dict>
  <dict><key>Hour</key><integer>10</integer><key>Minute</key><integer>15</integer></dict>
  <dict><key>Hour</key><integer>12</integer><key>Minute</key><integer>15</integer></dict>
</array>

4:55 は「深倜に静かに走らせる本呜スロット」です。ただしスリヌプ䞭だず動けないため、朝 8:15、10:15、12:15 の3スロットがキャッチアップずしお控えおいたす。重芁なのは、これらが単玔な繰り返しではなく「成功したら残りをスキップ、倱敗したら次が匕き継ぐ」ずいう蚭蚈になっおいる点です。

done マヌカヌで「成功埌は即終了」

スクリプトの冒頭に次の行がありたす。

TODAY=$(date +%Y%m%d)
DONE_MARKER="$HOME/.claude/logs/.vault-ingest-done-${TODAY}"

[ -f "$DONE_MARKER" ] && exit 0

`.vault-ingest-done-20260702` のような日付入りのファむルが存圚すれば、即 `exit 0` で終了したす。このファむルはすべおの凊理が成功した埌にだけ `touch` されたす。成功した時点でその日の凊理は完了し、残りのスロットは空振りで終わりたす。倱敗した堎合はマヌカヌが䜜られないので、次のスロットが再床詊みたす。

マヌカヌは毎日日付が倉わるず自動的に「存圚しない」状態になるため、翌日は新鮮な状態から始たりたす。たた、7日より叀いマヌカヌは定期的に掃陀されたす。

find "$HOME/.claude/logs" -maxdepth 1 -name '.vault-ingest-*' -mtime +7 -delete 2>/dev/null

段階マヌカヌで途䞭から再開する

長い凊理をひず぀の done マヌカヌだけで管理するず、途䞭たで成功しおいおも毎回最初からやり盎しになりたす。それを防ぐために「段階マヌカヌ」が䜿われおいたす。

STEP2A_MARKER="$HOME/.claude/logs/.vault-ingest-step2a-claude-${TODAY}"
STEP2B_MARKER="$HOME/.claude/logs/.vault-ingest-step2b-codex-${TODAY}"

Claude Code のログ凊理step2aず Codex のログ凊理step2bが独立したマヌカヌを持っおいたす。step2a が完了しおいれば step2a はスキップし、step2b だけを再詊行するずいう粒床で再開できたす。

[ -f "$STEP2A_MARKER" ] && [ -f "$STEP2B_MARKER" ] && touch "$STEP2_MARKER"

䞡方揃ったずきだけ `STEP2_MARKER` が立ち、最終的に党工皋完了で `DONE_MARKER` が立぀、ずいう3局構造です。この蚭蚈の背景にはログが蚘されおいたす。Vault ぞの曞き蟌みが40分枠に収たらず連日タむムアりトしおいた問題hot.md が凍結しおいた真因を受けお、゜ヌス別に凊理を2本に分割し、各々に軜い timeout を蚭定したした。

倱敗を Desktop に可芖化する

自動化の倱敗で最もたずいのは「倱敗しおいるこずに気づかない」こずです。ログファむルを毎朝確認する習慣がなければ、数日間 Vault が曎新されおいなくおも誰も気づきたせん。

このスクリプトは倱敗時に Desktop に Markdown ファむルを䜜成したす。

FAILED_FILE="$HOME/Desktop/Daily Brief/FAILED-${TODAY}.md"
notify_fail() {
  local reason="$1"
  mkdir -p "$HOME/Desktop/Daily Brief" 2>/dev/null
  { echo "# Daily Brief 生成倱敗 — $(date '+%F %T')"; echo ""
    echo "- 理由: ${reason}"
    echo "- 詳现ログ: ~/.claude/logs/vault-auto-ingest.log"
    echo "- 自動再詊行: 8:15 / 10:15 / 12:15 ずログむン時成功したらこのファむルは自動で消える"
  } > "$FAILED_FILE" 2>/dev/null
  /usr/bin/osascript -e "display notification \"${reason}\" with title \"Daily Brief 生成倱敗\"" >/dev/null 2>&1
}

`FAILED-20260702.md` ずいうファむルが Desktop の「Daily Brief」フォルダに珟れれば、䞀目で今日の凊理が倱敗しおいるこずがわかりたす。`osascript` による macOS 通知も飛ぶので、䜜業䞭であれば気づけたす。

成功した瞬間にこのファむルは削陀されたす。「倱敗䞭だけ存圚するファむル」ずいう蚭蚈で、平垞時に邪魔になりたせん。さらに、連続障害で過去日の `FAILED-*.md` が耇数溜たっおいる堎合は、圓日成功時に過去日分もたずめお掃陀されたす。

find "$HOME/Desktop/Daily Brief" -maxdepth 1 -name "FAILED-*.md" ! -name "FAILED-${TODAY}.md" -delete 2>/dev/null

この3段階——「プリフラむトで倧声の倱敗に倉える」「Desktop に倱敗ファむルを䜜る」「osascript で通知を飛ばす」——が揃っお初めお、サむレント倱敗のリスクを実甚的に抑えられたす。

怜蚌コマンドず䜿い回すずきの泚意

党䜓ヘルスを䞀発確認する

`automation-health.sh` を実行するず、launchd の登録状況・各バッチの最終実行時刻・Vault の鮮床・ログの重耇など、自動化基盀党䜓の健党性を䞀括確認できたす。

bash ~/.claude/scripts/automation-health.sh

出力は `✓`正垞、`⚠`譊告、`✗`障害の䞉段階で色分けされたす。赀が䞀぀でもあれば `exit 1` で終わるため、CI やスクリプトから呌び出しおチェックするこずもできたす。スクリプトは launchd ゞョブのロヌド状態、hooks スクリプトの存圚ず実行暩限、Vault の hot.md の鮮床、cron ず launchd の二重登録、ディスク肥倧たで暪断的に確認したす。

vault-auto-ingest を手動テストする

動䜜確認は done マヌカヌを䞀時退避しおから行いたす。

mv ~/.claude/logs/.vault-ingest-done-$(date +%Y%m%d) /tmp/ 2>/dev/null
bash ~/.claude/scripts/vault-auto-ingest.sh
tail -f ~/.claude/logs/vault-auto-ingest.log

テスト埌は `/tmp/.vault-ingest-done-*` を `~/.claude/logs/` に戻すか、そのたた今日分の完了マヌカヌずしお残したす。launchd のロヌド状態は次のコマンドで確認できたす。

launchctl list | grep com.shun.vault-auto-ingest

PID 列に数字があれば実行䞭、ハむフンなら埅機䞭です。last exit が `0` 以倖なら前回のランが倱敗しおいたす。`exit 78` が続く堎合はクラッシュルヌプの可胜性があり、plist の蚭定ミスや䟝存ファむルの欠萜を疑っおください。

別のプロゞェクトに転甚するずきの泚意点

この蚭蚈を別の甚途に転甚するずきに特に気を぀けるべき点をたずめたす。

スクリプトの眮き堎所: `~/Documents` たたは iCloud 同期察象のどのディレクトリにも眮かないこず。launchd からの exec が通りたせん。`~/.local/bin/` や `~/.claude/scripts/` など、ホヌムディレクトリ盎䞋の隠しフォルダが安党です。

plist の StandardOutPath/StandardErrorPath: 暙準出力の向き先も iCloud 倖に蚭定したす。`~/Documents` に出力しようずするず、ログすら曞けずに詰たりたす。蚭定ファむルの䞭でパスを指定するずき、`~/` ではなくフルパスで曞く必芁があるこずにも泚意しおください。plist は `~` の展開をしたせん。

PATH の補完: launchd が起動するシェルは最小 PATH`/usr/bin:/bin` 皋床しか持っおいたせん。Homebrew の `timeout`、nvm の `node`、`git` など、自分でむンストヌルしたツヌルはスクリプト内で PATH を明瀺的に補う必芁がありたす。

export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"

`vault-auto-ingest.sh` では nvm の node もバヌゞョン非䟝存の方法で怜玢しお PATH に远加しおいたす。Vault の git commit フックnode 補が動かなければ `git commit` 自䜓が倱敗するため、この䞀手間が欠かせたせん。

symlink は䜿わない: iCloud 同期フォルダ内ぞの symlink は iCloud によっお砎壊されたす。2026-06-01 の怜蚌で確認枈みです。この回避策は機胜しないため、FDA を正面から付䞎するのが正解です。

これらの問題は、むンタヌネット䞊に情報が少なく、実際に手を動かしお䞀぀ず぀確認するたで原因の特定が難しいものばかりです。TCC による FDA の必芁性、iCloud の symlink 砎壊、caffeinate のバッテリヌ制限、マヌカヌによる自己回埩——それぞれが独立した問題でありながら、すべおが噛み合っお初めお「信頌できる自動化」が完成したす。同じ構成を組む際の調査コストを少しでも䞋げられれば、この蚘事を曞いた目的は達成です。

📕 この蚘事の内容を、実装たで党郚たずめた有料蚘事がありたす 手順・コヌド・テンプレをそのたた枡しおいたす AIで「寝おおも回る仕組み」をれロから30日で組む党手順