newsjack 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp.json +9 -0
- package/.newsjack-npm +1 -0
- package/COMMIT +1 -0
- package/LICENSE +21 -0
- package/README.md +133 -0
- package/VERSION +1 -0
- package/bin/newsjack +74 -0
- package/package.json +37 -0
- package/skills/.gitkeep +0 -0
- package/skills/ETHICS.md +265 -0
- package/skills/WHY-NOT-SPAM.md +257 -0
- package/skills/angle-generator/SKILL.md +224 -0
- package/skills/angle-generator/examples.md +517 -0
- package/skills/angle-generator/rubric.md +219 -0
- package/skills/coverage-tracker/SKILL.md +124 -0
- package/skills/coverage-tracker-setup/SKILL.md +84 -0
- package/skills/crisis-holding/SKILL.md +336 -0
- package/skills/crisis-holding/examples.md +302 -0
- package/skills/crisis-holding/rubric.md +218 -0
- package/skills/fact-check/SKILL.md +212 -0
- package/skills/fact-check/examples.md +195 -0
- package/skills/fact-check/rubric.md +228 -0
- package/skills/journalist-fit-check/SKILL.md +199 -0
- package/skills/journalist-fit-check/examples.md +271 -0
- package/skills/journalist-fit-check/rubric.md +251 -0
- package/skills/meanest-editor/SKILL.md +112 -0
- package/skills/meanest-editor/examples.md +331 -0
- package/skills/meanest-editor/rubric.md +275 -0
- package/skills/media-list-manager/SKILL.md +204 -0
- package/skills/media-list-manager/examples.md +88 -0
- package/skills/media-list-manager/rubric.md +67 -0
- package/skills/news-search/SKILL.md +56 -0
- package/skills/newsjack-detector/SKILL.md +286 -0
- package/skills/newsjack-detector/examples.md +118 -0
- package/skills/newsjack-detector/references/engine-cli.md +29 -0
- package/skills/newsjack-detector/references/harness-routing.md +38 -0
- package/skills/newsjack-detector/references/rss-feeds.json +106 -0
- package/skills/newsjack-detector/rubric.md +160 -0
- package/skills/newsjack-monitor-setup/SKILL.md +202 -0
- package/skills/newsjack-monitor-setup/examples.md +106 -0
- package/skills/newsjack-triage/SKILL.md +98 -0
- package/skills/newsworthiness-check/SKILL.md +179 -0
- package/skills/newsworthiness-check/examples.md +232 -0
- package/skills/newsworthiness-check/rubric.md +218 -0
- package/skills/pr-strategist/SKILL.md +304 -0
- package/skills/reactive-comment/SKILL.md +297 -0
- package/skills/reactive-comment/examples.md +284 -0
- package/skills/reactive-comment/rubric.md +280 -0
- package/skills/relevance-coarse-filter/SKILL.md +61 -0
- package/skills/story-origin-check/SKILL.md +160 -0
- package/skills/voice-extractor/SKILL.md +330 -0
- package/skills/voice-extractor/examples.md +227 -0
- package/skills/voice-extractor/rubric.md +251 -0
- package/skills-manifest.json +254 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: newsjack-detector
|
|
3
|
+
description: "Monitor current news and reaction signals, then decide which are credible newsjacking opportunities for a client. Uses the local monitoring engine for evidence, but the skill owns PR judgment, brand safety, standing, decay, angle fit, and handoff."
|
|
4
|
+
when_to_use: "User wants to monitor news for pitchable hooks, find newsjacking opportunities, react to breaking industry news, watch competitors/topics, or decide whether a current signal is worth turning into an angle or reactive comment."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Newsjack Detector
|
|
8
|
+
|
|
9
|
+
Find timely public signals and decide whether a client has a credible, non-spammy reason to use them. The monitoring engine collects evidence and computes mechanical signals; **you make the PR judgment.**
|
|
10
|
+
|
|
11
|
+
This is a **molecule** skill — it orchestrates atomic skills rather than re-implementing them. Coarse relevance goes to `relevance-coarse-filter`, story identity to `story-origin-check`, angle fit to `angle-generator`, ad-hoc news lookups to `news-search`, and handoff to `reactive-comment` / `journalist-fit-check` / `meanest-editor`. Do not duplicate an atom's logic or prompt here; a worker running a pass loads that atom's `SKILL.md` directly, so the atom stays the single source of truth.
|
|
12
|
+
|
|
13
|
+
The monitoring engine's live `news_search` source needs a Medialyst key; without one it runs on RSS/X plus host-driven `news-search` and degrades gracefully. Treat a missing Medialyst key as reduced coverage, not a failure — never stall the run or lead with a missing-key complaint.
|
|
14
|
+
|
|
15
|
+
## Required Workflow (follow in order)
|
|
16
|
+
|
|
17
|
+
**Default mode: run the canonical pipeline and return a report.** This skill exists to produce a freshness-gated newsjack report, including for scheduled/cron runs. Execute by default — only drop into discussion/planning when Step 2 is blocked.
|
|
18
|
+
|
|
19
|
+
1. **CHECK DOCTRINE.** If `skills/ETHICS.md` or `skills/WHY-NOT-SPAM.md` exist, follow them. This skill refuses tragedy hooks, fabricated standing, fake urgency, and spray-and-pray output. These blocks are absolute and override every later step.
|
|
20
|
+
|
|
21
|
+
2. **ANCHOR THE CLIENT — ASK FIRST ONLY IF BLOCKED.** Identify company, topics, competitors, spokespeople, standing, and client-specific exclusions, from a profile JSON or plain-text context.
|
|
22
|
+
- No profile **and** no usable client context → ask for it before running. Never invent profile facts.
|
|
23
|
+
- Genuinely ambiguous (which client? which topic? one-off vs recurring?) → ask one clarifying question, then proceed. Otherwise do not stall the run.
|
|
24
|
+
- Missing standing is not a blocker: monitor, but mark opportunities `weak`/`no-standing`.
|
|
25
|
+
- **Load the client brief.** Read the monitor's `brief.md` (its path is surfaced as `brief_path` by `monitor run`/`monitor status`, or it sits next to the profile). It is the **source of truth** for what this client will and won't pitch and how to present the scan — see **Client Brief** below. An empty/template brief carries no rules.
|
|
26
|
+
|
|
27
|
+
3. **PICK THE RUN SHAPE.**
|
|
28
|
+
- One-off / "what's moving on X" → **Quick Run** below.
|
|
29
|
+
- Real judgment, agent run, or scheduled job → **Canonical Pipeline** below (the default for any output a human or pitch will rely on).
|
|
30
|
+
- Recurring / cron feed monitoring → Canonical Pipeline plus the recurring rules in **Freshness Gate** (`--feed-only --new-only --max-age-hours 24`, hard freshness gate).
|
|
31
|
+
|
|
32
|
+
4. **RUN THE PIPELINE.** Execute the chosen path end to end. For anything beyond a Quick Run, never skip the story-origin / freshness gate.
|
|
33
|
+
|
|
34
|
+
5. **JUDGE — NEVER TRUST MECHANICS AS PERMISSION.** `routing.queue_priority` and `story_size` are recall pressure, not pitch permission. You decide newsjacking-worthiness, standing, journalist shape, and brand safety (see **Engine vs Skill Boundary** and `rubric.md`). Gate angle fit through `angle-generator`.
|
|
35
|
+
|
|
36
|
+
6. **VERIFY & CONCLUDE.** Run the **Completion Checklist**, then report: the `run.md` path, whether coarse passes were cost-optimized or fallback, whether every surfaced signal has verified ≤24h first-public freshness, and top findings.
|
|
37
|
+
|
|
38
|
+
## Engine vs Skill Boundary
|
|
39
|
+
|
|
40
|
+
The Go CLI owns (mechanical, deterministic):
|
|
41
|
+
|
|
42
|
+
- ingestion, dedupe, clustering, novelty tracking
|
|
43
|
+
- mechanical scores only: freshness, source agreement, novelty, profile match, source quality, momentum, major-news weight
|
|
44
|
+
- deterministic story-size scoring from news-search metadata: log-scaled estimated monthly traffic + domain authority, with coverage spread across independently surfaced domains
|
|
45
|
+
- deterministic hygiene filtering for docs/help/product/SEO pages
|
|
46
|
+
- coarse-relevance application via `newsjack filter-apply`, plus two recall guards: a **big-story guard** that upgrades *any* `reject` of a `high`/`major` `story_size` signal to `monitor_only` (`big_story_recall`) — the cheap pass can never hard-drop a big story — and a **profile-match guard** that upgrades `reject/no_profile_bridge` to `monitor_only` when detector/profile evidence already matched the client, a competitor, or a profile term
|
|
47
|
+
- deterministic freshness gating via `newsjack origin-apply`
|
|
48
|
+
- operational routing: lane, queue priority, threshold-demotion flag
|
|
49
|
+
- deterministic safety flags
|
|
50
|
+
|
|
51
|
+
You own (PR judgment):
|
|
52
|
+
|
|
53
|
+
- whether the signal is newsjacking-worthy and whether the client has standing
|
|
54
|
+
- same-story / original-coverage judgment (via `story-origin-check`)
|
|
55
|
+
- final decay explanation from `freshness_gate`
|
|
56
|
+
- journalist shape, brand-safety judgment, and handoff to the next skill
|
|
57
|
+
|
|
58
|
+
Never treat `routing.queue_priority` as permission to pitch — it is only operational queue order.
|
|
59
|
+
|
|
60
|
+
## Client Brief
|
|
61
|
+
|
|
62
|
+
Each monitor may carry a `brief.md` — a prose, user-owned statement of what this client will and won't pitch and how they want the scan presented. It is the **source of truth** for client pitch/output policy; the profile JSON governs *collection*, the brief governs *what gets pitched and shown*. The CLI only creates and surfaces the file (`monitor init` scaffolds it; `brief_path` is reported by `monitor run`/`monitor status`); it never parses it — reading and applying it is yours.
|
|
63
|
+
|
|
64
|
+
- **Where it binds:** triage and report rendering — never collection. Keep retrieval and the coarse pass brief-agnostic so nothing is dropped before judgment; the brief only decides what an already-collected, already-fresh item is allowed to *be* and how it's *shown*.
|
|
65
|
+
- **Never pitch rules** are hard: an item matching one can never be `pitch_ready`. A non-big item drops to `watch` (`client_policy_exclusion`); a fresh `high`/`major` item stays `big_story` with `off_policy: true` (the never-drop doctrine still holds — surface it, don't hide it). `newsjack-triage` enforces this.
|
|
66
|
+
- **Audience / We pitch** set the standing *altitude*: topical overlap is not pitchability. A story can be on-topic and still off-brief.
|
|
67
|
+
- **How to surface** is presentation only: collapse a section to a disclosed count, never silence it. Disclose what the brief held back (count + reason) so nothing is hidden.
|
|
68
|
+
- **Feedback updates the brief.** When the user reacts to a run — "too policy-heavy," "stop showing me X," "this is exactly right" — propose an edit to `brief.md` (a new *We never pitch* rule, a *How to surface* line, or a dated *Example*) so the policy is captured durably, not just for this run. Confirm the edit. An empty/template brief means run with defaults.
|
|
69
|
+
|
|
70
|
+
## Profile Setup File
|
|
71
|
+
|
|
72
|
+
The monitor profile JSON is the source of truth for collection setup: a focused set of short broad beat topics, search terms, competitors, feeds, standing, spokespeople, and exclusions. Prefer 6-8 core 2-3 word topics, with one-word topics allowed when natural. If the user wants to change what the monitor looks for, edit the profile JSON rather than generating one-off retrieval terms during a detector run.
|
|
73
|
+
|
|
74
|
+
- Installed monitors keep the setup file at `~/.newsjack/monitors/<slug>/profile.json`; `brief.md` sits next to it.
|
|
75
|
+
- Direct detector runs use the file passed with `--profile`.
|
|
76
|
+
- Fixture profiles live under `fixtures/newsjack-detector-agent/profile.<slug>.json`.
|
|
77
|
+
|
|
78
|
+
Use `newsjack-monitor-setup` when the user wants to create or materially revise a profile. Collection feedback such as "watch broader accounting firm news" belongs in `profile.json` (`topics` / `search_terms` / `feed_urls`): put 6-8 core broad beats in `topics`, and put broad retrieval terms plus named platforms/products/regulators/competitors in `search_terms`. Pitch-policy feedback such as "don't pitch policy stories" belongs in `brief.md`. After editing `profile.json`, rerun a mock or fixture smoke before trusting the next live run.
|
|
79
|
+
|
|
80
|
+
## Quick Run
|
|
81
|
+
|
|
82
|
+
One-off discovery and scans:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
newsjack detector run --profile profile.json --save
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The detector emits JSON only; render any human scan yourself from the artifact facts. Use `--topic "explicit user topic"` only when the user deliberately asks to add a one-off retrieval topic. Routine profile runs should rely on the profile's durable `topics` and `search_terms`, not ad hoc generated retrieval terms. Use `--mock` for local verification without credentials. Full flag/source/env reference: `references/engine-cli.md`.
|
|
89
|
+
|
|
90
|
+
For each queued signal, inspect title, sources, evidence URLs, age, `routing.lane`, `mechanical_scores` (`major_news`, `novelty`, `source_agreement`), profile matches, and safety flags. For `x` evidence inspect `x_signal_type`, `x_social_signals`, `x_author_followers`, `x_query_counts`; treat lone low-reach posts as noise. A high `major_news` means the story is broadly important, **not** that the client has standing. Treat engine age/decay as provisional until `story-origin-check` verifies the first-public clock. Then apply `rubric.md` and the **Output Format**.
|
|
91
|
+
|
|
92
|
+
## Canonical Pipeline
|
|
93
|
+
|
|
94
|
+
The artifact contract is the source of truth. Write all artifacts to a timestamped run folder:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
RUN_DIR/
|
|
98
|
+
candidates.json # 1. detector output
|
|
99
|
+
coarse_relevance_decisions.json # 2. coarse pass
|
|
100
|
+
relevant_candidates.json # 3. filter-apply
|
|
101
|
+
clustered_candidates.json # 3b. cluster — same-story dedup + stale pre-gate
|
|
102
|
+
origin_findings.json # 4. story-origin pass (representatives only)
|
|
103
|
+
targeted_candidates.json # 5. origin-apply (freshness authority)
|
|
104
|
+
triaged_candidates.json # 5b. newsjack-triage — standing + consolidation
|
|
105
|
+
final_report.md # 7. compiled 3-bucket scan (pitch-ready / big stories / watch)
|
|
106
|
+
run.md # 8. skill-rendered — THE human-facing artifact
|
|
107
|
+
detector.stderr.log commands.log summary.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Only `run.md` is human-facing; the rest are provenance.
|
|
111
|
+
|
|
112
|
+
1. **Run the detector and save candidates.** This is the **canonical invocation** — use it verbatim for any run a human or pitch will rely on, across every harness, so runs stay comparable:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
newsjack detector run --profile profile.json --sources news_search,x --lookback-days 1 --depth quick --limit 80 --min-queue-priority 40 --min-major-news 0.55 > candidates.json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The floors `--min-queue-priority 40` and `--min-major-news 0.55` are the engine defaults; they define the emitted pool. **Do not lower them and do not pass `--include-all-scored` or `--no-hygiene-filter`** (debug-only) for a real run — they change which signals reach the report and make two runs of the same profile incomparable. Profile terms own durable retrieval; do not hand-tune the query per run unless the user explicitly asked for a one-off `--topic`. For recurring/cron precision add `--demote-unmatched-x` (see **Freshness Gate**); that is the only flag the canonical command grows.
|
|
119
|
+
|
|
120
|
+
2. **Coarse relevance pass** → `coarse_relevance_decisions.json`. High-recall junk removal only — no ranking, angles, dates, or pitch decisions. Each worker loads `skills/relevance-coarse-filter/SKILL.md` and applies it to its assigned signals; merge every worker's output into one `decisions` array. For model/worker routing and chunking, see `references/harness-routing.md`.
|
|
121
|
+
|
|
122
|
+
3. **Apply coarse decisions:**
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
newsjack filter-apply --candidates candidates.json --decisions coarse_relevance_decisions.json --include keep --include monitor_only --output relevant_candidates.json
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
3b. **Cluster same-story signals before the expensive retrieval pass:**
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
newsjack cluster --candidates relevant_candidates.json --drop-stale --window-hours 24 --output clustered_candidates.json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The Go CLI collapses syndicated pickups / near-duplicate headlines of the **same public event** into one representative (it shares findings, so 15 NVIDIA-GTC copies cost one story-origin retrieval, not 15) and records the rest in `clustered_duplicates`. `--drop-stale` deterministically pre-gates low-story-size signals whose detector decay is clearly outside the window (`week`/`month`) into `pre_gated_stale`, so they skip retrieval entirely; large stories (`high`/`major`) are always researched regardless of age. Run story-origin on `clustered_candidates.json` (representatives only). Disclose how many duplicates and stale items were collapsed.
|
|
135
|
+
|
|
136
|
+
4. **Story-origin pass** on `clustered_candidates.json` (representatives) → `origin_findings.json`. Each worker loads `skills/story-origin-check/SKILL.md` and applies it per signal: decide same-story vs material-new-development, recover `first_public_at`, `original_url`, and canonical major coverage. It must **not** compute `fresh`/`stale`, must return **one finding per signal (never skip)**, and must cite **≥2 independent corroborating sources** to support a fresh clock. Merge the per-signal results into one `findings` array, keyed by `signal_id`. Validate the count against the input and re-run any gaps. The story-origin pass needs retrieval — see `references/harness-routing.md`.
|
|
137
|
+
|
|
138
|
+
5. **Apply the deterministic freshness gate:**
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
newsjack origin-apply --candidates clustered_candidates.json --origins origin_findings.json --window-hours 24 --output targeted_candidates.json
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The Go CLI is the freshness authority — it computes `freshness_gate.computed_status` from the run timestamp and cutoff. If an LLM labels May 8 fresh for a May 25 run, `origin-apply` marks it stale. Non-fresh signals carry a specific reason: `stale`, `unverified_no_corroboration` (worker cited <2 independent sources — a pipeline/worker-quality miss), `unverified_boundary` (date-only clock straddling the cutoff), or `unverified_no_timestamp` (no clock recovered). Distinguish these in the report and in metrics: `unverified_no_corroboration` means *we* didn't verify, not that the story is old.
|
|
145
|
+
|
|
146
|
+
5b. **Standing triage** on the selected fresh signals in `targeted_candidates.json` → `triaged_candidates.json`. Load `skills/newsjack-triage/SKILL.md` and pass it the **client brief** when present: re-consolidate any same-story representatives that slipped through, apply the brief's **never-pitch** rules (off-policy items can never be `pitch_ready`; fresh big ones stay `big_story` with `off_policy: true`, small ones drop to `watch`/`client_policy_exclusion`), assign `strong`/`partial`/`none` standing at the brief's audience altitude with a journalist-shape sanity check, and **route each story to a tier**: `pitch_ready` (strong, or partial with a sharp shape), `big_story` (a fresh `high`/`major` story that lacks standing — **never dropped**, always surfaced as a suggestion with a `bridge_note` + `relevance_confidence`), or `watch` (small/non-big with no standing, off-beat, duplicate). This is the standing gate the engine cannot make — it replaces ad-hoc orchestrator judgment so the decision is auditable. Only `watch` withholds a story, and only for items that are neither pitchable nor big.
|
|
147
|
+
|
|
148
|
+
6. **Angle generation** on the **routed** candidates in `triaged_candidates.json`. Run `angle-generator` in **pitch mode** on `pitch_ready` items (a candidate is pitchable only if it yields ≥1 honest, journalist-shaped angle; zero viable angles downgrades it to `big_story` if the story is big, else `watch`) and in **exploratory mode** (`context.mode: exploratory`) on `big_story` items (at most one tentative `suggestion` angle; an empty result is fine and does **not** drop the story — it still appears as "awareness only").
|
|
149
|
+
|
|
150
|
+
7. **Compile `final_report.md`** — a 3-bucket scan, story-first and skimmable. The fixture's `scripts/build_report.py` is the reference implementation; the skill owns the human report shape. Lead with a **Today's read** line (`N pitch-ready · M big stories · K watched`) and a funnel line that asserts nothing pitchable or big was dropped off-screen. Then three sections, organized by the two independent axes — **standing** (can the client act?) and **magnitude** (how big is the story?):
|
|
151
|
+
- `## ✅ Pitch-Ready` (`pitch_ready` tier): each story shows freshness (with **both** the first-public date *and* the new-development date for `fresh_new_development`), standing, the angle-generator angles, and its link provenance.
|
|
152
|
+
- `## 🔥 Big Stories Worth a Look` (`big_story` tier): fresh `high`/`major` stories with **no confirmed standing**, surfaced as **suggestions only** — the section header says so explicitly ("your call, relevance unverified"). **Sorted by coverage spread (distinct surfaced outlet count) desc**, no cap. Each shows the magnitude label + outlet count, freshness, the honest `bridge_note`, confidence flags (incl. the coarse `weakness_flag` → e.g. `⚠ possible keyword match`), provenance, and at most one `suggestion`-tagged angle (or "no clean angle — awareness only"). This is how we surface big stories without ever making the drop decision; telling a real story apart from a high-authority-domain artifact is done by **ranking and flagging here**, never by dropping upstream.
|
|
153
|
+
- `## 👀 Watch / Context`: `watch`-tier (fresh but no standing, non-big) plus freshness-gated items (`stale`/`unverified_*`), with plain reasons and dates. Big-but-stale items are marked.
|
|
154
|
+
- **Link provenance (all sections):** **One main source = the source of record** — the article the detector actually surfaced, real `published_at`, flagged when thin (`⚠ single source`, `⚠ source of record is an aggregator`). **Related coverage** underneath: clustered duplicate pickups (tagged `surfaced duplicate`) plus any `canonical_coverage_url`/`original_url` the worker *proposed*, shown with date marked **unverified** and tagged `proposed by research — UNVERIFIED`. **Never promote a worker-proposed link into the main-source position** — the anti-laundering rule. Every link carries a date.
|
|
155
|
+
|
|
156
|
+
Links must be clickable Markdown, not backticked or bare URLs. Do not present mechanical rank as a final fit verdict.
|
|
157
|
+
|
|
158
|
+
**Honor the client brief's *How to surface*** here: if the brief asks to collapse a section (e.g. the big-stories/awareness section), render it as a one-line **disclosed count with reasons**, never silence it. Lead with whatever the brief prioritizes. State plainly when the brief moved an item out of `pitch_ready` or collapsed a section, and quote the rule (`policy_rule`). `scripts/build_report.py` is the brief-agnostic mechanical reference (`final_report.md`); the brief is honored in the skill-rendered `run.md`.
|
|
159
|
+
|
|
160
|
+
8. **Write `run.md` yourself from the artifacts.** The CLI does not render reports. It only emits deterministic JSON. Use `final_report.md` plus the artifact facts to write a human-facing `run.md` in the run folder.
|
|
161
|
+
|
|
162
|
+
The report must be rendered from the **gated/fresh/triaged artifacts**, never raw `candidates.json` alone. Do not resurface coarse-rejected or hard-safety-flagged signals in the ✅/🔥 sections. The only hard drops are mechanical (URL-pattern hygiene) and hard-safety flags; disclose their counts from the JSON artifacts so nothing is hidden — never silently truncate. If you need a machine-readable artifact index, run:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
newsjack run-summary targeted_candidates.json --output summary.json
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`run-summary` writes JSON metadata only; it does not write Markdown or make editorial decisions.
|
|
169
|
+
|
|
170
|
+
The whole pipeline works without any subagent API — harnesses with low-cost-model/worker controls should use them, but every harness produces the same artifact contracts and discloses fallback.
|
|
171
|
+
|
|
172
|
+
## Freshness Gate
|
|
173
|
+
|
|
174
|
+
For recurring scheduled output, a signal is not surfaceable until its Go-computed `freshness_gate.computed_status` is verified. News-search `published_at` values are good article-publication evidence for recovering originals, but they alone never decide same-story status or first publication — that is the `story-origin-check` atom's job.
|
|
175
|
+
|
|
176
|
+
Recurring output rules:
|
|
177
|
+
|
|
178
|
+
- Surface only `fresh` or `fresh_new_development`. Reject `stale` and every `unverified_*` status. The unverified statuses are distinct on purpose: `unverified_no_corroboration` (worker cited <2 independent sources — a *pipeline* miss, often re-runnable), `unverified_boundary` (date-only clock straddling the cutoff), `unverified_no_timestamp` (no clock recovered). Report them separately so worker-quality misses are not mistaken for genuinely old stories.
|
|
179
|
+
- Run with `--demote-unmatched-x` so unmatched X News/Trends clusters fall below the queue floor unless the large-story recall guard lifts them. X News surfaces for review by default; recurring precision wants it demoted unless it is a genuinely large story.
|
|
180
|
+
- Cluster (step 3b) before retrieval and prefer `--drop-stale` so syndicated duplicates and clearly-old low-value items never burn story-origin retrieval.
|
|
181
|
+
- Do **not** reset the clock for AOL, Yahoo, MSN, Apple News, partner syndication, wire pickup, SEO rewrites, or "published today" pages whose canonical/source story is older.
|
|
182
|
+
- A newer article restarts the clock only if it adds a concrete new public fact: official action, filing, statement, data/report publication, material company update, new local impact, or another independently coverable development.
|
|
183
|
+
- Prefer `story_origin.canonical_coverage_url` as the report's main link — the major/most authoritative same-story coverage, not the random pickup that triggered retrieval.
|
|
184
|
+
|
|
185
|
+
`origin-apply` attaches `story_origin` and the deterministic `freshness_gate` to selected and rejected signals. If the first-public timestamp can't be verified, write `first_public_at: null` and explain the gap; `origin-apply` computes the appropriate `unverified_*` status.
|
|
186
|
+
|
|
187
|
+
## Handoff
|
|
188
|
+
|
|
189
|
+
- Breaking / same-day sourced comment → `reactive-comment`
|
|
190
|
+
- Needs story framing → `angle-generator`
|
|
191
|
+
- Named journalist check → `journalist-fit-check`
|
|
192
|
+
- Draft critique → `meanest-editor`
|
|
193
|
+
|
|
194
|
+
## Completion Checklist
|
|
195
|
+
|
|
196
|
+
Before reporting the run complete:
|
|
197
|
+
|
|
198
|
+
- `coarse_relevance_decisions.json` has exactly one decision per emitted candidate (unless `--allow-missing`).
|
|
199
|
+
- `clustered_candidates.json` was produced by `cluster`; story-origin ran on its representatives, and the run disclosed how many duplicates/stale items were collapsed.
|
|
200
|
+
- `origin_findings.json` has exactly one finding per clustered representative (unless `--allow-missing`) — count validated, gaps re-run.
|
|
201
|
+
- `targeted_candidates.json` was produced by `origin-apply`; `triaged_candidates.json` was produced by `newsjack-triage` with a `tier` per signal; `pitch_ready` went to `angle-generator` in pitch mode and `big_story` in exploratory mode.
|
|
202
|
+
- No fresh `high`/`major` story was routed to `watch` — every fresh big story appears in **🔥 Big Stories Worth a Look** (or **✅ Pitch-Ready** if it earned standing). A brief never-pitch rule may move a big story *out of pitch-ready*, but it stays a surfaced `big_story` (`off_policy: true`), never dropped.
|
|
203
|
+
- If a client brief is present, the report applied it: off-policy items are out of `pitch_ready`, any collapsed section shows a disclosed count + reason, and feedback this turn that changes policy was offered as a `brief.md` edit.
|
|
204
|
+
- `final_report.md` is the 3-bucket scan (✅ Pitch-Ready / 🔥 Big Stories Worth a Look / 👀 Watch / Context), written from `targeted_candidates.json` / `triaged_candidates.json`, not raw `candidates.json`.
|
|
205
|
+
- `run.md` was skill-rendered from the gated/fresh/triaged artifacts after `final_report.md` existed — never from raw `candidates.json` alone.
|
|
206
|
+
- The ✅/🔥 sections contain **no** coarse-rejected or hard-safety-flagged signal; the only hard drops (URL-hygiene + hard-safety) have their counts disclosed from the JSON artifacts.
|
|
207
|
+
- The final response names the `run.md` path, the cost-optimized-vs-fallback status, whether every surfaced signal has verified ≤24h first-public freshness, and top findings.
|
|
208
|
+
|
|
209
|
+
## Output Format
|
|
210
|
+
|
|
211
|
+
Return exactly this JSON object. No prose before or after it. Every opportunity must include source URLs in `evidence_used` — `story_origin.canonical_coverage_url` first when present, then the original/source URL and other support (usually 1–3 links across news, RSS, and X).
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"opportunities": [
|
|
216
|
+
{
|
|
217
|
+
"signal_id": "engine signal id",
|
|
218
|
+
"signal_title": "Observed public signal",
|
|
219
|
+
"verdict": "pitch_now",
|
|
220
|
+
"decay": {
|
|
221
|
+
"stage": "4hr",
|
|
222
|
+
"rationale": "Why this clock applies"
|
|
223
|
+
},
|
|
224
|
+
"story_size": {
|
|
225
|
+
"band": "low | moderate | high | major",
|
|
226
|
+
"score": 0,
|
|
227
|
+
"rationale": "How publication traffic/domain authority and coverage spread should affect effort priority"
|
|
228
|
+
},
|
|
229
|
+
"first_publication": {
|
|
230
|
+
"status": "fresh | fresh_new_development",
|
|
231
|
+
"first_public_at": "ISO timestamp or YYYY-MM-DD",
|
|
232
|
+
"original_url": "https://...",
|
|
233
|
+
"canonical_coverage_url": "https://... or null",
|
|
234
|
+
"canonical_coverage_source": "Outlet/source name or null",
|
|
235
|
+
"rationale": "Why this first-public clock controls"
|
|
236
|
+
},
|
|
237
|
+
"why_newsjacking_worthy": "Specific reason this is timely and not generic trend-chasing.",
|
|
238
|
+
"client_standing": {
|
|
239
|
+
"assessment": "strong | partial | weak",
|
|
240
|
+
"rationale": "What gives the client standing, or what is missing"
|
|
241
|
+
},
|
|
242
|
+
"journalist_shape": {
|
|
243
|
+
"beat_description": "Specific reporter shape, not a name",
|
|
244
|
+
"why_they_care_now": "Why this beat plausibly cares now",
|
|
245
|
+
"do_not_target": "Who should not receive this"
|
|
246
|
+
},
|
|
247
|
+
"evidence_used": [
|
|
248
|
+
{
|
|
249
|
+
"source": "news_search",
|
|
250
|
+
"title": "Evidence title",
|
|
251
|
+
"url": "https://...",
|
|
252
|
+
"published_at": "YYYY-MM-DD"
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
"next_skill": "angle-generator"
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
"rejected_signals": [
|
|
259
|
+
{
|
|
260
|
+
"signal_id": "engine signal id",
|
|
261
|
+
"signal_title": "Rejected public signal",
|
|
262
|
+
"reason": "no_client_standing",
|
|
263
|
+
"first_publication": {
|
|
264
|
+
"status": "stale | unverified_no_corroboration | unverified_boundary | unverified_no_timestamp | null",
|
|
265
|
+
"first_public_at": "ISO timestamp, YYYY-MM-DD, or null",
|
|
266
|
+
"original_url": "https://... or null",
|
|
267
|
+
"canonical_coverage_url": "https://... or null"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
],
|
|
271
|
+
"brand_safety_blocks": [
|
|
272
|
+
{
|
|
273
|
+
"signal_id": "engine signal id",
|
|
274
|
+
"signal_title": "Blocked public signal",
|
|
275
|
+
"reason": "tragedy_or_human_suffering"
|
|
276
|
+
}
|
|
277
|
+
],
|
|
278
|
+
"monitor_notes": [
|
|
279
|
+
"Operational note or missing source, if relevant"
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- Allowed verdicts: `pitch_now`, `develop_angle`, `monitor`, `reject`.
|
|
285
|
+
- Allowed rejection reasons: `stale`, `freshness_unverified` (umbrella; or the specific `unverified_no_corroboration` / `unverified_boundary` / `unverified_no_timestamp`), `single_source`, `no_client_standing`, `no_journalist_shape`, `off_beat`, `already_seen`, `weak_signal`, `no_viable_angle`.
|
|
286
|
+
- Allowed brand-safety block reasons: `tragedy_or_human_suffering`, `client_exclusion`, `regulated_claim_risk`, `fabrication_risk`.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Newsjack Detector Examples
|
|
2
|
+
|
|
3
|
+
## Pitch Now
|
|
4
|
+
|
|
5
|
+
Engine signal:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"id": "s1",
|
|
10
|
+
"title": "FTC opens inquiry into AI compliance claims",
|
|
11
|
+
"sources": ["news_search", "x"],
|
|
12
|
+
"features": {
|
|
13
|
+
"decay_bucket": "4hr",
|
|
14
|
+
"source_count": 2,
|
|
15
|
+
"seen_before": false,
|
|
16
|
+
"profile_matches": ["AI compliance", "enterprise governance"],
|
|
17
|
+
"safety_flags": []
|
|
18
|
+
},
|
|
19
|
+
"routing": {
|
|
20
|
+
"lane": "profile_relevance",
|
|
21
|
+
"queue_priority": 86.2,
|
|
22
|
+
"demoted": false
|
|
23
|
+
},
|
|
24
|
+
"mechanical_scores": {
|
|
25
|
+
"freshness": 1.0,
|
|
26
|
+
"source_agreement": 0.78,
|
|
27
|
+
"novelty": 1.0,
|
|
28
|
+
"profile_match": 0.44,
|
|
29
|
+
"source_quality": 0.825,
|
|
30
|
+
"momentum": 0.21,
|
|
31
|
+
"major_news": 0.0
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Skill output:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"signal_id": "s1",
|
|
41
|
+
"signal_title": "FTC opens inquiry into AI compliance claims",
|
|
42
|
+
"verdict": "pitch_now",
|
|
43
|
+
"decay": {
|
|
44
|
+
"stage": "4hr",
|
|
45
|
+
"rationale": "The signal is same-cycle by verified first-public clock, not just the search-result timestamp."
|
|
46
|
+
},
|
|
47
|
+
"first_publication": {
|
|
48
|
+
"status": "fresh",
|
|
49
|
+
"surfaced_article_published_at": "2026-05-25T13:14:00Z",
|
|
50
|
+
"first_public_at": "2026-05-25T13:10:00Z",
|
|
51
|
+
"original_url": "https://www.ftc.gov/news-events/news/press-releases/example",
|
|
52
|
+
"canonical_coverage_url": "https://www.reuters.com/legal/government/ftc-opens-inquiry-ai-compliance-claims-2026-05-25/",
|
|
53
|
+
"canonical_coverage_source": "Reuters",
|
|
54
|
+
"rationale": "The official FTC press release is the earliest verified public source and is inside the 24-hour cron window."
|
|
55
|
+
},
|
|
56
|
+
"why_newsjacking_worthy": "Regulator action creates a live need for explainers on AI compliance claims.",
|
|
57
|
+
"client_standing": {
|
|
58
|
+
"assessment": "strong",
|
|
59
|
+
"rationale": "The client works directly in enterprise AI governance and can explain claim substantiation."
|
|
60
|
+
},
|
|
61
|
+
"journalist_shape": {
|
|
62
|
+
"beat_description": "Enterprise AI reporter covering compliance and regulator scrutiny",
|
|
63
|
+
"why_they_care_now": "They need sourced reaction while the inquiry is fresh.",
|
|
64
|
+
"do_not_target": "General startup roundups or consumer AI reviewers"
|
|
65
|
+
},
|
|
66
|
+
"evidence_used": [
|
|
67
|
+
{
|
|
68
|
+
"source": "Reuters",
|
|
69
|
+
"title": "FTC opens inquiry into AI compliance claims",
|
|
70
|
+
"url": "https://www.reuters.com/legal/government/ftc-opens-inquiry-ai-compliance-claims-2026-05-25/"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"source": "FTC",
|
|
74
|
+
"title": "FTC opens inquiry into AI compliance claims",
|
|
75
|
+
"url": "https://www.ftc.gov/news-events/news/press-releases/example"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"next_skill": "reactive-comment"
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Monitor
|
|
83
|
+
|
|
84
|
+
Engine signal: X discussion only, no news confirmation.
|
|
85
|
+
|
|
86
|
+
Verdict: `monitor`
|
|
87
|
+
|
|
88
|
+
Reason: "Single-source chatter with no confirmed news event. Watch for news search confirmation or official filing."
|
|
89
|
+
|
|
90
|
+
## Reject
|
|
91
|
+
|
|
92
|
+
Engine signal: "Influencers debate AI regulation again" with `month` decay and no new document.
|
|
93
|
+
|
|
94
|
+
Verdict: `reject`
|
|
95
|
+
|
|
96
|
+
Reason: `stale`
|
|
97
|
+
|
|
98
|
+
Engine signal: AOL article published today, canonical URL points to a BBC story from May 4 with no new development.
|
|
99
|
+
|
|
100
|
+
Verdict: `reject`
|
|
101
|
+
|
|
102
|
+
Reason: `stale`
|
|
103
|
+
|
|
104
|
+
`first_publication.status`: `stale`
|
|
105
|
+
|
|
106
|
+
Engine signal: secondary article published today, no canonical/source metadata, and searches do not verify the first public source.
|
|
107
|
+
|
|
108
|
+
Verdict: `reject`
|
|
109
|
+
|
|
110
|
+
Reason: `freshness_unverified`
|
|
111
|
+
|
|
112
|
+
## Brand-Safety Block
|
|
113
|
+
|
|
114
|
+
Engine signal: public tragedy with high social momentum.
|
|
115
|
+
|
|
116
|
+
Block reason: `tragedy_or_human_suffering`
|
|
117
|
+
|
|
118
|
+
Do not hand off to angle generation.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Engine CLI Reference
|
|
2
|
+
|
|
3
|
+
The Go monitoring engine collects evidence, computes mechanical scores, and emits JSON. The `newsjack-detector` skill owns PR judgment, standing, story-origin reasoning, brand safety, and human-facing rendering.
|
|
4
|
+
|
|
5
|
+
Do not duplicate the CLI surface in this file. Agents should discover current commands, flags, defaults, source availability, and credential recovery from the installed CLI:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
newsjack help
|
|
9
|
+
newsjack help detector
|
|
10
|
+
newsjack detector run --help
|
|
11
|
+
newsjack doctor
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
In this repo, prefer the source shim:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
./bin/newsjack help detector
|
|
18
|
+
./bin/newsjack detector run --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
For routine profile runs, rely on the profile:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
newsjack detector run --profile profile.json --save
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Use `--topic` only when the user explicitly asks for a one-off retrieval topic. Durable monitor discovery belongs in `profile.json`, not in ad hoc run terms.
|
|
28
|
+
|
|
29
|
+
Profile caveat for agents: when `search_terms` are present, retrieval uses them instead of raw `topics + competitors`. Keep `topics`, `competitors`, and `standing` as matching/judgment context; put broad retrieval terms plus named platforms, products, regulators, and competitors in `search_terms` when they must drive collection. Terms must be static, explicit, and provenance-safe: user input, client materials, named entities, or current coverage, not model-remembered sector trends.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Harness Routing & Chunking
|
|
2
|
+
|
|
3
|
+
The two coarse passes (relevance, story-origin) are low-cost tasks. They become low-cost *model* passes only when the harness supports model selection or low-cost worker/subagent routing. The artifact contracts (`coarse_relevance_decisions.json`, `origin_findings.json`) are the same regardless of harness — only the cost story changes, and that must be disclosed.
|
|
4
|
+
|
|
5
|
+
## Execution decision path
|
|
6
|
+
|
|
7
|
+
Before each coarse pass, identify the harness and take the first available path:
|
|
8
|
+
|
|
9
|
+
1. **Direct low-cost-model path.** If the harness can choose a model for a single step, run the coarse prompt with the lowest-cost reliable model below, then run the expensive pass with the strong model.
|
|
10
|
+
2. **Low-cost subagent/worker path.** If the harness can't switch the current model but can spawn workers/subagents with a model hint, split candidates into chunks. Relevance workers return only `decisions`; origin workers return only `findings`. Merge each pass into its single JSON artifact.
|
|
11
|
+
3. **Current-model fallback.** If neither is possible, run the prompts with the current model and state explicitly in the final response: `coarse passes ran with current model; this was semantic multi-stage, not cost-optimized multi-stage`.
|
|
12
|
+
|
|
13
|
+
## Harness hints
|
|
14
|
+
|
|
15
|
+
- **Claude Code / Claude-style coding harnesses:** if a `Task`/subagent tool or model override exists, use it for chunks and request the latest Haiku/low-cost alias; use the latest Sonnet or Opus alias for the expensive pass. No control exposed → current-model fallback.
|
|
16
|
+
- **Codex:** if `spawn_agent` is available and model override is allowed, spawn workers with a low-reasoning small/fast model (`gpt-5.4-mini`, `gpt-5-nano`, or the newest GPT-5.x at low reasoning). Use `gpt-5.5` or the strongest Codex model at medium/high reasoning for the expensive pass. If override is not allowed, spawn default workers for parallelism or use fallback; disclose which.
|
|
17
|
+
- **OpenClaw:** prefer low-cost worker fanout. Low-cost: Gemini 3 Flash Preview, Claude Haiku/latest alias, or GPT-5.x low-reasoning. Expensive: Gemini 3 Pro Preview, Claude Sonnet/Opus latest, or GPT-5.5+ higher reasoning.
|
|
18
|
+
- **API harnesses:** call the configured low-cost model for coarse prompts, then the configured stronger model for the expensive rubric pass.
|
|
19
|
+
- **Unknown harness:** current-model fallback unless an explicit low-cost-model or worker mechanism is exposed.
|
|
20
|
+
|
|
21
|
+
## Preferred models
|
|
22
|
+
|
|
23
|
+
- **Coarse passes:** Gemini 3 Flash Preview, Claude Haiku/latest Haiku alias, GPT-5-nano, GPT-5.4-mini low reasoning, GPT-5.5 low reasoning, or the harness's lowest-cost fast equivalent.
|
|
24
|
+
- **Expensive pass:** Gemini 3 Pro Preview, Claude Sonnet/Opus latest aliases, GPT-5.5 medium/high reasoning, GPT-5.4 medium/high reasoning, or the harness's strongest reasoning model.
|
|
25
|
+
- Treat Gemini 2.5 Pro as stale for this pipeline — fallback only when Gemini 3 Pro is unavailable. Gemini 2.5 Flash/Flash-Lite are coarse-pass fallbacks when Gemini 3 Flash is unavailable.
|
|
26
|
+
- If the exact named model is unavailable, choose the closest current low-cost/fast model for pass 1 and the closest current strong reasoning model for pass 2.
|
|
27
|
+
|
|
28
|
+
## Chunking guidance
|
|
29
|
+
|
|
30
|
+
- 1–15 signals: one call per coarse pass is fine.
|
|
31
|
+
- 16–40 signals: split into chunks of 8–15. Prefer at least 2 workers/subagents when the harness exposes them.
|
|
32
|
+
- 41–80 signals: split into chunks of 8–12. Use worker/subagent fanout if available.
|
|
33
|
+
- More than 80 signals: do not ask one low-cost call or one subagent to process everything. Split into chunks of 8–12; if that would need more than 8 low-cost workers, tighten detector `--limit`, lane caps, or rerun by profile/source lane before filtering.
|
|
34
|
+
- Each chunk must include the profile context plus only its assigned signals. Each worker returns only items for its assigned signal IDs.
|
|
35
|
+
- The merged `coarse_relevance_decisions.json` and `origin_findings.json` must each contain exactly one item per input signal unless intentionally using `--allow-missing`.
|
|
36
|
+
- Do not let coarse workers perform the expensive rubric pass, compare across chunks, pick best bets, or write the final report.
|
|
37
|
+
- If the harness has low-cost workers but no model override, still split large sets for reliability and disclose that model cost was not optimized.
|
|
38
|
+
- The story-origin pass needs retrieval. If a low-cost worker cannot open pages or search the web, either give it extracted page/search evidence from the orchestrator or run that pass in the current harness with retrieval tools — do not let a worker return a story-identity verdict it had no evidence for.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"default_feeds": [
|
|
4
|
+
"techmeme",
|
|
5
|
+
"google-news-technology",
|
|
6
|
+
"google-news-business"
|
|
7
|
+
],
|
|
8
|
+
"feeds": [
|
|
9
|
+
{
|
|
10
|
+
"id": "techmeme",
|
|
11
|
+
"name": "Techmeme",
|
|
12
|
+
"url": "https://www.techmeme.com/feed.xml",
|
|
13
|
+
"beats": ["technology", "ai", "startups", "venture", "platforms"],
|
|
14
|
+
"use_when": "Default for technology, AI, SaaS, startup, platform, and developer-tool profiles.",
|
|
15
|
+
"notes": "Curated tech/business front page. High precision for major tech stories."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "google-news-technology",
|
|
19
|
+
"name": "Google News Technology",
|
|
20
|
+
"url": "https://news.google.com/rss/headlines/section/topic/TECHNOLOGY?hl=en-US&gl=US&ceid=US:en",
|
|
21
|
+
"beats": ["technology", "ai", "consumer tech", "platforms"],
|
|
22
|
+
"use_when": "Use as a broad technology backstop when Techmeme may be too narrow.",
|
|
23
|
+
"notes": "Broader and noisier than Techmeme."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "google-news-business",
|
|
27
|
+
"name": "Google News Business",
|
|
28
|
+
"url": "https://news.google.com/rss/headlines/section/topic/BUSINESS?hl=en-US&gl=US&ceid=US:en",
|
|
29
|
+
"beats": ["business", "markets", "finance", "startups", "economy"],
|
|
30
|
+
"use_when": "Use for business, funding, M&A, markets, commercial real estate, and executive-change profiles.",
|
|
31
|
+
"notes": "Broad business feed; requires stricter relevance filtering."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "google-news-science",
|
|
35
|
+
"name": "Google News Science",
|
|
36
|
+
"url": "https://news.google.com/rss/headlines/section/topic/SCIENCE?hl=en-US&gl=US&ceid=US:en",
|
|
37
|
+
"beats": ["science", "research", "space", "climate", "biotech"],
|
|
38
|
+
"use_when": "Use for research, biotech, climate, space, and science-led profiles.",
|
|
39
|
+
"notes": "Often useful for research-backed companies, less useful for generic SaaS."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "google-news-health",
|
|
43
|
+
"name": "Google News Health",
|
|
44
|
+
"url": "https://news.google.com/rss/headlines/section/topic/HEALTH?hl=en-US&gl=US&ceid=US:en",
|
|
45
|
+
"beats": ["health", "healthcare", "biotech", "public health"],
|
|
46
|
+
"use_when": "Use for healthcare, digital health, biotech, pharma, and patient-safety profiles.",
|
|
47
|
+
"notes": "High brand-safety risk; tragedy/human-suffering blocks still apply."
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "google-news-us",
|
|
51
|
+
"name": "Google News U.S.",
|
|
52
|
+
"url": "https://news.google.com/rss/headlines/section/topic/NATION?hl=en-US&gl=US&ceid=US:en",
|
|
53
|
+
"beats": ["us", "policy", "regulation", "courts"],
|
|
54
|
+
"use_when": "Use when U.S. policy, courts, or national regulation are central to the client.",
|
|
55
|
+
"notes": "Broad and noisy. Avoid unless the client has policy standing."
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "google-news-world",
|
|
59
|
+
"name": "Google News World",
|
|
60
|
+
"url": "https://news.google.com/rss/headlines/section/topic/WORLD?hl=en-US&gl=US&ceid=US:en",
|
|
61
|
+
"beats": ["world", "geopolitics", "international business", "supply chain"],
|
|
62
|
+
"use_when": "Use for geopolitics, supply chain, global markets, and international policy profiles.",
|
|
63
|
+
"notes": "High tragedy/war exposure. Use only with direct public-interest standing."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "memeorandum",
|
|
67
|
+
"name": "Memeorandum",
|
|
68
|
+
"url": "https://www.memeorandum.com/feed.xml",
|
|
69
|
+
"beats": ["politics", "policy", "media", "washington"],
|
|
70
|
+
"use_when": "Use for U.S. politics, public affairs, policy, and media-politics profiles.",
|
|
71
|
+
"notes": "Politically sensitive. Usually not appropriate for normal company newsjacking."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "mediagazer",
|
|
75
|
+
"name": "Mediagazer",
|
|
76
|
+
"url": "https://www.mediagazer.com/feed.xml",
|
|
77
|
+
"beats": ["media", "publishing", "journalism", "creator economy"],
|
|
78
|
+
"use_when": "Use for media, journalism, publishing, creator, and ad-tech profiles.",
|
|
79
|
+
"notes": "Good companion to Techmeme for media-industry clients."
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "ftc-press",
|
|
83
|
+
"name": "FTC Press Releases",
|
|
84
|
+
"url": "https://www.ftc.gov/news-events/news/press-releases/rss.xml",
|
|
85
|
+
"beats": ["consumer protection", "antitrust", "privacy", "ai regulation", "advertising"],
|
|
86
|
+
"use_when": "Use for privacy, consumer protection, advertising claims, antitrust, and AI compliance profiles.",
|
|
87
|
+
"notes": "Official source; slow but high authority."
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "sec-press",
|
|
91
|
+
"name": "SEC Press Releases",
|
|
92
|
+
"url": "https://www.sec.gov/news/pressreleases.rss",
|
|
93
|
+
"beats": ["finance", "public companies", "securities", "crypto", "compliance"],
|
|
94
|
+
"use_when": "Use for fintech, crypto, public-company compliance, and investor-market profiles.",
|
|
95
|
+
"notes": "Official source; useful for same-day expert commentary."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"id": "govuk-news",
|
|
99
|
+
"name": "GOV.UK News",
|
|
100
|
+
"url": "https://www.gov.uk/search/news-and-communications.atom",
|
|
101
|
+
"beats": ["uk", "policy", "regulation", "property", "business"],
|
|
102
|
+
"use_when": "Use for UK policy, regulated industries, property, and public-sector profiles.",
|
|
103
|
+
"notes": "Broad official UK feed; requires topic filtering by the skill."
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|