Files
RedditBot/docs/configuration.md
T
jjbrunton 633bb0ec04 Restructure chat service, web routes, and add test suite
Split monolithic chat service into modular structure with Matrix client
support, extract web server into per-resource route modules, introduce
bootstrap/main-loop separation, and add comprehensive vitest coverage
across services, repositories, and utilities. Adds project docs and
CLAUDE.md agent instructions.
2026-05-21 01:32:10 +01:00

13 KiB

Configuration Guide

Complete reference for configuring RedditBot.


Table of Contents

  1. Configuration Overview
  2. Configuration Files
  3. Environment Variables
  4. config.yaml Reference
  5. Runtime Configuration
  6. Configuration Validation
  7. Troubleshooting

Configuration Overview

RedditBot uses a layered configuration approach:

┌──────────────────────────────────────────────────────────────┐
│                    Priority Order (High → Low)                │
├──────────────────────────────────────────────────────────────┤
│ 1. Environment Variables                                     │
│    (OPENROUTER_API_KEY, REDDIT_USERNAME, etc.)               │
│                                                              │
│ 2. config.yaml                                               │
│    (Primary configuration file)                              │
│                                                              │
│ 3. Defaults                                                  │
│    (Hardcoded defaults in code)                              │
└──────────────────────────────────────────────────────────────┘

Configuration is loaded at startup by loadConfig() in src/config/index.ts, which:

  1. Reads config.yaml from the project root
  2. Merges environment variable overrides
  3. Validates the entire configuration tree using Zod
  4. Returns a strongly-typed Config object

Configuration Files

config.yaml

The primary configuration file, located at the project root:

RedditBot/
├── config.yaml          # ← Main configuration
├── package.json
├── tsconfig.json
└── src/

Data Directory

Runtime data is stored in data/ (created automatically):

data/
├── reddit-bot.db        # SQLite database
├── browser/             # Browser session data (cookies, storage)
├── media/               # Downloaded media files
│   ├── index.json       # Media index (SHA-1 → filename)
│   ├── abc123.jpg       # Media file 1
│   └── def456.png       # Media file 2
└── chats/               # Cached conversation JSON files
    ├── chat_abc123.json
    └── chat_def456.json

Environment Variables

Environment variables override corresponding values in config.yaml.

Variable Required Type Description Example
OPENROUTER_API_KEY Yes string OpenRouter API key for AI services sk-or-v1-abc123...
REDDIT_USERNAME Yes string Reddit username for authentication MyBotUser
REDDIT_PASSWORD Yes string Reddit password for authentication secret123
BROWSER_HEADLESS No boolean Run browser in headless mode true or false

Setting Environment Variables

Option 1: .env file (recommended for development)

Create a .env file in the project root:

OPENROUTER_API_KEY=sk-or-v1-abc123...
REDDIT_USERNAME=MyBotUser
REDDIT_PASSWORD=secret123
BROWSER_HEADLESS=true

Note

: Add .env to .gitignore - never commit credentials.

Option 2: Shell export

export OPENROUTER_API_KEY=sk-or-v1-abc123...
export REDDIT_USERNAME=MyBotUser
export REDDIT_PASSWORD=secret123

Option 3: Docker

Pass via docker-compose.yml or Docker CLI:

environment:
  - OPENROUTER_API_KEY=sk-or-v1-abc123...
  - REDDIT_USERNAME=MyBotUser
  - REDDIT_PASSWORD=secret123

config.yaml Reference

Complete reference for every configuration option.

Reddit Settings

reddit:
  # Subreddits to monitor for new posts
  subreddits:
    - gonewild
    - ratemyboobs
    - HomemadeNsfw
    - realgirls
    - plussize_gonewild
    # ... add or remove subreddits

  # Minutes between polling cycles
  pollInterval: 15

  # Target gender for image analysis filtering
  # Options: "F" (female), "M" (male)
  targetGender: "F"

  # Keywords used to detect sellers/spam profiles
  # Posts from users matching these keywords are skipped
  sellerKeywords:
    - seller
    - onlyfans
    - link in bio
    - check my profile
    - promo
    - discount
    - affiliate

OpenRouter AI Settings

openrouter:
  # OpenRouter API key (can also be set via OPENROUTER_API_KEY env var)
  apiKey: "sk-or-v1-abc123..."

  # Primary AI model for image analysis
  # Models must be available on OpenRouter
  model: "meta-llama/llama-3.2-90b-vision-preview"

  # Fallback models tried if the primary model refuses or fails
  fallbackModels:
    - "google/gemini-2.0-flash-001"
    - "meta-llama/llama-3.2-11b-vision-instruct"

  # Quick detection model (cheaper/faster, used for gender pre-filter)
  quickModel: "google/gemini-2.0-flash-lite-001"

  # System prompt for image analysis
  # The AI will describe the image and detect gender
  systemPrompt: |
    Analyze this image and provide:
    1. Gender detected (F or M)
    2. Detailed description of the image content
    3. Notable features (hair color, clothing, setting, etc.)
    
    Return as JSON: {"gender": "F", "description": "...", "features": [...]}

  # System prompt for message generation
  # Used when crafting DMs to post authors
  messagePrompt: |
    Generate a natural, friendly DM for this Reddit post.
    
    Image analysis: {description}
    Post title: {title}
    Strategy: {strategy}
    
    Guidelines:
    - Be complimentary but not creepy
    - Reference something specific from the image
    - Keep it under 2 sentences
    - Sound like a genuine person, not a bot
    - Do NOT ask for anything in return

Rate Limiting

rateLimit:
  # Minimum delay between messages (milliseconds)
  # Higher values reduce detection risk
  minDelayMs: 30000

  # Maximum messages per hour
  # Bot will pause when this limit is reached
  maxMessagesPerHour: 20

  # Random jitter added to delay (milliseconds)
  # Adds unpredictability to timing
  jitterMs: 15000

Timing example with defaults:

Minimum delay: 30,000ms (30 seconds)
Jitter: 0 to 15,000ms (0-15 seconds)
Effective delay: 30-45 seconds between messages
Max messages: 20 per hour

Browser Settings

browser:
  # Run browser in headless mode (no UI)
  # Set to false for debugging
  headless: true

  # Directory for persistent browser data
  # Cookies and session storage are saved here
  userDataDir: "./data/browser"

Browser session persistence:

data/browser/
├── Default/
│   ├── Cookies           # Reddit session cookies
│   ├── Local Storage     # Local storage data
│   └── Preferences       # Browser preferences
├── Login Data            # Saved login info
└── Preferences           # Browser state

Important

: Keep this directory intact. Deleting it requires re-login.

Database Settings

database:
  # Path to SQLite database file
  path: "./data/reddit-bot.db"

The database is auto-created on first run. Migrations run automatically on startup.

Media Sync Settings

mediaSync:
  # Enable periodic media synchronization
  enabled: true

  # Interval between sync cycles (minutes)
  intervalMinutes: 30

Sync behavior:

  • Incremental sync (automatic): Downloads media from top 10 conversations
  • Full sync (manual via dashboard): Downloads media from all conversations

Auto-Reply Settings

autoReply:
  # Enable automatic chat replies
  enabled: true

  # Auto-send replies (true) or mark as pending for approval (false)
  autoSend: false

  # Minutes between checking for new messages
  checkInterval: 10

Reply modes:

autoSend Behavior
true Bot sends AI-generated replies automatically
false Bot suggests replies, user approves via dashboard

Strategy Variants (A/B Testing)

strategyVariants:
  # Variant 1: Compliment-based
  - name: "compliment"
    prompt: |
      Write a friendly compliment about the person's appearance.
      Be genuine and specific. Keep it short and natural.
    enabled: true

  # Variant 2: Question-based
  - name: "question"
    prompt: |
      Write a friendly message that includes a question.
      Engage them in conversation naturally.
    enabled: true

  # Variant 3: Casual observation
  - name: "observation"
    prompt: |
      Write a casual observation about the photo or setting.
      Sound like you're commenting to a friend.
    enabled: true

Web Dashboard Settings

web:
  # Port for the web dashboard
  port: 3000

Global Settings

# Global dry run mode
# When true, all actions are logged but not actually performed
dryRun: false

# Number of successful message examples to include in prompts
fewShotExamples: 3

# Minimum responses needed before trusting strategy stats
minStrategySamples: 10

# Exploration rate for A/B testing (0.0 to 1.0)
# 0.15 = 15% of messages use random variants (exploration)
explorationRate: 0.15

Runtime Configuration

The following settings can be modified via the web dashboard without restarting the bot:

Setting Endpoint Type Description
rateLimit.minDelayMs PUT /api/config number Message delay
rateLimit.maxMessagesPerHour PUT /api/config number Hourly cap
rateLimit.jitterMs PUT /api/config number Jitter range
reddit.pollInterval PUT /api/config number Poll frequency
dryRun PUT /api/config boolean Dry run mode

Updating Runtime Config

Via dashboard:

  1. Open the settings modal
  2. Modify desired values
  3. Click "Save"

Via API:

curl -X PUT http://localhost:3000/api/config \
  -H "Content-Type: application/json" \
  -d '{
    "rateLimit": {
      "minDelayMs": 45000,
      "maxMessagesPerHour": 15,
      "jitterMs": 20000
    },
    "dryRun": true
  }'

Note

: Runtime changes are in-memory only. They are lost when the bot restarts. To make changes persistent, update config.yaml.


Configuration Validation

All configuration is validated using Zod at startup. Invalid configuration will cause the bot to exit with a descriptive error.

Validation Rules

Field Validation
reddit.subreddits Must be non-empty array of strings
reddit.pollInterval Must be positive integer
reddit.targetGender Must be "F" or "M"
openrouter.apiKey Must be non-empty string
openrouter.model Must be non-empty string
openrouter.fallbackModels Must be non-empty array
rateLimit.minDelayMs Must be positive integer
rateLimit.maxMessagesPerHour Must be positive integer
rateLimit.jitterMs Must be non-negative integer
browser.headless Must be boolean
browser.userDataDir Must be non-empty string
database.path Must be non-empty string
mediaSync.enabled Must be boolean
mediaSync.intervalMinutes Must be positive integer (if enabled)
autoReply.enabled Must be boolean
autoReply.autoSend Must be boolean
autoReply.checkInterval Must be positive integer (if enabled)
strategyVariants Must be array with name + prompt
web.port Must be integer 1-65535
dryRun Must be boolean

Common Validation Errors

Error: Invalid config: openrouter.apiKey must be a string Fix: Set OPENROUTER_API_KEY environment variable or add apiKey to config.yaml

Error: Invalid config: reddit.subreddits must be a non-empty array Fix: Add at least one subreddit to reddit.subreddits in config.yaml

Error: Invalid config: browser.userDataDir must be a string Fix: Ensure browser.userDataDir is set in config.yaml


Troubleshooting

Configuration Not Loading

Symptom: Bot fails to start with validation errors.

Steps:

  1. Verify config.yaml is in the project root
  2. Check YAML syntax (use a YAML linter)
  3. Verify environment variables are set correctly
  4. Check bot logs for specific validation errors

Credentials Not Working

Symptom: Browser login fails.

Steps:

  1. Verify REDDIT_USERNAME and REDDIT_PASSWORD are correct
  2. Check that the account is not locked or requires 2FA
  3. Try manual login via npm run login
  4. Ensure BROWSER_HEADLESS=false for debugging login issues

AI Not Working

Symptom: Image analysis fails or returns errors.

Steps:

  1. Verify OPENROUTER_API_KEY is valid
  2. Check API key has sufficient balance
  3. Verify openrouter.model is available on OpenRouter
  4. Check fallback models are set correctly
  5. Review logs for specific AI errors

Browser Session Expired

Symptom: Bot stops with "Browser session expired" error.

Steps:

  1. Delete data/browser/ directory
  2. Run npm run login to re-authenticate
  3. Restart the bot

Port Already in Use

Symptom: Dashboard fails to start with "Port already in use".

Steps:

  1. Change web.port in config.yaml
  2. Or kill the process using the port: lsof -i :3000