Wake up to the UAE without opening ten news tabs.
uae-news-digest turns Google News RSS into a ranked, deduplicated terminal briefing with clean JSON for scripts and agents.
- Signal first. Preferred sources and UAE-specific keywords push important stories up.
- No repeat sludge. Exact keys plus fuzzy title matching collapse syndicated duplicates.
- Human or machine. Read the emoji digest in your terminal, or pipe stable JSON into agents, cron, Slack, or your own scripts.
- Bring your own feed. Use UAE by default, switch regions, or pass any RSS URL.
- Translate only when you ask. Optional DeepL support keeps the default path simple and dependency-light.
bun add -g @drakulavich/uae-news-digestOr run from source:
git clone https://github.com/drakulavich/uae-news-digest.git
cd uae-news-digest
bun install
bun linkuae-news-digest # fetch + print UAE news
uae-news-digest --hours 12 --limit 10 # tighter briefing window
uae-news-digest --json # stable envelope for automation
uae-news-digest --region de # Germany preset
uae-news-digest --rss-url http://localhost/feed.xml # any RSS feed
uae-news-digest healthcheck # JSON liveness probe
DEEPL_AUTH_KEY=xxx uae-news-digest --target-lang DE # optional DeepL translation| Flag | Default | Description |
|---|---|---|
--region <code> |
uae |
News region preset (uae, us, uk, de) |
--hours <n> |
36 |
Lookback window in hours |
--limit <n> |
6 |
Max items in digest |
--target-lang <code> |
DeepL target language (e.g. DE, FR, JA). Requires DEEPL_AUTH_KEY |
|
--rss-url <url> |
Custom RSS URL (overrides --region) |
|
--state-file <path> |
./seen_titles.txt |
Seen-items state file |
--timeout-ms <n> |
15000 |
RSS fetch timeout |
--topics-config <path> |
Path to topics config JSON (overrides auto-detect) | |
--no-topics |
Force legacy region mode even if a topics config is present | |
--dry-run |
false |
Preview without updating state |
--json |
false |
Output as JSON (agent-friendly envelope) |
π¦πͺ UAE Latest News Digest
π‘οΈ UAE intercepts 79 Iranian strike assets (The National, 2h ago)
π Dubai property sales drop more than 30% (Anadolu AjansΔ±, 5h ago)
β΄οΈ Container ship incident at Khor Fakkan (Reuters, 3h ago)
βοΈ Abu Dhabi airport reopens after rain (Khaleej Times, 1h ago)
π§οΈ Unstable weather hits some emirates (Gulf News, 4h ago)
π’οΈ Oil prices: OPEC+ mulls output increase (CNBC, 6h ago)
And when you need structured output:
uae-news-digest --json | jq '.items[].title'Every run automatically surfaces headlines that materially affect an expat family in the UAE across four areas:
- Safety / threats β missiles, drones, airspace closures, evacuation alerts, storms
- Money / daily life β rent, fees, fuel prices, salary, fines, subsidies
- Rules / visas / documents β visa changes, new laws, permit and licence updates
- Logistics / infrastructure β flight disruptions, road closures, metro outages
Items that score above the threshold are pulled into a π¨ Important block printed at the top of the digest, deduplicated from the regular listing below. Each important line shows a [signals] marker that explains why it surfaced. PR puff (launches, awards, "world's first/tallest/largest", festivals, and similar) is penalised and pushed down.
This is a heuristic β no API key required, always on.
Example output (topics mode):
π¦πͺ UAE digest β 2025-11-14
π¨ Important
π‘οΈ UAE intercepts Iranian missile barrage (The National, 1h ago) [missile, airspace] β UAE Security
βοΈ Dubai airport closes Terminal 2 for maintenance (Gulf News, 3h ago) [flight] β Travel
π° UAE economy
π OPEC+ weighs output cut for Q1 (Reuters, 4h ago)
...
In region mode the Important block has the same layout but without the β Topic Name suffix.
Google News sometimes returns loosely-matched articles for a query. Add optional match and matchMode keys to any topic to require real keyword matches in the article title:
| Key | Type | Default | Description |
|---|---|---|---|
match |
string[] |
β | Keywords that must appear in the article title. Omit to keep existing behaviour. |
matchMode |
"all" | "any" | <N> |
"all" |
"all" β every term must match; "any" β at least one; a positive integer N β at least N terms. |
When articles are dropped for failing the keyword filter, a warning reports how many were dropped (visible in non-JSON mode on stderr). The CLI equivalents for region mode are --match <terms...> and --match-mode <mode>.
--json enriches every item with importance, tier (breaking | impact | neutral | fluff), signals, and matchedTerms. Pipe that to an LLM with the ready-made filter criterion:
uae-news-digest --prompt # print the filter criterion
uae-news-digest --json | claude "$(uae-news-digest --prompt)"The agent can drop noise reproducibly based solely on the structured metadata β no extra API key, no custom prompt engineering required.
--prompt output:
You are a news filter for an expat family in the UAE. Keep only what materially affects safety, money, rules/visas, or logistics. Drop PR, launches, awards, rankings, and 'world's first/tallest/largest'.
For per-topic digests (e.g. economy, real estate, regional politics) instead of one undifferentiated regional feed, create a digest.config.json file:
{
"locale": { "hl": "en", "gl": "AE", "ceid": "AE:en" },
"topics": [
{
"slug": "economy",
"name": "UAE economy",
"emoji": "π°",
"query": "(UAE OR Emirates) AND (economy OR GDP OR inflation OR ADNOC OR non-oil)",
"limit": 5
},
{
"slug": "realty",
"name": "Real estate",
"emoji": "π ",
"query": "(Dubai OR \"Abu Dhabi\") AND (\"real estate\" OR property OR Emaar OR Aldar)",
"limit": 4
},
{
"slug": "chocolate",
"name": "Dubai chocolate",
"emoji": "π«",
"query": "\"Dubai chocolate\" OR pistachio OR kunafa",
"limit": 3
}
]
}The CLI looks for the config in this order:
--topics-config <path>(explicit override)./digest.config.json(current working directory)$XDG_CONFIG_HOME/uae-news-digest/topics.json(falls back to~/.config/uae-news-digest/topics.json)
When a config is found, the CLI fetches each topic in parallel and renders one section per topic. Cross-topic dedup is "first topic in config wins" β reorder the array to set priority. To force the legacy region mode while a config is present, pass --no-topics.
--target-lang translates all section titles in a single DeepL batch. --limit, when explicitly set, overrides every topic's per-topic limit for the run.
The example query strings above are starting points, not optimal β iterate them against real Google News output.
{
"tool": "uae-news-digest",
"version": "...",
"mode": "topics",
"query": { "hours": 36, "targetLang": null },
"topics": [
{ "slug": "economy", "name": "UAE economy", "count": 5 },
{ "slug": "realty", "name": "Real estate", "count": 4 },
{ "slug": "chocolate", "name": "Dubai chocolate", "count": 1 }
],
"count": 10,
"warnings": [],
"items": [
{ "topic": "economy", "title": "...", "source": "...", "score": 0, "publishedAt": "...", "hoursAgo": 4 }
]
}Items are emitted as a flat list in section order; each carries its topic slug so consumers can group. Legacy region mode emits the same envelope with mode: "region" and without the topics array.
import { parseRss, buildDigest, runDigest, renderDigest } from "@drakulavich/uae-news-digest/core";Use the core API when you already have RSS XML and want the same filtering, scoring, deduplication, translation fallback, and rendering logic without spawning the CLI.
uae-news-digest --region us --hours 12 --limit 10
β
βββ Region ββββββ resolve RSS URL from preset (or --rss-url override)
β
βββ Fetch RSS βββ Google News RSS feed
β
βββ Filter ββββββ skip: opinion, tabloids, sports, travel
β
βββ Score βββββββ +3 preferred source, +2 UAE mention, +2 priority topic
β
βββ Deduplicate β exact key match + Jaccard fuzzy (threshold 0.45)
β
βββ Translate βββ DeepL API (optional, when --target-lang set)
β
βββ Render ββββββ region flag + emoji + title + source + hours ago
State file (seen_titles.txt) tracks seen articles so scheduled runs do not repeat the same briefing forever.
healthcheck uses the default live Google News RSS feed. For deterministic smoke tests, pass healthcheck --rss-url <url>.
- Bun >= 1.3 (CI pins 1.3.14).
- CI validates Linux and macOS. Windows is not a supported target yet.
Made with ππ©΅ Published under MIT License.


{ "topics": [ { "slug": "schools", "name": "Schools", "query": "school fees Dubai", "match": ["school", "fees"], "matchMode": "all" } ] }