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.
This commit is contained in:
Teknium
2026-09-05 12:49:04 -07:00
parent 4dc9988f78
commit ee5b5ec21e
4 changed files with 74 additions and 19 deletions
+9
View File
@@ -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=
+28 -7
View File
@@ -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
@@ -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
@@ -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