+704
-884
docs/aggregators/PRD_KAGI_NEWS_RSS.md
························"description": "Automatically posts breaking news from Kagi News RSS feeds. Kagi News aggregates multiple sources per story with balanced perspectives and comprehensive source citations.",···-"description": "Optional: only post stories with these subcategories (e.g., 'World/Middle East', 'Tech/AI')"-"description": "How much content to include: full (all sections), summary (main paragraph + sources), minimal (title + link only)"-**Result:** Posts all world news stories with 3+ sources, full content including images/highlights/perspectives.-**Result:** Only posts tech stories about AI/ML or tech industry business news with 2+ sources.······-doc.Find("h3:contains('Highlights')").Next("ul").Find("li").Each(func(i int, s *goquery.Selection) {-doc.Find("h3:contains('Perspectives')").Next("ul").Find("li").Each(func(i int, s *goquery.Selection) {-doc.Find("h3:contains('Sources')").Next("ul").Find("li").Each(func(i int, s *goquery.Selection) {-**Cleanup:** Periodic job deletes rows older than 30 days (Kagi unlikely to re-post old stories).-buf.WriteString(fmt.Sprintf("• **%s**: %s ([Source](%s))\n", p.Actor, p.Description, p.SourceURL))-func (p *PostPublisher) PublishStory(ctx context.Context, story *KagiStory, communities []*CommunityAuth) error {-- `kagi_stories_filtered` (counter) - Stories filtered out by reason (duplicate, min sources, category)-mockAPI := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
···+- ✅ **HTML Parser** - Extracts all structured data (summary, highlights, perspectives, quote, sources)·········+Kagi migrated their RSS feeds from `kite.kagi.com` to `news.kagi.com`. The old domain now redirects (302) to the new domain, but for reliability, always use `news.kagi.com` directly in your feed URLs. Story links within the RSS feed still reference `kite.kagi.com` as permalinks.···+- **Only 3 H3 sections:** Highlights, Perspectives, Sources (no other sections like Timeline or Historical Background)+- **Historical context** is woven into the summary paragraph and highlights (not a separate section)+- **Feed contains everything shown on website** except for Timeline (which is a frontend-only feature)·········"description": "Automatically posts breaking news from Kagi News RSS feeds. Kagi News aggregates multiple sources per story with balanced perspectives and comprehensive source citations.",···+**Note:** The MVP implementation uses a simpler configuration model. Feed-to-community mappings are defined in the aggregator's own config file rather than per-community configuration. This allows one aggregator instance to post to multiple communities.+The MVP uses a simplified configuration model where the aggregator service defines feed-to-community mappings in its own config file.······+- **Bold** (`social.coves.richtext.facet#bold`) on section headers: "Highlights:", "Perspectives:", "Sources:"+- **Link** (`social.coves.richtext.facet#link`) on all URLs (source links, Kagi story link, perspective sources)+**Implementation Note:** Uses direct HTTP client instead of ATProto SDK for simplicity in MVP.+- `create_post(community_handle: str, title: str, content: str, facets: List[dict], ...) -> dict`+**Future Consideration:** If Kagi proxy becomes unreliable, migrate to blob storage in Phase 2.+The Kagi News RSS Aggregator implementation is complete and ready for integration testing and deployment. All 7 core components have been implemented with comprehensive test coverage (57 tests, 83% coverage).+- HTML parser that extracts all structured data from Kagi News feeds (summary, highlights, perspectives, quote, sources)