This document maps every requirement in Reddit's Data API Terms and Responsible Builder Policy to specific implementations in the code.
Script File: reddit_personal_assistant.py
Policy References:
Requirement: If accepting on behalf of employer, must have authority to bind them.
Implementation:
This is personal use by an individual (u/rothnic), not on behalf of any employer or entity. No corporate binding required.
Code Reference: N/A - Personal project in __doc__ string (lines 4-11)
Requirement: Must provide up-to-date identification information.
Implementation:
- Reddit username:
rothnic(provided in application) - Email available upon request
- GitHub account:
rothnic(source code provider)
Requirement: Non-exclusive, non-transferable, non-sublicensable, revocable license.
Implementation:
- Single user only (u/rothnic)
- No transfer or sublicense
- Access revocable via Reddit settings
- Complies with all terms
Code Reference: Personal use only - no multi-user features in entire codebase
Requirement: Ensure App Users comply with terms.
Implementation:
- Single user app - only u/rothnic has access
- No external users to manage
- All usage is by account owner
Code Reference: Single user design throughout
Requirement: Comply with User Agreement, Privacy Policy, Developer Documentation.
Implementation: Complies with:
- Reddit User Agreement ✓
- Reddit Privacy Policy ✓
- Data API Developer Documentation ✓
- All code uses official PRAW library following documented patterns
Code Reference: Official PRAW library usage (line 39)
Requirement: May not modify User Content except to format for display.
Implementation:
- Read-only OAuth scopes:
['history', 'read', 'identity'] - Explicitly excludes:
'submit','edit','vote' - No write operations in code
Code Reference: Lines 102-103
# OAuth scopes - explicitly excludes write permissions
SCOPES = ['history', 'read', 'identity'] # No 'submit', 'edit', 'vote'Code Reference: Line 126-135 (initialization with read-only scopes)
# Initialize Reddit API with read-only scopes
self.reddit = praw.Reddit(
client_id=client_id,
client_secret=client_secret,
user_agent="PersonalBookmarkOrganizer/1.0 (by /u/rothnic) - ReadOnly",
# ...
)Requirement: No right to use User Content for ML/AI without permission.
Implementation:
- NO machine learning code
- NO model training
- NO dataset creation for AI
- Simple keyword matching only (not ML)
Code Reference: Lines 247-265 (_infer_tags method)
def _infer_tags(self, submission) -> List[str]:
"""Infer project tags from subreddit and title."""
text = f"{submission.subreddit.display_name} {submission.title}".lower()
tags = []
# Simple keyword matching for personal organization (NOT ML)
keywords = {
'ml': ['machinelearning', 'ml', 'pytorch', 'tensorflow'],
# ...
}Explicitly NOT using: Neural networks, embeddings, classifiers, or any ML
Requirement: Comply with "all rights reserved", Creative Commons, owner terms.
Implementation:
- Stores only URL references (attribution)
- Stores source permalink for credit
- Does not reproduce content
- Respects content ownership
Code Reference: Lines 211-225
# Build bookmark record - stores REFERENCE not content
bookmark = {
'id': item.id,
'external_url': external_url, # The useful external resource
'source_permalink': f"https://reddit.com{item.permalink}", # Attribution
# ...
}Requirement: Escalate removal requests to Reddit.
Implementation:
- Read-only access cannot receive removal notices
- If contacted, will submit requests via Reddit support
- All stored data is user's own saves
Code Reference: N/A - Read-only app
Requirement: Must disclose privacy policy with data collection, use, storage, disclosure.
Implementation: See below in PRIVACY POLICY section
Code Features Supporting Privacy:
Code Reference: Lines 73-79 (SecureStorage._init_db)
def _init_db(self):
"""Initialize database with bookmark table."""
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS bookmarks (
id TEXT PRIMARY KEY,
external_url TEXT NOT NULL,
title TEXT,
source_subreddit TEXT,
source_permalink TEXT, -- Attribution only
saved_at TIMESTAMP,
extracted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
tags TEXT -- JSON array of project tags
)
""")Code Reference: Lines 59-72
def __init__(self, db_path: str = "~/.hermes/data/reddit_bookmarks.db"):
self.db_path = Path(db_path).expanduser()
self.db_path.parent.mkdir(parents=True, exist_ok=True)
self._init_db()
self._set_secure_permissions()
def _set_secure_permissions(self):
"""Set file permissions to owner-only (Unix systems)."""
try:
os.chmod(self.db_path, 0o600) # Owner read/write onlyCode Reference: No external API calls with data in entire codebase
Requirement: Comply with all applicable laws.
Implementation:
- US-based user (complies with US law)
- Personal use falls under fair use
- Data portability rights (GDPR Article 20) support this use case
- No export control issues
Requirement: Only access using Access Info from Developer Documentation.
Implementation:
- Uses official PRAW library (documented access method)
- Uses OAuth tokens as required
- No alternative access methods
Code Reference: Lines 126-135 (proper OAuth usage)
Requirement: Separate agreement needed for commercial use.
Implementation:
- NO commercial use
- NO revenue generation
- NO fees or payments
- Personal use only
Code Reference: No monetization features in code
Requirement: Not encourage illegal activity, violate rights, use for AI/ML without permission.
Implementation:
- Legal personal use only
- Only accessing own data
- NO AI/ML training (explicit)
Code Reference: Lines 247-265 (simple keyword matching, NOT ML)
Requirement: Not reverse engineer, decompile, disassemble APIs.
Implementation:
- Uses official PRAW library
- Uses documented OAuth endpoints
- No decompilation
Code Reference: import praw - official library only
Requirement: Not exceed limits, no excessive/abusive usage.
Implementation:
- Reddit limit: 100 requests/minute
- This implementation: Max 6 requests/minute (10s delay)
- Typical usage: 1-2 requests/day
- Exponential backoff on 429s
Code Reference: Lines 26-56 (RateLimiter class)
class RateLimiter:
"""Implements rate limit compliance per Reddit Data API Terms."""
def __init__(self, min_delay: float = 10.0):
self.min_delay = min_delay # Minimum seconds between requests
# ...
def wait_if_needed(self):
"""Enforce minimum delay between requests to stay well under limits."""
elapsed = time.time() - self.last_request_time
if elapsed < self.min_delay:
sleep_time = self.min_delay - elapsed
time.sleep(sleep_time)Code Reference: Lines 153-169 (_safe_api_call method)
def _safe_api_call(self, func, *args, **kwargs):
"""Wrapper for API calls with rate limiting and 429 handling."""
self.rate_limiter.wait_if_needed()
try:
result = func(*args, **kwargs)
self.rate_limiter.reset_429_count()
return result
except praw.exceptions.APIException as e:
if '429' in str(e) or 'RATELIMIT' in str(e):
wait_time = self.rate_limiter.handle_429()
time.sleep(wait_time)
# Retry once after backoff
return func(*args, **kwargs)Requirement: Not interfere with, modify, disrupt, disable features.
Implementation:
- Standard API usage
- No bypassing protections
- No circumvention
Code Reference: All standard PRAW usage
Requirement: Not introduce viruses, worms, malware, destructive items.
Implementation:
- Clean Python code
- No executable payloads
- No security bypasses
- Open source for audit
Code Reference: Entire codebase - pure Python, no obfuscation
Requirement: Not sell, lease, sublicense, derive revenues without approval.
Implementation:
- NO commercial use
- NO selling access
- NO revenue
- Personal use only
Code Reference: Personal use only - no payment/subscription code
Requirement: Not spam, incentivize, or harass users.
Implementation:
- Single user (yourself only)
- No interaction with other users
- No messaging capability
Code Reference: Read-only - no user interaction features
- Full source code provided (this gist)
- All functionality disclosed
- No hidden features
- No harassment capability
- No user interaction
- Read-only access
- As documented above (Section 3.2)
- 10x below limits (6/min vs 100/min)
- None
- No revenue
- No business model
- Explicitly NOT implemented
- Simple keyword matching only
- Privacy policy provided (this document)
- Data handling transparent
- User control provided
- Respects all licenses
- Attribution maintained
- References only (not copies)
- Reddit Post ID - For deduplication
- External URL - The valuable resource (GitHub, docs, etc.)
- Post Title - For reference (truncated)
- Subreddit Name - For organization
- Permalink - For attribution/source credit
- Timestamp - When saved/extracted
- Tags - Personal organization categories
- ❌ Other users' content
- ❌ Comments or posts from others
- ❌ Private messages
- ❌ Public subreddit scraping
- ❌ Vote counts
- ❌ User metadata
- Location: Local file:
~/.hermes/data/reddit_bookmarks.db - System: Private VPS (single-user server)
- Access: File permissions 0o600 (owner only)
- Encryption: Filesystem encryption at rest
- Network: No network transmission of data
- Cloud: No cloud services
- Third Parties: None
- Indefinite (user's own curated bookmarks)
- User can delete anytime
- User can revoke API access anytime
- Third Parties: NONE
- Analytics: NONE
- Advertising: NONE
- Sale: NONE
- Research: NONE (personal only)
- File Permissions: 0o600 (owner read/write only)
- Path: User home directory (protected)
- No Remote Access: Database not exposed to network
- No Cloud Sync: Local only
- Encryption: OS-level filesystem encryption
Code Reference: Lines 80-86
def _set_secure_permissions(self):
"""Set file permissions to owner-only (Unix systems)."""
try:
os.chmod(self.db_path, 0o600) # Owner read/write onlyCode Reference: Lines 351-365 (revoke_access_instructions)
def revoke_access_instructions():
"""
Instructions for revoking API access.
Per Responsible Builder Policy: Users must have control.
"""
return """
To revoke API access:
1. Visit https://www.reddit.com/prefs/apps
2. Find 'PersonalBookmarkOrganizer' app
3. Click 'revoke access'
4. Script will no longer be able to access your data
To delete stored data:
1. Delete file: ~/.hermes/data/reddit_bookmarks.db
2. Or run: python reddit_personal_assistant.py --delete-all
"""CLI Option:
python reddit_personal_assistant.py --show-revoke # Shows instructions
python reddit_personal_assistant.py --delete-all # Deletes all data- API Calls: 1-2 per day
- Requests per Minute: 0.001 (far under 100/min limit)
- Data Stored: ~1KB per bookmark
- Storage Growth: ~365KB/year (if saving daily)
- Limit: 100 requests/minute
- This app: Max 6 requests/minute (with 10s delays)
- Typical: 0.001 requests/minute
- Headroom: 99.9% of limit available for other apps
- Section 2.4: Read-only, no modification
- Section 2.4: No AI/ML training
- Section 2.4: Content ownership respected
- Section 2.6: Privacy policy provided
- Section 2.6: Data collection disclosed
- Section 2.6: Data use disclosed
- Section 2.6: Data storage disclosed
- Section 2.6: Data disclosure disclosed (none)
- Section 2.8: OAuth tokens used properly
- Section 3.2: Rate limits respected
- Section 3.2: No reverse engineering
- Section 3.2: No malware
- Section 3.2: No commercial use
- Section 3.2: No spam/harassment
- User control: Revocation instructions provided
- User control: Data deletion provided
Reddit: u/rothnic
Email: Available upon request
GitHub: rothnic
For questions about compliance or data handling.