OptionalResearchVersion 2.0.0

Blogwatcher: Track Blogs and RSS/Atom Feeds in Hermes Agent

Monitor blogs and RSS/Atom feeds via blogwatcher-cli tool.

Written by Neura Market from the official Hermes Agent documentation for Blogwatcher. Commands, paths, and version numbers are reproduced from the source unchanged.

Read the official documentation

Blogwatcher gives Hermes Agent a persistent feed database it can scan, query, and act on. It wraps blogwatcher-cli, a small Go tool that tracks blogs and RSS/Atom feeds, keeps read/unread state, and can fall back to scraping a page when no feed exists. Reach for it when you want the agent to watch a set of sources over time rather than read one feed once.

What it does

The skill installs and drives blogwatcher-cli, which maintains a local SQLite database of blogs and their articles. You add sources by name and URL, scan them on demand, and list what is unread. Feeds are discovered automatically from a homepage when you do not supply one, and if RSS fails you can point the tool at a CSS selector to scrape article links instead. Categories carried in the feed are stored alongside articles, so you can filter by them later. Bulk setup comes from OPML files exported by other readers.

The important split is that blogwatcher-cli is the database, and Hermes tools do the automation around it. A recurring watch belongs in the cronjob tool's monitor field, not a bare schedule. monitor runs a script each tick and only wakes the agent when the output changes, so you point it at a command that scans and then lists articles. New articles change the output, the agent wakes with the diff, and unchanged ticks cost nothing. deliver routes digests to a chat or channel, and continuity: true lets consecutive digests dedupe.

When a user asks about a specific article, use web_extract([url]) on the URL that blogwatcher-cli articles reported. Do not re-scrape by hand.

Before you start

This is an optional skill, installed on demand rather than bundled. It runs on linux, macos, and windows. The skill path is optional-skills/research/blogwatcher, version 2.0.0, authored by JulienTant as a fork of Hyaxia/blogwatcher, under the MIT license.

You need the blogwatcher-cli binary on the machine. Pick one install method:

  • Go: go install github.com/JulienTant/blogwatcher-cli/cmd/blogwatcher-cli@latest
  • Docker: docker run --rm -v blogwatcher-cli:/data ghcr.io/julientant/blogwatcher-cli
  • Binary (Linux amd64): curl -sL https://github.com/JulienTant/blogwatcher-cli/releases/latest/download/blogwatcher-cli_linux_amd64.tar.gz | tar xz -C /usr/local/bin blogwatcher-cli
  • Binary (Linux arm64): curl -sL https://github.com/JulienTant/blogwatcher-cli/releases/latest/download/blogwatcher-cli_linux_arm64.tar.gz | tar xz -C /usr/local/bin blogwatcher-cli
  • Binary (macOS Apple Silicon): curl -sL https://github.com/JulienTant/blogwatcher-cli/releases/latest/download/blogwatcher-cli_darwin_arm64.tar.gz | tar xz -C /usr/local/bin blogwatcher-cli
  • Binary (macOS Intel): curl -sL https://github.com/JulienTant/blogwatcher-cli/releases/latest/download/blogwatcher-cli_darwin_amd64.tar.gz | tar xz -C /usr/local/bin blogwatcher-cli

All releases: https://github.com/JulienTant/blogwatcher-cli/releases

Docker with persistent storage

By default the database lives at ~/.blogwatcher-cli/blogwatcher-cli.db. In Docker this is lost on container restart. Use BLOGWATCHER_DB or a volume mount to persist it:

# Named volume (simplest)
docker run --rm -v blogwatcher-cli:/data -e BLOGWATCHER_DB=/data/blogwatcher-cli.db ghcr.io/julientant/blogwatcher-cli scan

# Host bind mount
docker run --rm -v /path/on/host:/data -e BLOGWATCHER_DB=/data/blogwatcher-cli.db ghcr.io/julientant/blogwatcher-cli scan

Migrating from the original blogwatcher

If upgrading from Hyaxia/blogwatcher, move your database:

mv ~/.blogwatcher/blogwatcher.db ~/.blogwatcher-cli/blogwatcher-cli.db

The binary name changed from blogwatcher to blogwatcher-cli.

Common Commands

Managing blogs

  • Add a blog: blogwatcher-cli add "My Blog" https://example.com
  • Add with explicit feed: blogwatcher-cli add "My Blog" https://example.com --feed-url https://example.com/feed.xml
  • Add with HTML scraping: blogwatcher-cli add "My Blog" https://example.com --scrape-selector "article h2 a"
  • List tracked blogs: blogwatcher-cli blogs
  • Remove a blog: blogwatcher-cli remove "My Blog" --yes
  • Import from OPML: blogwatcher-cli import subscriptions.opml

Adding a blog is the setup step you repeat per source. Give it a name you will recognise in later output and the homepage URL. If the feed is not discoverable, pass --feed-url explicitly. If there is no feed at all, pass --scrape-selector with a selector that matches the article links, and the tool will scrape when RSS fails. blogs lists what is tracked. remove takes the name and, with --yes, skips the confirmation prompt. import reads an OPML file so you can bring a whole subscription list across in one go.

Scanning and reading

  • Scan all blogs: blogwatcher-cli scan
  • Scan one blog: blogwatcher-cli scan "My Blog"
  • List unread articles: blogwatcher-cli articles
  • List all articles: blogwatcher-cli articles --all
  • Filter by blog: blogwatcher-cli articles --blog "My Blog"
  • Filter by category: blogwatcher-cli articles --category "Engineering"
  • Mark article read: blogwatcher-cli read 1
  • Mark article unread: blogwatcher-cli unread 1
  • Mark all read: blogwatcher-cli read-all
  • Mark all read for a blog: blogwatcher-cli read-all --blog "My Blog" --yes

Scanning is what pulls new items into the database. Run it across everything, or name a single blog to limit the work. articles then shows what is unread, and the filters narrow that by blog or by category. Articles carry an index number, which is what read and unread take. read-all clears the unread state in bulk, and with --blog and --yes it does so for one source without prompting.

Environment Variables

All flags can be set via environment variables with the BLOGWATCHER_ prefix:

VariableDescription
BLOGWATCHER_DBPath to SQLite database file
BLOGWATCHER_WORKERSNumber of concurrent scan workers (default: 8)
BLOGWATCHER_SILENTOnly output "scan done" when scanning
BLOGWATCHER_YESSkip confirmation prompts
BLOGWATCHER_CATEGORYDefault filter for articles by category

Environment variables matter most in automation. A cron script that runs unattended wants BLOGWATCHER_YES so nothing blocks on a prompt, and BLOGWATCHER_SILENT if you only care about the scan completing. BLOGWATCHER_DB is the one to set in Docker, where the default path does not survive a restart.

Example Output

$ blogwatcher-cli blogs
Tracked blogs (1):

  xkcd
    URL: https://xkcd.com
    Feed: https://xkcd.com/atom.xml
    Last scanned: 2026-04-03 10:30
$ blogwatcher-cli scan
Scanning 1 blog(s)...

  xkcd
    Source: RSS | Found: 4 | New: 4

Found 4 new article(s) total!
$ blogwatcher-cli articles
Unread articles (2):

  [1] [new] Barrel - Part 13
       Blog: xkcd
       URL: https://xkcd.com/3095/
       Published: 2026-04-02
       Categories: Comics, Science

  [2] [new] Volcano Fact
       Blog: xkcd
       URL: https://xkcd.com/3094/
       Published: 2026-04-01
       Categories: Comics

When not to use it

For a one-off "watch this page for changes" with no feed semantics, skip this skill. The cronjob tool's monitor field accepts an http(s) URL directly.

For a one-off read of a feed or a site's latest posts, with nothing to install, use the bundled rss-feeds skill (scripts/feed.py read URL). Blogwatcher earns its install when you track many feeds with read/unread state.

For company or competitor tracking that needs analysis and citations, prefer the competitor-news-monitor skill. Blogwatcher is the lighter raw-feed layer it can sit on.

Limits and gotchas

Feed discovery is automatic only when you omit --feed-url. HTML scraping is a fallback, and it only runs if RSS fails and you configured --scrape-selector. Categories are whatever the feed supplies; if a feed carries none, there is nothing to filter on. The database sits at ~/.blogwatcher-cli/blogwatcher-cli.db by default, overridable with --db or BLOGWATCHER_DB, and in Docker that default path is lost on restart unless you mount a volume or set the variable. If you are coming from the original Hyaxia/blogwatcher, the binary was renamed from blogwatcher to blogwatcher-cli, and the database has to be moved. Run blogwatcher-cli --help to discover all flags and options.

What pairs with it

The cronjob tool is the natural companion: its monitor field turns a scan-and-list script into a recurring watch that only wakes the agent on change, with deliver for routing digests and continuity: true for dedupe. web_extract([url]) handles reading an article once you have its URL. The bundled rss-feeds skill covers the one-off read case, and competitor-news-monitor builds analysis and citations on top of the same raw feed layer.

More Research skills