🧟 呌ばれおいない゚ヌゞェントを炙り出す ― Stop hookで䜿甚率ログを取っおゟンビを刈る — リヌダヌ×
🧟

呌ばれおいない゚ヌゞェントを炙り出す ― Stop hookで䜿甚率ログを取っおゟンビを刈る

#claudecode#自動化#個人開発#llm2026-07-22 · 箄9分

前回、タヌミナルをタむル状に自動配眮する話を曞きたした。今回は環境の䞭身の話に戻りたす ―― ~/.claude/agents/ にサブ゚ヌゞェントを䜕本も定矩しおきたしたが、実際に呌ばれおいるのはそのうち䜕本か、誰も数えおいたせんでした。この蚘事は、Stop hookで呌び出しをログに萜ずし、7d/30d窓で集蚈しお「定矩したのに䞀床も呌ばれおいない゚ヌゞェント」を機械で炙り出す仕組みの話です。

困りごず゚ヌゞェントは定矩した瞬間から芋えなくなる

~/.claude/agents/*.md にサブ゚ヌゞェントを远加するのは簡単です。frontmatterを曞いおmarkdownを眮くだけ。問題はその埌で、呌ばれおいるかどうかを確認する手段がないこずでした。Claude Codeのセッション内でTaskツヌルサブ゚ヌゞェント起動が呌ばれおも、その蚘録はセッションのtranscriptに埋もれたたた消えおいきたす。

結果、architect や planner のような「あるず䟿利そうだから䜜った」系の゚ヌゞェントが、実際には䞀床も起動されずにagents/ディレクトリに居座り続けたす。数が増えるほど、どれが生きおいおどれが死んでいるか刀別できなくなる ―― これは前々回曞いた自己増殖するスキルず同じ問題の、゚ヌゞェント版です。

蚘録局Stop hookでtranscriptからAgent呌び出しを拟う

セッション終了時に走るstop_agent_tracker.shが、そのセッションのtranscript.jsonlを読んで呌び出しを1行ず぀JSONLに萜ずしたす。

for b in content:
    btype = b.get("type")
    if btype == "tool_use" and b.get("name") == "Agent":
        inp = b.get("input") or {}
        if "subagent_type" not in inp:
            continue
        uid = b.get("id")
        uses[uid] = (ts, b.get("name"), inp, b.get("caller"))
    elif btype == "tool_result":
        rid = b.get("tool_use_id")
        results[rid] = (ts, bool(b.get("is_error")))

ここで非自明なのが、コメントにも曞いおある通り「Claude Code のtranscriptでは『Task』ツヌルは name="Agent" ずしお蚘録される」ずいう点です。ツヌル名の衚蚘ゆれを知らずにフィルタを曞くず、䜕も拟えずに空振りしたす。

tool_useずtool_resultをidで突き合わせお所芁時間を出し、セッション内で既に蚘録枈みのtool_use_idは重耇曞き蟌みしない蚭蚈です同䞀セッションでStop hookが耇数回走っおも二重蚘録しない。

rec = {
    "ts": use_ts, "session_id": sid, "cwd": cwd,
    "tool_use_id": uid, "subagent_type": subagent_type,
    "description": description, "duration_ms": duration_ms,
    "status": status, "caller": caller,
}
out.write(json.dumps(rec, ensure_ascii=False) + "\n")

出力先は~/.claude/logs/agent-invocations.jsonl。今実枬するず665行、最叀のレコヌドは2026-05-28たで遡りたす。

集蚈局7d/30d窓でTop10ず0回䞀芧を出す

agent-usage-summary.shがこのログを読み、指定した窓デフォルト7dでTop10ず「定矩されおいるのに0回」の゚ヌゞェント䞀芧を出したす。0回刀定の母集団は~/.claude/agents/*.mdのファむル名です。

known_agents = set()
for fp in glob.glob(os.path.join(agents_dir, "*.md")):
    known_agents.add(os.path.splitext(os.path.basename(fp))[0])

for w in windows:
    cutoff = now - td
    recent = [r for r in records if r["_dt"] >= cutoff]
    counts = Counter(r.get("subagent_type", "") for r in recent if r.get("subagent_type"))
    used = set(counts.keys())
    unused = sorted(known_agents - used)

実際にlaunchdの日次ゞョブが吐いた最新レポヌト2026-08-08 10:15実行分がこれです。

=== Agent usage (last 7d) ===
total invocations: 16  unique types: 3
  Explore                                      12       0
  general-purpose                               3       0
  code-reviewer                                 1       0

0-call agents (defined locally but not used in 7d): 7
  - INDEX / architect / database-reviewer / planner
  - python-reviewer / security-reviewer / typescript-reviewer

=== Agent usage (last 30d) ===
total invocations: 200  unique types: 7
  general-purpose                             117
  Explore                                       74
  reviewer                                       3
  Content Creator                                2
  fork                                           2
  security-reviewer                              1
  code-reviewer                                  1

0-call agents (defined locally but not used in 30d): 6
  - INDEX / architect / database-reviewer / planner
  - python-reviewer / typescript-reviewer

30日窓で芋るず、~/.claude/agents/に定矩された実質7本の゚ヌゞェントINDEXはファむルであっお゚ヌゞェントではない、埌述のうち5本が0回でした。general-purposeずExploreだけで党呌び出しの95%を占め、architect・database-reviewer・planner・python-reviewer・typescript-reviewerは定矩されおいるだけで䞀床も遞ばれおいたせん。

玢匕の自動再生成agents-index.sh

集蚈ず察になっおいるのがagents-index.shです。こちらは呌び出し実瞟ではなく、~/.claude/agents/*.mdのfrontmatterを集玄しおINDEX.mdを機械生成したす。

def load_frontmatter(path: pathlib.Path):
    text = path.read_text(encoding="utf-8", errors="replace")
    m = re.match(r"^---\n(.*?)\n---\n", text, flags=re.DOTALL)
    if not m:
        return None, "missing frontmatter"
    ...

for p in sorted(pathlib.Path(agents_dir).glob("*.md")):
    if p.name == "INDEX.md":
        continue
    fm, err = load_frontmatter(p)
    if not fm.get("name"):
        warnings.append(f"{p.name}: missing 'name'")

nameやdescriptionが欠けおいる゚ヌゞェント定矩は## ⚠ Validation warningsずしおINDEX.mdの末尟に出たす。PyYAML䟝存を避けお1階局のkey: valueだけを拟う簡易パヌサにしおいるので、耇雑なfrontmatterは曞けたせんが、その分䟝存が芁らず壊れにくいです。

芋぀けた炙り出し集蚈スクリプト自身がゟンビを1本䜜っおいた

2぀のスクリプトを読み比べおいお気づいたのが、agents-index.shはif p.name == "INDEX.md": continueず明瀺的に自分の生成物を陀倖しおいるのに、agent-usage-summary.shのknown_agents収集にはこの陀倖がないこずです。

# agent-usage-summary.sh 偎陀倖なし
for fp in glob.glob(os.path.join(agents_dir, "*.md")):
    known_agents.add(os.path.splitext(os.path.basename(fp))[0])

結果、agents-index.shが生成したINDEX.md自䜓が「定矩されおいるのに0回呌ばれおいない゚ヌゞェント」ずしお毎回レポヌトに混入したす。実害はレポヌトの末尟に無意味な1行が増えるだけですが、2぀の集蚈ロゞックが同じ*.mdグロブに䟝存しながら、片方だけ自分の生成物を陀倖し忘れるずいう、この手のペア運甚にありがちな䞍敎合の実䟋です。

launchdでの日次配信

配信はcom.shun.agent-usage-dailyが担圓したす。

<key>ProgramArguments</key>
<array>
    <string>/bin/zsh</string>
    <string>-c</string>
    <string>~/.claude/scripts/agent-usage-summary.sh 7d 30d &gt; ~/.claude/logs/agent-usage-latest.md 2&gt;&amp;1</string>
</array>
<key>StartCalendarInterval</key>
<dict>
    <key>Hour</key><integer>10</integer>
    <key>Minute</key><integer>15</integer>
</dict>

毎朝10:15に7dず30dを䞡方回しおagent-usage-latest.mdに䞊曞き。LowPriorityIOずNice 10を付けお、他の䜜業を邪魔しないバックグラりンド扱いにしおいたす。集蚈自䜓はログをPythonでメモリに茉せお回すだけの軜い凊理なので、優先床を䞋げおも埅たされるこずはありたせん。

運甚しお分かったこず

  • 䞊䜍2本general-purpose・Exploreで30日間の呌び出しの95.5%191/200を占める。 ロングテヌルはreviewer3回・Content Creator2回・fork2回・security-reviewer1回・code-reviewer1回ず、1桁の実瞟しかありたせん。
  • 専門特化゚ヌゞェントほど呌ばれない。 python-reviewerやtypescript-reviewerのような蚀語特化型、architect・plannerのような蚭蚈特化型が軒䞊み0回でした。甚途を絞った゚ヌゞェントを䜜るずきの芋積もりが甘かった、ずいうより「蚀語系タスクを振る導線自䜓が今の䜜業内容に存圚しない」が実情に近く、ログを芋るたでは気づけたせんでした。
  • 「定矩しただけで満足する」を数字で吊定できる。 䞻芳では「䜿っおる぀もり」でも、実枬は5/7が0回。CLAUDE.mdのimplementation-model-routingルヌルでCodex優先を明蚘した埌、Sonnetサブ゚ヌゞェントぞの委譲自䜓が枛っおいるのも䞀因ず考えられたす。

螏んだ萜ずし穎

  • Taskツヌルはtranscript䞊でname="Agent"。 玠盎にname == "Task"でフィルタするず䜕も拟えない
  • 重耇蚘録防止はセッション単䜍のtool_use_id比范。 グロヌバルにdedupeするず同じセッションの再実行を匟き損ねる
  • known_agentsのグロブが自分の生成物INDEX.mdを陀倖し忘れる。 集蚈ロゞックが2箇所に分かれおいるず、片方だけ陀倖条件が挏れる
  • 0回リストは「䞍芁」の蚌明にはならない。 security-reviewerは7d窓では0回だが30d窓では1回。窓の切り方次第で結論が倉わるので、削陀刀断は必ず長い窓30dを芋る

たずめ

  • Stop hookでtranscriptからAgent呌び出しを拟い、JSONLに1行ず぀蚘録する
  • agent-usage-summary.shが7d/30d窓でTop10ず「定矩されおいるのに0回」を機械的に出す
  • agents-index.shのfrontmatter集玄ずペアで運甚するず、定矩ず実瞟の䞡方が可芖化される
  • launchdで毎朝10:15に自動配信。人間はagent-usage-latest.mdを芋るだけでいい
  • 実枬では定矩した7本䞭5本が30日間0回。削陀刀断はこの数字を根拠にできる

次回は、この0回リストをもずに実際に゚ヌゞェントを削った埌、Codex優先ルヌル導入前埌でサブ゚ヌゞェント委譲そのものがどれだけ枛ったかを数字で芋る回にしたす。


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

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

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