Inspiration

We follow a lot of news for work, and three tools kept failing us.

An RSS reader only follows sites that publish a feed, and what it collects piles up unread. A social feed follows the algorithm, not you. And AI news summaries have a quieter problem: when seven outlets run the same Reuters dispatch, a naive aggregator reports "seven sources." It is one story, printed seven times. Repetition starts to look like consensus.

Then the quotes. An LLM that summarizes a story and adds a quote gives you no way to know whether that sentence exists anywhere. We wanted a feed where every claim comes with something you can check — a receipt — and where no model writes that receipt.

What it does

WeOwnFeed builds a personal news feed from what you care about, not from a list of blogs.

You describe the feed. Pick from 7 categories and 66 subtopics, add up to three "+" follows (a company, a product, a person), paste the address of a newsroom that has no RSS feed, and write one sentence about why you read the news, in any language. Every topic and follow becomes a Tavily search. A short taste check tunes the result, and every card says why it is there ("Because you follow Revolut").

It follows sites that have no feed. Paste a newsroom URL. Tavily Map reads the site's link tree, and each day the server maps it again and diffs against what it already knows. The difference is the new posts, which Tavily Extract (or Crawl, for a burst) pulls in.

It replaces the pile-up with one paragraph. Home opens with "Latest developments": one paragraph on what changed across everything you follow. Open it in WAI, our news assistant, which answers only from the stories it was given and numbers its sources.

It counts origins, not outlets. Copies of the same story are recognized as they arrive; only one copy is processed, the rest are listed as "Also published by." A wire byline, dateline or attribution ("(Reuters)", "by Associated Press", "© Reuters"), or a body-text overlap of 50% or more (5-word shingles, Jaccard), puts copies into one origin. Regional editions of one outlet count as one publisher. A card shows "N outlets · M origins."

Fact Check gives every claim receipts. One tap, and:

  1. A model extracts 2–3 atomic, checkable claims. This is the only model step.
  2. For each claim, three Tavily searches run in parallel: one for support, one that actively looks for contradiction ("denied OR disputed OR false OR retracted"), and one on the official domain of the entity the claim is about.
  3. The outlets that published the story are excluded, so a story cannot confirm itself. Social and user-generated platforms never count as evidence.
  4. Five URLs (1 official, 2 support, 2 contradiction) are pulled with Tavily Extract, focused on the claim.
  5. Evidence sentences are cut from that extracted text by code and checked to appear in it verbatim. No model writes a quote. Tap a quote and the source page opens at that exact sentence.
  6. The verdict is a set of rules, not a model's opinion:
    • contradiction and no independent support → contradicted
    • official source confirms, no contradiction → supported
    • two or more independent origins support, no contradiction → supported
    • support and contradiction → disputed
    • under 6 hours old with a single origin → developing

A story that is six hours old and has one source is not false; other newsrooms have not reported yet. WeOwnFeed labels it "Developing" instead of punishing it for being early.

Research goes deeper on request. "Research deeper" runs Tavily Research and writes a cited report on any story while you keep reading.

Search works by meaning, in any language. A Turkish query finds English stories about the same thing.

How we built it

FastAPI (Python 3.11), PostgreSQL 16 with pgvector (HNSW, cosine), a background enrichment worker, and a Flutter web app.

NVIDIA Nemotron and Nebius Token Factory

Every model runs on Nebius Token Factory through one OpenAI-compatible client. We chose a model and a thinking mode per task, and measured before we chose.

Role Model Mode
Summary (2 sentences, ≤45 words) and briefing nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B thinking off
Taxonomy labels (7 categories, 66 subtopics) nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B thinking on + strict JSON schema
Multi-source synthesis, daily digest, article chat nvidia/nemotron-3-super-120b-a12b streaming
Topic gate, claim extraction, fallbacks Qwen/Qwen3-30B-A3B-Instruct-2507 non-thinking
Embeddings (1024 dimensions) Qwen/Qwen3-Embedding-8B retrieval instruction on queries
WAI assistant and Home card deepseek-ai/DeepSeek-V4-Flash-0731 thinking off

Nemotron Nano does the work every article goes through. In a blind comparison on 30 stored articles (judge: gpt-oss-120b) against our previous Laya + Qwen3-30B setup, Nano gave better tags in 23 of 29 cases (vs. 6), better summaries in 24 of 29 (vs. 3) and the right main category in 28 of 29 (vs. 21), at about 6.6 s and $0.0005 per article. Nemotron Super runs the server's heavier reasoning endpoints. In the app, conversation goes through WAI on DeepSeek-V4-Flash with thinking off, because it starts streaming in 1–2 seconds.

Where Token Factory accelerated our workflow:

  • One key, one client, many models. Six roles across four model families with no GPU provisioning. Moving a role to another model was a one-line config change, which is how we fixed our topic gate (see Challenges).
  • Fast benchmarking. We compared embeddings on 219 human-labeled articles (subtopic phrase → labeled articles), then re-embedded the whole database:
Model Dims AUC p@5 Turkish AUC Turkish p@5
all-MiniLM-L6-v2 (local) 384 0.903 0.56 0.598 0.18
Qwen3-Embedding-8B, no instruction 1024 0.917 0.53 — —
Qwen3-Embedding-8B, with retrieval instruction 1024 0.940 0.64 0.935 0.59

After switching, we re-calibrated every similarity threshold in the system for the new model (same-story clustering, follow matching, search tiers, feed scoring).

  • Thinking on and off per call. Nano labels with thinking on and summarizes with it off: the same model, two jobs.

Other Nebius services: none. We use Token Factory inference only; we did not use AI Cloud compute, Serverless Jobs, Serverless Endpoints or DevPods.

Tavily: all five endpoints, each with its own job

Endpoint Job
Search Demand-driven ingestion (topic=news), the live web tier in search, and the three Fact Check angles
Extract Full text when a result is short or paywalled; claim-focused chunks from the five evidence URLs
Map Newsrooms without RSS: daily link-tree map and diff against PostgreSQL
Crawl Bursts of new posts on a followed site
Research On-demand cited reports ("Research deeper")

Ingestion is demand-driven. A query runs only while at least one user follows it, at its own cadence (6 h category, 24 h core subtopic, 48 h specific subtopic or "+" follow). A query that keeps returning almost nothing slows down exponentially and recovers once it is productive again. Multiple Tavily keys rotate automatically, and automatic ingestion stops above a hard credit reserve so Fact Check never runs dry. Every call is logged with endpoint, purpose, latency, credits and cache hit, and exposed through /api/tavily/stats and /api/tavily/calls.

Personalization, search and resilience

The feed scores chosen topics, follows (by name or by meaning), the "why I read news" sentence and an interest vector that likes move 15% toward a story and dislikes 12% away. Search fuses vector similarity, PostgreSQL full-text search and taxonomy tags with Reciprocal Rank Fusion.

The app has two modes on purpose. If the API is reachable, it runs live on the real pipeline. If not, it serves a snapshot exported from a real WeOwnFeed instance — stories, saved Fact Checks, Research reports, taxonomy and Tavily telemetry — and says so in a banner. Anyone who opens the link sees a full product, not an empty screen.

Challenges we ran into

Our first scraper lost most of the news. The V0 prototype stitched DuckDuckGo, Yahoo RSS, Reddit and Hacker News together. Anti-bot walls, paywalls and brittle DOM selectors lost more than 60% of the data. We dropped it and moved collection to Tavily; the old code stays in server/legacy/.

Thinking models and small budgets don't mix. Some calls are tiny: a yes/no topic gate, a short claim query with max_tokens as low as 30. With thinking on, the budget is spent inside the reasoning block and the answer comes back empty. On the topic gate, thinking hurt quality too: Nano with thinking let 14–15 of 16 junk pages through. We split the work: a non-thinking Instruct model for gates, Nemotron Nano for summaries (thinking off) and labels (thinking on, schema-constrained). On 73 hand-labeled articles the final gate dropped 1 of 49 real stories.

Tavily's usage counter can lag. We saw /usage stay frozen for hours. Since the credit reserve depends on it, the server adds its own logged spend to the last reported value and never lets the estimate go down within a month.

Origins are harder than domains. "Apple denied a Reuters report" is not a Reuters story. Our wire patterns only match bylines, datelines, attribution phrases and copyright lines in the first 2,500 characters, so a passing mention of an agency does not make it the origin.

Accomplishments that we're proud of

  • A Fact Check where the model's only job is to name the claims. Search, evidence, quotes, origin counting and the verdict are code you can read and test.
  • "N outlets → M origins": syndication collapsed before it can pass for independent confirmation.
  • A fresh-news rule that refuses to call a six-hour-old, single-source story false.
  • Model choices made by measurement: Nemotron Nano's blind-test results, and Turkish retrieval going from 0.18 to 0.59 precision@5.
  • All five Tavily endpoints doing distinct, necessary work, with a credit system that protects verification.
  • A complete product, from onboarding to Fact Check, that stays usable even when the server is down.

What we learned

  • Pick the model per task, and measure it. The best model for a 2-sentence summary was not the best for a yes/no gate, and thinking helped labeling while it hurt gating.
  • Thresholds belong to a model. Changing embeddings meant re-calibrating every cut-off in the system.
  • The useful AI question in news is often not "is this true?" but "how many independent sources actually say this?" That one can be answered with evidence.
  • Trust comes from what a model is not allowed to do. Our receipts are credible because no model writes them.

What's next for WeOwnFeed

Known limits, stated plainly.

  • "Supported" means corroborated by an official source or by two or more independent origins. It does not mean "true."
  • Stance detection on evidence sentences is rule-based (keywords and negation patterns): transparent, but coarse.
  • Our measurements use small hand-labeled sets (29, 73 and 219 articles).

Next.

  • Act on the recheck time the verifier already computes, so "Developing" and "Disputed" stories are re-checked automatically.
  • Replace the keyword stance rules with a measured classifier, keeping the verbatim-quote and rule-based verdict guarantees.
  • Bring Nemotron Super's multi-source synthesis and daily digest into the app.
  • Larger labeled sets for every measurement above.

Built With

Share this project:

Updates

Submission history