An async Python agent that finds relevant Reddit posts, scores them for relevance, analyses subreddit tone, generates playbook-compliant comments and original posts, and exports everything to Google Sheets.
- Features
- Installation
- Configuration
- Usage
- Command-Line Reference
- Prompt File Format
- Multi-Account Support
- Karma Stage Playbook
- Subreddit Tone Analysis
- Profile Analysis
- Google Sheets Export
- Architecture
- Troubleshooting
- Intelligent search — natural language prompts mapped to relevant subreddits via LLM
- Relevance scoring — every post scored 0–1 with reasoning, boosted for organic engagement opportunities
- Competitor tracking — finds posts and comments mentioning Synthesia, Camtasia, Guidde, etc.
- Subreddit tone analysis — fetches hot posts/comments, extracts vocabulary and style, caches for 7 days
- Playbook-compliant comments — stage-gated product mentions, randomised structure, subreddit-matched tone
- Original post generation — question / insight / story formats, tone-aware, per-account assignment
- Profile analysis — audit any public Reddit account against the playbook
- Google Sheets export — deduplicated append with competitor flags, source prompt, and suggested comments
- Multi-account support — named accounts in
accounts.jsonwith per-account karma stage - Rate limit handling — exponential backoff, automatic retries
- Python 3.9+
- Reddit API credentials (client ID + secret)
- OpenAI API key
- Google service account JSON (for Sheets export)
# 1. Navigate to project directory
cd reddit-agent
# 2. Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Configure environment
cp .env.example .env # or create .env manually — see Configuration# ── Reddit API ────────────────────────────────────────────────
REDDIT_CLIENT_ID=your_client_id
REDDIT_CLIENT_SECRET=your_client_secret
REDDIT_USERNAME=your_username # required for posting
REDDIT_PASSWORD=your_password # required for posting
REDDIT_USER_AGENT=reddit-agent/0.1 by your_username
# ── OpenAI ────────────────────────────────────────────────────
OPENAI_API_KEY=your_openai_api_key
OPENAI_MODEL=gpt-4o-mini # or gpt-4o
# ── Subreddits ────────────────────────────────────────────────
DEFAULT_SUBREDDITS=r/ProductMarketing,r/elearning,r/instructionaldesign,r/Training,r/prodmgmt,r/SaaS
# ── Search limits ─────────────────────────────────────────────
MAX_POSTS=100
MAX_SUBREDDIT_MATCHES=5
CONCURRENCY_LIMIT=8
# ── Relevance ─────────────────────────────────────────────────
RELEVANCE_THRESHOLD=0.5
# ── Competitor tracking ───────────────────────────────────────
ENABLE_COMPETITOR_SEARCH=true
COMPETITORS=Synthesia,Camtasia,Guidde
CHECK_COMMENTS_FOR_COMPETITORS=true
# ── Smart subreddit matching ──────────────────────────────────
ENABLE_SMART_SUBREDDIT_MATCHING=true
# ── Engagement playbook ───────────────────────────────────────
KARMA_STAGE=1 # 1 = never mention product, 2 = build authority, 3 = light mention OK
# ── Google Sheets export ──────────────────────────────────────
GOOGLE_SHEET_ID=your_sheet_id
GOOGLE_SHEETS_CREDENTIALS_FILE=/path/to/service_account.json
# ── Multi-account ─────────────────────────────────────────────
ACCOUNTS_FILE=accounts.json # optional, see Multi-Account section
# ── Misc ──────────────────────────────────────────────────────
ENABLE_POSTING=false
LOG_LEVEL=INFO- Go to
reddit.com/prefs/apps - Create app → type: script
- Copy the client ID (below app name) and secret
- Google Cloud Console → create/select a project
- Enable the Google Sheets API
- IAM & Admin → Service Accounts → Create → download JSON key
- Share your spreadsheet with the service account email (
…@….iam.gserviceaccount.com) as Editor
# Single prompt
.venv/bin/python -m src.agent.main --prompt "reduce time to create training content"
# Multiple prompts from file, export to Google Sheets
.venv/bin/python -m src.agent.main --prompt-file prompt.txt --export
# With custom subreddits and post limit
.venv/bin/python -m src.agent.main \
--prompt "training video creation" \
--subreddits r/elearning r/instructionaldesign \
--limit 50 --top 10 --export.venv/bin/python -m src.agent.main \
--prompt "reduce time to create training content" \
--subreddits r/elearning r/instructionaldesign \
--generate-posts.venv/bin/python -m src.agent.main --analyze-profile example_username.venv/bin/python -m src.agent.main \
--prompt-file prompt.txt \
--account account_1 \
--generate-posts --export.venv/bin/python -m src.agent.main \
--prompt-file prompt.txt \
--refresh-tone| Flag | Description |
|---|---|
--prompt TEXT |
Single search prompt |
--prompt-file PATH |
File with multiple prompts (see Prompt File Format) |
--analyze-profile USERNAME |
Audit a Reddit profile against the playbook |
| Flag | Default | Description |
|---|---|---|
--subreddits |
from config | Override subreddits for this run |
--keywords |
— | Extra keywords appended to the search query |
--limit N |
100 | Max posts fetched per prompt |
--top N |
10 | Top N posts to generate comments for |
--max-age-weeks N |
12 | Filter posts older than N weeks |
--relevance-threshold F |
0.5 | Min relevance score to include a post |
| Flag | Default | Description |
|---|---|---|
--export |
false | Export all above-threshold posts to Google Sheets |
--format json|md |
md | Terminal output format |
| Flag | Default | Description |
|---|---|---|
--generate-posts |
false | Generate original posts (title + body) per subreddit |
--refresh-tone |
false | Force-refresh subreddit tone profiles (ignores 7-day cache) |
--post |
false | Actually post generated comments to Reddit (requires ENABLE_POSTING=true) |
| Flag | Default | Description |
|---|---|---|
--account NAME |
— | Use named account from accounts.json |
--accounts-file PATH |
accounts.json |
Path to accounts config file |
# Simple prompt — uses DEFAULT_SUBREDDITS or smart matching
reduce time to create training content
# Prompt with explicit subreddits (highest priority)
training video creation ||| r/instructionaldesign, r/elearning, r/Training
# Multiple prompts separated by blank lines
SOPs ||| r/instructionaldesign, r/elearning
product tour ||| r/ProductMarketing, r/productmanagement
|||syntax pins specific subreddits for that prompt- Blank lines separate prompts
- Subreddit names accept or omit the
r/prefix
Copy accounts.example.json to accounts.json and fill in your credentials:
{
"accounts": [
{
"name": "account_1",
"username": "your_reddit_username",
"password": "your_password",
"karma_stage": 1,
"preferred_subreddits": ["r/elearning", "r/instructionaldesign", "r/Training"]
},
{
"name": "new_account_1",
"username": "new_reddit_username",
"password": "your_password",
"karma_stage": 1,
"preferred_subreddits": ["r/ProductMarketing", "r/SaaS"]
}
]
}accounts.jsonis gitignored — never commit it--account NAMEswitches credentials and karma stage for that runpreferred_subredditsroutes generated post suggestions to the right account- If no
accounts.jsonexists, falls back to.envcredentials
Set KARMA_STAGE in .env (or per-account in accounts.json):
| Stage | Karma | Behaviour |
|---|---|---|
| 1 | < 100 | Pure value — no product, tool, or company names ever |
| 2 | 100–299 | Build authority — share experience, still no product mention |
| 3 | 300+ | Light [your product] mention allowed when it genuinely fits the thread |
Stage 3 comments include a transparency framing: "frame it as a personal recommendation from someone who works on or uses the product" — so if someone asks about affiliation, the reply is honest.
Before generating comments or posts, the agent fetches the top 20 hot posts and their top comments from each target subreddit and runs an LLM analysis to extract:
- Tone — e.g. "casual, practitioner-focused, sceptical of vendors"
- Vocabulary — insider jargon, acronyms, phrases that signal belonging
- Upvoted formats — what kinds of posts/comments get positive engagement
- Downvoted formats — what gets ignored or flagged
- Comment length — short / medium / long
- Self-promotion stance — how the community views promotional content
Tone profiles are cached in .tone_cache.json for 7 days. Force a refresh with --refresh-tone.
.venv/bin/python -m src.agent.main --analyze-profile example_usernameOutputs:
- Stats panel — comment karma, post karma, account age, karma stage
- Compliance flags — promotional language hits, copy-paste pattern detection
- Top subreddits — where the last 100 comments landed
- Playbook analysis — LLM assessment of tone variety, value quality, promotional risk, top 3 improvements
Works on any public Reddit account — no password required.
.venv/bin/python -m src.agent.main --prompt-file prompt.txt --exportThe sheet receives one row per unique post (deduplicated by Post ID across runs):
| Column | Description |
|---|---|
| Title | Post title |
| Subreddit | e.g. r/elearning |
| Link | Full Reddit URL |
| Relevance | Score 0–1 |
| Reasoning | LLM explanation of score |
| Suggested Comment | Generated comment text |
| Post ID | Reddit post ID (dedup key) |
| Source Prompt | Which prompt found this post |
| Mentions Competitor | Yes / No |
| Competitor Names | Comma-separated |
| Competitors in Comments | Yes / No |
| Competitor Names in Comments | Comma-separated |
Re-running with --export appends only new posts — duplicates are skipped automatically.
src/agent/
├── main.py # CLI orchestrator
├── config.py # Pydantic settings (loads .env)
├── types.py # Post, AnalyzedPost dataclasses
├── reddit_client.py # asyncpraw search, comments, posting
├── content_analyzer.py # Relevance scoring via OpenAI
├── comment_generator.py # Playbook-compliant comment generation
├── post_generator.py # Original post generation (title + body)
├── subreddit_tone.py # Tone profile fetching and caching
├── subreddit_matcher.py # LLM-based prompt→subreddit matching
├── profile_analyzer.py # Reddit profile audit
├── sheets_exporter.py # Google Sheets append with dedup
└── logging_utils.py # Structured logging
Prompt(s)
│
▼
Subreddit selection
Explicit (|||) → Smart LLM match → CLI --subreddits → DEFAULT_SUBREDDITS
│
▼
Tone profile fetch (cached 7 days per subreddit)
│
▼
Post search ─────────────────────────────────────────────┐
Main query (all subreddits) │
+ Competitor queries (if enabled) │
→ Date filter → Deduplicate │
│ │
▼ ▼
Relevance scoring (OpenAI, concurrent) Comment checking (comments for competitors)
│
▼
Threshold filter → Sort → Top N
│
▼
Comment generation (tone-aware, stage-gated)
│
├─ Post generation (if --generate-posts)
├─ Google Sheets export (if --export)
├─ Terminal display
└─ Reddit posting (if --post and ENABLE_POSTING=true)
| Operation | Calls |
|---|---|
| Smart subreddit matching | 1 per prompt (if no explicit subreddits) |
| Tone profile fetch | 1 per subreddit (cached 7 days) |
| Relevance scoring | 1 per fetched post |
| Comment generation | 1 per shortlisted post |
| Post generation | 1 per subreddit (if --generate-posts) |
| Profile analysis | 1 per --analyze-profile call |
Set DEFAULT_SUBREDDITS in .env, use --subreddits, or add ||| to your prompt file.
Wait a few minutes. The agent retries with exponential backoff (5s → 60s, up to 5 attempts). Reduce the number of subreddits if it persists.
Try a broader/more natural phrasing — Reddit search is literal. Check the prompt file examples for what works.
Share the spreadsheet with your service account email (…@….iam.gserviceaccount.com) as Editor.
Set GOOGLE_SHEETS_CREDENTIALS_FILE in .env to the absolute path of your service account JSON.
REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET, and OPENAI_API_KEY are required. Check your .env file.
LOG_LEVEL=DEBUG # in .envVersion: 0.2
Last updated: April 2026