Monitor Iran-Israel-US military escalation and attack alerts using 85+ OSINT sources, satellite fire detection, seismic monitoring, cyber warfare tracking, military flight tracking, and real-time alert APIs. Includes interactive Leaflet strikes dashboard with 49K+ geolocated events, live feed pipeline, US/Iran military base overlays, PWA mobile support, and event type filtering. Use when checking for breaking military news, missile alerts, airstrikes, or geopolitical escalation between Iran, Israel, and the US. Triggers on questions about Iran attacks, Israel strikes, Middle East military alerts, OSINT updates, or escalation monitoring.
Resources
14Install
npx skillscat add magen-yehuda-intel/magen-yehuda-bot Install via the SkillsCat registry.
Iran-Israel Attack Alert Monitor
Multi-source intelligence aggregation for Iran/Israel/US military escalation with adaptive threat-level system, 85+ source channels, real-time OSINT scanning, NASA satellite fire detection, USGS seismic monitoring, cyber warfare monitoring (19 hacktivist groups), wire service integration (Reuters/AP), multi-source breaking news corroboration, multi-channel bilingual dispatch with per-channel timezones, Hebrew-first OSINT prioritization for Hebrew channel, live feed data pipeline, and instant Telegram delivery with auto-generated intel maps and interactive strikes dashboard (PWA-enabled).
Quick Start
bash ctl.sh status # See what's running
bash ctl.sh check # One-time full SITREP (stdout)
bash ctl.sh post # Full check → post to Telegram
bash ctl.sh start # Start real-time watcher (adaptive threat system)
bash ctl.sh stop # Stop real-time watcher
bash ctl.sh teardown # 🛑 Kill everything (watcher + cron + state)Architecture
┌──────────────────────────────────────────────────────────────┐
│ Real-Time Watcher (daemon) │
│ │
│ 🚨 Oref sirens every 10-30s (threat-adaptive) │
│ 📡 OSINT scanner every 30s-5min (threat-adaptive) │
│ ├─ 📢 12 Telegram channels (t.me/s/ web preview) │
│ ├─ 🐦 13 Twitter accounts (syndication API) │
│ ├─ 📰 10 RSS feeds (TOI, JPost, AJ, TASS, Ynet, Reuters, │
│ │ AP, Maariv, Walla, Channel 13) │
│ └─ 🌍 USGS seismic (Iran region, M3.5+) │
│ 📊 Polymarket every 60s-5min (threat-adaptive) │
│ 🔥 NASA FIRMS fires every 3-15min (threat-adaptive) │
│ 🌍 USGS seismic every 3-15min (threat-adaptive) │
│ 🗺️ Intel map auto-generated on fire/quake alerts │
│ 🌐 Iran internet every 5-30min (blackout detection) │
│ ✈️ Military flights every 5-30min (OpenSky ADS-B) │
│ ✈️ Flight radar map hourly (FR24 air traffic + intel) │
│ 🛡️ Cyber warfare every 5-30min │
│ ├─ 📢 25 hacktivist TG handles (19 groups) │
│ ├─ 🐦 8 CTI Twitter accounts │
│ └─ 📰 4 dark web / breach RSS feeds │
│ 🚢 Naval tracking every 5-30min (AIS vessel data) │
│ ⚔️ Strikes map data every 6h (ACLED + local sensors) │
│ 🎯 Strike correlation after every fire/seismic scan │
│ 📌 Pinned status edited every 60s + instant on threat │
│ │ level change │
│ 📡 Live feed export every 5min (intel-feed.json → GitHub) │
│ │
│ → Instant Telegram push on changes │
│ → Breaking news corroboration (3+ reputable = CONFIRMED) │
│ → Confirmed topics suppressed after first alert │
│ → Hebrew-first OSINT prioritization for Hebrew channel │
│ → Auto-escalate/deescalate threat level │
│ → Per-channel timezones (EN=ET, HE=IST) │
│ → Pikud HaOref stand-down messages detected (no escalation) │
└──────────────────┬─────────────────────────────────────────────┘
│
┌──────────────────▼─────────────────────────────────────────────┐
│ Scheduled Reports │
│ 📊 Hourly: intel map + Hebrew + English summaries → Telegram │
│ 🎬 Hourly: 24h time-lapse GIF → Telegram │
│ 📋 2-Hour Full SITREP (Oref + RSS + Poly + Oil + ADS-B) │
└──────────────────┬─────────────────────────────────────────────┘
│
dispatch.py → EN Channel (ET) + HE Channel (IST)Sources (80+ channels)
Real-Time Watcher Sources
| # | Source | Channels | Method | Auth |
|---|---|---|---|---|
| 1 | 🚨 Pikud HaOref (sirens) | 1 | REST API (Israeli IP req.) | None |
| 2 | 📢 Telegram OSINT | 12 channels | Web preview scraping | None |
| 3 | 🐦 X/Twitter OSINT | 13 accounts | Syndication API | None |
| 4 | 📰 RSS News | 10 feeds (4 Hebrew, 6 English) | RSS/XML parsing | None |
| 5 | 🌍 USGS Seismic | Iran region | REST API (GeoJSON) | None |
| 6 | 📊 Polymarket | Dynamic | REST API | None |
| 7 | 🔥 NASA FIRMS | 4 satellites | Area CSV API | MAP_KEY |
| 8 | 🌐 IODA Internet | Iran ASNs | Georgia Tech API | None |
| 9 | 🔍 Direct Probes | 3 Iranian sites | HTTP health check | None |
| 10 | ✈️ OpenSky ADS-B | ME region | REST API | None |
| 11 | ✈️ FlightRadar24 | ME region | Public feed | None |
| 12 | 🛡️ Cyber Hacktivist TG | 25 handles (19 groups) | Web preview scraping | None |
| 13 | 🛡️ Cyber CTI Twitter | 8 accounts | Syndication API | None |
| 14 | 🛡️ Cyber/DarkWeb RSS | 4 feeds | RSS/XML parsing | None |
| 15 | 🚢 Naval AIS | Persian Gulf | AIS data feeds | None |
| 16 | ⚔️ ACLED Strikes | ME region (9 countries) | REST API (OAuth2) | Free account |
Telegram OSINT Channels
warmonitors— War Monitors (fastest English breaking)intelslava— Intel Slava Z (military OSINT)liveuamap— Liveuamap (mapped conflict updates)AbuAliExpress— Abu Ali Express (Hebrew OSINT king)flash_news_il— Flash News IL (Hebrew breaking)idfonline— IDF Online (English)idfofficial— IDF Spokesman / דובר צה״ל (Hebrew, official)IDFarabic— IDF Arabic Spokespersoniranintl_en— Iran International EnglishBBCPersian— BBC Persiankann_news— Kan Newsaharonyediot— Aharon Yediot (HIGH reliability Hebrew OSINT)
RSS Feeds (10)
- Times of Israel — direct RSS
- Jerusalem Post — direct RSS
- Al Jazeera — direct RSS
- TASS — direct RSS
- Ynet (Hebrew) — direct RSS
- Reuters — via Google News RSS proxy (
site:reuters.com) - AP News — via Google News RSS proxy (
site:apnews.com) - מעריב (Maariv) — Hebrew RSS (direct)
- וואלה (Walla) — Hebrew RSS (direct)
- חדשות 13 (Channel 13) — Hebrew RSS (direct)
Note: Direct Reuters/AP RSS feeds are behind Cloudflare/paywalls. Google News RSS filtered to
site:reuters.comworks reliably as a proxy, including<source>tags for attribution.
Twitter OSINT Accounts
@PenPizzaReport, @Conflict_Radar, @Worldsource24, @sentdefender, @beholdisrael, @Osint613, @Osinttechnical, @IsraelRadar_, @Intel_Sky, @ELINTNews, @IsraelWarRoom, @IDF, @IDFSpokesperson
SITREP-Only Sources (2-hour cron)
| # | Source | Method | Auth |
|---|---|---|---|
| 8 | 🛢️ Oil/Commodities | OilPriceAPI | None |
| 9 | ✈️ Military Aviation | OpenSky ADS-B | None |
🔥 NASA FIRMS Satellite Fire Detection
Monitors thermal anomalies across Iran using 4 NASA satellites to detect fires, explosions, and bombing near military/nuclear sites.
How It Works
# Standalone test
python3 scripts/scan-fires.py config.json state # Scan for new fires
python3 scripts/scan-fires.py config.json state --seed # Seed baseline (no alerts)
python3 scripts/format-fires.py < fires.json # Format for TelegramSatellites
- VIIRS SNPP — Suomi NPP (375m resolution)
- VIIRS NOAA-20 — Joint Polar Satellite System
- VIIRS NOAA-21 — Latest generation
- MODIS — Terra/Aqua (1km resolution, highest coverage)
Features
- Point-in-polygon Iran filtering — Excludes Iraq/Afghanistan/Pakistan fires even if in bounding box
- FRP-based priority — Fire Radiative Power determines alert urgency (≥50 MW = HIGH, ≥15 = MEDIUM)
- Proximity to 23 known sites — Nuclear (Natanz, Fordow, Isfahan, Bushehr, Arak), military (Parchin, Shahrud, Bandar Abbas), oil (Kharg Island), capital (Tehran)
- Reverse geocoding — Nominatim converts coordinates to city/province names (cached, 1 req/sec, max 20/scan)
- Deduplication — Tracks seen fires in
state/firms-seen.json, only alerts on new detections - API key required — Free, see Getting a FIRMS API Key below. Store in
secrets/firms-map-key.txt
Priority Classification
| Priority | Trigger |
|---|---|
| 🚨 CRITICAL | Near nuclear site or capital (<30km) |
| 🔴 HIGH | Near military/oil site (<30km) OR FRP ≥50 MW |
| 🟡 MEDIUM | FRP ≥15 MW |
| ⚪ LOW | FRP <15 MW, no nearby sites |
Getting a FIRMS API Key
NASA FIRMS requires a free API key (MAP_KEY). The registration form asks for an email — they send the key instantly, no verification needed.
Quick method using a disposable email:
- Go to https://mail.tm or any temp email service
- Copy the generated email address
- Go to https://firms.modaps.eosdis.nasa.gov/api/area/
- Click "Get MAP_KEY" → enter the temp email
- Check the temp inbox — key arrives within seconds
- Save it:
mkdir -p secrets echo "YOUR_KEY_HERE" > secrets/firms-map-key.txt
The key is permanent and has no rate limits for the area CSV endpoint. No real email required — NASA just needs something to send the key to.
Alternative: Use your real email at the same URL if you prefer. Same instant delivery.
🌍 USGS Seismic Activity Monitoring
Real-time earthquake detection in Iran (M2.5+) via USGS FDSNWS API. Identifies potentially suspicious seismic events near nuclear facilities.
How It Works
# Standalone test
python3 scripts/scan-seismic.py config.json state # Scan for new quakes
python3 scripts/scan-seismic.py config.json state --seed # Seed baseline
python3 scripts/scan-seismic.py config.json state --days 7 # Look back 7 days
python3 scripts/format-seismic.py < seismic.json # Format for TelegramFeatures
- Iran bounding box — lat 25-40, lon 44-63.5 (full coverage)
- Proximity to 10 known sites — Same nuclear/military/oil sites as fire detection
- Suspicious event flagging — Shallow (<10km depth) + moderate magnitude (≥3.5) near nuclear sites
- Explosion type detection — USGS classifies some events as "explosion" — auto-flagged CRITICAL
- Deduplication — Tracks in
state/seismic-seen.json, 7-day retention - No API key needed — USGS is free and open
Priority Classification
| Priority | Trigger |
|---|---|
| 🚨 CRITICAL | Type = explosion, OR shallow + near nuclear site |
| 🔴 HIGH | M5.0+ OR near nuclear site |
| 🟡 MEDIUM | M4.0+ |
| ⚪ LOW | M2.5-3.9 |
Why It Matters
Shallow high-magnitude events near nuclear facilities could indicate:
- Underground nuclear tests
- Bunker-buster strikes on hardened facilities
- Large conventional bombing campaigns
🗺️ Auto-Generated Intel Map
Every fire/seismic alert includes a satellite imagery map sent as a Telegram photo.
Features
- ESRI satellite tile basemap (zoom level 5, 768x512px)
- Country borders — GeoJSON from Natural Earth, all neighbors labeled
- Iran highlighted — Gold border with subtle fill tint
- Fire dots — Color-coded by priority, sized by FRP, glow effects
- Earthquake markers — Concentric ring style with magnitude + depth labels
- Suspicious triangle — Purple ⚠️ overlay for suspicious seismic events
- Known sites — Diamond markers with labels (Natanz, Fordow, etc.)
- Legend — Dynamic, shows active layers (fires/quakes/both)
- Timestamp — UTC time in title bar
# Standalone generation
python3 scripts/generate-fire-map.py fires.json output.png
python3 scripts/generate-fire-map.py fires.json output.png --seismic seismic.jsonDependencies
Pillow(PIL) —pip3 install Pillow- Downloads ESRI tiles at runtime (6 tiles per map, cached by OS)
- Border data in
references/borders.geojson(17 countries, 473KB)
Adaptive Threat-Level System
The watcher automatically adjusts monitoring frequency based on siren activity:
| Level | Hebrew | Trigger | Oref | OSINT | Poly | Fires | Intel (blackout+flights+cyber) |
|---|---|---|---|---|---|---|---|
| 🟢 GREEN | שגרה | No sirens >30min | 30s | 5min | 5min | 15min | 30min |
| 🟡 ELEVATED | מוגבר | Sirens <30min ago | 15s | 2min | 2min | 10min | 15min |
| 🔴 HIGH | גבוה | Active sirens NOW | 10s | 60s | 60s | 5min | 10min |
| ⚫ CRITICAL | קריטי | Major cities under fire | 10s | 30s | 60s | 3min | 5min |
All threat levels and transition reasons are fully translated for the Hebrew channel — e.g., "רמת איום: מוגבר" (not "THREAT LEVEL: ELEVATED").
Pikud HaOref Stand-Down Detection
The watcher classifies every Oref API response before escalating:
- THREAT alerts (cat 1-7: missiles, rockets, UAVs) → escalate normally
- STANDDOWN alerts ("ניתן לצאת מהמרחב המוגן") → send ✅ message, NO escalation
- Prevents false escalation on informational "you can leave shelter" broadcasts
🌐 Iran Internet Blackout Detection
Monitors Iran's internet connectivity as an early warning signal — Iran has historically cut internet before/during military operations.
Sources
- IODA (Georgia Tech) — BGP, active probing, Google traffic, MERIT telescope data for Iran ASNs
- Direct probes — HTTP pings to irna.ir, president.ir, mehrnews.com with latency tracking
Assessment Levels
| Level | Score | Description |
|---|---|---|
| 🟢 NORMAL | 0-9 | Internet operating normally |
| 🟠 MINOR_ISSUES | 10-24 | Some connectivity fluctuations (common, may not be military) |
| 🟡 DEGRADED | 25-49 | Significant disruptions — possible throttling |
| ⚫ BLACKOUT | 50+ | Major outage — internet appears cut off |
Features
- 24h history graph — Visual bar chart in Telegram showing connectivity trend
- Threat meter —
████░░░░░░░░░░░░░░░░ 20/100visual bar - Probe latency — Shows each Iranian website's response time
- Throttled alerts — Max once/hour (every 15 min for BLACKOUT level)
- State tracking —
state/blackout-state.json+state/blackout-history.json
python3 scripts/scan-blackout.py config.json state # Check status
python3 scripts/scan-blackout.py config.json state --seed # Seed baseline🎯 Strike Correlation Engine
Automatically correlates fire + seismic events to detect possible kinetic strikes. When a fire and earthquake occur within 50km and 30 minutes of each other, it's flagged as a possible strike.
How It Works
- Loads recent fires from
firms-seen.json(parses lat/lon from key formatlat_lon_date) - Loads recent quakes from
seismic-seen.json+ USGS API for coordinates - Computes haversine distance between all fire-quake pairs
- Scores confidence based on distance + time proximity
- Identifies nearest known military/nuclear site
Confidence Scoring
| Factor | Score |
|---|---|
| Distance <10km | +0.3 |
| Distance 10-30km | +0.2 |
| Time <10min apart | +0.3 |
| Near known site | +0.2 |
| Base | +0.1 |
python3 scripts/correlate-strikes.py state # Run correlationRuns automatically after every fire+seismic scan in the watcher loop.
✈️ US Military Flight Tracking
Monitors military aircraft over the Middle East using OpenSky Network ADS-B data.
Coverage
- Bounding box: lat 20-42, lon 40-65 (full ME region)
- Classification by callsign prefix: RCH/REACH (airlift), DUKE/DARK (ISR), DOOM/BONE (bomber), SHELL/TEXACO (tanker), SNTRY/MAGIC (C2)
- Classification by ICAO24 hex ranges: US military transponder blocks
- Categories: ISR, BOMBER, TANKER, C2, AIRLIFT, NUCLEAR_CAPABLE, UNKNOWN_MIL
Alerts
- New military aircraft entering the zone triggers Telegram alert
- Shows callsign, altitude, speed, aircraft category
- Heavy tanker/bomber activity may indicate imminent strike sortie
python3 scripts/scan-military-flights.py config.json state # Scan
python3 scripts/scan-military-flights.py config.json state --seed # Seed baseline✈️ Flight Radar Map (Air Traffic Intelligence)
FlightRadar24-style live map of Middle East air traffic, generated hourly as part of the intel report.
Data Source
- Primary: FlightRadar24 public feed (300-400+ aircraft, full ADS-B coverage)
- Fallback: OpenSky Network API (~80 aircraft, free tier)
- FR24 provides aircraft type, callsign, origin/dest airports, altitude, speed, airline, registration
Map Features
- Dark Palantir-style map with country borders from GeoJSON
- Aircraft arrows showing heading direction (yellow=civil, red=over Iran, green=US/IL military)
- Iran airspace highlighted with red border and dark fill
- Side intel panel with:
- Traffic count (total + over Iran)
- Airport disruption status (Iran/Iraq/Syria/Israel/Lebanon/Jordan)
- US / Israeli military aircraft with role descriptions (e.g. "Tactical airlift", "SIGINT reconnaissance", "Strategic bomber")
- Top origin airports
US/Israeli Military Detection
- US callsign prefixes: RCH, REACH, EVAC, FORTE, JAKE, SAM, AF1, AF2, NAVY, CNV, DOOM, BOLT, IRON, LANCE, ETHYL, SHELL, TEXAS, HOMER, SNOOP, EPIC, GHOST, SNTRY, etc.
- Israeli callsign prefixes: IAF, ISF
- Aircraft type matching: C-17, KC-135, E-3, RC-135, B-52, F-35, RQ-4, MQ-9, G550, etc.
- Registration heuristics: N-prefix (US), 4X-prefix (Israel) for unidentified military types
- Filters out non-US/IL military (Saudi, Omani, RAF, etc.) — only shows relevant assets
Aircraft Role Descriptions (50+ types mapped)
| Type | Role |
|---|---|
| F-35 | Stealth strike fighter |
| B-52 | Strategic bomber |
| KC-135 | Aerial refueling tanker |
| RC-135 | SIGINT reconnaissance |
| E-3 | AWACS airborne radar |
| E-6 | Nuclear command relay |
| C-17 | Strategic airlift |
| C-130 | Tactical airlift |
| RQ-4 | High-alt surveillance drone |
| MQ-9 | Armed recon drone |
| P-8A | Maritime patrol / ASW |
| G550 | SIGINT / early warning |
Airport Disruption Monitoring
Tracks live flight counts for airports in conflict zone countries:
- Iran: THR, IKA, MHD, ISF, TBZ, SYZ, KER, AWZ, BND + 20 more
- Israel: TLV, SDV, VDA, ETH, BEV, RPN, HFA
- Iraq: BGW, BSR, EBL, NJF, SDA
- Syria: DAM, ALP, LTK
- Lebanon: BEY
- Jordan: AMM, AQJ
Status: [X] CLOSED (0 flights), [!] Limited (<5 flights), [+] Operating (5+ flights)
Data Logging
Two structured logs updated on every scan:
state/flight-history.jsonl (7-day retention) — Full snapshot:
{
"ts": 1772305939, "utc": "2026-02-28T19:12:19+00:00",
"source": "fr24", "total": 332, "over_iran": 36,
"iran_flights": 0, "israel_flights": 1,
"airports": {"Iran": {"count": 0, "status": "CLOSED"}, ...},
"military": [{"callsign": "CNV3869", "type": "C130", "tag": "US", "role": "Tactical airlift", ...}],
"top_origins": {"JED": 33, "IST": 25, ...},
"top_dests": {"JED": 38, "CAI": 18, ...}
}state/intel-log.jsonl (flight_scan event) — Summary for hourly reports:
{
"type": "flight_scan",
"data": {
"total": 332, "over_iran": 36,
"military_count": 2, "military_callsigns": ["CNV3869", "C130"],
"airports_closed": ["Iran", "Iraq", "Syria"],
"airports_limited": ["Israel:1", "Lebanon:3"]
}
}Bilingual Captions
- English channel:
✈️ Air Traffic — 332 aircraft, 36 over Iran - Hebrew channel:
✈️ תנועה אווירית — 332 מטוסים, 36 מעל איראן
python3 scripts/generate-flight-map.py config.json state output.pngSent automatically with every hourly report. Image dispatched to both channels with language-appropriate captions via dispatch.py.
🚢 Naval Vessel Tracking
Monitors military vessel movements in Persian Gulf, Strait of Hormuz, Gulf of Oman.
Features
- US Navy vessel database — CVNs (carriers), DDGs (destroyers), CGs (cruisers), SSGNs (subs), LHDs
- IRGC Navy detection — Iranian fast attack boats, frigates, support ships
- Zone classification — Strait of Hormuz, Persian Gulf, Gulf of Oman, Arabian Sea
- Naval base proximity — Bandar Abbas, NSA Bahrain (5th Fleet), Jask, Bushehr, Al Dhafra, Duqm, Diego Garcia
python3 scripts/scan-naval.py config.json state # Scan
python3 scripts/scan-naval.py config.json state --seed # Seed baselineNote: Most AIS APIs are paywalled. Script structure supports multiple data sources; currently uses public AIS feeds.
🎬 24h Time-Lapse GIF
Animated satellite map showing fire + seismic event progression over the last 24 hours.
Features
- ESRI satellite tile basemap with Iran gold border + all neighbor borders
- Known sites marked — Natanz, Fordow, Isfahan, Bushehr, Arak, Tehran, Parchin, Shahrud, etc.
- Fire dots animate in chronologically — color by priority, sized by FRP, glow effects
- Earthquake rings pulse with magnitude labels
- Progress bar + timestamp header, event counter, legend
- Smart frame pacing — slow start (empty map), fast event progression, hold on final state
- 36 frames, variable duration per frame
python3 scripts/generate-timelapse.py config.json state output.gif --hours 24Sent automatically with every hourly report.
📌 Pinned Live Status Message
A single Telegram message edited every 60 seconds with current system status — pinned to the top of the channel.
Shows
- Current threat level with visual bar
- System online/offline status
- Monitoring grid (all source types active/inactive)
- Iran Watch: tracked fires, quakes, nuclear/military sites
- Scan frequency by current threat level
- Last update timestamp
Escalation is instant (sirens detected → immediately bump level).
Deescalation is gradual (cooldown timers prevent premature step-down).
Major cities triggering CRITICAL: תל אביב, ירושלים, חיפה, באר שבע, פתח תקווה, ראשון לציון, רמת גן, בני ברק, חולון, בת ים, הרצליה, נתניה, אשדוד, אשקלון, רחובות, מודיעין, גבעתיים
Hourly Status Report
Automated hourly report sent to Telegram via cron — five items:
- 🗺️ Intel Map — Fresh satellite map with fires, quakes, borders
- ✈️ Flight Radar Map — FR24 air traffic with airport disruptions, US/IL military tracker, role descriptions
- 🇮🇱 Hebrew Summary (סיכום מצב שעתי — מגן יהודה) — Confident Israeli analyst style, cheers up the audience, references צה״ל, כיפת ברזל, חץ. Motivational sign-offs adjusted by threat level.
- 🇺🇸 English Summary (HOURLY INTEL SUMMARY — Magen Yehuda) — Professional analyst style with personality. "Am Yisrael Chai!" energy.
- 🎬 24h Time-Lapse GIF — Animated fire + seismic progression
Both summaries include: sirens, OSINT highlights, fire/seismic detections, market moves, threat changes, and an analyst assessment section.
Cron: 0 * * * * — runs scripts/hourly-report.sh
Intel Logging
Every alert the watcher sends to Telegram is also saved to state/intel-log.jsonl for hourly summary generation.
Event Types Logged
| Type | Description |
|---|---|
siren |
Pikud HaOref siren alerts with details |
siren_standdown |
Pikud HaOref stand-down messages |
breaking_news |
Breaking news alerts (with corroboration status) |
osint |
OSINT batch (Telegram, Twitter, RSS alerts with full text) |
seismic_osint |
Seismic events from OSINT scanner |
seismic |
USGS seismic from dedicated scanner |
fires |
NASA FIRMS fire detections |
polymarket |
Market spike alerts |
blackout |
Iran internet blackout status changes |
cyber |
Cyber warfare alerts (hacktivist, CTI, breach) |
threat_change |
Threat level transitions with reason |
flight_scan |
Air traffic snapshot (total, over Iran, military, airport status) |
strike_correlation |
Fire + seismic coincidence detection |
strikes_map |
Strikes map image with hourly report |
Usage
# Read last 2 hours of intel
python3 scripts/log-intel.py state --read --since 2
# Read only siren events
python3 scripts/log-intel.py state --read --type siren
# Rotate old entries (keeps 48h)
python3 scripts/log-intel.py state --rotate- Auto-rotates at 5MB, retains 48 hours of data
- Each line is a JSON object with
logged_at(epoch) andlogged_utctimestamps
OSINT Scanner
The unified Python scanner (scripts/scan-osint.py) handles Telegram, Twitter, RSS, and inline seismic:
python3 scripts/scan-osint.py config.json state --source all
python3 scripts/scan-osint.py config.json state --source telegram
python3 scripts/scan-osint.py config.json state --source twitter
python3 scripts/scan-osint.py config.json state --source rss
python3 scripts/scan-osint.py config.json state --source seismicFeatures:
- Keyword filtering (52 keywords, Hebrew + English)
- Deduplication via per-source seen-state files
- NordVPN proxy support for rate-limited sources
- Graceful error handling per source
- JSON output for integration with watcher
🚨 Breaking News Detection
The OSINT scanner automatically detects breaking news by matching topic triggers against credibility signals. Both must match for an alert to be flagged as breaking.
Topic Categories
- Leader elimination — Khamenei, Nasrallah, Sinwar (Hebrew + English variants, 20+ phrasings)
- Nuclear events — Detonation, nuclear strike, nuclear bomb
- Compound matching — Words appearing anywhere in text (e.g., "khamenei" + "dead")
Credible Sources
Reuters, AP News, IDF Official (idfonline), Kan News, Flash News IL, Iran International, BBC Persian, Aharonovic (aharonyediot), BeholdIsrael, SentDefender, IsraelRadar
Credible Attribution Keywords
Netanyahu, Biden, Trump, IDF confirms, Pentagon confirms, Reuters, Associated Press, AFP, BBC confirms, "official statement"
Flow
- OSINT scanner matches text against topic trigger phrases
- Checks if source channel is credible OR text contains credible attribution
- Both must match → alert flagged
breaking: truewith topic string - Watcher dispatches as
breaking_newsevent atCRITICALseverity - Corroboration engine tracks all sources per topic (see below)
Multi-Source Corroboration
Breaking alerts are tracked per topic in state/breaking-corroboration.json. When 3+ reputable sources report the same topic within a 2-hour window, the alert upgrades from UNVERIFIED to CONFIRMED:
| Reputable Sources | Status | Header |
|---|---|---|
| 1-2 | ⚠️ UNVERIFIED | "BREAKING NEWS" / "ידיעה חדשותית דחופה" |
| 3+ | ✅ CONFIRMED | "CONFIRMED" / "ידיעה מאומתת" |
Reputable source list (30+): Reuters, AP, BBC, CNN, Times of Israel, Ynet, Haaretz, Jerusalem Post, Al Jazeera, Sky News, France24, NY Times, Washington Post, Wall Street Journal, plus trusted OSINT accounts (SentDefender, IntelPoint, Aurora Intel, etc.)
Rules:
- Same outlet doesn't count twice (deduplication by source name)
- Entries auto-expire after 2 hours (24 hours if confirmed)
- CONFIRMED alerts display the full list of corroborating sources
- Full alert suppression after confirmation —
confirmed_sentflag blocks ALL re-alerts (both confirmed AND unverified) for the same topic - Unverified dedup —
alerted_at_counttracks source count at last alert; only fires when NEW sources found, not every scan cycle - State persists across scan cycles in
breaking-corroboration.json - Expiry preserves
confirmed_sentandalerted_at_countflags via sentinel entries
Hebrew-First OSINT Prioritization
Both format-osint.py (real-time alerts) and generate-summary.py (hourly report) filter OSINT by language:
| Channel | Priority | Behavior |
|---|---|---|
| Hebrew (@opssheagathaariupdates) | Hebrew sources first | Ynet, Maariv, Walla, Ch13, Kann, IDF, AbuAli, flash_news_il prioritized; English fills remaining slots |
| English (@magenyehudaupdates) | English sources first | Reuters, AP, TASS, warmonitors, intelslava prioritized; Hebrew fills remaining |
Hebrew detection: Channel name match against known Hebrew sources OR Hebrew Unicode chars (\u0590-\u05FF) in text.
📡 Multi-Channel Dispatch (dispatch.py)
Central routing module that sends alerts to multiple Telegram channels with language-specific formatting.
Config
{
"outputs": [
{
"id": "main",
"chat_id": "@english_channel",
"language": "en",
"timezone": "America/New_York",
"content": ["all"],
"min_severity": "LOW",
"images": "all"
},
{
"id": "hebrew",
"chat_id": "@hebrew_channel",
"language": "he",
"timezone": "Asia/Jerusalem",
"content": ["siren", "siren_standdown", "siren_clear", "breaking_news", "threat_change", "osint", "fires", "seismic", "strike_correlation", "blackout", "military_flights", "cyber", "polymarket", "map", "flight_map", "summary_he", "timelapse", "pinned_status"],
"images": "high_only"
}
]
}Output Options
| Field | Values | Description |
|---|---|---|
language |
"en", "he", "both" |
Which language text to send |
timezone |
IANA tz string | Timestamps for this output (e.g. "America/New_York", "Asia/Jerusalem") |
content |
["all"] or specific types |
Event type filter |
min_severity |
"LOW" to "CRITICAL" |
Minimum severity to send |
images |
"all", "high_only", "critical_only", "none" |
Image inclusion policy |
Event Types
siren, siren_standdown, siren_clear, breaking_news, threat_change, osint, fires, seismic, strike_correlation, blackout, military_flights, cyber, polymarket, map, flight_map, summary_he, summary_en, timelapse, pinned_status
Usage from Python
from dispatch import Dispatcher
d = Dispatcher("config.json")
d.emit("breaking_news", "CRITICAL", text_he="...", text_en="...",
image_path="map.png", image_importance="high", image_caption_he="...")Usage from Bash (stdin)
echo '{"type":"fires","severity":"HIGH","text_en":"...","text_he":"..."}' \
| python3 scripts/dispatch.py config.jsonFeatures
- Backward-compatible: works with single
telegram_chat_idif nooutputsarray - Image importance decided at call site (low/medium/high/critical)
- Separate
image_captionvsimage_caption_hefor bilingual captions - Supports text, photo, GIF animation, and message editing
- Dispatch audit log:
state/dispatch-log.jsonl(7-day retention, auto-rotates at 2MB)
📰 Wire Service Integration (Reuters/AP)
Direct Reuters and AP News RSS feeds are behind Cloudflare/paywalls. Google News RSS is used as a reliable proxy:
# Reuters filtered to Iran+Israel
https://news.google.com/rss/search?q=site:reuters.com+iran+OR+israel&hl=en-US&gl=US&ceid=US:en
# AP News filtered to Iran+Israel
https://news.google.com/rss/search?q=site:apnews.com+iran+OR+israel&hl=en-US&gl=US&ceid=US:en- Google News RSS items include
<source url="...">Reuters</source>tags for attribution - Both are in the
CREDIBLE_SOURCESset — alerts from Reuters/AP skip "UNVERIFIED" labeling - Returns dozens of items per feed, updates frequently
⚔️ Strikes Map (scan_strikes.py + generate-strikes-map.py)
Comprehensive geolocated strikes database and visual map covering the entire Middle East theater since October 7, 2023.
Data Layers
- ACLED API — Structured conflict events with lat/lon, actors, fatalities (1-3 day lag, analyst-verified)
- NASA FIRMS — Satellite thermal anomalies near known military sites
- USGS Seismic — Earthquake events in Iran region
- Strike Correlation — Fire+seismic coincidence detections from correlation engine
- OSINT Text Extraction — Location mentions in intel-log.jsonl matched against 80+ known cities/sites
ACLED Registration (required for Layer 1)
- Register at acleddata.com/register — free, institutional email recommended
- Accept non-commercial terms, verify email
- Add credentials:
secrets/acled-creds.txt(line 1: email, line 2: password) ORconfig.json → strikes.acled_email/acled_password - Scanner auto-handles OAuth2 (24h access token, 14-day refresh, auto-refresh)
Config (config.json → strikes)
| Field | Default | Description |
|---|---|---|
start_date |
"2023-10-07" |
How far back to collect |
window_days |
null |
Rolling window (overrides start_date) |
countries |
9 countries | ACLED country filter |
event_types |
3 types | Explosions, Battles, Violence against civilians |
sub_event_types |
7 types | Air/drone strike, shelling, etc. |
poll_interval_hours |
6 |
ACLED refresh frequency |
max_events |
50000 |
API row limit |
include_firms/seismic/correlations/osint |
true |
Toggle each data layer |
min_fatalities |
0 |
Fatality filter |
actor_filter |
[] |
Empty=all, or ["Israel","Iran"] |
map_width/map_height |
1600×1000 |
Output image size |
highlight_recent_hours |
48 |
Yellow outline threshold |
Map Visual
- Color-coded by actor side: 🔵 Israel, 🔴 Iran, 🟠 Proxies, 🔵 US
- Shape by event type: ● Airstrike, ◆ Missile, ▲ Ground, ✚ Satellite, ○ Seismic
- Size scaled by fatalities, opacity by confidence
- Sent with hourly report via dispatch
Integration
- Watcher:
check_strikes()runs on extended intel interval (5-30min) - Hourly report:
--backfillrefresh + map generation + dispatch asstrikes_mapevent - State files:
strikes-data.json,strikes-last-fetch.json,strikes-map.png,acled-token.json
🗺️ Interactive Strikes Dashboard
Standalone Leaflet-based HTML dashboard for theater operations visualization. Hosted on GitHub Pages at https://magen-yehuda-intel.github.io/magen-yehuda-bot/.
Features
- 48,900+ geolocated events from ACLED + FIRMS + OSINT + Pikud HaOref
- Dark military theme — CartoDB dark tiles, Orbitron/JetBrains Mono fonts, scanline overlay
- Theater select — ALL, Iran, IL/Gaza, Lebanon, Syria, Iraq, Yemen, Red Sea, Persian Gulf (with event count badges)
- 15 conflict phase presets — Oct 7, Ground Op, True Promise I/II, US→Houthis, Days of Repentance, US+IL→Tehran, Iran-Israel War 2, etc.
- Force disposition bars — Israel (IDF), Iran (IRGC), Iran Proxies, Syria (SAA), US (CENTCOM), Gulf States
- Country breakdown grid with event counts and toggles
- Zoomable timeline — mouse wheel zoom, +/−/FIT buttons, brush selection, 13 annotated key events, starts collapsed
- Timeline auto-fits to active filter range with 15% padding
- Search bar — instant results with fly-to popups
- Analytics panel — stats cards, escalation gauge, sparkline, casualties chart, top actors
- Keyboard shortcuts — 1-9 for theaters, Escape to clear, F for fullscreen, S for search
- URL hash state — shareable URLs preserve map view, filters, and time range
- Fullscreen mode — F11 or F key
- Marker/font size controls — adjustable marker scale (0.5×–3×) and font scale (0.7×–1.5×)
- Collapsible panel sections — click any section title to toggle
- PWA support — add to home screen on mobile with native app feel
Live Feed Pipeline
scripts/export-feed.py— cron every 5 min, exports last 48h OSINT →docs/intel-feed.json- Dashboard fetches
intel-feed.jsonon load + polls every 60s - Deduplication via date|source|notes[:60] keys
- 🟢 LIVE indicator shows event count + freshness
- Only commits+pushes to GitHub if data changed (MD5 hash check)
Map Overlays
- 20 US/Coalition bases — Al Udeid (CENTCOM HQ), Al Dhafra, NSA Bahrain (5th Fleet), Incirlik, Akrotiri, Nevatim, Diego Garcia, etc. Toggleable ON/OFF
- 28 Iran military sites — nuclear (☢️ Natanz, Isfahan, Fordow, Bushehr, Arak), missile (🚀 Dezful, Semnan, Khojir, Bid Kaneh), naval (⚓ Bandar Abbas, Chabahar, Jask), airbases (✈️ Mehrabad, Isfahan, Bushehr, Hamadan), air defense (🛡️ S-300 Tehran, Isfahan, Bushehr). Toggleable ON/OFF
- 14 Iran key sites with proximity event counts — click to fly-to
Event Type Filtering
- 9 event subtypes: Air/drone strike, Shelling/artillery/missile, Armed clash, Attack, Remote explosive/IED, Possible strike (FIRMS), Thermal anomaly (FIRMS), Location mention in OSINT, Suicide bomb
- Click any type to isolate on map; click again to clear; multi-select supported
- FIRMS markers: orange (#ff8800), confidence-based radius (high=5, medium=3.5, low=2.5)
Data Sources
| Source | Events | Coverage |
|---|---|---|
| ACLED | ~48,000 | Oct 7, 2023 → Feb 2025 (analyst-verified, ~1yr lag) |
| NASA FIRMS | ~380 | Real-time satellite fire detections in Iran |
| OSINT | ~930 | Intel-log OSINT events (48h rolling merge) |
| Pikud HaOref | 1+ | Siren events with coordinates |
Mobile Support
- Full-screen map with 5-tab bottom bar (Map, Phase, Feed, Forces, Layers)
- Persistent search bar above tabs — accessible from any tab
- Swipe between tabs (touch gesture left/right)
- Card-style mobile feed with source, location, headline, timestamp, fly-to-on-tap
- Slide-up sheets for panel content
- PWA manifest — add to home screen with native app feel
- Responsive CSS for ≤768px screens
Files
- Template:
scripts/strikes-dashboard.html(~2,300 lines, no inline data) - Standalone:
scripts/strikes-dashboard-standalone.html(~5.4MB, data embedded) - Pages:
docs/index.html(copy of standalone for GitHub Pages) - Live feed:
docs/intel-feed.json(auto-updated every 5 min by cron) - Feed exporter:
scripts/export-feed.py(cron job) - GitHub Gist:
cce8ab4f861d240f21dc2916e7cd187e - GitHub Pages:
https://magen-yehuda-intel.github.io/magen-yehuda-bot/
Local Timezone Support
All times displayed in the user's local timezone (auto-detected via Intl.DateTimeFormat):
- Clock — shows local time + timezone name (e.g.,
03/01/2026 03:36:00 America/New_York) - Feed timestamps —
fmtFeedTime(ev)showsMM-DD HH:MMin local time for events with real timestamps - Popup times —
fmtPopupTime(ev)shows full date + local HH:MM + timezone name - Feed sorting —
feedSortKey(ev)sorts by unix timestamp (newest first), falls back to date string
Rebuild Standalone
python3 scripts/build-standalone.pyThe build script (scripts/build-standalone.py) reads state/strikes-data.json, compacts events into ultra-compact array format (day_num, lat×1000, lon×1000, country_idx, side_idx, fatalities, subtype_idx, location_idx, actor1, actor2, confidence, notes, timestamp), replaces COMPACT_DATA placeholder in the template, and writes both scripts/strikes-dashboard-standalone.html and docs/index.html.
UI/UX Overhaul (Mar 1 — in progress)
3-hour improvement plan (UI-IMPROVEMENT-PLAN.md):
Hour 1: Custom SVG Icons + Larger Defaults
- 10 custom SVG marker icons per event type: starburst explosion (shelling), jet silhouette (airstrike), crossed swords (armed clash), crosshair (attack), bomb (IED), radar pulse (OSINT), skull (suicide bomb), flame (FIRMS fire), heat shimmer (thermal), siren beacon (alert)
- Dual rendering:
L.circleMarkerat zoom <7 (performance),L.divIcon+ SVG at zoom ≥7 (detail) SVG_ICONSdict with color-parameterized factory functions +_iconCachefor memoization- Icon scaling: base 16-48px by fatalities ×
markerScale; hover scale 1.3× with CSS transition - Default
markerScaleraised from 1× to 1.5×;MARKER_STEPS = [0.75, 1, 1.5, 2, 2.5, 3] - Default
fontScaleraised from 1× to 1.15×;FONT_STEPS = [0.85, 1, 1.15, 1.3, 1.5, 1.7]
Hour 2: Panel & Feed UI Overhaul
- All font sizes increased: section titles 8→10px, body 9→12px, stats 9→12px, feed items 9→12px, theater/phase buttons 9→11px, HUD stats 9→11px, logo 11→14px, clock 9→11px
- HUD bar height 40→48px, panel width 320→360px
- Event type legend shows emoji icons next to each type name
- Feed item headlines 8→11px, type tags 7→9px
- Force disposition bars wider (48px) and taller (5px)
- Legend panel larger (max-width 220px, font 11px)
- Popup fonts 12→13px with 14px header
- Mobile feed cards larger (source 13px, text 13px, time 11px)
- Mobile tab bar taller (52px) with bigger icons (22px)
- Stat numbers in analytics 16→18px
- All 7px labels upgraded to 9px minimum
Hour 3: Mobile UX + Visual Polish (planned)
- Mobile gesture refinements, loading screen, marker hover glow, legend with SVG icons
🛡️ Cyber Warfare Monitor (scan_cyber.py)
Monitors 19 hacktivist groups (25 TG handles), 8 CTI Twitter accounts, and 4 dark web/breach RSS feeds for Iran-Israel cyber operations. Classifies attacks, identifies targets, and dispatches bilingual alerts.
Sources
1. Hacktivist Telegram Channels (~25 channels)
Directly monitors the public preview (t.me/s/) of known hacktivist group channels:
| Side | Group | Affiliation | Threat | TTPs |
|---|---|---|---|---|
| 🇮🇷 | Handala Hack | IRGC-linked | HIGH | Data leak, wiper, TG hijack |
| 🇮🇷 | CyberAv3ngers | IRGC | CRITICAL | ICS/SCADA, PLC exploit |
| 🇮🇷 | Moses Staff | IRGC | HIGH | Data leak, encryption, extortion |
| 🇮🇷 | Cyber Toufan | Iran-linked | HIGH | Hack-and-leak, data destruction |
| 🇮🇷 | DieNet | Pro-Iran | MEDIUM | DDoS, defacement, psyop |
| 🇮🇷 | Dark Storm Team | Pro-Palestine/Russia | MEDIUM | DDoS-for-hire |
| 🇮🇷 | RipperSec | Pro-Palestine (MY) | MEDIUM | DDoS, SCADA intrusion |
| 🇮🇷 | Cyber Fattah | Pro-Iran | MEDIUM | Data leak, recon |
| 🇮🇷 | Arabian Ghosts | Pro-Iran | MEDIUM | DDoS, defacement |
| 🇮🇷 | Fatimion Cyber Team | Iran proxy | LOW | DDoS |
| 🇮🇷 | Cyber Islamic Resistance | Hezbollah-linked | HIGH | ICS recon, surveillance |
| 🇮🇱 | Predatory Sparrow | Israel-linked | HIGH | ICS attack, financial disruption |
| 🇮🇱 | Israeli Elite Force | Pro-Israel | MEDIUM | Financial, data leak |
| 🇮🇱 | WeRedEvils | Pro-Israel | LOW | DDoS, defacement |
Plus CTI aggregator channels: FalconFeedsio, DarkWebInformer, cyaboreh, vaboreh, Ransomware_gang_report
2. Cyber Threat Intel Twitter (8 accounts)
@FalconFeedsio · @CyberKnow20 · @DarkWebInformer · @HackManac · @MonThreat · @cybaboreh · @BrettCallow · @vaboreh
3. Dark Web / Breach RSS Feeds (4 default)
- Darkfeed Ransomware tracker
- CISA Advisories (US govt)
- The Hacker News
- BleepingComputer
Attack Classification
The scanner automatically classifies attacks using keyword matching:
| Type | Severity | Indicators |
|---|---|---|
| 🏭 ICS/SCADA | CRITICAL | SCADA, PLC, water system, power grid, gas station |
| 📂 Data Breach | HIGH | Data leak, exfiltrated, database, credentials |
| 💀 Ransomware/Wiper | HIGH | Ransomware, wiper, encrypted, destroyed |
| 🕵️ Espionage | HIGH | APT, spyware, backdoor, surveillance |
| 🌐 DDoS | MEDIUM | DDoS, denial of service, offline |
| 🎨 Defacement | LOW | Defaced, website hacked |
Target Detection
Determines who is being targeted (Israel 🇮🇱 or Iran 🇮🇷) based on:
- Entity mentions in text (IDF, Mossad, IRGC, Tehran, etc.)
- Group affiliation fallback (Pro-Iran → targets Israel, Pro-Israel → targets Iran)
Config
Add custom cyber channels/accounts/feeds in config.json:
{
"cyber_telegram_channels": ["my_custom_channel"],
"cyber_twitter_accounts": ["my_cti_analyst"],
"cyber_rss_feeds": [
{"name": "My Feed", "url": "https://...", "type": "cyber_news"}
]
}Pikud HaOref — Israeli IP Requirement
The Oref siren API is geo-restricted to Israeli IPs. The script handles this with a fallback chain:
- Custom proxy →
secrets/proxy-override.txt - NordVPN →
secrets/nordvpn-auth.txtroutes throughil66.nordvpn.com:89 - Direct → Falls back to direct connection
- Graceful failure → Reports Oref unavailable; all other sources still work
Setup options
mkdir -p secrets
# Option A: NordVPN (service credentials, NOT login)
echo "USERNAME\nPASSWORD" > secrets/nordvpn-auth.txt
# Option B: Any HTTPS/SOCKS5 proxy
echo "https://user:pass@host:port" > secrets/proxy-override.txt
# Option C: SSH tunnel
ssh -D 1080 user@israeli-vps
echo "socks5://localhost:1080" > secrets/proxy-override.txt
# Option D: Skip it — most sources still work globallySafety Rules
⚠️ Never say "all clear" — Only Pikud HaOref can tell people it's safe to leave shelter. The system shows "NO NEW ALERTS BROADCASTING" when sirens stop, with a warning to follow official instructions.
Threat Level Scoring (SITREP)
| Signal | Points |
|---|---|
| Active Pikud HaOref sirens | +30 |
| Major oil spike (>10%) | +25 |
| Polymarket price spike (≥5pp) | +15 |
| High oil move (5-10%) | +15 |
| Heavy news cycle (>8 headlines) | +8 |
| Elevated oil (3-5%) | +8 |
| Active news (4-8 headlines) | +5 |
| Score | Level | Action |
|---|---|---|
| 0-7 | 🟢 LOW | No auto-post (use --force) |
| 8-19 | 🟡 ELEVATED | Auto-post |
| 20-39 | 🟠 HIGH | Auto-post |
| 40+ | 🔴 CRITICAL | Immediate alert |
ctl.sh Commands
| Command | Description |
|---|---|
start |
Start real-time watcher daemon |
stop |
Stop watcher |
status |
Show watcher state, cron, last threat level |
dashboard |
📊 Full dashboard: processes, state, logs, resources |
check |
One-time full check (JSON to stdout) |
post |
Full check → format → post to Telegram |
log [N] |
Show last N lines of watcher log |
rotate |
Force log rotation + show archive status |
install-launchd |
Auto-start watcher on boot (macOS) |
teardown |
🛑 Kill everything: watcher, cron, launchd, state |
Aliases: dash, ps → dashboard
Log Rotation
- Watcher log rotates at 500KB (checked every 5min during runtime + on start)
- Keeps 5 archived logs in
state/logs/ ctl.sh rotateforces rotation check + shows archive statusctl.sh dashboardshows log size and archive count
Scan Overlap Protection
- OSINT scan uses a lock file (
state/osint-scan.lock) to prevent concurrent scans - If a scan is still running when the next cycle fires, it skips with a log message
- Stale locks (>120s) auto-break to prevent permanent deadlock
- Twitter/Telegram scraping goes through NordVPN proxy (curl subprocess) to avoid home IP rate limits
File Structure
iran-israel-alerts/
├── SKILL.md # This file
├── README.md # Open-source documentation
├── ctl.sh # Master control (start/stop/status/teardown)
├── config.example.json # Template — copy to config.json
├── config.json # Your config (gitignored)
├── .gitignore
├── scripts/
│ ├── realtime-watcher.sh # Background daemon (adaptive threat system)
│ ├── check-alerts.sh # Full SITREP (structured JSON output)
│ ├── post-telegram.sh # Check → format → post to Telegram
│ ├── format-telegram.py # JSON → war-room HTML formatter
│ ├── scan-osint.py # Unified OSINT scanner (TG + X + RSS + seismic)
│ ├── scan-fires.py # NASA FIRMS fire scanner for Iran
│ ├── scan-seismic.py # USGS earthquake scanner for Iran
│ ├── scan-blackout.py # Iran internet blackout detector (IODA + probes)
│ ├── scan-military-flights.py # US military ADS-B flight tracker (OpenSky)
│ ├── scan-naval.py # Naval vessel tracker (Persian Gulf AIS)
│ ├── scan_cyber.py # Cyber warfare & hacktivist monitor (30+ groups)
│ ├── correlate-strikes.py # Fire + seismic strike correlation engine
│ ├── generate-fire-map.py # Satellite intel map generator
│ ├── generate-flight-map.py # FR24 air traffic map + intel panel
│ ├── generate-timelapse.py # 24h animated time-lapse GIF
│ ├── generate-summary.py # Hourly Hebrew + English analyst summaries
│ ├── generate-strikes-map.py # Dark-themed ME strikes map
│ ├── strikes-dashboard.html # Interactive Leaflet dashboard (template)
│ ├── strikes-dashboard-standalone.html # Standalone (~5.4MB, data embedded)
│ ├── build-standalone.py # Compaction build script → standalone + docs/index.html
│ ├── marker-icons.js # 10 custom SVG marker icon definitions (reference/standalone)
│ ├── pinned-status.py # Live pinned status message (every 60s + immediate on threat change)
│ ├── dispatch.py # Multi-channel alert dispatcher (EN/HE routing)
│ ├── format-fires.py # Fire data → Telegram HTML formatter
│ ├── format-seismic.py # Seismic data → Telegram HTML formatter
│ ├── format-osint.py # OSINT bilingual formatter (EN/HE channel names)
│ ├── log-intel.py # JSONL intel event logger
│ └── hourly-report.sh # Hourly: map + summaries + GIF → Telegram
├── references/
│ ├── sources.md # Full source list with ratings
│ └── borders.geojson # Country borders GeoJSON (17 countries)
├── secrets/ # gitignored, chmod 600
│ ├── nordvpn-auth.txt # NordVPN service credentials (optional)
│ ├── proxy-override.txt # Custom proxy override (optional)
│ └── firms-map-key.txt # NASA FIRMS API key
└── state/ # Auto-created, runtime data (gitignored)
├── watcher.pid / watcher.log
├── watcher-threat-level.txt
├── firms-seen.json
├── seismic-seen.json
├── blackout-state.json / blackout-history.json
├── military-flights.json
├── naval-state.json
├── strike-correlations.json
├── intel-log.jsonl
├── flight-history.jsonl # Air traffic snapshots (7-day, JSONL)
├── dispatch-log.jsonl # Dispatch audit trail (7-day)
├── breaking-corroboration.json # Multi-source breaking news tracker (2h window)
├── flight-map.png # Latest flight radar map
├── intel-map-latest.png
├── pinned-message-id-main.txt # EN channel pinned msg ID
├── pinned-message-id-hebrew.txt # HE channel pinned msg ID
├── last-standdown-ts.txt # Standdown throttle timestamp
├── watcher-oref-last.txt # Last Oref API response
├── poly_current.json # Current Polymarket state
├── osint-{telegram,twitter,rss,seismic}-seen.json
├── cyber-{telegram,twitter,rss}-seen.json
├── strikes-data.json # Unified strikes database
├── strikes-last-fetch.json # ACLED poll timestamp
├── strikes-map.png # Latest strikes map
├── acled-token.json # ACLED OAuth2 token cache
└── logs/ # Rotated watcher logs (max 5)Setup
Requirements
- Python 3.9+ with
Pillow(pip3 install Pillow) curl,jq,bash- NASA FIRMS API key (free: https://firms.modaps.eosdis.nasa.gov/api/area/)
Quick Setup
cp config.example.json config.json
# Edit config.json with your Telegram bot token, chat ID, FIRMS key
mkdir -p secrets
echo "YOUR_FIRMS_KEY" > secrets/firms-map-key.txt
bash ctl.sh startCron Jobs
Important: crontab must include Homebrew Python in PATH for Pillow/PIL:
# First line of crontab:
PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
# Hourly status report (auto-installed)
0 * * * * bash scripts/hourly-report.sh
# 2-hour full SITREP
0 */2 * * * bash scripts/post-telegram.sh --force⚠️ Without
PATH=/opt/homebrew/bin, cron uses macOS system Python (3.9) which lacks Pillow — causing silent failures in fire map / timelapse / flight map generation.
V2 CENTCOM Dashboard
Interactive Leaflet map with real-time data layers, deployed to GitHub Pages as the main dashboard.
URL: https://magen-yehuda-intel.github.io/magen-yehuda-bot/
Features
- US/Iran military bases with MarkerCluster (cyan/orange bubble clusters)
- Pulsing red siren markers from Pikud HaOref
- NASA FIRMS fire hotspots
- OSINT event markers synced with live feed filters
- Pikud HaOref live banner (green "no alerts" / red pulsing "ACTIVE", 3-state toggle)
- Live feed panel with time filters (15M/1H/6H/24H/48H/ALL) and side filters (Iran/Israel/US/Proxy)
- CNN-style breaking news ticker
- Click-to-highlight with pulsing cyan ring
- Source links for Telegram channels and Twitter accounts
- Mobile bottom toolbar with 6 action buttons
- Keyboard shortcuts for all layers
- NASA Black Marble night satellite imagery
Data Pipeline
Watcher (Mac) → log-intel.py → JSONL file + Azure Table DB (best-effort)
↓
export-feed.py (cron 5min) → intel-feed.json + DB sync → git push → GitHub Pages
↓
Watcher → push/oref → Azure API (on siren detect/clear)
↓
Dashboard loads: API (DB, real-time) + static JSON (backup) → merged + dedupedThe dashboard hardcodes the Azure API URL and merges both data sources for maximum coverage.
Files
docs/index.html— Main dashboard (V2, promoted from /v2/)docs/v2-data.js— Military bases, nuclear sites, missile sites, energy, IRGC, air defense data (354 lines)docs/v1/index.html— Archived V1 dashboard (5.6MB legacy)docs/v2/index.html— Redirect to rootdocs/intel-feed.json— Static backup feed (exported every 5min)docs/oref-alerts.json— Static Oref backup (exported every 5min)
Azure Cloud Backend
Container App API (magen-yehuda-api)
Flask/gunicorn API deployed on Azure Container Apps (consumption plan, ~$0/month).
URL: https://magen-yehuda-api.blackfield-628213bb.eastus.azurecontainerapps.io
Endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/oref |
GET | Pikud HaOref alerts (from watcher push) |
/api/oref/last |
GET | Most recent Oref alert from DB |
/api/oref/history |
GET | Oref alert history (?hours=, ?limit=) |
/api/fires |
GET | NASA FIRMS hotspots (self-polling, 5min) |
/api/intel-feed |
GET | Intel events from Azure Table (?hours=, ?side=, ?limit=) |
/api/aircraft |
GET | Live aircraft from FR24 (~400 in ME, 60s). ?filter=military for military only |
/api/seismic |
GET | USGS earthquakes M2.5+ in ME (50 latest, 2min refresh) |
/api/threat |
GET | Current threat level (GREEN/ELEVATED/HIGH/CRITICAL) |
/api/health |
GET | Health check with cache ages |
/api/debug |
GET | Debug info |
/api/push/oref |
POST | Push Oref data (API key auth) |
/api/push/intel |
POST | Push intel events (API key auth) |
/api/push/threat |
POST | Push threat level changes (API key auth) |
Project: ~/.openclaw/workspace/projects/magen-yehuda-api/
Azure Table Storage
Primary data store for intel events and Oref alerts. Practically free (~$0.01/month).
- Account:
magenyehudadata(eastus) - Auth: Entra ID (shared key blocked by tenant policy)
- Managed identity: Container app has
Storage Table Data Contributorrole
Table: intelevents
- Schema:
PartitionKey=YYYY-MM-DD,RowKey=SHA256(src+text[:60])[:32] - Fields:
ts,src,text,side,type,sub_event_type,lat,lon,location,breaking,confidence,link
Table: orefalerts
- Schema:
PartitionKey=YYYY-MM-DD,RowKey=SHA256(title+cat+areas[:5])[:32] - Fields:
ts,title,cat,area_count,areas(JSON array),cleared_ts,duration_s - API:
/api/oref/last(most recent),/api/oref/history?hours=24&limit=50
Azure Resources
| Resource | Type | Location |
|---|---|---|
magen-yehuda-intel |
Resource Group | eastus |
magenyehudacr |
Container Registry | eastus |
magen-yehuda-env |
Container App Environment | eastus |
magen-yehuda-api |
Container App | eastus |
magenyehudadata |
Storage Account | eastus |
Key Notes
- Oref API is geo-blocked outside Israel — watcher pushes siren data from Mac (via NordVPN IL proxy) to the API
- DB sync happens via
export-feed.py(compares DB vs static by content key, inserts missing) - Empty events are rejected by
db.pyand filtered by dashboard - Container builds:
az acr build --registry magenyehudacr --image magen-yehuda-api:latest . - Push API key: set as
PUSH_API_KEYenv var on container
Troubleshooting
Known Issues & Fixes (Feb–Mar 2026)
| Issue | Root Cause | Fix |
|---|---|---|
| Hourly report cron silently fails | Cron's PATH uses /usr/bin/python3 (3.9.6) missing Pillow — set -euo pipefail kills script |
Add PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin as first line of crontab |
| Polymarket tracks 0 markets | STATE_DIR bash variable not exported → Python os.environ.get() gets . → writes state to wrong path |
Add export STATE_DIR after assignment in realtime-watcher.sh |
| Cyber alerts found but never dispatched | scan-cyber.py (hyphen) can't be Python-imported → from scan_cyber import format_cyber_summary fails |
Renamed to scan_cyber.py (underscore); format uses heredoc-based Python |
| OpenSky returns HTTP 429 | Rate limiting (no API key configured) | Register free OpenSky account for higher limits, or rely on FR24 for hourly flight maps |
| Darkfeed RSS returns 404 | Feed URL changed or removed | Replace with alternative ransomware feed, or remove from config |
| Hourly summary shows "Threat Level: UNKNOWN" | generate-summary.py parsed watcher.log for threat level but regex didn't match log format (emoji prefixes, startup lines) |
Fixed: reads state/watcher-threat-level.txt first (written by watcher), falls back to log parsing |
| Cyber config has empty source arrays | config.json cyber section had no Telegram channels, Twitter accounts, or RSS feeds configured |
Add sources to cyber.telegram_channels, cyber.twitter_accounts, cyber.rss_feeds in config.json |
| Duplicate threat level alerts on restart | Watcher initialized THREAT_LEVEL=GREEN on every start, then detected stale OREF_LAST → spammed GREEN→CRITICAL |
Fixed: watcher reads watcher-threat-level.txt on startup to restore last known level |
| Hebrew channel missing some content types | Hebrew output had explicit content allowlist — new event types silently dropped | Switched to content: ["all"] + content_exclude: ["summary_en"]; added content_exclude support to dispatch.py |
| OSINT scan "still running" skips | Slow proxy causes scan to exceed cycle interval → lock file blocks next scan | Stale locks auto-break at 120s; check proxy latency if persistent |
Literal \u200F in Telegram messages |
macOS bash 3.2 doesn't support \u escapes in $'...' syntax |
Use RLM=$(printf '\xe2\x80\x8f') variable; Python files are fine |
| FIRMS time filter shows 0 or all fires | acq format is YYYY-MM-DD HHMM (no colon, 3-4 digit time) — new Date() returns NaN |
Parse manually: pad to 4 digits, build ISO. Also: satellites pass few times/day so short time windows show 0 |
| 4800+ fire markers clutter map | Most are agricultural/brush fires | Filter by FRP intensity (>10MW) instead of time window |
| Threat indicator stuck at HIGH | Watcher died, API cached stale level | Push correct level via /api/push/threat; indicator now hidden when GREEN |
| Ballistic arcs flicker/disappear | Each arc faded independently — some faded while others still launching | Moved cleanup to barrage level; ALL arcs fade together after last missile lands |
| Ballistic arcs look like growing arrows | Progressive strokeDashoffset reveal |
Draw full arc instantly, no progressive reveal |
Azure Container App latest tag no-op |
latest doesn't trigger new revision |
Use explicit versioned tags (e.g. v18) |
| DB query returns stale events | Azure Table returns by RowKey (hash), early break at limit grabbed random old rows |
Collect ALL matching, sort by ts desc, THEN limit |
| Duplicate DB rows from re-scraping | _row_key() included ts in hash |
Use src + text[:60] only |
Debugging Tips
# Test hourly report under simulated cron environment
env -i HOME="$HOME" PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin" \
bash scripts/hourly-report.sh
# Test single monitor
python3 scripts/scan_cyber.py config.json state
python3 scripts/scan-blackout.py config.json state
python3 scripts/scan-fires.py config.json state
# Check watcher health
bash ctl.sh dashboard
# Binary search for bash syntax errors
for end in $(seq 900 1000); do head -$end scripts/realtime-watcher.sh | bash -n 2>&1 && continue; echo "Error at line $end"; break; doneEnvironment Variables
The watcher uses these bash variables — STATE_DIR must be exported for inline Python:
| Variable | Usage | Exported? |
|---|---|---|
SKILL_DIR |
Base directory for all paths | No (bash only) |
STATE_DIR |
Runtime state files directory | Yes (Python reads via os.environ) |
CONFIG_FILE |
Path to config.json | No (passed as arg) |
THREAT_LEVEL |
Current threat level string | No (bash only) |
Updates (Mar 2 2026)
New Data Tables (Azure Table Storage):
seismicevents— USGS earthquakes, polled every 2minfireevents— NASA FIRMS hotspots (FRP>10MW), polled every 5min- Strike correlation engine:
/api/correlate?hours=1&radius_km=50 - Historical endpoints:
/api/seismic/history,/api/fires/history
Dashboard Additions:
- 40 regional energy assets (Qatar, UAE, Saudi, Iraq, Kuwait, Bahrain, Oman, Israel, Egypt)
- DAMAGED_FACILITIES overlay: 💥 struck / ⚠️ shutdown / 🚫 blocked markers with pulsing borders
- All 23 sidebar layer toggles now functional (7 were missing)
- Feed auto-refreshes every 30s regardless of panel state
- Oref banner shows English category names via
OREF_CAT_ENdictionary
Strikes Map Rewrite:
- Replaced PIL rectangle-based rendering with Cartopy + Matplotlib
- Real Natural Earth coastlines, borders, ocean. Country labels. Dual legends.
- Dependencies: cartopy, pyproj, shapely, pyshp
API v19 deployed — revision magen-yehuda-api--0000019