$npx -y skills add Varnan-Tech/opendirectory --skill newsletter-digestAggregates RSS feeds from the past week, synthesizes the top stories using Gemini, and publishes a newsletter digest to Ghost CMS. Optionally outputs formatted Markdown for Substack or any other platform. Use when asked to generate a newsletter, create a weekly digest, summarize
| 1 | # Newsletter Digest |
| 2 | |
| 3 | Aggregate content from RSS feeds, synthesize the week's top stories with Gemini, and publish a digest to Ghost CMS. Supports weekly digests, topic-focused roundups, and curated picks formats. |
| 4 | |
| 5 | ## Writing Style |
| 6 | |
| 7 | Apply to all generated digest content: |
| 8 | |
| 9 | - Active voice only |
| 10 | - Short sentences, one idea per sentence |
| 11 | - No em dashes — use a period or comma instead |
| 12 | - No semicolons |
| 13 | - No markdown or asterisks in the final newsletter body |
| 14 | - No hashtags |
| 15 | |
| 16 | Banned words — do not use any of these in the digest: |
| 17 | incredible, amazing, leveraging, synergize, game-changing, game changer, delve, harness, unlock, groundbreaking, cutting-edge, remarkable, paradigm, revolutionize, disruptive, transformative, thrilled, excited to share, powerful, innovative, comprehensive, actionable, crucial, vital, pivotal, elucidate, utilize, dive deep, tapestry, illuminate, revolutionize |
| 18 | |
| 19 | ## CRITICAL RULE |
| 20 | |
| 21 | Every claim, statistic, and summary in the digest must come from the fetched articles. Never fabricate data points, quotes, or facts. If a source article has no meaningful content, skip it. |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## Step 1: Check Setup |
| 26 | |
| 27 | **1a. Verify feeds are configured** |
| 28 | |
| 29 | Check if `feeds.json` exists in the skill directory: |
| 30 | |
| 31 | ```bash |
| 32 | ls /Users/ksd/Desktop/Varnan_skills/newsletter-digest/feeds.json 2>/dev/null |
| 33 | ``` |
| 34 | |
| 35 | If missing, ask the user: "Which RSS feeds should I monitor? Share a list of URLs and I'll create feeds.json." |
| 36 | |
| 37 | The format is: |
| 38 | ```json |
| 39 | [ |
| 40 | { "url": "https://example.com/feed", "name": "Source Name" }, |
| 41 | { "url": "https://another.com/rss", "name": "Another Source" } |
| 42 | ] |
| 43 | ``` |
| 44 | |
| 45 | **1b. Verify required environment variables** |
| 46 | |
| 47 | Check that these are set: |
| 48 | - `GEMINI_API_KEY` (required): for synthesis |
| 49 | - `GHOST_URL` and `GHOST_ADMIN_KEY` (required for Ghost publishing, optional if output-only) |
| 50 | |
| 51 | If GEMINI_API_KEY is missing, stop and ask the user to set it. |
| 52 | |
| 53 | GHOST config is optional. If not set, the skill outputs formatted Markdown instead of publishing. |
| 54 | |
| 55 | **1c. Verify script dependencies** |
| 56 | |
| 57 | ```bash |
| 58 | ls /Users/ksd/Desktop/Varnan_skills/newsletter-digest/node_modules 2>/dev/null | head -1 |
| 59 | ``` |
| 60 | |
| 61 | If missing: |
| 62 | |
| 63 | ```bash |
| 64 | cd /Users/ksd/Desktop/Varnan_skills/newsletter-digest && npm install |
| 65 | ``` |
| 66 | |
| 67 | --- |
| 68 | |
| 69 | ## Step 2: Fetch and Parse Feeds |
| 70 | |
| 71 | Run the fetch script: |
| 72 | |
| 73 | ```bash |
| 74 | node /Users/ksd/Desktop/Varnan_skills/newsletter-digest/scripts/fetch-feeds.js |
| 75 | ``` |
| 76 | |
| 77 | The script: |
| 78 | - Reads `feeds.json` for the list of feeds |
| 79 | - Fetches each feed using `rss-parser` |
| 80 | - Filters items published in the last 7 days |
| 81 | - Deduplicates by URL |
| 82 | - Sorts by publish date, newest first |
| 83 | - Saves results to `/tmp/newsletter-digest-articles.json` |
| 84 | |
| 85 | If the script errors on a specific feed, it logs a warning and continues. One bad feed does not stop the run. |
| 86 | |
| 87 | After the script completes, verify the output: |
| 88 | |
| 89 | ```bash |
| 90 | node -e " |
| 91 | const fs = require('fs'); |
| 92 | const data = JSON.parse(fs.readFileSync('/tmp/newsletter-digest-articles.json', 'utf8')); |
| 93 | console.log('Total articles:', data.articles.length); |
| 94 | console.log('From feeds:', data.feedsSummary.map(f => f.name + ': ' + f.count).join(', ')); |
| 95 | console.log('Date range:', data.dateRange.from, 'to', data.dateRange.to); |
| 96 | " |
| 97 | ``` |
| 98 | |
| 99 | If fewer than 3 articles are found, warn the user and ask if they want to extend the date range to 14 days. Pass `--days=14` to the script to widen the window. |
| 100 | |
| 101 | --- |
| 102 | |
| 103 | ## Step 3: Read Format Rules |
| 104 | |
| 105 | Read `references/digest-format.md` in full before generating any content. Internalize: |
| 106 | - Three digest formats (Weekly Roundup, Topic Deep Dive, Curated Picks) and when to use each |
| 107 | - Section structure and length requirements per format |
| 108 | - Attribution rules (every claim links to a source) |
| 109 | - Tone and voice guidelines |
| 110 | |
| 111 | Read `references/output-template.md` and select the template matching the requested format. |
| 112 | |
| 113 | If the user did not specify a format, default to Weekly Roundup. |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## Step 4: Synthesize with Gemini |
| 118 | |
| 119 | Read `/tmp/newsletter-digest-articles.json` and build a synthesis prompt. |
| 120 | |
| 121 | **Prompt structure:** |
| 122 | |
| 123 | ``` |
| 124 | You are a newsletter editor writing a digest of this week's top stories. |
| 125 | |
| 126 | Sources (use ONLY these — do not invent facts): |
| 127 | [For each article: Title | Source | Date | Summary] |
| 128 | |
| 129 | Task: |
| 130 | Write a [FORMAT] digest following this structure: |
| 131 | [Paste the selected template from references/output-template.md] |
| 132 | |
| 133 | Rules: |
| 134 | - Every claim, statistic, and quote must come from the sources above |
| 135 | - Write in active voice, short sentences, contractions allowed |
| 136 | - Do not use: incre |