The thread between stories
Imagine three unrelated news events in one week. An Israeli strike kills a Hamas commander. The US Treasury sanctions a set of Hezbollah financiers. Houthi fighters attack Red Sea shipping. Three beats, three reporters, three piles of articles. The interesting question isn't inside any one of them — it's what runs through all three.
To answer that by hand, you'd have to read hundreds of articles and hold every name in your head until one of them reappears in a story it shouldn't. Investigator does that crossover detection mechanically.
The interesting finding is rarely inside one story. It's the financier named in a sanctions story who also appears in a separate shipping story — the one name that crosses over.
From a pile of articles to a map
Under the hood it's six steps. The first two pull facts out of text; the next three turn that soup of per-article facts into a structured network; the last lets a confidence calculation flow across it.
What each step is really doing
- Merge evidence. The same actor is written a dozen ways. Surface variants collapse into one node, and the list of articles that mention it becomes that node's evidence. Three articles asserting the same link become one edge of weight 3 carrying three URLs.
- Filter to the backbone. Rank every relationship by how many independent articles attest it, drop the one-offs — but then restore the shortest path from any stranded actor back to your subject, so nothing relevant gets cut off.
- Triangulate. A method called TMFG keeps only the strongest, non-redundant links and groups the actors into tight clusters of four — the themes (next section).
- Confidence. Each actor starts with a score from its own coverage; the network then nudges it by the company it keeps — surrounded by well-attested actors, your score rises; propped up only by shaky ones, it falls.
From that run: 449 fetched → 312 extracted → a 57-node graph (36 events + 21 actors) → 90 directly attested relationships, each carrying its source URL → 2 cross-story bridges → 8 ranked leads.
Themes — which actors belong together
A theme is the system's answer to "who goes with whom?" — a tight group of four actors that keep showing up together. Open one and it expands into the relationships binding its four members, each with its source.
Themes come out of step 5 (TMFG). The trick of TMFG is that it builds a graph you can decompose cleanly into overlapping four-actor cliques, and each clique is a theme. Some links TMFG draws weren't stated outright in any single article — those fill-in edges become the system's structural hypotheses, kept visually distinct (dashed) from facts (solid) so you know which is which.
Here's that theme expanded, the way an analyst sees it — every member relationship with its quote and source:
CIPS ↔ RUSSIA — "CIPS has seen increased usage by Russian entities… following Western sanctions."
CIPS ↔ IRAN — "CIPS volumes reached record highs in global oil trade involving Iran." theme CHINA · CIPS · IRAN · RUSSIA — evidence-weighted score 5.9 · [cnbc.com]
Bridges — the actor in two stories
Every search you add is fed into one session, and every actor is stamped with which search produced it. The actors that show up in more than one search are the bridges — the backbone of any cross-story claim, and usually the whole point of the exercise.
In the three-story example, two bridges fell out: HAMAS (the strike story and the sanctions story) and IRAN (the sanctions story and the shipping story). Each bridge comes with a small dossier you can verify: the articles in each story that mention it, the actual quotes with URLs, and the structural reason it was flagged.
From the bridges, the system ranks concrete cross-story leads — the kind of thing you'd want to go read:
Grounded in a source-cited relation on the Binance node: "Iran funneled $850 million through Binance… used as a channel for Iranian financial transactions." newsmax.com (citing WSJ)
The shape of the bridges is itself a finding. In a separate sanctions run, three state actors — CHINA, IRAN, RUSSIA — bridged all three stories at once (a triangle, each at full confidence), a very different structure from a chain of adjacent pairs.
The key network — done for you automatically
The Key network tab runs that same hidden-connection machinery with no manual selection. It seeds itself with the investigation's most important nodes — the theme members plus the bridges — and surfaces the brokers that stitch those otherwise-separate clusters into one skeleton.
It's the connective tissue the themes view doesn't show: not which actors group together, but the single node the whole investigation hinges on.
How many sources actually agree
Corroboration — the heart of fact-checking — is shown right on the screen. Every actor and every piece of evidence carries a badge for how many independent sources confirm the same claim.
Two things make the badges trustworthy. First, claims are clustered by meaning, so "X was sanctioned" and "X faces sanctions" count as the same claim. Second, syndication is collapsed: twenty outlets running the same wire copy count as one independent source, not twenty. Well-corroborated actors also get a quiet nudge up the confidence scale, so they rank above single-source ones.
Does the network support your case?
Every investigation runs against a domain hypothesis — one focused question the whole analysis is testing. Pick a domain (terror financing, sanctions evasion, corporate misconduct, …) and that question scores every piece of evidence.
Now the Analyse reports — both for a Connections sub-map and the Key network — close with a Hypothesis assessment: a plain verdict on whether what you're looking at actually supports that question, in the standard intelligence-community confidence language (the ICD-203 scale), citing the specific links that drive it.
If no link in the sub-map actually bears on your question, the report says so plainly and gives the lowest-confidence verdict — it won't manufacture a case from coincidence.
A memory that spans investigations
On its own, each run is amnesiac — it only sees the articles it just fetched. Turn on the analytics engine and every finished investigation folds into one persistent knowledge base that later runs draw on, and that you can question directly.
It remembers actors across cases
"We've seen this name before, in a different investigation, doing a different thing." New runs are pre-seeded with what the base already knows about the subject.
It merges carefully, never recklessly
It auto-merges only safe name variants (U.S. ↔ US) and sends genuine
ambiguities to a review log. It will not silently fuse James Comer and James Comey.
Because it knows when things happened, you can even ask time questions without naming the actor — "which organization was banned by Germany in 2024?" and "what entity was subject to an OFAC action in October 2024?" both correctly return Samidoun, from its assembled timeline. A conflicts panel flags date disagreements as data-quality leads.
What it is, what it isn't — and how to try it
Investigator turns a bag of source material into a scored, source-traced map, finds the structure that crosses stories, and tells you — in plain confidence language — whether that structure supports the question you're asking. But it's a place to start, not a verdict to publish.
Not a causation engine
It surfaces co-occurrence and source-stated relationships. "Iran bridges Hezbollah and the Houthis" means the same Iran is attested in both — not that Iran caused either.
Only as good as the corpus
If coverage leans one way, so does the graph. Treat a thin or one-publisher run as a thin finding.
Not a final answer
A cross-story lead is a place to start reading — which is exactly why every claim ships with its URLs. Someone still has to read them.
Try it
Investigator is open source. Clone it, point it at a few news queries, and watch the map build:
★ github.com/dsivov/investigator
# 1) one focused investigation from the command line
PYTHONPATH=.:src python research/cross_event_investigation.py \
--domain sanctions_evasion --period 30d \
--event "russia_oil:Russia oil sanctions evasion dark fleet 2026" \
--event "china_yuan:China yuan settlement Russia trade sanctions 2026" \
--event "iran_drone:Iran Russia military drone supply 2026"
# 2) or run the full UI (engine :5003 · API :5050 · web :5180)
INVESTIGATOR_TMFG=1 PYTHONPATH=src:. python -m investigator # pipeline engine
PYTHONPATH=.:src python ui/server.py --port 5050 # API + reports
cd ui && npm install && npm run dev # → http://localhost:5180
Full setup, search-source toggles, and the cumulative knowledge base
(--analytic_engine_enabled) are documented in the project
README.