News
The full news stack — feed discovery, catalog management, preference-aware fetching, LLM story fusion, and static HTML rendering. Ships four model extensions (news-feed-discovery, news-feed-catalog, news-reader, news-feed-analysis), one report extension (news_html_report), the four news workflows (news-fetch, news-fusion, news-curation, news-full), and the decoupled feedback server that closes the 👍/👎 loop between the generated HTML page and the workflows. When the optional @svendowideit/systemd-service extension is installed, the feedback server runs as a systemd user service (via user lingering) so it starts at boot; otherwise the ensure-feedback-server step is skipped and you run it manually. Install: swamp extension pull @svendowideit/news. Model instances (local-news, feed-catalog, feed-discovery, feed-analysis) are auto-registered by the workflows on first run — no manual swamp model create needed. Setup: swamp model @svendowideit/news-reader method run setup local-news (set llmModel + llmBaseUrl to enable LLM fusion). Run: swamp workflow run @svendowideit/news-fetch | @svendowideit/news-fusion | @svendowideit/news-curation | @svendowideit/news-full.
Global Arguments
| Argument | Type | Description |
|---|---|---|
| llmBaseUrl | string | Base URL of an OpenAI-compatible LLM server. The /v1/chat/completions path is used. Defaults to a local Ollama instance. |
| llmModel | string | LLM model tag used for story fusion (Ollama model, e.g. llama3, mistral, qwen2.5). |
| llmApiKey? | string | Optional API key for LLM servers that require authentication. Ollama typically does not need one. |
| llmTemperature | number | Sampling temperature for fusion LLM calls. Low values keep extraction deterministic. |
| fusionMinClusterSize | number | Minimum cluster size to trigger LLM fusion. Singletons stay as ordinary summaries unless a story already exists. |
| citationRetentionDays | number | How long article citations live before aging out of a story. Core facts always survive. |
| llmConcurrency | number | Max concurrent LLM requests for fusion steps. Start at 1 and increase if the server supports it. |
| maxFusions | number | Hard cap on the number of LLM fusion calls made within a single fusion step (fuseStories / seedStories / regenStories). Once reached, the remaining clusters are skipped and persisted as-is. |
| llmTimeoutSec | number | Per-call timeout (seconds) for LLM chat/completions requests. Lower values surface server outages faster. |
| llmFailureThreshold | number | Server-side LLM failures (outage / timeout / HTTP 5xx) tolerated in a step before the step halts. 1 = fail fast on the first server error. Client-side errors are not counted. |
| feedbackServerPort | number | Port the feedback queue HTTP server listens on (default 8765). |
| feedbackServerServiceName | string | systemd user service name for the feedback server. |
| feedbackServerScriptPath? | string | Override the path to the bundled feedback-server.ts script. Defaults to the script bundled with this extension. |
| Argument | Type | Description |
|---|---|---|
| llmBaseUrl? | string | Base URL of an OpenAI-compatible LLM server (e.g. http://localhost:11434) |
| llmModel? | string | LLM model tag for story fusion. Empty = fusion disabled; set a tag to enable. |
| llmApiKey? | string | Optional API key for LLM servers that require authentication. |
| llmTemperature? | number | Sampling temperature (0..2). Low values keep extraction deterministic. |
| fusionMinClusterSize? | number | Minimum cluster size to trigger LLM fusion. |
| citationRetentionDays? | number | How long article citations live before aging out. |
| llmConcurrency? | number | Max parallel LLM requests. |
| maxFusions? | number | Hard cap on LLM fusion calls per step before the step stops and the workflow continues. |
| llmTimeoutSec? | number | Per-call LLM request timeout in seconds. |
| llmFailureThreshold? | number | Server-side LLM failures tolerated in a step before the step halts. |
| Argument | Type | Description |
|---|---|---|
| feeds | array | RSS/Atom feed URLs to fetch — either string URLs or feed objects from news-feed-catalog |
| maxArticlesPerFeed | number | Maximum articles to keep per feed (default 25) |
| Argument | Type | Description |
|---|---|---|
| newsAge | string | Time range of news to show (e.g., 2h, 7d, 4w, 1m). Supports h (hours), d (days), w (weeks), m (months). Defaults to 3 days. |
| Argument | Type | Description |
|---|---|---|
| topN | number | Number of articles to include in the HTML report (0 = all articles, default 0) |
| title | string | Title for the HTML report page |
| Argument | Type | Description |
|---|---|---|
| topN | number | Number of articles to include in the mobile HTML report (0 = all articles, default 0) |
| title | string | Title for the mobile HTML report page |
| Argument | Type | Description |
|---|---|---|
| articleId | string | Article ID (hash of URL) |
| action | enum | Whether the user found this article interesting or ignored it |
| source? | string | Feed source name |
| title? | string | Article title |
| keywords? | array | Keywords/tags from the article |
| Argument | Type | Description |
|---|---|---|
| serverUrl | string | URL of the feedback queue HTTP server |
| batchSize | number | Number of feedback entries to process per batch |
| maxBatches | number | Maximum number of batches to process in one run |
| Argument | Type | Description |
|---|---|---|
| serverUrl | string | URL of the pages queue HTTP server |
| batchSize | number | Number of queued pages to process per batch |
| maxBatches | number | Maximum number of batches to process in one run |
| category? | string | Category tag applied to each page when adding to the catalog |
| Argument | Type | Description |
|---|---|---|
| snapshotName | string | |
| maxClusterSize | number |
| Argument | Type | Description |
|---|---|---|
| minClusterSize | number |
| Argument | Type | Description |
|---|---|---|
| port? | number | Port the feedback server listens on (defaults to global feedbackServerPort). |
| serviceName? | string | systemd user service name (defaults to global feedbackServerServiceName). |
| scriptPath? | string | Override the path to the feedback-server.ts script (defaults to the bundled script). |
Resources
Files
Global Arguments
| Argument | Type | Description |
|---|---|---|
| catalogName | string | Catalog name (for multiple catalogs) |
| dedupeStalenessDays | number | Max days before a cached feed identity is re-fetched during dedupe. New feeds are always fetched. |
| Argument | Type | Description |
|---|---|---|
| url | string | RSS/Atom feed URL to add |
| category | string | Category tag (e.g., tech, news, programming, podcasting) |
| name? | string | Human-readable feed name (defaults to hostname) |
| Argument | Type | Description |
|---|---|---|
| url | string | Feed URL to add when the catalog is empty |
| category | string | Category tag for the seeded feed |
| Argument | Type | Description |
|---|---|---|
| title | string | Page title |
| prefs? | object | News-reader preferences used for per-feed seen/read/interested/ignored counts |
| snapshot? | object | News-reader feed snapshot used to map article IDs to feed sources |
| Argument | Type | Description |
|---|---|---|
| serverUrl | string | URL of the feedback queue HTTP server |
| batchSize | number | Number of feed state entries to process per batch |
| maxBatches | number | Maximum number of batches to process in one run |
| Argument | Type | Description |
|---|---|---|
| url | string | RSS/Atom feed URL to remove |
| Argument | Type | Description |
|---|---|---|
| category? | string | Filter by category (optional) |
| limit | number | Maximum feeds to return. Use 0 for unlimited. |
Resources
Files
Global Arguments
| Argument | Type | Description |
|---|---|---|
| newsReaderModelId | string | Model ID of the news-reader instance to read snapshots from (empty = find any) |
| feedCatalogModelId | string | Model ID of the news-feed-catalog instance to upsert into (empty = find any) |
| Argument | Type | Description |
|---|---|---|
| maxSitesToCrawl | number | Maximum new domains to crawl this run (default 10) |
| category | string | Category tag for discovered feeds (default 'discovered') |
| dryRun | boolean | If true, discover feeds but don't add them to the catalog (default false) |
| reCrawlAfterDays | number | Domains crawled within this many days are skipped unless their feed is still unknown (default 7) |
| articleUrls? | array | Article URLs to crawl for new feeds (strings or {url} objects). When |
| nonFeedUrls? | array | URLs known to be HTML pages (not feeds) to crawl (strings or {url} |
Resources
Global Arguments
| Argument | Type | Description |
|---|---|---|
| newsReaderModelId | string | Model ID of the news-reader instance whose pages-current data to read |
| Argument | Type | Description |
|---|---|---|
| maxPagesPerRun | number | Maximum pages to analyze this run (default 50) |
| probeCommonPaths | boolean | Probe common feed paths on pages that advertise no feed link (default true) |
| pages? | array | Page entries gathered by the news-reader's gatherPages method. When |
Resources
Fast-path news workflow — gathers feedback, fetches feeds from the catalog, deduplicates articles, filters by age, and generates the HTML report. Runs every 4 hours. No LLM calls, no catalog maintenance, no feed discovery. Fusion (LLM story clustering) runs separately via the @svendowideit/news-fusion workflow. Curation (feed dedupe, discovery, page analysis) runs separately via the @svendowideit/news-curation workflow. Loop: gather-feedback → fetch → dedupe-articles → filter → generate → gene
LLM-driven story fusion — clusters filtered articles into same-story groups, fuses them into persistent stories via LLM delta passes, seeds new stories for fresh clusters, and renders stories to an inline HTML fragment. Runs every 12 hours. All steps allow failure — fusion is best-effort enrichment. The news workflow reads the rendered stories HTML from the datastore and includes it in the news page. Steps: cluster → fuse → seed → render
Feed catalog maintenance — deduplicates feeds by content identity, gathers feed enable/disable state from the feedback server, discovers new RSS feeds from article URLs, and analyzes queued pages for feed discovery. Runs daily at 3am. All steps allow failure — curation is best-effort maintenance. The news workflow reads the catalog's current state directly from the datastore. Steps: dedupe → gather-feed-state → discover → upsert-feed gather-pages → analyze-pages → upsert-page (independe
Full news feedback loop — gathers feedback from the queue server, fetches feeds from the catalog, generates an HTML summary ranked by your preferences, then discovers new RSS feeds from the article URLs and upserts them into the catalog for the next run, finally rendering feeds.html (a duplicate-grouped catalog listing). Loop: gather-feedback → dedupe (flag duplicate catalog feeds) → fetch → dedupe-articles (merge duplicate articles by URL) → filter by age (default: last 3 days) → cluster relat
Summary of the generated news HTML page with article count
Modified 1 models
Modified 1 models
Modified 1 models
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License declared1/1earned
- Verified public repository2/2earned