Skip to content
Back to skills

Rss Feed

ASecurity

Generate an Atom XML feed from articles, validate it, and notify only when it actually changes

  • 6 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added September 5, 2026
toolsshellbashgit

Security analysis

A100/100

Scanned September 5, 2026

npx -y skills add anajuliabit/aeon --skill rss-feed --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Rss Feed?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Rss Feed
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anajuliabit-rss-feed/badge)](https://www.skillsdirectory.com/skills/anajuliabit-rss-feed)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: RSS Feed Generator
description: Generate an Atom XML feed from articles, validate it, and notify only when it actually changes
var: ""
tags: [content]
---
<!-- autoresearch: variation B — sharper output via change detection, XML validation, and what-changed notification -->

> **${var}** — Repo slug override (`owner/repo`) for feed URLs. If empty, the script auto-detects from the git remote. Pass through unchanged; do not invent a value.

Generate a valid Atom XML feed from all markdown articles in `articles/`, validate it, and notify only when the feed content actually changed. Unchanged runs are a silent no-op.

## Steps

### 1. Read context

Read `memory/MEMORY.md`.

### 2. Capture the baseline

Before regenerating, snapshot the current feed so we can tell whether anything changed:

```bash
if [[ -f articles/feed.xml ]]; then
  PREV_HASH="$(sha256sum articles/feed.xml | awk '{print $1}')"
  grep -oP '(?<=<title>)[^<]+' articles/feed.xml | tail -n +2 | sort -u > /tmp/rss-feed-prev-titles.txt
else
  PREV_HASH=""
  : > /tmp/rss-feed-prev-titles.txt
fi
```

The `tail -n +2` skips the feed-level `<title>` so only entry titles remain.

### 3. Regenerate the feed

Run the script. Pass `${var}` as the repo slug override only if it is non-empty:

```bash
if [[ -n "${var}" ]]; then
  bash scripts/generate-feed.sh "${var}"
else
  bash scripts/generate-feed.sh
fi
```

### 4. Validate the XML

Invalid XML breaks every subscriber. Fail loud if the feed is malformed:

```bash
if command -v xmllint >/dev/null 2>&1; then
  xmllint --noout articles/feed.xml || { STATUS="RSS_FEED_ERROR"; VALIDATION_ERR="xmllint failed"; }
else
  # Fallback: verify the root element and a closing tag
  head -2 articles/feed.xml | grep -q '<feed' || { STATUS="RSS_FEED_ERROR"; VALIDATION_ERR="missing <feed> root"; }
  tail -1 articles/feed.xml | grep -q '</feed>' || { STATUS="RSS_FEED_ERROR"; VALIDATION_ERR="missing </feed> close"; }
fi
```

If `STATUS=RSS_FEED_ERROR`, stop, notify with the error, log it, and exit without committing. Do **not** commit a broken feed.

### 5. Detect what changed

Compare new feed against the baseline:

```bash
NEW_HASH="$(sha256sum articles/feed.xml | awk '{print $1}')"
grep -oP '(?<=<title>)[^<]+' articles/feed.xml | tail -n +2 | sort -u > /tmp/rss-feed-new-titles.txt

ADDED="$(comm -13 /tmp/rss-feed-prev-titles.txt /tmp/rss-feed-new-titles.txt)"
REMOVED="$(comm -23 /tmp/rss-feed-prev-titles.txt /tmp/rss-feed-new-titles.txt)"
ENTRY_COUNT="$(wc -l < /tmp/rss-feed-new-titles.txt | tr -d ' ')"
```

Classify the run:
- **RSS_FEED_NO_CHANGE** — `PREV_HASH == NEW_HASH` (byte-identical). Exit silently after logging. No commit, no notify.
- **RSS_FEED_METADATA_ONLY** — hashes differ but `ADDED` and `REMOVED` are both empty (e.g. `<updated>` timestamp drifted). Commit so the feed stays fresh, but **do not notify** — it is not a subscriber-visible change.
- **RSS_FEED_OK** — `ADDED` or `REMOVED` is non-empty. Commit and notify.

### 6. Commit (only if changed)

Skip entirely for `RSS_FEED_NO_CHANGE`. Otherwise build a descriptive commit message:

```bash
if [[ "$STATUS" == "RSS_FEED_OK" ]]; then
  MSG="chore(feed): $(echo "$ADDED" | grep -c .) added, $(echo "$REMOVED" | grep -c .) removed ($ENTRY_COUNT total)"
else
  MSG="chore(feed): metadata refresh ($ENTRY_COUNT entries)"
fi

git add articles/feed.xml
git diff --cached --quiet || git commit -m "$MSG"
git push || true
```

If the push fails because the runner can't push directly, that's fine — the generated file remains in the workspace and a later skill/PR can carry it.

### 7. Notify (only on RSS_FEED_OK)

Silence is the feature. Do not notify on `RSS_FEED_NO_CHANGE` or `RSS_FEED_METADATA_ONLY`. On `RSS_FEED_OK`, build a concise message:

```
*RSS feed updated* — $ENTRY_COUNT entries

New:
- <first added title>
- <second added title>
[Removed: <removed titles> — only include this line if REMOVED is non-empty]

Subscribe: https://raw.githubusercontent.com/${repo}/main/articles/feed.xml
```

Keep it to one paragraph plus the bullet list. Cap at 5 added titles; if there are more, show the first 5 and append `(+N more)`. Send via `./notify "<message>"`.

On `RSS_FEED_ERROR`, notify with:

```
*RSS feed ERROR* — $VALIDATION_ERR
Feed not committed. Investigate scripts/generate-feed.sh or articles/ inputs.
```

### 8. Log

Append to `memory/logs/${today}.md`:

```
### rss-feed
- Status: RSS_FEED_OK | RSS_FEED_METADATA_ONLY | RSS_FEED_NO_CHANGE | RSS_FEED_ERROR
- Entries: $ENTRY_COUNT
- Added: <titles or "none">
- Removed: <titles or "none">
- Prev hash: <first 8 chars>, new hash: <first 8 chars>
```

Always log, even on `RSS_FEED_NO_CHANGE` — the log line is how the operator distinguishes "ran and was idle" from "never ran."

## Sandbox note

This skill is entirely local: it reads/writes files and shells out to `scripts/generate-feed.sh`. No network calls required. If `git push` is blocked by the sandbox, the commit still lands locally and the workflow's post-step commit/push path will handle it.

## Constraints

- Never commit a feed that fails validation.
- Never notify on an unchanged feed — noise destroys the signal.
- Preserve the script interface: `scripts/generate-feed.sh [repo_slug]`. Do not rewrite the generator inline.
- Keep `${var}` semantics aligned with what the script actually accepts (repo slug, not base URL).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…