Stop hook — block until background_tasks and session_crons drain
Use the background_tasks and session_crons fields in Stop/SubagentStop input to keep Claude working until every background bash command and scheduled task has finished.
#!/usr/bin/env python3
# Save as .claude/hooks/wait-for-background.py and wire up under Stop.
import json, sys
data = json.load(sys.stdin)
pending_bg = [
t for t in data.get("background_tasks", [])
if t.get("status") in ("running", "starting")
]
pending_cron = data.get("session_crons", [])
if pending_bg or pending_cron:
reason_bits = []
if pending_bg:
names = ", ".join(t.get("description") or t.get("id", "?") for t in pending_bg[:3])
reason_bits.append(f"{len(pending_bg)} background task(s) still running: {names}")
if pending_cron:
reason_bits.append(f"{len(pending_cron)} scheduled task(s) still queued")
print(json.dumps({"decision": "block", "reason": "; ".join(reason_bits)}))
sys.exit(0)
# Nothing pending — let Claude stop.
sys.exit(0)