Self-contained OSINT workstation · hardware-validated
Flashpoint
A U.S. civil-unrest monitoring console that lives on a Raspberry Pi 5 with a seven-inch touchscreen, boots to READY on its own, and never phones a cloud.
Public OSINT in, deterministic judgment out: classified, deduplicated, corroborated, clustered into hotspots, and drawn on a dark map that reads at a glance from across a desk.
in » ▊
· phrase "police clash" → police_clash 0.85
· phrase "highway blocked" → protest_related_road_shutdown 0.80
· phrase "looting" → riot 0.85
· token "protest" → protest 0.65
Real rules, real weights, real event classes from classifier.py. Sample headlines are synthetic; the judgment is the actual code path.
Five stages, all legible
Ingest
GDELT 2.0 on a 15-minute cadence as the backbone; Event Registry as supplement; NWS alerts and curated local-news RSS for context. A mock source seeds dev and demo.
Classify
A four-signal deterministic pipeline: title keywords, body keywords, DMOZ categories, Wikipedia concepts. No LLM, no external calls, eight event classes out.
Deduplicate
Three layers ending in a six-rule syndication detector that knows the wire families (AP, Reuters, UPI, AFP). Syndicated copies get zero trust weight so they can't fake corroboration.
Cluster
Greedy radius clustering: 75-mile metro radius, 72-hour window, minimum three events. Hotspot names are proximity-weighted, so five events near Boston beat eight events scattered across the state.
Judge
Every cluster gets confidence, severity, momentum, and a trend state (escalating, stable, declining) recomputed each ingest cycle by comparing the last 8 hours against the 16 before them.
Eight event classes
protestriotpolitical_violencepolice_clashvandalism_tied_to_unrestcrowd_disruptionprotest_related_road_shutdownunrest
Why deterministic, and why it costs something
In a monitoring system, a plausible-but-wrong label is worse than a conservative miss, and an unexplainable label is worst of all. Every classification in Flashpoint traces to a specific phrase, token, category, or concept with a specific weight. Rules miss paraphrases a model would catch; in exchange, the same input produces the same output forever, and 180 tests pin that promise down.
The same discipline runs through corroboration. Confidence only rises when independent source families agree, and the syndication detector exists precisely so that one AP story printed by forty outlets counts once.
Installed equipment, not a website
The whole stack runs on a Raspberry Pi 5: FastAPI and SQLite behind a React and MapLibre front end, wrapped in a Qt shell with zero browser chrome. A systemd service and autostart bring it from power-on to a READY screen with no keyboard attached; if the backend blinks, the shell shows a native retry state instead of a browser error. It is designed to sit on a desk for months and be glanced at, like a barometer.
Raspberry Pi 5 (8GB) · Pi Touch Display 2, 7″ · FastAPI · SQLite · React 19 · MapLibre GL · PySide6/PyQt6 kiosk shell · systemd + autostart · GDELT 2.0 · Event Registry · NWS · local RSS