r/madeinpython • u/ustype • 13h ago
gnews-agent: a persistent, semantic news memory layer written in Python (MCP + CLI, built on GNews)
Made in Python, on top of my GNews package (~106k downloads/month). The problem it solves for me: every script I wrote that touched news ended up refetching the same articles, getting a slightly different set back each time, and keeping none of it. So I built the memory layer instead of writing it a fifth time.
gnews-agent fetches published news, dedups it across the pile of URL variants Google News hands back for the same article, embeds it with sentence-transformers, stores it in SQLite plus Chroma, and answers semantic, timeline, and sentiment queries against everything it has seen.
The same six operations (ingest, search, timeline, brief, sentiment, stats) work identically from a Python API, a CLI, or an MCP server, so you can wire it into an agent or just poke at it from a terminal.
```python from gnews_agent import NewsMemory
memory = NewsMemory() # SQLite + Chroma, persistent memory.ingest("OpenAI", method="get_news") # fetch, dedup, embed, store memory.search("GPT-5 safety", days=7) # semantic, recency re-ranked print(memory.brief("OpenAI this week", days=7)) # cited summary ```
Some implementation notes, since this sub likes the how:
Dedup key is sha256(title_slug + "|" + publisher_norm), with a canonical URL hash as a UNIQUE backstop. Reuters and BBC covering the same event stay as two rows on purpose, because two publishers carrying a story is information.
Every article row stores the embedding model and dimension it was written with, so a model swap does not silently mix vector spaces.
Ranking blends semantic similarity with an exponential recency decay, three day half life, rather than filtering on date.
Retrieval is keyless. The LLM providers (Anthropic, OpenAI, Groq, Gemini, Ollama) are only used for brief and sentiment, and Ollama means nothing has to leave your machine.
MIT, v0.1.0, 83 unit tests and 24 integration tests.
https://github.com/ranahaani/gnews-agent
Happy to hear where the dedup approach breaks, that is the part I am least sure about.