ð Stopããã¯ã§ãµããšãŒãžã§ã³ãå°åž³ãèªåçæãã
æ10äžã®å€§åŠçã ã£ãããã坿¥ãæãæã¡ããŠæ60äžãŸã§äŒžã°ããŸãããäŒç€Ÿéœåã§è§£éãããŠäžåºŠ0ã«æ»ããŸããããå幎ãããŠClaude Codeã®èªåŸç°å¢ãæ§ç¯ããä»ã¯æå120äžã§åããŠããŸãããã®ç°å¢ã®åå°ã«ãªã£ãŠããã®ããStopããã¯ã䜿ã£ãã»ãã·ã§ã³åŸã®èªåãã°åéã§ãã
ãªããã®ä»çµã¿ãå¹ãã®ã
Claude Codeã䜿ãã¯ãããŠãã°ããçµã€ãšããã©ãã«ã³ã¹ããããã£ãŠããã®ãããããªãããšããæèŠãåºãŠããŸããExploreãšãŒãžã§ã³ããcode-reviewerãšãŒãžã§ã³ããgeneral-purposeãšãŒãžã§ã³ãââè€æ°ã®ãµããšãŒãžã§ã³ããçµã¿åãããŠäœæ¥ãããªããŠãããã¡ãæ°ã¥ãã°ã»ãã·ã§ã³ãäœååãåã£ãŠãããã§ãã©ã®ãšãŒãžã§ã³ããé ãã®ããã©ã®ãšãŒãžã§ã³ãããããšã©ãŒãåºããŠããã®ããæ°åã§èŠãããšã¯ãããŸããã§ããã
æèŠã§ããã®ãšãŒãžã§ã³ãã¯éãããšèšãã®ã¯ãããŒã¿ã§ã¯ãããŸãããæ¹åãããã«ããã©ããçŽãã°ããããäžæã®ãŸãŸãããã¯å人éçºã§ã·ã¹ãã ãéç£ããŠãã身ãšããŠã¯èŽåœçãªç¶æ ã§ããä»äºã®æµããæé©åããã«ã¯ããŸãèšæž¬ããå§ããå¿ èŠããããŸãã
Claude Codeã«ã¯ãã®èšæž¬ãèªååã§ããä»çµã¿ãæåããçµã¿èŸŒãŸããŠããŸããStopããã¯ã§ãã
Stopããã¯ã¯ãClaude Codeã®ã»ãã·ã§ã³ãçµäºãããã³ã«åŒã°ããã·ã§ã«ã¹ã¯ãªããã§ããããã¯ã«ã¯transcript_pathãæž¡ãããŸããããã¯ãã®ã»ãã·ã§ã³å
šäœã®äŒè©±ãã°ââããŒã«åŒã³åºãããšãŒãžã§ã³ãèµ·åãã¬ã¹ãã³ã¹ã®ã¿ã€ã ã¹ã¿ã³ããŸã§å«ãçã®JSONLââãžã®ãã¹ã§ããã€ãŸãã»ãã·ã§ã³ãçµãããã³ã«ãããã®ã»ãã·ã§ã³ã§äœãèµ·ãããããäžžããšèªã¿èŸŒããã£ã³ã¹ãèªåçã«çãŸããŸãã
ããã«æ°ã¥ããŠãããèããå€ãããŸãããèšé²ãæåã§ã€ããå¿
èŠã¯ãããŸãããã»ãã·ã§ã³çµäºãèµ·ç¹ã«ã¹ã¯ãªãããèµ°ãããtranscript_pathãè§£æããŠãµããšãŒãžã§ã³ãåŒã³åºãã®äžèЧãJSONLã«æžãåºããããã ãã§ãã©ã®ãšãŒãžã§ã³ããäœç§ããã£ããã»æåããã倱æãããããèç©ãããŠãããŸãã
ããšã¯ãã®å°åž³ãjqã§éèšããã°ãæèŠè«ããæ°åã®è°è«ãžç§»è¡ã§ããŸãã
ããäžã€éèŠãªç¹ããããŸãããã®ã¢ãããŒãã¯Claude Codeæ¬äœã«äœãæãå ããŸãããStopããã¯ã¯~/.claude/settings.jsonã«1è¡è¿œå ããã ãã§æå¹ã«ãªããŸããå
ã®åäœãå€ãããã»ãã·ã§ã³çµäºãšããæ¢åã®ã€ãã³ãã«ä¹ã£ããã ãã§ããå¯äœçšããŒãã«è¿ãã®ã¯ãéç£ç°å¢ãç¶æããããã§å€§ããªã¡ãªããã§ãã
transcript.jsonlã«äœãå ¥ã£ãŠããã
Stopããã¯ãåãåãJSONã®ãã¡éèŠãªãã£ãŒã«ãã¯äºã€ã§ãã
{
"session_id": "...",
"transcript_path": "/path/to/transcript.jsonl"
}
transcript_pathãæããã¡ã€ã«ã«ã¯ããã®ã»ãã·ã§ã³ã§äº€ãããããã¹ãŠã®ã¡ãã»ãŒãžãJSONL圢åŒïŒ1è¡1JSONïŒã§äžŠãã§ããŸããåè¡ã®message.contentã®äžã«ãããŒã«åŒã³åºãã瀺ã"type": "tool_use"ã®ãããã¯ãå«ãŸããŠããŸãã
ãµããšãŒãžã§ã³ãã®èµ·åã¯ãã®äžã§"name": "Agent"ãšããŠèšé²ãããŸããæ³šæç¹ãšããŠãClaude Codeã®å
éšã§ã¯UIã«ãTaskããšè¡šç€ºãããŠããã«ãããããããtranscriptäžã®ããŒã«åã¯"Agent"ã§ãïŒã¹ã¯ãªããã®ã³ã¡ã³ãã«ããClaude Code ã® transcript ã§ã¯ãTaskãããŒã«ã¯ name="Agent" ãšããŠèšé²ãããããšæç€ºãããŠããŸãïŒãsubagent_typeã¯input.subagent_typeã«å
¥ã£ãŠããŸãã
ãšãŒãžã§ã³ãåŒã³åºãã«å¯Ÿããçµæã¯"type": "tool_result"ãšããŠå¥è¡ã«çŸããtool_use_idã§åŒã³åºãåŽãšçµã³ã€ããŠããŸããis_error: trueãããã°ãšã©ãŒçµäºããªããã°æåã§ãã
ãã®æ§é ããææ¡ããŠããã°ãPythonã§2ãã¹åŠçããã ãã§ãµããšãŒãžã§ã³ãã®å®è¡èšé²ãåããŸãã
å šäœã®æµã
ã·ã¹ãã å šäœãå³ã§ç€ºããšæ¬¡ã®ããã«ãªããŸãã
Claude Codeã»ãã·ã§ã³
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â tool_use (name="Agent", subagent_type="Explore") â
â ...åŠçäž... â
â tool_result (tool_use_id=xxx, is_error=false) â
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â ã»ãã·ã§ã³çµäº (Stop ã€ãã³ã)
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â Stop hook: stop_agent_tracker.sh â
â stdin: {"session_id", "transcript_path", ...} â
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â transcript_path ãèªã¿èŸŒã
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â Python: 2ãã¹è§£æ â
â Pass1: uses{} / results{} ãæ§ç¯ â
â Pass2: tool_use_id ã§çªãåããã»durationç®åº â
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â 远èš
~/.claude/logs/agent-invocations.jsonl
Stopããã¯ãèµ·åããããšãstdinããJSONãåãåãããã®äžã®transcript_pathã䜿ã£ãŠPythonã¹ã¯ãªããããã©ã³ã¹ã¯ãªãããèªã¿ãŸããåºåå
ã¯åºå®ã§~/.claude/logs/agent-invocations.jsonlã§ãã
stop_agent_tracker.sh ã®äžèº«
ã¹ã¯ãªããã®å®äœã¯ã»ãŒPythonã§ããshelléšåã¯ç°å¢å€æ°ã®åãæž¡ãã®ã¿æ åœããŠããŸãã
INPUT=$(cat) # stdin ãã Stop ã€ãã³ã JSON ãåãåã
export STOP_INPUT="$INPUT"
export OUT_LOG_PATH="$OUT_LOG" # ~/.claude/logs/agent-invocations.jsonl
Pythonéšåã¯å€§ãã3ãããã¯ã«åãããŠããŸãã
éè€é²æ¢ãããã¯
åäžã»ãã·ã§ã³ã§è€æ°åStopããã¯ãèµ°ã£ãå ŽåïŒClaude Codeã®ä»æ§äžããããŸãïŒã«åããšã³ããªãäºéæžãããªããããæ¢åãã°ããsession_idãštool_use_idã®çµã¿åãããèªã¿èŸŒãã§seen_idsã»ããã«å
¥ããŸãã
seen_ids = set()
if os.path.exists(out_path):
with open(out_path, "r", ...) as f:
for line in f:
r = json.loads(line)
if r.get("session_id") == sid and r.get("tool_use_id"):
seen_ids.add(r["tool_use_id"])
第1ãã¹: ã€ã³ããã¯ã¹æ§ç¯
ãã©ã³ã¹ã¯ãªããã1è¡ãã€èªã¿ã"name": "Agent"ãã€subagent_typeãæã€tool_useãããã¯ãusesèŸæžãžãtool_resultãããã¯ãresultsèŸæžãžããããæ ŒçŽããŸãã
uses = {} # tool_use_id -> (ts, name, input, caller)
results = {} # tool_use_id -> (ts, is_error)
for b in content:
if b.get("type") == "tool_use" and b.get("name") == "Agent":
inp = b.get("input") or {}
if "subagent_type" not in inp:
continue
uses[uid] = (ts, b.get("name"), inp, b.get("caller"))
elif b.get("type") == "tool_result":
results[rid] = (ts, bool(b.get("is_error")))
subagent_typeãæããªãAgentåŒã³åºãã¯ã¹ãããããŠããŸããããã¯ã¡ã€ã³ã®ClaudeãšãŒãžã§ã³ãèªèº«ã®åŒã³åºããé€å€ããããã®å€å®ã§ãã
第2ãã¹: çªãåãããšæžãåºã
usesãèµ°æ»ãã察å¿ããresultsãšã³ããªãããã°duration_msãèšç®ããŠæžãåºããŸãã
t0 = parse_ts(use_ts) # tool_use ã®ã¿ã€ã ã¹ã¿ã³ã
t1 = parse_ts(res_ts) # tool_result ã®ã¿ã€ã ã¹ã¿ã³ã
if t0 and t1:
duration_ms = int((t1 - t0).total_seconds() * 1000)
çµæããŸã è¿ã£ãŠããŠããªããšã³ããªã¯"status": "pending"ã§èšé²ããŸãã
descriptionãã£ãŒã«ãã¯300æåã§ãã©ã³ã±ãŒããããŸããããã¯ãšãŒãžã§ã³ããžã®æç€ºæãé·ãå Žåã§ããã°ãã¡ã€ã«ã®ãµã€ãºãå¶åŸ¡ããããã®æªçœ®ã§ãã
if len(description) > 300:
description = description[:300] + "âŠ"
æçµçã«æžãåºãããJSONLã®1è¡ã¯æ¬¡ã®åœ¢ã§ãã
{
"ts": "2026-09-10T08:30:00Z",
"session_id": "abc123",
"cwd": "~/dev/my-project",
"tool_use_id": "toolu_01Xyz...",
"subagent_type": "Explore",
"description": "Find all TypeScript files that reference the Auth moduleâŠ",
"duration_ms": 18420,
"status": "ok",
"caller": null
}
ãã£ãŒã«ããæŽçãããšãsubagent_typeããšãŒãžã§ã³ãã®çš®é¡ãduration_msãå®è¡æéïŒããªç§ïŒãstatusã"ok" / "error" / "pending"ã®3å€ã§ããcallerã¯åŒã³åºãå
ã®æ
å ±ã§ãããå€ãã®å Žånullã«ãªããŸãã
ãªã2ãã¹ãªã®ã
1ãã¹ã§tool_useãèªãã æç¹ã§ã¯ã察å¿ããtool_resultããŸã çŸããŠããªãå¯èœæ§ããããŸããJSONLã¯æç³»åé ã«äžŠãã§ããŸãããé·ããšãŒãžã§ã³ãå®è¡ã§ã¯éã«ä»ã®ã¡ãã»ãŒãžãæãŸãããšããããŸããå
ã«å
šè¡ãèªãã§ã€ã³ããã¯ã¹ãäœããåŸããçªãåããã2ãã¹æ§é ã«ããããšã§ç¢ºå®ã«ãã¢ãååŸã§ããŸãã
ãŸããparse_ts颿°ã¯ISO8601ã®ã¿ã€ã ã¹ã¿ã³ããdatetimeãªããžã§ã¯ãã«å€æããéã«ãæ«å°Ÿã®Zã+00:00ã«çœ®æããŠfromisoformatã«æž¡ããŸãã
def parse_ts(s):
try:
return datetime.datetime.fromisoformat(s.replace("Z", "+00:00"))
except Exception:
return None
Pythonã®fromisoformatã¯3.11æªæºã§ã¯Zãµãã£ãã¯ã¹ãçŽæ¥ããŒã¹ã§ããªãããããã®å€æãå¿
èŠã§ãã
ãã°ã®èç©æ¹æ³
ã¹ã¯ãªããã¯"a"ã¢ãŒãïŒè¿œèšïŒã§ãã¡ã€ã«ãéããŸããæ¯ã»ãã·ã§ã³æ°ããã¬ã³ãŒããæ«å°Ÿã«è¿œå ãããŠãã圢ã§ãããã¡ã€ã«ãååšããªãå Žåã¯èªåäœæãããŸãïŒLOG_DIRã®mkdir -pã§æ
ä¿ïŒã
ã»ãã·ã§ã³ããŸããã ããŒã¿ãèç©ããããããæ°æ¥ããæ°é±é䜿ãç¶ãããšããã€ãExploreãšãŒãžã§ã³ãã20ç§ä»¥äžããã£ãŠããããcode-reviewerãšãŒãžã§ã³ããããŸã«ãšã©ãŒãåºããŠããããšãã£ãåŸåãæµ®ãã³äžãã£ãŠããŸãã
ã³ã¹ããã°ã¹ã¯ãªããã®è§£å
stop_agent_tracker.shãšäžŠãã§åããŠããã®ãstop_cost_log.shã§ãããã¡ãã¯ã»ãã·ã§ã³ã§æ¶è²»ãããããŒã¯ã³æ°ãšæšå®ã³ã¹ãã~/.claude/logs/cost-log.jsonlã«èšé²ããŸãããšãŒãžã§ã³ãã®é
ããšäžŠãã§ããã€ã»ã©ã®ã»ãã·ã§ã³ã§ãããããã£ããããææ¡ããŠããã®ã¯ãéç£ç°å¢ã®ç¶æã«æ¬ ãããŸããã
PRICINGããŒãã«ãšãã¬ãã£ãã¯ã¹ããã
æéããŒãã«ã®å®è£ ã¯æ¬¡ã®ããã«ãªã£ãŠããŸãã
PRICING = {
"claude-opus-4-7": {"input": 15.0, "output": 75.0, "cache_read": 1.5, "cache_create_5m": 18.75, "cache_create_1h": 30.0},
"claude-sonnet-4-6": {"input": 3.0, "output": 15.0, "cache_read": 0.3, "cache_create_5m": 3.75, "cache_create_1h": 6.0},
"claude-haiku-4-5": {"input": 1.0, "output": 5.0, "cache_read": 0.1, "cache_create_5m": 1.25, "cache_create_1h": 2.0},
}
DEFAULT_RATE = PRICING["claude-sonnet-4-6"]
def rate_for(model: str):
for k, v in PRICING.items():
if model.startswith(k):
return v
return DEFAULT_RATE
èŸæžã®ããŒããå®å
šäžèŽãã§ã¯ãªããåæ¹äžèŽïŒstartswithïŒãã«ããŠããã®ããã€ã³ãã§ããClaude Codeããã©ã³ã¹ã¯ãªããã«æžãåºãã¢ãã«åã«ã¯ãclaude-sonnet-4-6-20250620ã®ããã«ãªãªãŒã¹æ¥ãµãã£ãã¯ã¹ãã€ãå ŽåããããŸããå®å
šäžèŽã«ããŠããŸããšããã€ããŒããŒãžã§ã³ãæŽæ°ããããã³ã«PRICINGãæžãçŽã矜ç®ã«ãªããŸãããã¬ãã£ãã¯ã¹ã§åŒã£ãããã°ããµãã£ãã¯ã¹ã®å€åãåžåã§ããŸããæªç¥ã®ã¢ãã«ã¯Sonnetçžåœã§ãã©ãŒã«ããã¯ããDEFAULT_RATEããããããããŒãã«ã«ãªãã¢ãã«ãç»å ŽããŠãéèšãæ¢ãŸããŸããã
ãã£ãã·ã¥ããŒã¯ã³ã®5åæ ãš1æéæ
Anthropic APIã®ãã£ãã·ã¥ã«ã¯5åæå¹ã®ãšãã§ã¡ã©ã«ãã£ãã·ã¥ãš1æéæå¹ã®ãã£ãã·ã¥ã®2çš®é¡ããããæéãç°ãªããŸãïŒå䟡æ¯ã¯çŽ1:1.6ïŒãã¹ã¯ãªããã¯ãããå¥ã ã«éèšããŠããŸãã
cc_5m = (usage.get("cache_creation", {}) or {}).get("ephemeral_5m_input_tokens", 0) or 0
cc_1h = (usage.get("cache_creation", {}) or {}).get("ephemeral_1h_input_tokens", 0) or 0
if cc_5m + cc_1h == 0 and cc_total > 0:
cc_5m = cc_total
æåŸã®3è¡ãæŽåæ§ãã§ãã¯ã§ããClaude Codeã®å€ãããŒãžã§ã³ãç¹å®ã®æ¡ä»¶ã§ã¯ãcache_creationã®å
¥ãåãªããžã§ã¯ããååšããããã©ãããªcache_creation_input_tokensã®ã¿ãè¿ã£ãŠããããšããããŸãããã®å Žåã«cc_5m + cc_1h == 0ãã€cc_total > 0ãšããç¶æ
ã«ãªããããå
šéã5åæ ãšããŠæ±ããŸãã5åæ ã®ã»ããå®ãã®ã§ãããã¯ã³ã¹ãéå°è©äŸ¡ã®æ¹åã«ãã€ã¢ã¹ãããããŸããé倧ã«åºãããã¯ææ¡ãããããšãã倿ã§ãã
ã³ã¹ãèšç®åŒ
cost_usd += (
inp / 1_000_000 * r["input"]
+ out / 1_000_000 * r["output"]
+ cr / 1_000_000 * r["cache_read"]
+ cc_5m / 1_000_000 * r["cache_create_5m"]
+ cc_1h / 1_000_000 * r["cache_create_1h"]
)
åäœã¯ã$/MTokïŒçŸäžããŒã¯ã³ããããã«ïŒããªã®ã§ãããŒã¯ã³æ°ã1_000_000ã§å²ã£ãŠããæããŸãã_åºåãã®æ°å€ãªãã©ã«ã䜿ã£ãŠããã®ã¯å¯èªæ§ã®ããã§ãPython 3.6以éãªãåããŸããã»ãã·ã§ã³ã®ãã¹ãŠã®ã¡ãã»ãŒãžãèµ°æ»ããŠcost_usdãç©ç®ããæåŸã«round(cost_usd, 4)ã§å°æ°ç¹4æ¡ã«äžžããŠèšé²ããŸãã
jqã§å°åž³ãéèšãã
ãã°ãæºãŸã£ããjqã§åããç«ãŠãããŸãã以äžã¯ãã¹ãŠ~/.claude/logs/agent-invocations.jsonlã察象ã«ããå®éã®ã¯ãšãªã§ãã
ãšãŒãžã§ã³ãçš®å¥ããšã®å¹³åã»æå€§å®è¡æéãåºã
jq -s '
group_by(.subagent_type) |
map({
type: .[0].subagent_type,
count: length,
avg_ms: (map(select(.duration_ms != null) | .duration_ms) | add / length | round),
max_ms: (map(select(.duration_ms != null) | .duration_ms) | max)
}) | sort_by(-.avg_ms)
' ~/.claude/logs/agent-invocations.jsonl
group_byã§çš®å¥ããšã«æããavg_msãšmax_msãèšç®ããŠéé ã«äžŠã¹ãŸããå®éã«ãããèµ°ããããšãç§ã®ç°å¢ã§ã¯ExploreãšãŒãžã§ã³ããå¹³å22ç§ååŸãcode-reviewerãå¹³å37ç§ãgeneral-purposeãå¹³å18ç§ãšããååžã§ãããcode-reviewerãé
ãçç±ã¯è€æ°ãã¡ã€ã«ãèªã¿èŸŒãã§ããããã§ããããæ°åã§ç¢ºèªã§ããŠãããè€æ°ãã¡ã€ã«æšªæã®ç¢ºèªã«code-reviewerã䜿ãã®ã¯éãããšããæèŠè«ã«æ ¹æ ãã€ããŸããã
ãšã©ãŒçãé«ããšãŒãžã§ã³ããç¹å®ãã
jq -s '
group_by(.subagent_type) |
map({
type: .[0].subagent_type,
total: length,
errors: map(select(.status == "error")) | length,
error_rate: ((map(select(.status == "error")) | length) / length * 100 | round)
}) | sort_by(-.error_rate)
' ~/.claude/logs/agent-invocations.jsonl
ç¹å®ã®ãããžã§ã¯ãïŒcwdïŒã§ã®ã³ã¹ããåç®ãã
jq -s '
map(select(.cwd | contains("my-project"))) |
{ total_cost: (map(.cost_usd) | add) }
' ~/.claude/logs/cost-log.jsonl
ã³ã¹ããã°ã®ã»ãã«ãcwdãã£ãŒã«ããå
¥ã£ãŠããããããããžã§ã¯ãã®ãã¹åã§ãã£ã«ã¿ããŠåèšã³ã¹ããåºããŸããã©ã®ãããžã§ã¯ãã«ã©ãã ã䜿ã£ãããäžç®ã§èŠããããã«ãªããšãæ¡ç®ã®æèŠãå€ãããŸãã
ç§ãè©°ãŸã£ã話
å®è£ ã宿ãããŸã§ã«4ã€ã®å ·äœçãªè©°ãŸããçµéšããŸãããããããããªãåããªãã®ãããããããªããã¿ã€ãã®ãã°ã§ãçç¶ã ãèŠããšåå ãèŠãã«ãããã®ã§ãã
è©°ãŸãâ ïŒstdnã空ã«ãªã£ãŠPythonãäœãåŠçããªã
æåã«æžããããŒãžã§ã³ã§ã¯ãã·ã§ã«ãšPythonãæ¬¡ã®ããã«ç¹ãã§ããŸããã
cat | python3 - <<'PY'
data = json.load(sys.stdin) # â ããã§ç©ºãè¿ã£ãŠãã
PY
ããã¢ããã¥ã¡ã³ãã®Pythonã¹ã¯ãªããèªäœãstdinã§æž¡ããŠããã®ã§ãsys.stdinã§å
¥åãèªããããšããåéãã§ããå®éã«ã¯<<'PY'ãã·ã§ã«ã«ãšã£ãŠã®stdinãå æããŠãããããã¹ã¯ãªããå®è¡æç¹ã§ã®sys.stdinã¯ãã§ã«EOFã«ãªã£ãŠããŸããcatã§Stopããã¯ã®JSONãåãåã£ãŠããŠãããããPythonã«å±ãçµè·¯ããããŸããã
çŽãæ¹ã¯ã·ã³ãã«ã§ããäžåºŠã·ã§ã«å€æ°ã«å ¥ããŠããç°å¢å€æ°ãšããŠæž¡ããã§ãã
INPUT=$(cat)
export STOP_INPUT="$INPUT"
python3 - <<'PY'
data = json.loads(os.environ.get("STOP_INPUT", ""))
PY
INPUT=$(cat)ã§Stopããã¯ã®JSONãèªã¿èŸŒã¿ãexportã§ç°å¢å€æ°ã«ããŸãããã¢ããã¥ã¡ã³ãã®Pythonå
ã§ã¯os.environããèªãããã®è¿åè·¯ãåãããšã§ãstdinã®ç«¶åãåé¿ã§ããŸããå®éã®ã¹ã¯ãªããããã®åœ¢ã«ãªã£ãŠããã®ã¯ãã®çµç·¯ãããããã§ãã
è©°ãŸãâ¡ïŒfromisoformatãZã§èœã¡ã
ãã©ã³ã¹ã¯ãªããã®ã¿ã€ã ã¹ã¿ã³ãã¯"2026-09-10T08:30:00Z"ã®åœ¢åŒã§å
¥ã£ãŠããŸããæåã¯çŽ çŽã«datetime.fromisoformat(ts)ãšæžããŸããã
# Python 3.10以åã§ã¯ããã ValueError ã«ãªã
datetime.datetime.fromisoformat("2026-09-10T08:30:00Z")
macOSã®ã·ã¹ãã Pythonã3.10ã ã£ãããããã®1è¡ãValueErrorãæããŠã¹ã¯ãªãããæ¢ãŸããŸãããtry/exceptãæžããŠããªãã£ãã®ã§ãStopããã¯å
šäœããšã©ãŒçµäºãããã°ãäœãæ®ããªãç¶æ
ãæ°æ¥ç¶ããŸããããªããã°ãçæãããªãã®ããå
šããããããæçµçã«CC_AGENT_TRACKER_DEBUG=1ã§ãããã°ãã°ãæå¹ã«ããŠåããŠåå ãããããŸããã
ä¿®æ£ã¯parse_ts颿°ã®äžã«åãŸã£ãŠããŸãã
def parse_ts(s):
if not s:
return None
try:
return datetime.datetime.fromisoformat(s.replace("Z", "+00:00"))
except Exception:
return None
Zã+00:00ã«çœ®æããŠããæž¡ããšãPython 3.7以éã§åããŸããããã«try/exceptã§å²ãã§ãããããæ³å®å€ã®åœ¢åŒãæ¥ãŠãã¹ã¯ãªãããæ¢ãŸããã«Noneãè¿ããŸããduration_msã®èšç®ã¯ãt0ãšt1ãäž¡æ¹Noneã§ãªãå Žåã®ã¿è¡ãããšããæ¡ä»¶ã«ãªã£ãŠããã®ã§ãNoneãè¿ã£ãŠãããšã³ããªã¯duration_ms: nullã§èšé²ãããŸããèšç®ã諊ããŠèšé²ã¯æ®ãããšããæ¹éã§ãã
è©°ãŸãâ¢ïŒStopããã¯ãåäžã»ãã·ã§ã³ã§è€æ°ååŒã°ããŠéè€æžããèµ·ãã
Stopããã¯ãæå¹ã«ããŠæ°æ¥åŸããã°ã«åãtool_use_idã®ãšã³ããªãéè€ããŠããã®ãçºèŠããŸãããããšãã°3æéåãããã»ãã·ã§ã³ã®ããšãagent-invocations.jsonlã確èªãããšåäžIDã®ã¬ã³ãŒãã2è¡å
¥ã£ãŠããã
Claude Codeã¯æ¡ä»¶ã«ãã£ãŠSessionã®çµäºã€ãã³ããè€æ°åçºè¡ããããšããããŸãïŒãµãããã»ã¹ã®çµäºãšã¡ã€ã³ã»ãã·ã§ã³ã®çµäºãéãªãã±ãŒã¹çïŒãã€ãŸãåäžã»ãã·ã§ã³ã«å¯ŸããŠStopããã¯ã2åèµ°ãã2åç®ãåããã©ã³ã¹ã¯ãªãããèªãã§åãã¬ã³ãŒããæžãåºãããšããç¶æ ã§ããã
察åŠãšããŠããã®ã»ãã·ã§ã³ã§æ¢ã«æžããtool_use_idãã»ããåããŠã次åã¹ãããããããšããéè€é²æ¢ããžãã¯ãåé ã«è¿œå ããŸããã
seen_ids = set()
if os.path.exists(out_path):
with open(out_path, "r", encoding="utf-8", errors="replace") as f:
for line in f:
try:
r = json.loads(line)
if r.get("session_id") == sid and r.get("tool_use_id"):
seen_ids.add(r["tool_use_id"])
except Exception:
continue
æžãåºãæã¯æ¬¡ã®ããã«å€å®ããŸãã
for uid, (use_ts, _, inp, caller) in uses.items():
if uid in seen_ids:
continue # æ¢ã«èšé²æžã¿ãªãã¹ããã
session_idãštool_use_idã®çµã¿åããã§åäžæ§ãå€å®ããŠããã®ã¯ãã»ãã·ã§ã³ããŸããã§åãtool_use_idãè¡çªãã確çããŒãã§ãªãããã§ãïŒUUIDãªã®ã§æ¥µããŠäœãã§ããã念ã®ããïŒãæ¢åãã°å
šäœãèªãã®ã§ã¯ãªããåäžsession_idã®ç¯å²ã ããèªãç¹ãããã©ãŒãã³ã¹äžã®é
æ
®ã§ãã
è©°ãŸãâ£ïŒname="Task"ã§ãã£ã«ã¿ãããäœãåããªã
æåã«ãã©ã³ã¹ã¯ãªããã®æ§é ã調ã¹ããšããClaude Codeã®ã€ã³ã¿ãŒãã§ãŒã¹äžã«ãTaskããšè¡šç€ºãããŠãããããã¹ã¯ãªããã§ã次ã®ããã«æžããŸããã
if btype == "tool_use" and b.get("name") == "Task":
ããã§å®è¡ããŠããã°ã«äœãèšé²ãããŸããããããã°ã®ããã«ãã£ã«ã¿ãã¯ãããŠå
štool_useãåºåãããšãããå®éã®ãã©ã³ã¹ã¯ãªããã«ã¯"name": "Agent"ãšããŠèšé²ãããŠããããšãããããŸããã
UIã®è¡šç€ºåãšãã©ã³ã¹ã¯ãªããäžã®ããŒã«åãäžèŽããŠããªããããã¯Claude Codeã®ã€ã³ã¿ãŒãã«ãªåœåã®é察称æ§ã§ãããã¥ã¡ã³ãã«ã¯æèšãããŠããŸãããå®éã®ã¹ã¯ãªããã«ã³ã¡ã³ãã§ãClaude Code ã® transcript ã§ã¯ãTaskãããŒã«ã¯ name="Agent" ãšããŠèšé²ãããããšæç€ºããŠããã®ã¯ãã®çµéšããã§ããåãèœãšã穎ã«ã¯ãŸããªããããæåã«ç®ã«ããå Žæã«æžãæ®ããŠããŸãã
æ£ãããã£ã«ã¿ã¯æ¬¡ã®2æ¡ä»¶ã®çµã¿åããã§ãã
if btype == "tool_use" and b.get("name") == "Agent":
inp = b.get("input") or {}
if "subagent_type" not in inp:
continue
name == "Agent"ãã€inputã«subagent_typeãååšããè¡ã ãã察象ã«ããŸããsubagent_typeã®ãªãAgentåŒã³åºãã¯ã¡ã€ã³ã®Claudeã»ãã·ã§ã³èªäœã®ãšã³ããªã§ããå Žåãããããããé€å€ããããã«2段ãã£ã«ã¿ã«ãªã£ãŠããŸãã
è©°ãŸãâ€ïŒset -eã§ç¡èšæ»ãããã°ãå
šãæ®ããªã
åæããŒãžã§ã³ã®ã·ã§ã«ãããã¯set -euo pipefailã§ããã-eã¯ã³ãã³ããéãŒãã§çµäºãããã·ã§ã«å
šäœãå³çµäºããèšå®ã§ãã
åé¡ãèµ·ããã®ã¯ããã©ã³ã¹ã¯ãªãããååšããªãã»ãã·ã§ã³ãã§å®è¡ããããšãã§ããClaude Codeã®è»œéã»ãã·ã§ã³ïŒçã質åãããŠçµäºããã ãïŒã§ã¯ãã©ã³ã¹ã¯ãªãããçæãããªãããšããããŸãããã®ãšãos.path.exists(tp)ãFalseãè¿ããŠPythonãsys.exit(0)ã§çµäºããŸããããã®å段ã®[ -z "$INPUT" ] && exit 0ã§ã·ã§ã«ãæ£åžžçµäºãããã¹ããããŸãã-eãæå¹ã ãš&&ã®è©äŸ¡çµæã«ãã£ãŠã¯æå³ããã¹ã¯ãªãããæ¢ãŸãã±ãŒã¹ãåºãŠããŸããã
ãŸããPythonã¹ã¯ãªããå
ã§sys.exit(0)ãåŒã¶ãšæ£åžžçµäºïŒçµäºã³ãŒã0ïŒãªã®ã§åé¡ãªãã®ã§ãããç°å¢ã«ãã£ãŠpython3ã³ãã³ãèªäœãèŠã€ãããªãïŒPATHãéã£ãŠããªãïŒå Žåã«çµäºã³ãŒã127ãè¿ãã-eã«ãã£ãŠã·ã§ã«ãæ¢ãŸã£ãŠåŸæ®µã®åŠçãå
šéšã¹ããããããããšããããŸããã
ä¿®æ£ã¯-eãå€ããŠ-uo pipefailã«ããããšã§ãã
set -uo pipefail
-uã¯æªå®çŸ©å€æ°ãžã®ã¢ã¯ã»ã¹ãå³ãšã©ãŒã«ããŸããpipefailã¯ãã€ãã®éäžã§ãšã©ãŒãåºãå Žåã«ãã€ãå
šäœã倱æãšããŸãã-eã¯å€ããŠããŸããããã¯ã¹ã¯ãªããã¯ãèªåãã³ã±ãŠãClaude Codeã®åäœã«åœ±é¿ãäžããªããã®ãååãªã®ã§ãç©æ¥µçã«exit 0ã§æããã»ããå®å
šã§ãããšã©ãŒã¯DEBUG_LOGïŒ~/.claude/logs/stop_agent_tracker.logïŒã«æžãåºãèšèšã«ãªã£ãŠããããã-eã§ç¡èšæ»ããããããããã°ãã°ã§åå ãèŠããç¶æ
ãåªå
ããŠããŸãã
ãããŸã§å®è£
ã®è©³çްãšå€±æã®èšé²ãæžããŠããŸãããæ¬¡ã®ããŒãã§ã¯ãããã®ãã°ãã©ãéçšã«çµã¿èŸŒãããå
·äœçã«æ°åãå€ãã£ãäŸãšãjqã¬ã·ãã®å®è·µéãæ±ããŸãã
ã€ãŸãããã€ã³ãïŒè¿œå ã»ç¶²çŸ çïŒ
åããŒãã§5ã€ã®è©°ãŸããæžããŸããããå®éçšã«å ¥ããšè¿œå ã§ã¶ã€ãããã€ã³ãããããŸããããããé ã«äžŠã¹ãŸãã
-
â¥
python3ãèŠã€ãããããã¯ãç¡èšçµäºãã
Claude Codeã¯GUIããèµ·åãããšãã°ã€ã³ã·ã§ã«ãèªã¿èŸŒãŸãã/usr/bin:/binçšåºŠã®æå°éã®PATHããæã¡ãŸããã~/.pyenv/shims/python3ã~/.nvm/versions/.../bin/python3ã¯ãã®PATHã«å«ãŸããŸãããçç¶ã¯ãããã¯ãç»é²ãããŠããã®ã«ãã°ãäžåçããªãããset -uo pipefailã§-eãå€ããŠããã°127ã§æ»ãã§ãåŸç¶ã¹ã¯ãªããã¯åãç¶ããŸãããåºåãã¡ã€ã«ã¯ç©ºã®ãŸãŸã§ãã察çã¯2ã€ãããŸããã¹ã¯ãªããåé ã«export PATH="/usr/local/bin:/usr/bin:$HOME/.pyenv/shims:$PATH"ãæžããã/usr/bin/env python3ã§ã¯ãªããã«ãã¹ã§/usr/bin/python3ãåºå®ãããmacOS Ventura以éã§ã¯XCode Command Line Toolsã/usr/bin/python3ãæäŸããŠãããããã·ã¹ãã PythonãååšãããªãåŸè ãæãå®å šã§ãã -
âŠ
contentãã£ãŒã«ããlistã§ãªãstringã«ãªã£ãŠããã¡ãã»ãŒãžããã
transcript.jsonlã®ã»ãšãã©ã®ã¡ãã»ãŒãžã¯contentããªã¹ãã§ãããããäžéšã®ã·ã¹ãã ã¡ãã»ãŒãžã§ã¯contentãæååã«ãªã£ãŠããŸããfor b in contentã§ã€ãã¬ãŒãããããšãããšæååã1æåãã€åŠçããŠããŸããŸããå®éã®ã¹ã¯ãªããã«ã¯if not isinstance(content, list): continueãšããã¬ãŒããå ¥ã£ãŠããŸããïŒ94ã96è¡ç®ïŒãèªåã§ã¹ã¯ãªãããæ¹å€ãããšãã«ãã®è¡ãåããšå£ããŸããcontentãlistãã©ããã¯æ¯è¡ç¢ºèªããã®ãéåã§ãã -
â§
jq -sã§æ°äžè¡ã®JSONLãã¡ã¢ãªã«å±éãããšOOMã«ãªã
jq -sã¯ãã¡ã€ã«å šäœãã¡ã¢ãªã«èªã¿èŸŒãã§ããåŠçããŸããagent-invocations.jsonlãæ°äžè¡ãè¶ ããŠãããšãMacã®ã¡ã¢ãªãæ°çŸMBæ¶è²»ããã¯ãšãªã«ãªããŸããæã«æ°çŸã»ãã·ã§ã³åãããš3ã4ã¶æã§å°éããŸãã解決çã¯--streamãªãã·ã§ã³ãã宿çãªã¢ãŒã«ã€ãã§ããç§ã¯ææ¬¡ã§ãã°ã~/logs/archive/agent-YYYY-MM.jsonlã«éé¿ãããagent-invocations.jsonlã«ã¯çŽè¿30æ¥åã ãæ®ãéçšã«ããŠããŸãã# ææ¬¡ããŒããŒã·ã§ã³ïŒlaunchdã§èªåå®è¡ïŒ MONTH=$(date -v-1m +%Y-%m) jq -c 'select(.ts | startswith("'"$MONTH"'"))' \ ~/.claude/logs/agent-invocations.jsonl \ >> ~/.claude/logs/archive/agent-${MONTH}.jsonl -
âš
status: "pending"ã®ãšã³ããªã倧éã«èç©ããã
ãµããšãŒãžã§ã³ãã®å®è¡äžã«Claude Codeã匷å¶çµäºïŒâQãOSã·ã£ããããŠã³ãOOM killïŒãããå Žåãtool_resultãæžã蟌ãŸããªããŸãŸãã©ã³ã¹ã¯ãªãããçµãããŸãããã®ç¶æ ã§Stopããã¯ãèµ°ããšã察å¿ããresultsãååšããªãããstatus: "pending"ã§èšé²ãããŸããããèªäœã¯æ£ããåäœã§ãããpendingãšã³ããªãæã«æ°åä»¶ããŸããšå¹³åå®è¡æéã®éèšãæªã¿ãŸãïŒduration_ms: nullãªãšã³ããªãselect(.duration_ms != null)ã§ãã£ã«ã¿ããå¿ èŠããããŸãïŒãææ¬¡ã®éèšã¯ãšãªã«ã¯å¿ ãselect(.status == "ok")ã远å ããŠããã®ãå®å šã§ãã -
â© éè€é²æ¢ãããã¯ã巚倧ãã°ã§é ããªã
ã»ãã·ã§ã³åé ã®éè€ãã§ãã¯ã§ã¯ãæ¢åãã°ãå šè¡èªãã§session_idãäžèŽããã¬ã³ãŒããæ¢ããŸãïŒ58ã69è¡ç®ïŒããã°ã10äžè¡ãè¶ ãããšã1ã»ãã·ã§ã³ãããã®ããã¯å®è¡ã«æ°ç§ãããããã«ãªããŸããå®çšäžã®å¯Ÿçã¯2ã€ã§ãããŸãJSONLãã»ãã·ã§ã³æ¥ä»ã§ããŒãã£ã·ã§ã³ãããæ¬¡ã«seen_idsã®èªã¿èŸŒã¿ããææ°Nè¡ã ããã«å¶éããïŒåäžã»ãã·ã§ã³ã®ãšã³ããªãé£ç¶ããŠãããšã¯éããªãã®ã§å®å šãªåé¿çã§ã¯ãããŸããããçŸå®çãªåŠ¥åç¹ã§ãïŒã -
âª
cwdã«å®ãã¹ãèšé²ãããŠã¹ã¯ãªãããå ¬éã§ããªããªã
stop_agent_tracker.shãåºåããJSONLã«ã¯"cwd": "/Users/å®å/dev/my-project"ãå ¥ããŸãããã®ãã°ã.gitignoreã«è¿œå ãå¿ããŠãªããžããªã«ã³ããããããšãããŒã ãã£ã¬ã¯ããªã®çµ¶å¯Ÿãã¹ãå€éšã«æŒããŸãã~/.claude/logs/ã¯ãªããžããªå€ã«çœ®ããŠããã®ã§åé¡ãããŸãããããã°ãåæçšã¹ã¯ãªããã«æž¡ããšãããã°ãã¡ã€ã«ããšgistãå ±æãã©ã«ãã«åºããŠããŸãã±ãŒã¹ããããŸããjq 'del(.cwd)'ã§å å·¥ããŠããå ±æããããcwdãã£ãŒã«ãããã£ã¬ã¯ããªåã ãïŒbasenameïŒã«äžžããååŠçãå ¥ãããšå®å šã§ãã -
â« ãããã°ãã°ãæå¹ã«ããæ¹æ³ãç¥ããªããŸãŸæ°æ¥æº¶ãã
stop_agent_tracker.shã«ã¯CC_AGENT_TRACKER_DEBUG=1ãšããç°å¢å€æ°ã¹ã€ãããå®è£ ãããŠããŸãïŒ31è¡ç®ïŒã1ãèšå®ãããš~/.claude/logs/stop_agent_tracker.logã«è©³çްãã°ãæžãåºãããŸããstop_cost_log.shã¯CC_COST_DEBUG=1ã§åæ§ã«~/.claude/logs/stop_cost_log.logãžæžãåºããŸããããã¯ãåããŠãããã©ãã確èªãããã¡ãŒã¹ãã¹ãããã¯tail -f ~/.claude/logs/stop_agent_tracker.logã§ãããããç¥ããã«ããã°ãçããªãåå ãããããªããç¶æ ã§æ°æ¥æº¶ãããçµéšãç§ã«ã¯ãããŸããæ°ããç°å¢ã§ããã¯ãèšå®ãããããŸããããã°ã¢ãŒãã§1ã»ãã·ã§ã³åãããŠåäœç¢ºèªããã®ãå¿ é æé ã§ãã
ãã¹ããã©ã¯ãã£ã¹
å®è£ ã»éçšãçµãŠåºãŸã£ãã«ãŒã«ãæžãåºããŸãã
1. ããã¯ã¹ã¯ãªããã¯å¿
ãexit 0ã§çµãã
Stopããã¯ãéãŒãã§çµäºãããšãClaude Codeãæ¬¡ã®ã»ãã·ã§ã³èµ·åæã«èŠåãåºãããšããããŸããã¹ã¯ãªããå
ã§äœãåé¡ãèµ·ãããšããŠãããã°ã«æžããŠexit 0ã§æããèšèšãéåã§ããset -eãå€ãã®ãåãçç±ã§ããããã¯ã®å€±æãClaude Codeæ¬äœã®åäœã«æ³¢åããªãç¶æ
ãç¶æããŸãã
2. stdinã¯æåã®1è¡ã§INPUT=$(cat)ã«åããŠç°å¢å€æ°ã«è©°ãæ¿ãã
ãã¢ããã¥ã¡ã³ãã®Pythonãžstdinãæž¡ãæ¹æ³ã¯ãããŸãããå¿
ãINPUT=$(cat) â export STOP_INPUT â os.environã®çµè·¯ã䜿ããŸããããã¯P2ã§è©³è¿°ããè©°ãŸãâ ã®çŽæ¥ã®æèšã§ãããã®åœ¢ã厩ããªãéããã©ããªã«Pythonã³ãŒããæ¹å€ããŠãå
¥åãå±ããŸãã
3. Pythonã³ãŒãã¯1ã€ã®å€§ããªtry/exceptã§å
ã¿ãäŸå€ãæ¡ãã€ã¶ãããããã°ãã°ã«æžã
try:
# ã¡ã€ã³åŠç
...
except Exception as e:
log(f"unexpected_error: {e}")
sys.exit(0)
äŸå€ãåºãŠãsys.exit(0)ã§æ£åžžçµäºããŸãããã°ã«ã¯æ®ããClaude Codeã«ã¯åœ±é¿ããªãããã®3ç¹ãåæã«éæããã®ãäžèšã®æ§é ã§ãã
4. ã¿ã€ã ã¹ã¿ã³ãã¯parse_ts颿°ã«éã蟌ããŠNoneãè¿ãèšèšã«ãã
fromisoformatã®Zåé¡ïŒè©°ãŸãâ¡ïŒã象城ããããã«ãã¿ã€ã ã¹ã¿ã³ãåŠçã¯ç°å¢äŸåã®ãšããžã±ãŒã¹ãå€ãã§ãã倿ã¯å¿
ãå°çšé¢æ°ã«åé¢ãã倱ææã¯Noneãè¿ããŸããduration_msã®èšç®ã¯ãt0ãšt1ãã©ã¡ããNotNoneã®ãšãã ãè¡ãããšããæ¡ä»¶ã«ããŠããã°ãNoneã®ããã§TypeErrorãåºãããšããããŸããã
5. éè€é²æ¢ã¯æåããå ¥ãããåŸããå ¥ãããšæ¢åãã°ã®æ±æãåããªã
è©°ãŸãâ¢ïŒStopããã¯ã®å€éåŒã³åºãïŒã¯ãæ°æ¥åŸã«ããªãåããšã³ããªã2è¡ããã®ãããšããåœ¢ã§æ°ã¥ããŸãããã®æç¹ã§æ¢åãã°ã«ã¯éè€ãåãŸã£ãŠãããsort -uã§åãé€ãããšããŠãJSONLã¯ããŒãé åºäžå®ãªã®ã§ãã®ãŸãŸã§ã¯äœ¿ããŸãããéè€é²æ¢ããžãã¯ã¯å®è£
åœåããå
¥ããã®ãååã§ããã³ã¹ãã¯ãæ¢åãã°ãèªã1ãã¹ãã ãã§ãã
6. jqã¯ãšãªã«ã¯å¿
ãselect(.duration_ms != null)ãšselect(.status == "ok")ãå
¥ãã
pendingãšã³ããªïŒduration_ms: nullïŒãå«ããå¹³åãåºããšæ°åããŒãåŽã«åŒãå¯ããããŸããéèšã¯ãšãªã®ããã©ã«ãã«äžèš2æ¡ä»¶ã远å ããŠãããšãæå¹ãªããŒã¿ã ãã察象ã«ããæ£ç¢ºãªæ°åãåºãŸãã
jq -s '
map(select(.duration_ms != null and .status == "ok")) |
group_by(.subagent_type) |
map({type: .[0].subagent_type, avg_ms: (map(.duration_ms) | add / length | round)})
' ~/.claude/logs/agent-invocations.jsonl
7. ãã°ãã¡ã€ã«ã¯æ¯æã¢ãŒã«ã€ãããŠçŸè¡ãã¡ã€ã«ã軜éã«ä¿ã€
agent-invocations.jsonlã倧ãããªããšéè€ãã§ãã¯ãã¹ãé
ããªãïŒè©°ãŸãâ©ïŒãjq -sã§ã¡ã¢ãªãé£ããŸãïŒè©°ãŸãâ§ïŒãææ¬¡ã§ã¢ãŒã«ã€ãããlaunchdãžã§ããæåããèšå®ããŠãããšããããã®åé¡ãçºçããŸãããå®éã«ã¯ããã°ãéããªã£ãããšæ°ã¥ããæç¹ã§ã¢ãŒã«ã€ããã人ãå€ãã§ãããæåããå
¥ããŠããã»ããéçšã楜ã§ãã
8. PRICINGããŒãã«ã¯å®å šäžèŽã§ãªããã¬ãã£ãã¯ã¹ãããã§åŒã
stop_cost_log.shã®rate_for颿°ã®å®è£
ããã®ãŸãŸãã¹ããã©ã¯ãã£ã¹ã§ããmodel.startswith(k)ã§ããŒãåŒãããšã§ãclaude-sonnet-4-6-20250620ã®ããã«ãªãªãŒã¹æ¥ãµãã£ãã¯ã¹ãä»ããã¢ãã«åã®å€åãåžåã§ããŸããæªç¥ã¢ãã«ã¯Sonnetçžåœã§ãã©ãŒã«ããã¯ãããããããŒãã«ã«ãªãã¢ãã«ãåºãŠãéèšãæ¢ãŸããŸããã
9. ããã¯ãèšå®ãããå¿ ããããã°ã¢ãŒãã§1ã»ãã·ã§ã³éããŠç¢ºèªãã
# ~/.claude/settings.json ã«è¿œå ïŒæ¢åã®hooksãããã¯ã«è¿œèšïŒ
CC_AGENT_TRACKER_DEBUG=1 claude # â ãããã°ã¢ãŒãã§èµ·å
tail -f ~/.claude/logs/stop_agent_tracker.log # å¥ã¿ãŒããã«ã§ç£èŠ
ãèšå®ããããšãåããŠãããã¯å¥ã§ããå®éã«ã»ãã·ã§ã³ãèµ°ãããŠãã°ãçãããŸã§ã確èªããŠããããããã°ã¢ãŒããå€ããŠãã ããã
10. subagent_typeã§ãã£ã«ã¿ããinput.subagent_typeã®ååšã§å€å®ãã
è©°ãŸãâ£ïŒname="Task"åé¡ïŒãšå¯Ÿã«ãªããã¹ããã©ã¯ãã£ã¹ã§ããname == "Agent"ã ãã§ã¯ãµããšãŒãžã§ã³ãåŒã³åºã以å€ã®ãšã³ããªãåŒã£ãããå¯èœæ§ããããŸãã"subagent_type" in inpã®2段ãã£ã«ã¿ãå¿
ãå
¥ããŠãã ããããããå®éã®ã¹ã¯ãªããã®èšèšã§ãã
11. cwdãã£ãŒã«ãã䜿ã£ãŠãããžã§ã¯ãå¥ã«éèšãã
cost-log.jsonlã«ãagent-invocations.jsonlã«ãcwdãå
¥ã£ãŠããŸãããããžã§ã¯ãããšã®æèŠæéãšã³ã¹ããåºãã«ã¯ã次ã®jqã§ååã§ãã
# ãããžã§ã¯ãå¥ã³ã¹ã
jq -rsc '
group_by(.cwd) |
map({cwd: .[0].cwd, cost_usd: (map(.cost_usd) | add | . * 10000 | round / 10000)}) |
sort_by(-.cost_usd)[] |
"\(.cost_usd) USD \(.cwd)"
' ~/.claude/logs/cost-log.jsonl
ã©ã®ãããžã§ã¯ãã«ã©ãã ãClaude Codeã䜿ã£ãŠããããèŠãããšãæ¡ç®ã®æèŠãå€ãããŸãã
12. Stopããã¯ã¯è€æ°ç»é²ã§ããç¬ç«ããŠåã
~/.claude/settings.jsonã®hooks.Stopã¯é
åã§è€æ°ãšã³ããªãæžããŸããstop_agent_tracker.shãšstop_cost_log.shãå¥ã
ã«ç»é²ãããŠããã®ã¯ãã®ããã§ããäžæ¹ã倱æããŠãããäžæ¹ã¯åããŸãã圹å²ããšã«ã¹ã¯ãªãããåããŠãããšãä¿®æ£ã»å·®ãæ¿ããç¬ç«ããŠã§ããŸãã
13. æ°åãé±1ã§èŠãç¿æ £ãã€ãã
ãã°ãèç©ãããŠãèŠãªããã°æå³ããããŸãããç§ã¯æ¯é±ææã®æã«ãšã€ãªã¢ã¹ccstatsãå®è¡ããŠããŸãã
alias ccstats='
echo "=== ãšãŒãžã§ã³ãå¹³åæéïŒçŽè¿7æ¥ïŒ ===";
jq -sc "map(select(.status==\"ok\" and .duration_ms != null)) |
group_by(.subagent_type) |
map({type:.[0].subagent_type, avg_ms:(map(.duration_ms)|add/length|round)}) |
sort_by(-.avg_ms)[]" \
~/.claude/logs/agent-invocations.jsonl;
echo "=== é±éã³ã¹ã ===";
jq -sc "map(.cost_usd) | add | . * 100 | round / 100" \
~/.claude/logs/cost-log.jsonl
'
ãã®æ°åãèŠãŠãããä»é±ã¯code-reviewerã®åŒã³åºããæžããããããã®ãããžã§ã¯ãã¯ExploreãæžãããŠGrepã«å€ãããããšãã倿ãã§ããŸããæèŠè«ããæ°åããŒã¹ã®å€æãžç§»è¡ããã®ãããã®ä»çµã¿ã®æ¬æ¥ã®ç®çã§ãã
ãŸãšã
Claude Codeã®Stopããã¯ã¯ãã»ãã·ã§ã³çµäºãšããæ¢åã®ã€ãã³ãã«ä¹ã£ããã ãã§ãã°åéãèªååã§ããŸããtranscript_pathãåãåã£ãŠPythonã§2ãã¹åŠçããagent-invocations.jsonlã«è¿œèšããããã®èšèšã®æ žå¿ã¯ãClaude Codeæ¬äœã«äœãå€ããªãããšããç¹ã§ããããã¯ã倱æããŠãexit 0ã§æãããããæ¬äœã®åäœã«æ³¢åããŸãããå¯äœçšããŒãã«è¿ãä»çµã¿ã ãããéç£ç°å¢ã«çµã¿èŸŒãã§ãå®å¿ããŠçœ®ãç¶ããããŸãã
å®éã«æ°åãèŠãŠããã£ãã®ã¯ãæèŠã§ãéãããšæã£ãŠãããšãŒãžã§ã³ããšãããŒã¿ã§ãéãããšãŒãžã§ã³ãã¯å¿ ãããäžèŽããªãããšããããšã§ããç§ã®ç°å¢ã§ã¯äœæäžã¯general-purposeãéãå°è±¡ã§ããããèšæž¬ãããå¹³å18ç§ã§ExploreïŒ22ç§ïŒãããéãã£ããcode-reviewerã®37ç§ãšããæ°åãèŠãŠããããè€æ°ãã¡ã€ã«æšªæç¢ºèªã¯code-reviewerããå ã«Grepã§çµã蟌ãããšããç¿æ £ãçãŸããé±éã³ã¹ããäœæã§15ã20%èœã¡ãŸããã
ãã®å€åã¯ãèšæž¬ãªãã«ã¯çãŸããŸããã§ããã
ã»ãã·ã§ã³çµäºã®ãã³ã«éãã«åããŠããããã¯ã¹ã¯ãªããããæå120äžãæ¯ããèªåŸç°å¢ã®ç²ŸåºŠãå°ããã€äžãç¶ããŠããŸãã
ä»çµã¿ã®å šäœåã»æ120äžã®å èš³ã»30æ¥æé ã¯æænoteã«ãŸãšããŠããŸãã
ð Claude CodeèªåŸç°å¢ã§ãå®éã©ã皌ãã â ä»çµã¿ã»å®äŸã»å§ãæ¹ã»ãµããŒã
LilyïŒ@bokuwalilyïŒâ å人éçºè ãClaude Code ã§èªåååºç€ãçµã¿ãªãããiOSã¢ããªãWebãµãŒãã¹ãéç£ããŠããŸã
- AIã§ãå¯ãŠãŠãåãä»çµã¿ããäœã£ãŠæ120äžã«ãã話㯠noteã®ææèšäº ã«ð°
- OSS: github.com/bokuwalily ð
- ææ°æ å ±ã»ãåãåãã㯠X @bokuwalily ãžð
- AIå°å ¥ã»èªååã®çžè«ãšå®è£ ãã³ãã¬7æ¬ã®é åžã¯ å ¬åŒLINE ããð¬
çããã® â€ïž ãã·ã§ã¢ãå±ã¿ã«ãªããŸãïŒ