Skip to content

About

Free indie developer news aggregator — curated RSS feeds, no ads, no paywalls.

Topics

Resources

Contributing

Stars

10 stars

Watchers

0 watching

Forks

Latest commit

 

History

4,186 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

  ██████╗ ███████╗███████╗██╗  ██╗███████╗██████╗ ██╗   ██╗██╗     ███████╗███████╗
 ██╔════╝ ██╔════╝██╔════╝██║ ██╔╝██╔════╝██╔══██╗██║   ██║██║     ██╔════╝██╔════╝
 ██║  ███╗█████╗  █████╗  █████╔╝ ███████╗██████╔╝██║   ██║██║     ███████╗█████╗  
 ██║   ██║██╔══╝  ██╔══╝  ██╔═██╗ ╚════██║██╔═══╝ ██║   ██║██║     ╚════██║██╔══╝  
 ╚██████╔╝███████╗███████╗██║  ██╗███████║██║      ╚██████╔╝███████╗███████║███████╗
  ╚═════╝ ╚══════╝╚══════╝╚═╝  ╚═╝╚══════╝╚═╝       ╚═════╝ ╚══════╝╚══════╝╚══════╝

{ GeeksPulse } — Feel the pulse of dev.

Live Feeds Paywalls No Ad Trackers No Ads Indie Tests

Your daily dev briefing, minus the noise.


> geekspulse fetch --all --fresh

✓ Hacker News ............. 30 stories
✓ Krebs on Security ....... 12 stories
✓ IEEE Spectrum ........... 18 stories
✓ GitHub Blog ............. 8 stories
✓ Google AI Blog .......... 10 stories
✓ Rust Blog ............... 6 stories
✓ Go Blog ................. 5 stories
# 51 feeds · 0 paywalls · 100% signal
✓ Ready. No paywalls. You're welcome.
▮

📡 What Is GeeksPulse?

GeeksPulse is a static developer-news site powered by a scheduled feed-generation pipeline. A Node.js script fetches and normalises RSS feeds into static JSON files, and the frontend renders from that cache for speed and reliability.

It pulls from 50 hand-picked RSS feeds across 11 categories, sorts them newest-first, and presents them in a fast, editorial reading interface with light and dark themes — no doomscrolling Twitter required.

  • 🚫 No ads. No VC money. No ad trackers.
  • ⚡ Static hosting. The site is served as plain HTML/CSS/JS — no application server required.
  • 🔓 No paywalls. Every article is directly accessible.
  • 🧠 No framework bloat. Just clean, fast, modern vanilla web.

✨ Features

Feature Details
📡 50 RSS Feeds Hand-curated from the best dev sources on the web
🗂️ 11 Categories General · Security · AI · Python · JavaScript · Java · DevOps · Open Source · Rust · Go · Architecture
🤖 AI Summaries On-demand article summaries via pre-cached snippets or local Ollama fallback
⚡ Static Cache Articles pre-built by a Node.js pipeline; browser loads JSON instantly
🔄 Auto-Refresh Configurable: 1m · 5m · 10m · 15m · 30m · 1h
🃏 Grid & List View Lead story + card grid, or a dense numbered list — preference saved locally
💾 localStorage Prefs Your filter, view mode & refresh interval persist across sessions
💀 Skeleton Loaders Shimmer placeholders while feeds are loading
🌗 Light & Dark Themes Follows the OS by default; override in Settings (no flash on load)
📰 Feed-first Layout Compact briefing header, sticky topic sidebar, "Show more" paging
🆕 New Since Last Visit Stories published since your previous visit are marked New
🔗 Deep Links ?q= search, ?topic= filter and ?source= views are shareable URLs
♿ Accessible WCAG AA contrast in both themes, focus-trapped dialogs, aria-pressed toggles, prefers-reduced-motion
📱 Responsive Compact media rows and sticky topic chips on phones, bottom-sheet dialogs
🔖 Bookmarks Save articles to localStorage for later reading
⌨️ Keyboard Shortcuts / search · j/k navigate · o open · b save · v view · r refresh · ? help
🏥 Feed Health Panel Live status: last updated time, online/failed feed counts
🔗 Share Articles Web Share API with automatic clipboard fallback

🗞️ Feed Sources

📡 General
🔐 Security
🤖 AI / ML
🐍 Python
🟡 JavaScript
🐳 DevOps
🌍 Open Source
☕ Java
🦀 Rust
🐹 Go
🏛️ Architecture

🧪 Testing

GeeksPulse has a full layered test suite — 181 tests that run in CI on every push before any deploy can happen.

Stack

Tool Role
Vitest Unit, integration & DOM component tests
happy-dom Lightweight DOM environment for browser-side tests
Playwright End-to-end smoke tests (Chromium)
@vitest/coverage-v8 V8-based coverage with per-file thresholds

Commands

# Run all unit, integration & DOM tests (171 tests, ~800ms)
npm test

# Run in watch mode during development
npm run test:watch

# Run with coverage report (outputs to coverage/)
npm run test:coverage

# Run end-to-end smoke tests (10 tests, ~25s — starts Vite dev server automatically)
npm run test:e2e

# Open Playwright UI runner
npm run test:e2e:ui

Test layout

tests/
  unit/
    utils.test.mjs           ← scripts/lib/utils.mjs       (46 tests)
    browser-utils.test.js    ← js/utils.js                 (32 tests)
    storage.test.js          ← js/storage.js               (22 tests)
    classifier.test.mjs      ← scripts/lib/classifier.mjs  (12 tests)
    sponsored.test.mjs       ← scripts/lib/sponsored.mjs   (13 tests)
  integration/
    parser.test.mjs          ← scripts/lib/parser.mjs      (22 tests)
    build-feed.test.mjs      ← pipeline dedup, sort, cap    (5 tests)
  dom/
    cards.test.js            ← js/cards.js  (happy-dom)    (19 tests)
  e2e/
    smoke.spec.js            ← Playwright full-browser     (10 tests)
  fixtures/
    rss-valid.xml / rss-encoded-content.xml / rss-single-item.xml / rss-empty.xml
    atom-valid.xml / atom-alternate-link.xml

CI pipeline

push / schedule
    │
    ▼
 test job  — npm test (171 Vitest tests)
    │  needs: test
    ▼
 build job — Ollama + feed data + GitHub Pages deploy
    │  needs: build  (main branch only)
    ▼
 e2e job   — npm run test:e2e (10 Playwright tests)
             └─ report uploaded as CI artifact (7-day retention)

A failing unit or integration test blocks the entire pipeline — no bad code can reach production.


🏗️ Architecture

const architecture = {
  hosting:    "Static files — no application server required",
  markup:     "HTML5",           // semantic, accessible
  styles:     "Vanilla CSS",     // custom properties, animations, grid
  logic:      "Vanilla JS",      // ES2022+ native ES modules, no bundler
  modules:    "js/ — 15 focused ES modules loaded via <script type=\"module\">",
  fonts:      ["JetBrains Mono", "Space Grotesk", "Bangers"],
  feedPipeline: "Node.js (scripts/build-feed.mjs + scripts/lib/*.mjs)",
  bundler:    "Vite 6",          // dev server + production build
  storage:    "localStorage",    // preferences & bookmarks
  deps:       ["fast-xml-parser", "ollama"], // build-time; ollama for local AI summaries
  devDeps:    ["vite", "vitest", "happy-dom", "@playwright/test", "@vitest/coverage-v8", "msw"],
  analytics:  "Google Analytics (basic traffic insights)",
};

The frontend's primary data source is the pre-built public/feed.json file. If that file is missing or empty, the app silently falls back to fetching RSS feeds directly via browser-side CORS proxies — this is an emergency path only and is not used during normal page loads.


⚙️ Feed Pipeline

The scripts/build-feed.mjs script is a Node 18+ server-side utility that pre-fetches all feeds and writes a static JSON cache to public/. GitHub Actions runs this every 30 minutes on a schedule to keep the cache fresh.

The build script is split into focused modules under scripts/lib/ — see 📂 Project Structure for the full layout.

# Install dependencies (build-time + dev)
npm install

# Fetch all feeds and write public/feed.json + public/feed-health.json
npm run build:feed

# Regenerate sitemap.xml (homepage-only canonical URLs)
npm run build:sitemap

# Inject latest articles into index.html for SEO crawlers
npm run build:seo

# Write public/version.json
npm run build:version

# Run the full pipeline (data + Vite production build)
npm run build
Output file Description
public/feed.json Up to 300 deduplicated articles, sorted newest-first
public/feed-health.json Per-feed health: ok/error/article count + last updated time
public/version.json Build timestamp and version metadata
sitemap.xml Minimal canonical sitemap (homepage only)
index.html SEO fallback articles injected between GENERATED_LATEST_ARTICLES_START/END markers

How to add a new feed

  1. Open data/feeds.json.
  2. Add a new entry:
    { "id": "my-blog", "name": "My Blog", "url": "https://myblog.com/feed.xml", "category": "General", "enabled": true }
  3. Run npm run build to regenerate the cache.
  4. Commit both data/feeds.json and the updated public/feed.json.

🚀 Running Locally

# Clone the repo
git clone https://github.com/dante0747/geekspulse.dev.git
cd geekspulse.dev

# Install dependencies
npm install

# Start the Vite dev server (hot-reload, proper module resolution)
npm run dev
# or serve the static files with any other server
npx serve .
# or
python -m http.server 8080

Then open http://localhost:5173 (Vite default) or http://localhost:8080 if using a plain static server.

To regenerate the feed cache with live data:

npm install
npm run build

📂 Project Structure

geekspulse.dev/
├── index.html           # App shell — nav, briefing header, sidebar, feed, FAQ, source directory
├── styles.css           # Design tokens (light + dark) and all component styles
├── playwright.config.js # Playwright E2E configuration
├── vite.config.js       # Vite + Vitest config; copies root static files into dist/
├── js/                  # ES module source (loaded via <script type="module">)
│   ├── main.js          # Entry point — app state, render loop, event wiring
│   ├── config.js        # Static data: feeds list, categories, SVG icons, constants
│   ├── analytics.js     # GA4 event helper
│   ├── storage.js       # localStorage — preferences & bookmarks
│   ├── utils.js         # Pure utilities: esc, relTime, truncate, toast, etc.
│   ├── http.js          # CORS proxy chain (fetchViaCorsProxy)
│   ├── images.js        # Image pipeline: extraction, scoring, caching, resolution
│   ├── consent.js       # Cookie consent banner logic
│   ├── feed.js          # RSS/Atom parsing & feed fetching
│   ├── cards.js         # Card HTML generators (grid, list, skeleton, placeholder)
│   ├── feeds-registry.js # Feed registry loader — fetches & caches data/feeds.json at startup
│   ├── settings-panel.js # Settings popover (theme, layout, auto-refresh, clear data)
│   ├── theme.js         # Light / dark / system theme preference
│   ├── pulse-panel.js   # My Pulse drawer (topic/source filters, presets)
│   ├── summary.js       # AI Summary modal — pre-cached snippets or Ollama fallback
│   └── signal.js        # Headline ticker + 24h activity graph in the header
├── favicon.ico          # Browser favicon (16/32/48 px)
├── manifest.json        # PWA manifest (served from the site root)
├── sw.js                # Service worker (must live at the root for full scope)
├── icons/               # Logo, favicon and PWA icons rendered from assets/brand/logo.png
├── og-image.jpg         # Link preview image (Open Graph, X, WhatsApp, Telegram)
├── assets/brand/        # Master logo + link-preview artwork (generated with GPT Image)
├── sitemap.xml          # SEO sitemap (auto-generated by scripts/generate-sitemap.mjs)
├── robots.txt           # Crawler rules
├── assets/
│   └── fallbacks/       # Category SVG fallback images (ai, security, devops, …)
├── data/
│   └── feeds.json       # Feed registry — 50 hand-curated RSS/Atom sources
├── public/
│   ├── feed.json        # Pre-built article cache (generated by build script)
│   ├── feed-health.json # Per-feed health report (generated by build script)
│   └── version.json     # Build version info (generated by build script)
├── scripts/
│   ├── build-feed.mjs          # Entry point — orchestrates the feed build pipeline
│   ├── generate-sitemap.mjs    # Generates sitemap.xml from data/feeds.json
│   ├── generate-seo-content.mjs # Injects latest stories, source directory + ItemList JSON-LD into index.html
│   ├── generate-version.mjs    # Writes public/version.json
│   └── lib/                    # Build pipeline modules (imported by build-feed.mjs)
│       ├── config.mjs          # All constants, regex patterns, XML parser instance
│       ├── utils.mjs           # Pure helpers (normalizeUrl, stripHtml, …) + streamHtml
│       ├── ai.mjs              # Ollama client + shared AI cache (live ESM bindings)
│       ├── classifier.mjs      # Keyword + LLM article category classification
│       ├── sponsored.mjs       # Regex + LLM sponsored/promotional content detection
│       ├── summarizer.mjs      # LLM article summarization (fills missing snippets)
│       ├── images.mjs          # Image scoring/extraction + og:image resolver
│       ├── parser.mjs          # RSS/Atom XML parsing + per-feed HTTP fetcher
│       └── pipeline.mjs        # Article set helpers + named pipeline pass functions
└── tests/
    ├── unit/                   # Pure-logic tests (Vitest, Node + happy-dom)
    ├── integration/            # Build-pipeline integration tests (Vitest, Node)
    ├── dom/                    # Browser component tests (Vitest, happy-dom)
    ├── e2e/                    # Full-browser smoke tests (Playwright, Chromium)
    └── fixtures/               # RSS/Atom XML fixtures for parser tests

🎨 Design System — "Signal Terminal"

GeeksPulse is dressed as a live instrument for developers: a tmux-style status line, an LED headline ticker, btop-style panels with their titles cut into the border, ncdu-style usage bars on every topic, a nano key bar of shortcuts, a man-page FAQ, a tree source directory and an amber-phosphor accent. Two themes share one token set in styles.css: paper (light, the base) and phosphor (dark, when the OS prefers it or <html data-theme="dark"> is set from Settings). Text tokens meet WCAG AA (4.5:1) on their surfaces in both themes.

Token Paper (light) Phosphor (dark) Usage
--bg / --surface #F3F0E7 / #FBF9F3 #0B0C0A / #121410 Page / panels and cards
--ink / --ink2 / --ink3 #17160F / #47443A / #6B675A #EDEADC / #B8B5A4 / #8D8B7B Headlines / body / metadata
--accent / --accent-fill #9E5600 / #F2A516 #FFB224 / #FFB224 Amber text / amber blocks, bars, cursor
--signal #187A3A #6EF08F Live status, "new" badges
--c-<topic> per topic per topic Topic LEDs, pills, usage bars, image tints
--font / --mono / --dot Mona Sans / Martian Mono / Doto Reading / interface / dot-matrix numerals

Story images are shown as a topic-tinted monochrome (a risograph-style duotone) and switch to full colour on hover or focus; stories without an image get an LED-board placeholder with a shell prompt. The header's pulse graph plots stories per hour for the last 24 hours from real article timestamps (js/signal.js). Motion is limited to short entrance and hover transitions plus the ticker; everything respects prefers-reduced-motion. Card layouts adapt to the feed column with container queries (compact media rows on narrow columns, a horizontal lead story on wide ones).

The logo and the link-preview artwork were generated with GPT Image and live as masters in assets/brand/. node scripts/render-brand-assets.mjs builds favicon.ico, every icon in icons/ and the 1200×630 og-image.jpg (kept under 300 KB so WhatsApp shows it) from them.

---|---|---|---| | --bg / --surface | #F6F6F4 / #FFFFFF | #0B0C10 / #14161C | Page / cards | | --ink / --ink2 / --ink3 | #15171C / #454A55 / #626773 | #EDEEF1 / #AEB4C0 / #878E9C | Headlines / body / metadata | | --accent | #4F46E5 | #9496FF | Links, active states, focus | | --c-<topic> | per topic | per topic | Topic dots, pills, icons, placeholders | | --font / --mono | Inter / JetBrains Mono | | UI text / metadata & code |

Motion is limited to short entrance and hover transitions; everything respects prefers-reduced-motion. Card layouts adapt to the feed column with container queries (media rows on narrow columns, a horizontal lead story on wide ones).


🔒 Privacy

GeeksPulse has no ads and no paywalls. It uses Google Analytics for basic traffic insights so the project owner can understand usage and improve the site. It does not use advertising trackers, sell user data, or personalise ads.


🤝 Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

Quick ways to help:

  • 📡 Suggest a new RSS feed via Issues
  • 🐛 Report bugs or broken feeds
  • ⭐ Star the repo to spread the word
  • 💬 Open a PR — all skill levels welcome

💖 Sponsor

GeeksPulse is free and indie. No ads, no investors, no data selling. If it saves you from opening 12 tabs every morning, you can sponsor it on GitHub — monthly or one-time:

Sponsor on GitHub

$ npm fund
geekspulse.dev@1.0.0
└── https://github.com/sponsors/dante0747

Repository Metadata

Recommended settings for the GitHub repository:

Description: Developer news without the noise — a fast, open-source RSS-powered news hub for software engineers.

Website: https://geekspulse.dev/

Suggested topics: developer-news rss news-aggregator javascript static-site open-source ai-news security-news programming software-engineering


// thank you, you absolute legend ❤

© 2026 GeeksPulse — No ads. No paywalls. No ad trackers.

Built for developers who like clean feeds, good tools, and fewer tabs.

About

Free indie developer news aggregator — curated RSS feeds, no ads, no paywalls.

Topics

Resources

Contributing

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages