From ee5b5ec21e576ccf9b941f9ff71330418415a5cb Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sat, 5 Sep 2026 12:49:04 -0700 Subject: [PATCH] docs(skills): reddit-reading spells out that no login is needed and OAuth is app-only The default backend needs no Reddit account, login, cookie or API key; the optional upgrade is a free 'script' app registration using the app-only client_credentials grant, never a user login. Said in the skill's Prerequisites (with a comparison table), Procedure, Pitfalls, the runtime doctor/thread notes, and a delimited .env.example block. --- .env.example | 9 +++++ skills/social-media/reddit-reading/SKILL.md | 35 +++++++++++++++---- .../reddit-reading/scripts/reddit.py | 14 +++++--- .../social-media-reddit-reading.md | 35 +++++++++++++++---- 4 files changed, 74 insertions(+), 19 deletions(-) diff --git a/.env.example b/.env.example index 02985b54a4..78c0108e1c 100644 --- a/.env.example +++ b/.env.example @@ -533,3 +533,12 @@ IMAGE_TOOLS_DEBUG=false # GOOGLE_CHAT_ALLOW_ALL_USERS=false # Set true to skip the allowlist # GOOGLE_CHAT_HOME_CHANNEL= # Default space (spaces/XXXX) for cron delivery # GOOGLE_CHAT_HOME_CHANNEL_NAME= # Display name for the home channel + +# ============================================================================= +# reddit-reading skill (optional) — app-only credentials, NOT a user login +# ============================================================================= +# The skill works with no credentials via Reddit's public feeds (~1 request/minute). +# For faster access with scores and nested comments, register a free "script" app +# at https://www.reddit.com/prefs/apps and paste its id and secret here. +# REDDIT_CLIENT_ID= +# REDDIT_CLIENT_SECRET= diff --git a/skills/social-media/reddit-reading/SKILL.md b/skills/social-media/reddit-reading/SKILL.md index 8d97c6ece2..7cc4e1f163 100644 --- a/skills/social-media/reddit-reading/SKILL.md +++ b/skills/social-media/reddit-reading/SKILL.md @@ -29,18 +29,32 @@ backend routing in [Agent Reach](https://github.com/Panniantong/Agent-Reach). ## Prerequisites -None for the anonymous path. For anything beyond a handful of calls per task, create -a free Reddit "script" app at https://www.reddit.com/prefs/apps and put the two values -in `~/.hermes/.env`: +**None.** No Reddit account, login, cookie, or API key is needed. The default backend is +Reddit's public Atom feeds (`.rss` endpoints), the only unauthenticated route Reddit still +serves to non-residential IPs. It is throttled to about one request per minute per IP and +returns thinner data (no scores, top-level comments only), which is fine for a few calls. + +**Optional upgrade (app credentials, still no user login):** for sustained use or full +data, register a free "script" type app at https://www.reddit.com/prefs/apps and put its +two values in `~/.hermes/.env`: ``` REDDIT_CLIENT_ID=... REDDIT_CLIENT_SECRET=... ``` -The script picks the OAuth backend automatically when both are set (~100 requests per -minute, scores, comment nesting, `num_comments`). Without them it uses Reddit's Atom -feeds, which are the only unauthenticated endpoints still served to non-residential IPs. +This is an application registration, not a login: the script uses the app-only +`client_credentials` grant, never a username, password, or browser cookie, and never +acts as the user. With both values set it switches to the OAuth API automatically +(~100 requests per minute, scores, nested comments, `num_comments`); if they are +missing or rejected it falls back to the anonymous feeds and says so on stderr. + +| | Anonymous feeds (default) | OAuth app credentials | +|---|---|---| +| Setup | nothing | 1-minute app registration, two `.env` values | +| Rate limit | ~1 request / minute / IP | ~100 requests / minute | +| Thread data | post + top-level comments, no scores | nested comments, scores, comment counts | +| Acts as a user | no | no | ## How to Run @@ -57,6 +71,8 @@ python3 scripts/reddit.py --json search "topic" # machine-reada ## Quick Reference +Every command works on both backends; the script chooses the backend, you never pass a flag. + | Need | Command | Anonymous | OAuth | |---|---|---|---| | Subreddit front page | `sub NAME --sort hot\|new\|top\|rising [--time week]` | ✔ | ✔ | @@ -83,7 +99,9 @@ than stopping at titles; the listing only carries the first ~300 characters of e `grounded-citations` registers these URLs like any other source. ⑤ If the user needs sustained Reddit access (monitoring, more than ~10 calls), stop and -ask them to add the OAuth credentials rather than grinding through the throttle. +ask them to register the app credentials (Prerequisites) rather than grinding through the +throttle. Tell them plainly: it is a free app registration, not logging Hermes into their +account. Never ask for a Reddit password or browser cookies. ## Pitfalls @@ -98,6 +116,9 @@ ask them to add the OAuth credentials rather than grinding through the throttle. - Reddit's `limit` on feeds is advisory — expect 5–25 entries regardless of what you ask. - Never paste `REDDIT_CLIENT_SECRET` into a chat or log; the script reads it from the environment only. +- Do not "fix" a 429 by retrying in a loop or adding a proxy; the throttle is per IP and + the script already waits out the window once. More than one 429 in a row means the + task needs the app credentials. ## Verification diff --git a/skills/social-media/reddit-reading/scripts/reddit.py b/skills/social-media/reddit-reading/scripts/reddit.py index 3f00646437..85769c9f85 100644 --- a/skills/social-media/reddit-reading/scripts/reddit.py +++ b/skills/social-media/reddit-reading/scripts/reddit.py @@ -4,8 +4,10 @@ Two backends, chosen automatically: * **OAuth API** (preferred when ``REDDIT_CLIENT_ID`` + ``REDDIT_CLIENT_SECRET`` are set): - a free "script" app from https://www.reddit.com/prefs/apps; ~100 requests/minute, - full JSON including scores and nested comments. + app-only ``client_credentials`` grant for a free "script" app registered at + https://www.reddit.com/prefs/apps. No username, password or cookie is ever used and + the script never acts as a user. ~100 requests/minute, full JSON including scores + and nested comments. * **Anonymous Atom feeds** (``.rss`` endpoints): the only unauthenticated path Reddit still serves to server IPs (``.json`` and old.reddit return 403 / an empty shell). Roughly ONE request per minute per IP; the script sleeps until the window resets @@ -181,7 +183,8 @@ def atom_thread(sub: str, post_id: str, limit: int) -> dict: raise SystemExit("thread feed returned no entries") post, comments = entries[0], entries[1:] post["comments"] = [{"author": c["author"], "created": c["created"], "body": c["body"], "url": c["url"]} for c in comments] - post["note"] = "anonymous feed: scores and nesting unavailable; set REDDIT_CLIENT_ID/SECRET for full data" + post["note"] = ("anonymous feed: scores and nesting unavailable; register a free Reddit script app and set " + "REDDIT_CLIENT_ID/REDDIT_CLIENT_SECRET (no user login) for full data") return post @@ -241,9 +244,10 @@ def cmd_doctor(a, token): except urllib.error.HTTPError as exc: report["anonymous_feed"] = f"HTTP {exc.code}" report["notes"] = [ - "anonymous .rss: ~1 request/minute per IP (x-ratelimit-remaining drops to 0 after each call)", + "anonymous .rss needs no account, login, cookie or key; ~1 request/minute per IP", "www.reddit.com .json, api.reddit.com and old.reddit are 403 / an empty shell for server IPs", - "for more than a few calls per task create a free script app and export REDDIT_CLIENT_ID/SECRET", + "for more than a few calls per task register a free 'script' app at reddit.com/prefs/apps and set " + "REDDIT_CLIENT_ID/REDDIT_CLIENT_SECRET in .env (app-only credentials; Hermes never logs in as the user)", ] return report diff --git a/website/docs/user-guide/skills/bundled/social-media/social-media-reddit-reading.md b/website/docs/user-guide/skills/bundled/social-media/social-media-reddit-reading.md index 219195c947..812e9d89b9 100644 --- a/website/docs/user-guide/skills/bundled/social-media/social-media-reddit-reading.md +++ b/website/docs/user-guide/skills/bundled/social-media/social-media-reddit-reading.md @@ -47,18 +47,32 @@ backend routing in [Agent Reach](https://github.com/Panniantong/Agent-Reach). ## Prerequisites -None for the anonymous path. For anything beyond a handful of calls per task, create -a free Reddit "script" app at https://www.reddit.com/prefs/apps and put the two values -in `~/.hermes/.env`: +**None.** No Reddit account, login, cookie, or API key is needed. The default backend is +Reddit's public Atom feeds (`.rss` endpoints), the only unauthenticated route Reddit still +serves to non-residential IPs. It is throttled to about one request per minute per IP and +returns thinner data (no scores, top-level comments only), which is fine for a few calls. + +**Optional upgrade (app credentials, still no user login):** for sustained use or full +data, register a free "script" type app at https://www.reddit.com/prefs/apps and put its +two values in `~/.hermes/.env`: ``` REDDIT_CLIENT_ID=... REDDIT_CLIENT_SECRET=... ``` -The script picks the OAuth backend automatically when both are set (~100 requests per -minute, scores, comment nesting, `num_comments`). Without them it uses Reddit's Atom -feeds, which are the only unauthenticated endpoints still served to non-residential IPs. +This is an application registration, not a login: the script uses the app-only +`client_credentials` grant, never a username, password, or browser cookie, and never +acts as the user. With both values set it switches to the OAuth API automatically +(~100 requests per minute, scores, nested comments, `num_comments`); if they are +missing or rejected it falls back to the anonymous feeds and says so on stderr. + +| | Anonymous feeds (default) | OAuth app credentials | +|---|---|---| +| Setup | nothing | 1-minute app registration, two `.env` values | +| Rate limit | ~1 request / minute / IP | ~100 requests / minute | +| Thread data | post + top-level comments, no scores | nested comments, scores, comment counts | +| Acts as a user | no | no | ## How to Run @@ -75,6 +89,8 @@ python3 scripts/reddit.py --json search "topic" # machine-reada ## Quick Reference +Every command works on both backends; the script chooses the backend, you never pass a flag. + | Need | Command | Anonymous | OAuth | |---|---|---|---| | Subreddit front page | `sub NAME --sort hot\|new\|top\|rising [--time week]` | ✔ | ✔ | @@ -101,7 +117,9 @@ than stopping at titles; the listing only carries the first ~300 characters of e `grounded-citations` registers these URLs like any other source. ⑤ If the user needs sustained Reddit access (monitoring, more than ~10 calls), stop and -ask them to add the OAuth credentials rather than grinding through the throttle. +ask them to register the app credentials (Prerequisites) rather than grinding through the +throttle. Tell them plainly: it is a free app registration, not logging Hermes into their +account. Never ask for a Reddit password or browser cookies. ## Pitfalls @@ -116,6 +134,9 @@ ask them to add the OAuth credentials rather than grinding through the throttle. - Reddit's `limit` on feeds is advisory — expect 5–25 entries regardless of what you ask. - Never paste `REDDIT_CLIENT_SECRET` into a chat or log; the script reads it from the environment only. +- Do not "fix" a 429 by retrying in a loop or adding a proxy; the throttle is per IP and + the script already waits out the window once. More than one 429 in a row means the + task needs the app credentials. ## Verification