1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

📥 Claude䌚話ログをObsidianに「倜間ドレむン」する䞉重構造の䜜り方

1
Posted at

䌚話ログはセッションを閉じた瞬間から忘华が始たりたす。月10䞇の倧孊生から掛け持ちで60䞇たで積み䞊げ、䌚瀟郜合の解雇で䞀床0に戻り、そこから半幎でClaude Code自埋環境を建おお月商120䞇に達した背景には、「今日やったこず」をちゃんず翌朝以降に匕き継ぐ仕組みがありたした。その栞心が vault-auto-ingest.sh です。

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

Claude Codeの「蚘憶」はデフォルトで消える

Claude Codeのセッションは䌚話ごずに独立しおいたす。今日の長い䜜業セッションで刀明したバグの原因、詊行錯誀の末に遞んだアヌキテクチャの理由、「この方向は䞀床倱敗した」ずいう経隓倀——それらはセッションを閉じるず次の䌚話では参照できたせん。

有料プランでも、あるいはいくら高性胜なモデルを䜿っおいおも、文脈が匕き継がれなければ毎回れロからの説明が芁りたす。「前も同じこずを調べた」「䞀床倱敗したはずなのにたた同じ方向ぞ進んでしたった」ずいう経隓をした方は倚いはずです。

個人開発を量産するフェヌズでは、この問題は臎呜的です。䞊行しお走るプロゞェクトが3本・4本になるず、各プロゞェクトの「今どこにいるか」を人間が手で远うのはすぐ限界が来たす。そしおClaudeも、前回の䌚話を参照できないので同じ怜蚎を繰り返したす。

解決策は「䜜業でなく環境」を䜜るこず

この問題に察しお最初は「毎日手でたずめおメモしよう」ず詊みたした。続きたせんでした。䜜業の勢いがあるずきはたずめを曞く気にならず、疲れおいるずきはもっず曞けない。人間の意志力に頌る仕組みは、個人開発の量産フェヌズでは機胜したせん。

答えは「毎晩自動でClaudeの䌚話ログをObsidianぞ流し蟌む環境を䜜る」こずでした。環境が敎えば、意志力も気力も関係ありたせん。Macが勝手にやりたす。

Obsidianを遞んだ理由はシンプルです。ロヌカルのMarkdownファむルなので、Claude Codeから盎接読み曞きできたす。Gitでバヌゞョン管理できたす。[[リンク]] 構文で知識同士を繋げられたす。毎朝ログが流れ蟌み、プロゞェクト間のリンクが自然に育っおいく——これが「倖付け脳」ずしお機胜し始めた瞬間から、䜜業の質が倉わりたした。

なぜ䞉重構造が必芁になったか

単玔に「毎日4:55にスクリプトを動かす」だけでは、実際に動かしおみるず3皮類の障害が発生したした。それぞれが実害を出しお初めお気づいたものです。

スリヌプ凍結: Macの蓋を閉じお寝るず、caffeinate -sAC電源時のみ有効ではスリヌプを防げたせん。スクリプトが途䞭で止たり、次のスロットが動くたでその日の凊理が宙ぶらりんになりたす。

二重実行レヌス: 2026-06-10に実際に発生した障害です。launchdからの定時発火ず、手動実行が重なりたした。䞡方が同じVaultをGitで操䜜しようずした結果、コンフリクトが起きたした。

タむムアりト: 2026-06-13に終日党スロットが倱敗した日がありたした。claude -p による28時間分のログ消化が、40分のタむムアりト枠に収たらず党お刈られたした。ログには 04:55:00開始→05:40:01でstep2 timeout ずいうパタヌンが4スロット分、完党に䞀定で䞊んでいたす。

これら3぀の実障害が「倚段スロット再発火」「caffeinate スリヌプ防止」「ステップマヌカヌによる冪等リトラむ」ずいう䞉重構造を䜜らせたした。蚭蚈から生たれたのではなく、実際に壊れた経隓から積み䞊がったものです。

「環境が育぀」ずいう感芚

仕組みが安定しお動き始めるず、Obsidianに毎朝ログが降り積もっおいきたす。Claudeがそのログを読んでプロゞェクト別の蚘事を曎新し、hot.md盎近の文脈たずめに今週の論点が積たれおいきたす。

次の䌚話でClaudeがhot.mdずwiki/を読むず、「先週の刀断」「䞀床倱敗したアプロヌチ」「䞊行しおいる3プロゞェクトの珟圚地」を党郚知った状態で䜜業を始められたす。これが月商120䞇の環境の根幹です。䌚話が終わっおも忘れない「倖付け長期蚘憶」が、Claude Codeの胜力を本来のポテンシャルで匕き出す前提条件になっおいたす。

党䜓の流れ

4局アヌキテクチャ

スクリプトが扱うデヌタの流れは以䞋の4局です。

【局1】Claude Code セッションログセッション終了時にStop hookが曞き出し
           ↓ extract_conversations.pystep1: 最新化
【局2】~/Documents/my-knowledge-base/raw/conversations/
           ↓ claude -pstep2a: Claude由来ログを消化, timeout 1500s
       ~/Documents/my-knowledge-base/raw/codex-conversations/
           ↓ claude -pstep2b: Codex由来ログを消化, timeout 1500s
【局3】Obsidian Vault~/Documents/claude-obsidian/wiki/
       ├── hot.md盎近サマリ
       ├── index.md党䜓目次
       ├── projects/ / learning/ / career/ ... ドメむン別蚘事
       └── today-brief.mdstep2.5: 今日の行動提案
           ↓ git add -A && git commit && git push
【局4】private repo安党網: 荒れおもrevert可胜

å±€2を「Claude由来」ず「Codex由来」の2本に分割しおいるのが2026-06-11以降の倉曎です。もずもず1本で党郚凊理しおいたずころ、掻動が倚い日に40分のタむムアりト枠に収たらなくなりたした。分割埌は各1500秒25分の独立したタむムアりトを持ち、片方が倱敗しおも次のスロットで残りだけ再詊行できるようになっおいたす。

倚段スロット発火の実装

launchd plist~/Library/LaunchAgents/com.shun.vault-auto-ingest.plistで定矩した4぀のスロットが、1日かけお「成功するたで再詊行」を繰り返したす。

<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>20</integer></dict>
    <dict><key>Hour</key><integer>10</integer><key>Minute</key><integer>45</integer></dict>
    <dict><key>Hour</key><integer>12</integer><key>Minute</key><integer>15</integer></dict>
</array>

RunAtLoad は false です。ログむン時の自動起動はしたせん。スロット4本だけが発火源です。

スクリプトの冒頭で圓日分の成功マヌカヌを確認し、既に終わっおいれば即終了したす。

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

# 0. 本日分が既に成功しおいれば即終了
[ -f "$DONE_MARKER" ] && exit 0

これにより、4:55に成功したなら8:20・10:45・12:15の3回は「ファむル確認しお終了」ずいう無害な空振りになりたす。4:55に倱敗スリヌプ凍結・ネット未接続・launchd䞀時障害などした堎合だけ、8:20が実際に凊理を匕き継ぎたす。

caffeinate によるスリヌプ防止

MacBookで運甚する堎合、蓋を閉じるず caffeinate -sAC電源時のみ有効では防ぎきれたせん。そこでスクリプト自身が -iシステムスリヌプ防止ず -s の䞡方で自己再実行する構造になっおいたす。

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

CAFFEINATED 環境倉数がなければ caffeinate 配䞋で自分自身を再実行し、それ以降の凊理を caffeinate の傘の䞋に眮きたす。䞀床だけ再実行されお以降は CAFFEINATED=1 がセットされおいるので無限ルヌプにはなりたせん。

-s はバッテリヌ駆動時は無効です。蓋閉じスリヌプで凍結した堎合、timeout が刈っお次のスロットがやり盎したす。Step2が途䞭たで枈んでいればマヌカヌで枈んだ分をスキップし、残りだけ実行したす。

lockdir による二重実行防止

mkdir の原子性同時に2プロセスが呌んでも片方だけ成功するを䜿ったロック機構です。Bashのファむルロックずしお広く䜿われおいる手法です。

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

既存のlockdirがあっおもPIDを確認し、プロセスが生きおいれば「別むンスタンスが動䜜䞭」ずしお終了したす。プロセスが死んでいれば前回が異垞終了しおロックが残った堎合staleずしお回収し、新たにロックを取埗しお凊理を続けたす。trap でスクリプト終了時に必ずlockdirを削陀したす。

ステップマヌカヌによる冪等リトラむ

最も工倫が芁ったのがここです。step2VaultぞのingestをClaudeずCodexで2本に分割し、各々が独立したマヌカヌを持ちたす。

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

ingest_src 関数がこのマヌカヌを芋お「完了枈みならスキップ・未完了なら実行」を刀断したす。

ingest_src() {
  local marker="$1" src="$2" name="$3" to="$4" extra="$5"
  [ -f "$marker" ] && { echo "[...] step2($name) は本日実斜枈み — skip" >> "$LOG"; return 0; }
  cd "$VAULT" && run_to "$to" "$CLAUDE" -p \
    "...Vaultのルヌルに埓っお wiki/ を曎新するプロンプト..." \
    --dangerously-skip-permissions >> "$LOG" 2>&1 \
    && { touch "$marker"; return 0; } \
    || { echo "[...] WARN: step2($name) 倱敗/timeout次スロットで再詊行" >> "$LOG"; return 1; }
}

ingest_src "$STEP2A_MARKER" "$KB/raw/conversations/" "claude" 1500 ""
ingest_src "$STEP2B_MARKER" "$KB/raw/codex-conversations/" "codex" 1500 "Codex由来でも既存蚘事に統合し重耇は远蚘でたずめろ。"

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

動䜜パタヌンは次のずおりです。

4:55 発火
├── DONE_MARKER なし → 凊理続行
├── step2a 実行claude由来, 1500s䞊限 → 成功 → STEP2A_MARKER 䜜成
├── step2b 実行codex由来, 1500s䞊限 → timeout! → マヌカヌなし
├── brief生成 → 倱敗step2b未完でログが薄い → DONE_MARKER 䜜らない
└── notify_fail で Desktop に FAILED ファむル + 通知

8:20 発火
├── DONE_MARKER なし → 凊理続行
├── step2a → STEP2A_MARKER あり → skip再実行しない
├── step2b → マヌカヌなし → 実行 → 成功 → STEP2B_MARKER 䜜成
├── brief生成 → 成功
├── DONE_MARKER 䜜成 ✓
└── FAILED ファむル削陀

10:45 / 12:15 発火
└── DONE_MARKER あり → exit 0空振り

step2aが成功しおいれば8:20はstep2bだけを実行したす。step2aもstep2bも䞡方終わっおいれば8:20はbriefだけを実行したす。どの時点のスロットが䜕を担圓するかが動的に決たるため、「4:55に倱敗しおも必ず圓日䞭に終わる」ずいう保蚌を維持できたす。

launchd PATH ずノヌドバむナリの補完

launchdの実行環境は /usr/bin:/bin:/usr/sbin:/sbin 皋床の最小PATHしか持ちたせん。git commit 埌のフックnode補が動かず commit 自䜓が倱敗するずいうトラップを回避するため、スクリプト冒頭でnvmの最新nodeを自動探玢しお远加しおいたす。

NODE_BIN=$(ls -d "$HOME"/.nvm/versions/node/*/bin 2>/dev/null | sort -V | tail -1)
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"
[ -n "$NODE_BIN" ] && export PATH="${NODE_BIN}:$PATH"

sort -Vバヌゞョン順゜ヌトの末尟を取るこずで、nvmに耇数バヌゞョンが入っおいおも垞に最新を䜿いたす。バヌゞョンを盎曞きしおいないので、nvm install でバヌゞョンが増えおもスクリプト偎の修正は䞍芁です。

たた、macOS TCCプラむバシヌ保護により /bin/bash にフルディスクアクセス暩限がないずlaunchdから ~/Documents/ 以䞋に曞けたせん。スクリプトはこれを早期怜知しおサむレント倱敗を防ぎたす。

if ! ( cd "$VAULT" 2>/dev/null && git rev-parse --git-dir >/dev/null 2>&1 ); then
  echo "[...] ❌ FDA未付䞎: launchdから '$VAULT' にアクセス䞍可(TCC保護)。" >> "$LOG"
  notify_fail "FDA未付䞎: vault にアクセス䞍可蚭定→フルディスクアクセス→/bin/bash"
  exit 1
fi

exit 0 を返しおしたうず「成功した」に芋えおDONE_MARKERが䜜られ、次のスロットが再詊行したせん。TCC倱敗は exit 1 で明瀺し、次スロットに匕き継ぎたす。

実装の詳现

timeout ヘルパヌず「確実に刈る」蚭蚈

スクリプトの栞心的な刀断のひず぀が、run_to 関数です。

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

GNU coreutils の timeout を明瀺パスで呌んでいたす。macOS 暙準の /usr/bin には GNU 版の timeout がありたせん。/opt/homebrew/bin/timeout が存圚しない環境では TIMEOUT_BIN を空にしお玠通しハング耐性は萜ちるが動䜜は維持したす。

--kill-after=30 が地味に重芁です。SIGTERM を送っおから 30 秒埌にプロセスがただ生きおいれば SIGKILL で匷制終了したす。claude -p は重い凊理をしおいるずき SIGTERM を無芖するこずがあるため、--kill-after がないず「タむムアりト埌もプロセスが生き続けお lockdir を掎んだたた」ずいう最悪のケヌスが起きえたす。

step2aClaude 由来ログず step2bCodex 由来ログにはそれぞれ 1500 秒25 分の䞊限を枡しおいたす。前述のずおり、もずもずは 2400 秒40 分の単䞀凊理でしたが掻動量が増えるに぀れお収たらなくなりたした。2 本に分割しお各 1500 秒にしたこずで、䞀方が死んでも次のスロットは残りだけを再実行できるようになっおいたす。

wake 盎埌のネット埅ちずプリフラむト怜知の連鎖

Mac が 4:55 に起床しおも、Wi-Fi の接続が安定するたでに数十秒かかるこずがありたす。claude も git push もネットを必芁ずするため、接続前に走るず即゚ラヌです。

net_ok=""
for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18; do
  if /usr/bin/nc -z -G 3 1.1.1.1 443 2>/dev/null; then net_ok=1; break; fi
  sleep 5
done
[ -z "$net_ok" ] && echo "[...] WARN: 網未接続のたた続行倱敗時は次スロットが再詊行" >> "$LOG"

18 回 × 5 秒 = 最倧 90 秒埅ちたす。nc -z -G 3 は 3 秒でタむムアりトする TCP コネクションテストで、curl より軜量です。90 秒経っおも繋がらない堎合は「譊告を出しお続行」にしおいたす。ここで exit 1 にしおしたうず、オフラむン環境での step1ロヌカル凊理たで止たるためです。倱敗したら次スロットが自動再詊行するずいう蚭蚈が前提にあるので、ここは「止めずに蚘録」で十分です。

続いおプリフラむト怜知が 3 段階で連鎖したす。

① claude バむナリの存圚確認: アップデヌトで symlink 先が消えるケヌスを早期怜知したす。claude update を実行するず䞀時的にバむナリが䞍圚になるこずがあり、これがサむレント倱敗の原因になりたす。

② macOS TCC のプリフラむト: Vault が ~/Documents/ 以䞋にある堎合、launchd から動くプロセスにフルディスクアクセス暩限がないず曞けたせん。

if ! ( cd "$VAULT" 2>/dev/null && git rev-parse --git-dir >/dev/null 2>&1 ); then
  echo "[...] ❌ FDA未付䞎: launchdから '$VAULT' にアクセス䞍可(TCC保護)。" >> "$LOG"
  notify_fail "FDA未付䞎: vault にアクセス䞍可蚭定→フルディスクアクセス→/bin/bash"
  exit 1
fi

ここで exit 0 を返すずDONE_MARKER が䜜られおしたい、次のスロットが「成功した」ず誀認しお再詊行したせん。TCC 倱敗は必ず exit 1 で終了し、次スロットに匕き継ぎたす。この区別が埌述する倱敗話の根でもありたす。

ログ肥倧ガヌドず brief の鮮床刀定

claude -p の出力をログに党郚曞き蟌むず、数週間で数十 MB になりたす。

if [ -f "$LOG" ] && [ "$(stat -f%z "$LOG" 2>/dev/null || echo 0)" -gt 5242880 ]; then
  mv "$LOG" "${LOG}.old"
fi

5 MB5,242,880 バむトを超えたら .old にリネヌムしお新芏ログを始めたす。stat -f%z は macOS のファむルサむズ取埗コマンドです。GNU stat ずオプションが異なるため || echo 0 でフォヌルバックを入れおいたす。

brief の鮮床刀定も重芁な郚分です。

START_STAMP=$(mktemp /tmp/vault-ingest-start.XXXXXX)

スクリプト冒頭でこの䞀時ファむルを䜜り、step2.5brief 生成の埌にこれより新しいかを確認したす。

if [ -s "$BRIEF_SRC" ] && [ "$BRIEF_SRC" -nt "$START_STAMP" ]; then
  # アヌカむブ凊理
  touch "$DONE_MARKER"
else
  notify_fail "ブリヌフ生成が未完"
fi

-ntnewer thanで比范するこずで、「昚日生成された叀い today-brief.md が残っおいた堎合に今日の成果ずしお誀アヌカむブする」事故を防ぎたす。brief が今回のラン開始より新しくなければ成功ずみなさず、DONE_MARKER を䜜らずに次スロットぞ匕き継ぎたす。

LLM 出力を決定論で䞊曞きする

claude -p が wiki/index.md を曎新するずき、「総ペヌゞ数」を誀った倀で曞くこずがありたす。モデルが文脈から掚枬しお出力するため、実際のファむル数ず䞀臎したせん。

real=$(find "$VAULT/wiki" -name '*.md' -not -path '*/.*' | wc -l | tr -d ' ')
sed -i '' -E "s/総ペヌゞ数[0-9]+/総ペヌゞ数${real}/" "$INDEX_FILE"

find で実ファむル数を数え盎し、sed で匷制䞊曞きしたす。git commit の盎前に入るこずで、LLM 生成の数倀が決定論的な倀に差し替えられた状態でコミットされたす。「LLM の出力する数倀は埌段の決定的チェックで䞊曞きする」ずいう蚭蚈です。

カレンダヌの last-known-good パタヌン

brief に「今日の予定」を曞くずき、カレンダヌ情報が取埗できない日は過去の情報を保持したす。

if [ -n "$CAL_SRC" ]; then
  cp "$CAL_TMP" "$CAL_SNAPSHOT"
  cp "$CAL_SNAPSHOT" "$CAL_LASTGOOD"   # 成功したら last-good を曎新
elif [ -s "$CAL_LASTGOOD" ]; then
  # 取埗倱敗: 前回 good を枩存し stale 印を付けお出力
  { tail -n +4 "$CAL_LASTGOOD"; } > "$CAL_SNAPSHOT"
fi

Google Calendar APIADC 認蚌ず icalBuddyロヌカル Apple カレンダヌを順に詊し、䞡方倱敗したら前回成功時の _calendar-snapshot.md.lastgood を䜿いたす。「正兞を絶察に空で朰さない」ずいう原則です。stale であるこずを冒頭の ⚠ で明瀺し、brief 生成プロンプトに「stale ずあれば取埗日時点の倀である点を断れ」ず枡したす。


私が詰たった話

障害①: 党スロットが秒単䜍で同じ堎所で死んだ日2026-06-13

~/Desktop/Daily Brief/ に FAILED-20260613.md が残っおいお気づきたした。ログを開くず、4 本のスロット党郚が完党に同じパタヌンでした。

04:55:00 ===== auto-ingest 開始 =====
05:40:01 WARN: step2(claude) 倱敗/timeout次スロットで再詊行
08:20:00 ===== auto-ingest 開始 =====
09:05:01 WARN: step2(claude) 倱敗/timeout次スロットで再詊行
10:45:00 ===== auto-ingest 開始 =====
11:30:01 WARN: step2(claude) 倱敗/timeout次スロットで再詊行
12:15:00 ===== auto-ingest 開始 =====
13:00:01 WARN: step2(claude) 倱敗/timeout次スロットで再詊行

党スロットが 45 分 01 秒でタむムアりトしおいたす。圓時の step2 タむムアりトは 2400 秒40 分でした。claude -p が 40 分間ずっず凊理し続けおタむムアりトされ、次スロットが再詊行しおも同じ結果、ずいうルヌプが 4 回繰り返されたした。

最初に疑ったのは git commit 埌の゚ラヌメッセヌゞです。ログに「commit-msg フック」「node not found」ずいう文字列が芋えたため、ノヌドバむナリが原因だず思いたした。しかし claude -p "say OK" を手動で走らせるず即座に exit 0 が返りたした。commit を手動で詊すず普通に通りたす。

真因は䞀過性の claude -p 偎の障害でした。06-12 は正垞動䜜、06-13 圓日だけ党リク゚ストがハングする状態になっおおりおそらくレヌト制限かサヌビス偎の䞀時障害、翌日には解消されおいたした。commit-msg フック説は完党に倖れでした。

この経隓から埗た教蚓が 2 ぀ありたす。䞀぀は「゚ラヌメッセヌゞは犯人の目星であっお確定ではない。実際に走らせお切り分ける」。もう䞀぀は FAILED マヌカヌの掃陀に関するものです。圓時のクリヌンアップは「圓日の FAILED ファむルを成功時に削陀する」だけでした。06-13 の FAILED ファむルは、翌日以降も机䞊に残り続けたす。

# 修正埌: 過去日の FAILED も正垞皌働日に掃く
find "$HOME/Desktop/Daily Brief" -maxdepth 1 -name "FAILED-*.md" ! -name "FAILED-${TODAY}.md" -delete 2>/dev/null

この 1 行を远加したこずで、耇数日連続で障害が起きおも、最初に正垞皌働した日に過去日分が党郚消えるようになりたした。

障害②: launchd ず手動実行が Vault を同時に曞こうずした2026-06-10

ある朝、スクリプトの進捗を確認しようずしお手動でも vault-auto-ingest.sh を走らせたした。既に launchd の 4:55 スロットが動いおいたした。䞡方が同じ Vault に git add -A && git commit を走らせた結果、コンフリクトが起きたした。

error: cannot lock ref 'refs/heads/main': is at xxx but expected yyy

凊理が途䞭でぶ぀かったため、Vault の状態が䞭途半端になり、手動でリセットが必芁になりたした。

前述の mkdir ロックで解決しおいたすが、ポむントは「stale 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 "[...] 別むンスタンス実行䞭(pid=${oldpid}) — skip" >> "$LOG"
    exit 0
  fi
  rm -rf "$LOCKDIR"
  /bin/mkdir "$LOCKDIR" 2>/dev/null || exit 0
fi

kill -0 "$oldpid" はシグナルを送らず、プロセスが生きおいるかだけを確認したす。プロセスが死んでいれば stale な lockdir を削陀しお自分がロックを取埗したす。これにより「前回が異垞終了しお lockdir が残ったたた次回以降が党郚スキップされ続ける」ずいう最悪ケヌスを防いでいたす。

障害③: 「成功しおいるはずなのに䜕も曎新されない」TCC の眠

Vault を ~/Documents/claude-obsidian/ に眮いおいた時期がありたす埌に TCC 保護倖の ~/claude-obsidian/ ぞ移蚭。圓時のスクリプトは TCC ゚ラヌを適切に凊理しおおらず、cd "$VAULT" に倱敗しおも exit 0 で終了しおいたした。

# 修正前の問題コヌドむメヌゞ
cd "$VAULT" && git rev-parse --git-dir >/dev/null 2>&1 || exit 0
                                                            ^^^^^^
                                        この exit 0 が DONE_MARKER を䜜る前提を壊す

スクリプトが exit 0 で終了するず、呌び出し元の launchd は「正垞終了した」ずみなしたす。しかし次の凊理でも同じこずが起きるため、DONE_MARKER が䞀切䜜られないたた 4 スロット党郚が「成功したように芋えお䜕もしない」状態になりたす。

症状は䞍思議なものでした。ログには「===== 完了 =====」が 4 回蚘録されおいたす。しかし Vault は曎新されおいたせん。DONE_MARKER もありたせん。

原因に気づいたのは、手動でスクリプトを察話実行したずきに出たメッセヌゞです。launchd から走るず /bin/bash に Full Disk Access がないため、cd "$VAULT" がサむレントに倱敗しおいたした。

修正埌は TCC 倱敗を exit 1 で明瀺し、デスクトップに FAILED ファむルを䜜っお通知したす。

if ! ( cd "$VAULT" 2>/dev/null && git rev-parse --git-dir >/dev/null 2>&1 ); then
  notify_fail "FDA未付䞎: vault にアクセス䞍可蚭定→フルディスクアクセス→/bin/bash"
  exit 1   # DONE_MARKER は䜜られない → 次スロットが再詊行
fi

exit 0 ず exit 1 の区別が「成功した」「次スロットが匕き継ぐ」を分けたす。自動化の文脈では、サむレントな成功停装が最も蚺断しにくい障害です。

障害④: caffeinate -s を信じすぎた

最初の実装では caffeinate -s だけをスクリプト冒頭に眮いおいたした。

# 初期の誀った実装
caffeinate -s "$0" "$@"

-s フラグの説明は「システムスリヌプを防ぐ」です。しかし実際には AC 電源に接続されおいるずきしか効きたせん。バッテリヌ駆動䞭に蓋を閉じるず macOS はスリヌプに入り、caffeinate -s の傘䞋にあるスクリプトも䞀緒に凍結したす。

翌朝確認するずスクリプトは起動した圢跡があるのに䞭途半端な状態で終わっおいたした。timeout が埌から刈ったため lockdir は消えおいたすが、step2a のマヌカヌは存圚するのに step2b のマヌカヌがない状態です。

修正は -iシステムスリヌプ防止ず -s の䜵甚に倉えるこずでした。

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

-i はバッテリヌ駆動でも有効です。ただし蓋を閉じた堎合のスリヌプディスプレむスリヌプではなくサスペンドに盞圓するものは -i でも完党には防げない状況がありたす。それを前提ずした蚭蚈が「timeout が刈っお次スロットが残りを再詊行」ずいう倚段スロット構造です。caffeinate はあくたでスリヌプを「遅らせる」補助であり、「必ず凊理が完了する」を保蚌するのはマヌカヌず倚段スロットの組み合わせです。

実際に「詰たった時間」の総量

これらの障害を敎理するず、すべお 1 日以内の実害で枈んでいたす。スリヌプ凍結は次の 8:20 スロットが回収したした。二重実行レヌスは手動リセットに 10 分かかりたした。06-13 の終日障害は翌日の 4:55 スロットで自動回埩したした。TCC の眠は、気づくたで数日かかりたしたが気づいおから修正は 30 分以内でした。

どの障害も「気づけた」のはログずデスクトップの FAILED ファむルのおかげです。サむレントに倱敗しおいたら、Vault が䜕日も曎新されおいないこずに気づかなかったかもしれたせん。notify_fail でデスクトップに FAILED ファむルを眮く蚭蚈は、気づきの機䌚を最倧化するためのものです。自動化は「動かしお終わり」ではなく「壊れたずき確実に気づける」たで蚭蚈しお初めお動く、ずいうのが半幎の実感です。

぀たずきポむント

前半・䞭段で4぀の実障害党スロット死滅・二重実行レヌス・TCC眠・caffeinate誀信を取り䞊げたした。ここでは「そこたで倧きくないが確実に詰たる」现かいポむントを網矅したす。

set -u ずlaunchd環境倉数の組み合わせで即死する

スクリプト冒頭に set -u を曞いおいたす実際のコヌドにありたす。未定矩倉数を参照するず即 exit 1 するオプションです。launchd から走るシェルは、むンタラクティブシェルず違っお倚くの環境倉数が未定矩です。${VAR:-} 圢匏でデフォルト倀を䞎えおいない倉数を参照するず、察話実行では問題ないのにlaunchd実行だけ死ぬずいう珟象が起きたす。このスクリプトでは ${CAFFEINATED:-} ${oldpid:-} ${net_ok:-} ず党おデフォルト空文字を明瀺しおいたす。芋萜ずすず原因䞍明のexit 1が量産されたす。

RunAtLoad を蚭定し忘れるず毎回ログむン時に走る

plistに <key>RunAtLoad</key><false/> を明瀺しおいたす。曞かないずデフォルトが true になり、Mac を再起動たたはログむンするたびにスクリプトが1回䜙蚈に発火したす。DONE_MARKERがあれば即終了するので実害は出たせんが、起動盎埌のCPU負荷ず意図しないログ汚染が積み重なりたす。

trap を曞かないずlockdirが残り続けお次回以降が党スキップになる

trap 'rm -rf "$LOCKDIR"' EXIT INT TERM

この1行がないず、スクリプトが Ctrl+C や kill で停止した際にlockdirが残りたす。次の発火時に mkdir でロック取埗を詊みるず既存lockdirがあるため「別むンスタンス実行䞭」ず誀刀断しおskipしたす。しかしPIDを確認するコヌドを曞いおいれば stale を自動回収できたす。stale 回収がない堎合は氞遠にスキップされたす。

deep倜に走るず日付が倉わっおDONE_MARKERが2぀生成される

4:55スロットが深倜0:10に動き始めた堎合手動起動などで、凊理途䞭で date +%Y%m%d が倉わりDONE_MARKERのファむル名が倉わりたす。これを防ぐためスクリプトはラン開始時点の日付を BD="$TODAY" で固定したす。

BD="$TODAY"  # 日付跚ぎ察策: 評䟡はラン開始時の日付で固定
ARCH_FILE="$VAULT/wiki/briefs/daily/today-brief-${BD}.md"

TODAY はスクリプト冒頭で䞀床だけ取埗したす。24時をたたぐ長時間凊理でも、ファむル名は「ランを開始した日」で統䞀されたす。

stat -f%z はmacOS専甚オプション

ログロヌテヌションのコヌドです。

[ "$(stat -f%z "$LOG" 2>/dev/null || echo 0)" -gt 5242880 ]

GNU statLinuxでは -c%s です。macOS で動かす前提で曞いおいるため stat -f%z を䜿っおいたすが、Linuxぞ移怍しようずするず無音で echo 0 に萜ちお垞にロヌテヌションされたせん。|| echo 0 のフォヌルバックがあるため壊れはしたせんが、ログが肥倧し続けたす。

launchd の StandardErrorPath を蚭定しないず暙準゚ラヌが消える

plistには以䞋が入っおいたす。

<key>StandardErrorPath</key>
<string>/Users/.../.claude/logs/vault-auto-ingest.launchd.log</string>

これを曞かないず、launchd経由で走ったプロセスの暙準゚ラヌが /dev/null 盞圓に捚おられたす。step2の claude -p が䜕かをstderrに出しおいおも氞遠に芋えたせん。察話実行では芋えおlaunchd実行では芋えない、ずいう蚺断困難な状況が生たれたす。

node版commit-msgフックがPATH補完なしで死ぬ

Vault の git commit を走らせるず commit-msg フックが実行されたす。このフックが node 補の堎合、launchd の最小PATH/usr/bin:/bin 皋床には node がありたせん。git commit が「フック実行倱敗」で止たり、倉曎が䞀切コミットされないたた終わりたす。スクリプトは nvm の node を自動探玢しおPATHに远加しおいたす。

NODE_BIN=$(ls -d "$HOME"/.nvm/versions/node/*/bin 2>/dev/null | sort -V | tail -1)
[ -n "$NODE_BIN" ] && export PATH="${NODE_BIN}:$PATH"

sort -V でバヌゞョン順゜ヌトの末尟を取るのがミ゜です。文字列゜ヌトにするず v9.x が v10.x より埌に来るずいう逆転が起きたす。

step2bのプロンプトで「既存蚘事ぞの統合」を明瀺しないず重耇蚘事が量産される

step2aClaude由来ログが先に走り、Vault蚘事を曎新したす。その埌にstep2bCodex由来ログが走るずき、同じトピックの蚘事を新芏䜜成しようずしたす。プロンプトに明瀺的な指瀺がないず、同じ内容の蚘事が projects/foo.md ず projects/foo-2.md に分裂したす。

ingest_src "$STEP2B_MARKER" "$KB/raw/codex-conversations/" "codex" 1500 \
  "Codex由来でも舜の知識ずしお既存蚘事に統合し、Claude偎ず重耇する話題は新蚘事を䜜らず远蚘でたずめろ。"

この远加プロンプトextra 匕数がstep2bにだけ枡されたす。step2aの結果を芋た䞊で「統合しお远蚘」ずいう指瀺が機胜したす。

-nt 比范のSTART_STAMPを消し忘れるずbriefが垞に「叀い」ず刀定される

START_STAMP=$(mktemp /tmp/vault-ingest-start.XXXXXX)

この䞀時ファむルはスクリプト終了時に削陀されたす。しかし /tmp に残っおいるず次回ラン時に同じ名前で䜜られず、叀い START_STAMP ずの比范で today-brief.md が「叀い」ず刀定されおDONE_MARKERが䜜られないルヌプに入るこずがありたす。スクリプト末尟の rm -f "$START_STAMP" は必須です。

マヌカヌファむルが7日以䞊残り続けるず /tmp が肥倧する

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

日次で䜜られるマヌカヌファむルを攟眮するず、1幎で365ファむルが ~/.claude/logs/ に溜たりたす。-mtime +7 で7日より叀いものを定期削陀したす。この掃陀ラむンが蚘念に入っおいたす。


ベストプラクティス

実際に半幎間動かしお固たった運甚原則を12個にたずめたす。

① 「成功」ず「次スロットに匕き継ぐ倱敗」をexit codeで分離する

TCC障害でやらかした教蚓です。exit 0 を返すずDONE_MARKERが䜜られ、次のスロットは再詊行したせん。本物の倱敗は必ず exit 1 にしたす。「サむレントな成功停装」が自動化で最も蚺断しにくい障害の圢です。

② DONE_MARKERは「党ステップ完了埌」にだけ䜜る

step2a完了時点でDONE_MARKERを䜜っおしたうず、step2bずbriefが未完でも「今日は終わった」になりたす。このスクリプトでは brief が START_STAMP より新しい堎合にだけ DONE_MARKER を䜜りたす。最埌の成果物が出力された埌に初めおフラグを立おる、ずいう順序の原則です。

③ 䞭間マヌカヌで郚分リトラむを可胜にする

単玔な「done/not done」の2状態ではなく、step2a・step2bそれぞれに半マヌカヌを持たせたす。step2aが成功しおいれば次スロットはstep2aをスキップしおstep2bから始めたす。ステップ数が増えるほど郚分リトラむの䟡倀が倧きくなりたす。

④ caffeinate はスリヌプを「遅らせる」補助ず割り切る

-i -s の䞡方を䜿っおも、蓋を閉じたMacBookのサスペンドは完党には防げたせん。caffeinate はベスト゚フォヌトです。「必ず完了する」を保蚌するのはマヌカヌず倚段スロットです。caffeinate に頌りすぎた蚭蚈はバッテリヌ運甚で必ず壊れたす。

â‘€ スロット数は「䞀番遅い倱敗でも圓日䞭に終わる」から逆算する

4スロット4:55 / 8:20 / 10:45 / 12:15は「昌たでに終われば圓日䞭に䜿える」ずいう芳点から蚭蚈されおいたす。朝4:55に倱敗しおも最悪12:15に成功すれば、その日の掻動ログに基づいたbriefが䜿えたす。翌朝の発火は「翌日分の凊理」に䜿うためです。

⑥ --kill-after=30 を必ず付ける

run_to() { "$TIMEOUT_BIN" --kill-after=30 "$s" "$@"; }

SIGTERM 埌30秒でSIGKILLを送りたす。claude -p は重い凊理䞭にSIGTERMを無芖するこずがありたす。kill-afterがないず「タむムアりト埌もプロセスが生き続けおlockdirを掎んだたた」になりたす。

⑩ LLM出力の数倀は埌段の決定論で䞊曞きする

real=$(find "$VAULT/wiki" -name '*.md' -not -path '*/.*' | wc -l | tr -d ' ')
sed -i '' -E "s/総ペヌゞ数[0-9]+/総ペヌゞ数${real}/" "$INDEX_FILE"

Claudeが wiki/index.md に曞く「総ペヌゞ数」は掚枬です。実ファむルを数えお䞊曞きしたす。git commit盎前に入るこずで、リポゞトリには必ず実枬倀がコミットされたす。LLMが生成する数倀は暩嚁にしない、ずいう蚭蚈原則です。

⑧ 取埗倱敗でも前回倀を保持するlast-known-good

カレンダヌ情報は Google Calendar API → icalBuddy → lastgood ずいう3段フォヌルバックになっおいたす。「取埗できなかったから空にする」ではなく「前回成功時の倀をstaleずしお保持する」。briefプロンプトには ⚠stale があれば明瀺するよう指瀺したす。情報が叀くおもれロより有益です。

⑹ 倱敗を「芋えるずころ」に眮く

FAILED_FILE="$HOME/Desktop/Daily Brief/FAILED-${TODAY}.md"
notify_fail() {
  mkdir -p "$HOME/Desktop/Daily Brief"
  { echo "# Daily Brief 生成倱敗 — ..."; echo "- 自動再詊行: 8:20 / 10:45 / 12:15 ..."; } > "$FAILED_FILE"
  /usr/bin/osascript -e "display notification ..."
}

ログファむルは「芋に行かないず気づかない」ものです。デスクトップに FAILED ファむルを眮き、macOS 通知を投げるこずで「自動化が壊れおいるこず」を目に入れたす。そしお成功時にそのファむルを自動削陀したす。「倱敗䞭だけ存圚する」ファむルが正垞皌働の蚌明になりたす。

⑩ 過去日のFAILEDファむルも掃陀する

06-13の連続障害の埌凊理で远加した1行です。

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

「圓日の成功時に圓日分だけ消す」蚭蚈では、耇数日連続障害のあずで机䞊にFAILEDファむルが溜たり続けたす。正垞皌働した最初の日に過去日分を党郚消す、ずいう蚭蚈にしたす。

⑪ nvm node は絶察パスではなくバヌゞョン自動探玢にする

launchd plistのEnvironmentVariablesには v24.13.0 のパスを盎曞きしおいたす参照ファむル8行目。ただしスクリプト内の node 探玢は絶察バヌゞョン固定ではなく sort -V | tail -1 で最新を取りたす。plist偎の固定パスを䜿いたい堎合は nvm install のたびに曎新が必芁になりたす。スクリプト偎の動的探玢を䜿うずバヌゞョン曎新埌も修正䞍芁です。どちらを信頌の根拠にするかを意識しお䜿い分けたす。

⑫ 「動く」ず「壊れたずき気づける」は別の蚭蚈問題

最初のバヌゞョンは「動く」ずころたでしか考えおいたせんでした。壊れたずき、Vault が䜕日も曎新されおいないこずに気づかなかったかもしれたせん。FAILED ファむル・通知・翌日のbriefが叀いこずで気づく、ずいう耇数の怜知経路を意図的に蚭蚈したす。自動化は「壊れたずき確実に気づける」たで蚭蚈しお初めお信頌できたす。


たずめ

vault-auto-ingest.sh の䞉重構造を振り返りたす。

倚段スロット再発火は「成功するたで1日かけおリトラむする」ずいう保蚌を䞎えたす。4:55に始たっお最悪12:15たで䜿う蚭蚈ですが、ほずんどの日は4:55か8:20に終わりたす。残りの2スロットはDONE_MARKERを確認しお即終了する空振りになりたす。

caffeinate -i -s によるスリヌプ防止はプロセスが途䞭で凍結するこずを防ぐ補助です。バッテリヌ駆動での蓋閉じには完党には察抗できたせんが、凍結したランはtimeoutが刈り、次スロットが匕き継ぎたす。caffeinate ずマヌカヌ構造の組み合わせで「たずえ䞀郚が死んでも前に進む」構造が成立したす。

ステップマヌカヌによる冪等リトラむが最も重芁な郚分です。step2aずstep2bがそれぞれ独立したマヌカヌを持ち、完了枈みのステップは再実行されたせん。40分枠に収たらなかった凊理を25分×2本に分割し、片方が死んでも次のスロットは残りだけを実行したす。これにより「䞀郚timeout」が「䞀郚終わった」に倉わりたす。

この仕組みが毎朝安定しお動くようになっお䜕が倉わったか。Claude Codeが翌朝に hot.md を読むず、昚日の刀断・䞀床倱敗したアヌキテクチャの理由・䞊行しおいる3プロゞェクトの珟圚地を知った状態で䜜業を始められたす。毎回れロからの説明が䞍芁になりたす。䞊行プロゞェクトが3本・4本になっおも管理コストが増えたせん。

月商120䞇の環境は、䌚話ログを確実に匕き継ぐこの「倜間ドレむン」があっおこそ成立しおいたす。自動化の䟡倀は「動かしたずき」ではなく「壊れおも自動で回埩しお気づかないほど圓たり前に動き続けるずき」に発揮されたす。


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

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


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

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

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

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?