Personal knowledge database that pulls content via RSS feeds or Exa semantic search. Two purposes: (1) accurate, first-principles understanding of how things work, and (2) longitudinal tracking of how real-world situations develop over time.
RSS keeps track of your configured feeds. Exa produces high-relevance materials via semantic search. The LLM layer summarises neutrally and tags ontologically for future clustering.
First ~25s of the run, looping GIF. Full recording (~79s, H.264): demo.mp4.
| Aspect | RSS Mode | Exa Mode |
|---|---|---|
| Objective | Keep track of interested feeds | Produce high-relevance materials |
| Approach | Feed-based (pull from configured sources) | Semantic search (meaning-based retrieval) |
| Input | Feed URLs in config/rss_feeds.txt |
Search topic (e.g. "ai and datacentre buildout") |
| Selection | Latest N articles per feed, within --since-days |
Top matches for topic, filtered by --since-days |
| Config | config/rss_feeds.txt, --since-days |
--topic, --since-days |
| API | None (public RSS) | Exa (requires EXA_API_KEY) |
RSS pulls from your configured feeds by recency. Exa uses semantic search to surface content that matches the meaning of your topic, not just keywords.
flowchart TB
subgraph inputs [ ]
rssFeeds[RSS Feeds: config/rss_feeds.txt]
exaQuery[Exa Search: topic query]
end
rssFeeds -->|"Feed-based: latest N per feed, filtered by since-days"| fetch
exaQuery -->|"Semantic: top matches for topic, filtered by since-days"| fetch
fetch[Fetch Articles]
fetch --> grok[Grok LLM]
grok --> filter{Exa: relevance >= 7?}
filter -->|Yes or RSS| notion[(Notion Database)]
filter -->|No| skip[Skip article]
Create a Notion database with these 13 properties:
| Property | Notion Type | Source |
|---|---|---|
| Title | Title | article title |
| Summary | Rich text | LLM summary |
| Keywords | Multi-select | flattened keyword list from allowed taxonomy (see config/keywords.txt) |
| Source_URL | URL | article url |
| Entry_Type | Select | LLM entry_type |
| Cluster_Tag | Select | LLM situation_tag from allowed list (see config/cluster_tags.txt) |
| Trunk_Branch | Rich text | LLM trunk_branch |
| Relevance_Score | Number | LLM relevance_score |
| Source_Mode | Select | "rss" or "exa" |
| Feed_Source | Rich text | feed name or "exa-search" |
| Date_Published | Date | article published_date |
| Date_Added | Date | utcnow() on first insert |
| Last_Updated | Date | utcnow() on every upsert |
Share the database with your Notion integration (••• → Add connections). See Screenshots for the populated table view.
-
Copy
.env.exampleto.envand fill in your values:NOTION_TOKEN– Notion integration tokenNOTION_DATABASE_ID– Target database ID (32 chars) or full Notion database URLGROK_API_KEY– xAI API keyEXA_API_KEY– Exa API key (required for--mode exaonly)
-
Install dependencies (Python 3.12):
pip install -r requirements.txt
-
Create the Notion database with the 13 properties above and share it with your integration.
| File | Purpose |
|---|---|
config/rss_feeds.txt |
RSS feed URLs (one per line) |
config/cluster_tags.txt |
Allowed cluster tags for situation-updates. The LLM picks from this list to group related articles. Add your own tags; existing Notion tags are merged automatically. Override path with RSS_CLUSTER_TAGS_FILE. |
config/keywords.txt |
Controlled vocabulary for domain, concept, time_signal. Entity and region stay open. Sections: [domain], [concept], [time_signal]. Override path with RSS_KEYWORDS_FILE. |
RSS mode is the default; Exa mode is for targeted discovery when researching a specific topic.
| Command | What it does |
|---|---|
python src/rss_to_notion.py |
RSS mode (default), last 2 days |
python src/rss_to_notion.py -i |
Interactive: prompts for mode, topic, since-days |
python src/rss_to_notion.py --since-days 7 |
RSS, extend lookback window |
python src/rss_to_notion.py --mode exa |
Exa discovery, default topic |
python src/rss_to_notion.py --topic "X" --mode exa |
Exa search on custom topic |
Exa mode limits output to 5 results and only upserts articles with relevance score ≥ 7.
Run with -i to be prompted instead of passing flags:
python src/rss_to_notion.py -iPrompts: Mode (rss/exa), Topic (Exa only), Since days (both modes). See Screenshots for an example run.
# List Notion databases shared with your integration
python src/rss_to_notion.py --list-databasesThe workflow runs automatically every day at 7am Hong Kong Time (UTC+8). You can also trigger it manually from the Actions tab. Daily run uses RSS only. Configure these secrets:
NOTION_TOKENNOTION_DATABASE_IDGROK_API_KEY
For manual Exa runs, also set EXA_API_KEY and optionally RSS_TOPIC.
- Share the database: Click ••• on the database page → Add connections → select your integration.
- Database ID: Run
python src/rss_to_notion.py --list-databasesto list databases. - Property names: Must match exactly (e.g.
Source_URL, notSource URL). - Exa mode: Requires
EXA_API_KEYin.env.
Open an issue for bugs, ideas, or questions. See CONTRIBUTING.md for guidelines.
Repository visibility (topics, profile pin): Step-by-step on GitHub is in docs/github-ui-setup.md. If you use the GitHub CLI (gh auth login), run scripts/add-github-topics.sh to add suggested topics. With a GITHUB_TOKEN that has repo access, scripts/follow-up-github.sh sets topics and publishes the v0.1.0 release (see script header).
- Exa
findSimilarseeding: pass URL of a saved entry to discover related content - Notion filtered view per
situation_tagas a chronological tracker - Weekly digest: new
trunk_branchentries grouped by domain - Obsidian export of
trunk_branchentries as a concept graph
Video demo
The demo GIF above plays inline in this README. For the full capture, open assets/demo.mp4.
Example outputs from interactive Exa mode.
CLI interactive run
Interactive mode: prompts for mode, topic, since-days. Example run with mode=exa and 5 articles created in Notion.
Notion database view
Table view with Title, Summary, Cluster_Tag, Keywords, and Feed_Source columns.


