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 Code環境を毎朝Mermaid図に自動生成する

1
Last updated at Posted at 2026-06-23

「Claude Codeを無人で自律改善させる」前作との続きで、今回は環境の肥大化を自覚する仕掛けの話です。

~/.claude/ 配下にスキルが積み重なり、launchdジョブが増え、プロジェクトが二桁を超えたとき、「全体が何層あって今何が動いているか」を即答できなくなりました。毎朝 ls を打つのではなく、Obsidianを開けば俯瞰できる状態を目指して、~/.claude/scripts/env-map.sh を書きました。

困りごと:環境が増えると全体像を忘れる

現状のスナップショットはこうです。

  • plugin bundleのスキル: 1,004個
  • 自己生成スキル(auto/): 77個
  • launchdジョブ(com.shun.*.plist): 24本
  • 把握しているプロジェクト: 11本

スキル・ジョブ・プロジェクトそれぞれの最終更新やgit状態がバラバラで、毎回確認しに行くコストが積み重なります。「今日のautopilotは何をした?」「あのプロジェクトのブランチは?」を1ページで答えられる場所が欲しかった。

設計:3層Mermaid + Obsidianへ出力

図にするのは3層です。

収集内容
💻 PC環境 macOSバージョン・チップ・RAM・ディスク空き・主要CLI
🤖 Claude環境 スキル数・エージェント数・プラグイン数・Hookイベント数・MCP接続数・launchdジョブ数
📦 プロジェクト環境 既知リポジトリのbranch・最終コミット日・未コミット変更数

出力先はObsidian Vault(~/Documents/claude-obsidian/wiki/meta/environment-map.md)。vault-auto-ingest(4:55)が拾って自動コミットするので、バージョン管理もタダで付いてきます。

スクリプトの設計方針はコメントに書いてあります。

# 何が起きても生成を完走させる(個別の収集失敗は "?" で degrade)。set -e は使わない。
set -uo pipefail

set -e を使わないのがポイント。MCP接続確認などで部分的に失敗しても ? を埋めて最後まで出力させます。

launchd最小PATH対策

launchdから起動するとPATHは /usr/bin:/bin:/usr/sbin:/sbin 程度しかない。nodeclaudejqも見つかりません。スクリプトの先頭でPATHを明示的に組み立てます。

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

nvmはnodeバージョンを上げるとパスが変わるので、sort -V | tail -1 で最新版binを動的に解決しています。固定パスを書くと次のバージョンアップで壊れます。

launchdの最小PATHで詰まるのは「ユーザが入れたCLI全般」です。~/.local/bin(uv・claude等)→ Homebrew → nvm の順でフォールバックを積んでおくと、どの環境構成でも当たります。

何を図にすると俯瞰が効くか

Claude環境の収集

AUTO_SKILLS="$(ls "$HOME/.claude/skills/auto/" 2>/dev/null | grep -vc README)"
AGENTS="$(find "$HOME/.claude/plugins" "$HOME/.claude/agents" -path '*/agents/*.md' \
           -o -path "$HOME/.claude/agents/*.md" 2>/dev/null | wc -l | tr -d ' ')"
PLUGINS="$(jq -r '.enabledPlugins // {} | length' "$SETTINGS" 2>/dev/null || echo '?')"
HOOK_EVENTS="$(jq -r '.hooks // {} | keys | length' "$SETTINGS" 2>/dev/null || echo '?')"
LAUNCHD="$(ls "$HOME/Library/LaunchAgents/"com.shun.*.plist 2>/dev/null | wc -l | tr -d ' ')"

MCPだけは注意が必要です。claude mcp listはライブ接続を試みるので起動が遅く、失敗することもある。タイムアウトで押さえます。

MCP_OK="?"
if have claude; then
  _mcp="$(timeout 12 claude mcp list 2>/dev/null)"
  [ -n "$_mcp" ] && MCP_OK="$(printf '%s' "$_mcp" | grep -c 'Connected')"
fi

timeout 12 で12秒経ったら諦め、? のままにします。生成は止めません。

プロジェクトの状態

リポジトリごとにbranch・最終コミット日・未コミット変更数を取得して、ノードの色に反映させます。

proj_meta() {
  local path="$1"
  PROJ_EXISTS=0; PROJ_BRANCH="-"; PROJ_LAST="-"; PROJ_DIRTY=0
  [ -d "$path" ] || return
  PROJ_EXISTS=1
  if git -C "$path" rev-parse --git-dir >/dev/null 2>&1; then
    PROJ_BRANCH="$(git -C "$path" rev-parse --abbrev-ref HEAD 2>/dev/null || echo '-')"
    PROJ_LAST="$(git -C "$path" log -1 --format=%cd --date=format:%Y-%m-%d 2>/dev/null || echo '-')"
    PROJ_DIRTY="$(git -C "$path" status --porcelain 2>/dev/null | wc -l | tr -d ' ')"
  fi
}

未コミット変更があるプロジェクトはオレンジ、ディスクに存在しないプロジェクトは赤で表示します。

echo '  classDef dirty fill:#3a2a00,stroke:#e8a33d,color:#fff;'
echo '  classDef gone  fill:#3a1a1a,stroke:#e06666,color:#fff;'

朝Obsidianを開いただけで「どのプロジェクトにコミット漏れがあるか」が色で分かります。

Mermaidラベルのサニタイズ

ホスト名やチップ名に ()[] が入るとMermaidのパースが壊れます。全ラベルをサニタイズ関数に通します。

san() { printf '%s' "$1" | tr '"[]()#|<>' '        ' | tr '\n' ' ' | sed 's/  */ /g; s/ *$//'; }

Apple M4 Pro (14-core) のような文字列も安全に出力されます。

生成される図のイメージ

Claude環境の内訳はこうなります(実測値)。

launchd設定

<key>StartCalendarInterval</key>
<array>
  <dict><key>Hour</key><integer>4</integer><key>Minute</key><integer>50</integer></dict>
  <dict><key>Hour</key><integer>8</integer><key>Minute</key><integer>10</integer></dict>
</array>
<key>RunAtLoad</key><false/>

4:50に発火するのは、4:55のvault-auto-ingestより前に出力を置くためです。ingestがそのままObsidianへコミットしてくれるのでgit操作が不要。8:10は夜間スリープで4:50がスキップされた場合のキャッチアップです。冪等なので多重発火しても無害。RunAtLoad: false でplist読み込み時の即時発火は抑制します。

ログは1本のファイルに集約します。

<key>StandardOutPath</key>
<string>~/.claude/logs/env-map.launchd.log</string>
<key>StandardErrorPath</key>
<string>~/.claude/logs/env-map.launchd.log</string>

最後の行に generated (N lines) が出ればOKです。

[2026-06-20 04:50:03] environment-map.md generated (218 lines)

踏んだ落とし穴

  • set -eを入れるとMCP timeout時点で終了set -uo pipefailのみ。MCPやgit失敗は?-で継続
  • NVM固定パスを書いたらNode更新で壊れたsort -V | tail -1で最新版binを動的解決
  • Mermaidラベルに()が入ると図がパースエラーsan()関数を全ラベルに通す。チップ名で踏んだ
  • vault-ingestより遅れると生成物が前日分 → 4:50に先行発火、8:10にキャッチアップの二重設定
  • プロジェクトパス変更に気づかない(未検出)赤ノードで可視化。PRIの変更時にリストも更新する
  • 出力先ディレクトリが存在しないと失敗mkdir -p "$(dirname "$OUT")"mv の直前に置く
  • ノードIDのカンマ結合が空白のままだとMermaidが壊れるsed 's/ /,/g' で整形してからclassに渡す

まとめ

  • スキル・launchd・プロジェクトが二桁を超えたらMermaid図で俯瞰する場所を1枚用意する
  • launchd起動時の最小PATHはスクリプト先頭で明示的に組み立てる。nvmはバージョン昇格を想定して動的解決
  • MCP接続確認など遅い処理は**timeoutで囲い、失敗は?でdegrade**させて完走を優先する
  • 出力先をvault-ingest前に置くとバージョン管理もコミットも自動でついてくる
  • プロジェクトの未コミット変更をノード色で可視化すると、朝Obsidianを開いただけでアクションが分かる

本稿と死活監視(automation-health-check)を組み合わせると、「何が動いていて・何が壊れていて・何が積み残されているか」の朝のスナップショットが1ページで揃います。


Lily@bokuwalily)― 個人開発者。Claude Code で自動化基盤を組みながら、iOSアプリやWebサービスを量産しています

皆さんの ❤️ やシェアが励みになります!

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?