---
name: coo-hunt-watch
description: No-agent script. Polls hunt PM2 + scraper output rate every 30 min. Wakes agent only if scrapers stopped >24h or extraction rate falls to zero.
agent: hermes-coo
type: no-agent-script
schedule: "*/30 * * * *"
delivery: telegram:7377499346
---

# coo-hunt-watch skill

## Purpose

Cheap polling watchdog. Reads PM2 status + scraped_leads insert rate. Only invokes Hermes-COO LLM if something actually needs attention. Saves token budget compared to a full-agent cron.

Pattern from Hermes built-in cron `--no-agent --script ... wakeAgent: false` (per cron docs).

## Script (bash, runs on VPS)

Location: `/root/scripts/coo-hunt-watch.sh`

```bash
#!/bin/bash
# coo-hunt-watch — fires every 30 min via Hermes cron --no-agent

# 1. PM2 status check
EXPECTED_RUNNING=("hunt-monitor" "hunt-outreach")
EXPECTED_CRON=("hunt-aggregator" "hunt-workers" "hunt-contractors" "hunt-matchmaker")

PROBLEMS=()

for svc in "${EXPECTED_RUNNING[@]}"; do
  status=$(pm2 jlist 2>/dev/null | jq -r ".[] | select(.name==\"$svc\") | .pm2_env.status")
  if [ "$status" != "online" ]; then
    PROBLEMS+=("$svc not online (status=$status)")
  fi
done

# Cron-driven scrapers — expected to be "stopped" between runs but should have run within last 25h
for svc in "${EXPECTED_CRON[@]}"; do
  last_run_iso=$(pm2 jlist 2>/dev/null | jq -r ".[] | select(.name==\"$svc\") | .pm2_env.created_at")
  last_run_epoch=$((last_run_iso / 1000))
  now=$(date +%s)
  age_hours=$(( (now - last_run_epoch) / 3600 ))
  if [ "$age_hours" -gt 25 ]; then
    PROBLEMS+=("$svc last ran ${age_hours}h ago (>25h, missed cron)")
  fi
done

# 2. Scraper output rate — query growth-engine Supabase
SUPABASE_URL="https://memscjotxrzqnhrvnnkc.supabase.co"
SUPABASE_KEY=$(grep "^SUPABASE_SERVICE_ROLE_KEY=" /home/ccuser/rateright-growth/.env | cut -d= -f2-)

# scraped_leads inserted in last 24h
NEW_LEADS_24H=$(curl -sS "${SUPABASE_URL}/rest/v1/scraped_leads?select=count&created_at=gt.$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)" \
  -H "apikey: $SUPABASE_KEY" \
  -H "Authorization: Bearer $SUPABASE_KEY" \
  -H "Prefer: count=exact" 2>/dev/null | head -1)

# Detect zero inflow (the actual problem since 2026-04-28)
if [ "$NEW_LEADS_24H" = "0" ] || [ -z "$NEW_LEADS_24H" ]; then
  PROBLEMS+=("scraped_leads inflow = 0 in last 24h (Gumtree selector still broken?)")
fi

# 3. Output decision
if [ ${#PROBLEMS[@]} -eq 0 ]; then
  # Healthy — emit JSON instructing Hermes to NOT wake the agent
  echo '{"wakeAgent": false}'
  exit 0
else
  # Problems found — emit findings, Hermes will wake agent + deliver to telegram
  printf '🐛 HUNT WATCHDOG — %d issue(s) detected:\n\n' "${#PROBLEMS[@]}"
  for p in "${PROBLEMS[@]}"; do printf "  • %s\n" "$p"; done
  printf '\nLast healthy: %s\n' "$(date -d '24 hours ago' '+%Y-%m-%d %H:%M')"
  exit 0
fi
```

## Cron creation

```bash
hermes --profile coo cron create "*/30 * * * *" \
  --no-agent \
  --script /root/scripts/coo-hunt-watch.sh \
  --name "coo-hunt-watch" \
  --deliver telegram:7377499346
```

`--no-agent` = script-only, no LLM. `wakeAgent: false` in output suppresses delivery on healthy ticks. Only fires Telegram when problems detected.

## Cost

Effectively zero. Bash + 2 curl calls per tick. ~1KB output per tick. No LLM tokens unless wake-on-problem triggers.

## When this gets noisy

If Gumtree stays broken, watchdog will fire every 30 min forever. Rocky decisions to silence:
- Disable watchdog: `hermes --profile coo cron pause coo-hunt-watch`
- Per Goal 3 (decide by 2026-07-15): fix or retire hunt — once retired, this watchdog goes too

## Dependencies

- `pm2` + `jq` on VPS path
- Supabase service-role key in `/home/ccuser/rateright-growth/.env`
- Internet access to `memscjotxrzqnhrvnnkc.supabase.co`

## Failure modes

- PM2 not responding → return `{"wakeAgent": true, "alert": "pm2 jlist failed"}` — wakes agent with critical message
- Supabase unreachable → return `{"wakeAgent": true, "alert": "growth-engine Supabase unreachable"}`
- Script crash → systemd journal logs, cron records `last_run: fail`. Hermes COO surfaces in next pulse.

## What good looks like

Hunt running normally → watchdog runs 48× per day, zero Telegram notifications, zero LLM cost. Hunt breaks → first detection within 30 min, Rocky on Telegram, no surprise drift.
