# Configuration Guide Complete reference for configuring RedditBot. --- ## Table of Contents 1. [Configuration Overview](#configuration-overview) 2. [Configuration Files](#configuration-files) 3. [Environment Variables](#environment-variables) 4. [config.yaml Reference](#configyaml-reference) 5. [Runtime Configuration](#runtime-configuration) 6. [Configuration Validation](#configuration-validation) 7. [Troubleshooting](#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: ```env 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** ```bash 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: ```yaml 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 ```yaml 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 ```yaml 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 ```yaml 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 ```yaml 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 ```yaml 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 ```yaml 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 ```yaml 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) ```yaml 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 ```yaml web: # Port for the web dashboard port: 3000 ``` ### Global Settings ```yaml # 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: ```bash 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`