# Example configuration. Copy to ~/.moonlighter/config.yaml (or set MOONLIGHTER_HOME) # and adjust. All values here are generic placeholders. # Browser executable path (Chrome/Chromium/Brave). Required for the LinkedIn scan and # for browser-based applications. Examples per platform: # macOS Chrome: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome # macOS Brave: /Applications/Brave Browser.app/Contents/MacOS/Brave Browser # Linux Chrome: /usr/bin/google-chrome browser_path: "" # LLM backend. This is the default; switch it any time by editing this line. # "cli" -> uses the Claude Code CLI (no API key; uses the claude.ai session). # "api" -> uses the Anthropic SDK (requires ANTHROPIC_API_KEY in the environment). # Anything else is rejected at startup rather than silently falling back. llm_backend: cli # Main model (answer generation) and evaluation model (cheaper, for scoring jobs). llm_model: claude-sonnet-4-6 eval_model: claude-haiku-4-5-20251001 # Jobs scoring below this threshold are archived. score_threshold: 6.5 # Delay (ms) between browser actions — helps stabilize dynamic forms. slow_mo_ms: 300 # Job titles discarded without calling the LLM (substring, case-insensitive). title_blocklist: - "sales" - "account executive" - "marketing" - "recruiter" - "product manager" # ─── Portal-wide job boards ────────────────────────────────────────────── # Unlike the per-company ATS scanners (driven by company_list.yaml), these # scan an entire public board in one pass. All OFF by default: an ungated # board floods the pipeline (and the LLM evaluation spend) with every job # it lists. When enabled, pass keywords to scan_and_evaluate — the feeds # are filtered by title before anything reaches the LLM. # # scan_remoteok: true # remoteok.com — remote jobs, all categories # scan_remotive: true # remotive.com — ToS caps polling at 4 requests/DAY; # # there is no rate limiter here, you are the control # scan_wwr: true # weworkremotely.com — programming category RSS # scan_hn_whoishiring: true # HN's monthly "Who is hiring?" thread; free-text # # comments, so titles/companies are best-effort # scan_gupy: true # gupy.io — BR-focused portal, keyword-driven # Country-dependent work authorization. Empty -> always __NEEDS_REVIEW__ (never guesses). # citizenship_country accepts free forms ("Brazil"/"Brasil"/"BR"/"USA"/"United States"). work_authorization: citizenship_country: "" authorized_answer: "Yes" not_authorized_answer: "No" # CV per company (paths relative to MOONLIGHTER_HOME). 'default' is used when a # company has no entry. by_company matches the company name case-insensitively. cv: default: "cv.pdf" by_company: {} # acme: "cv-acme.pdf" # Email monitoring (Gmail OAuth). Optional — only if you want to track replies. email: address: "your-email@gmail.com" # Relative filenames resolve under MOONLIGHTER_HOME (works with a custom # MOONLIGHTER_HOME too — a hardcoded ~/.moonlighter path would not). credentials_path: "gmail-client.json" token_path: "gmail-token.json" # Post-sync cleanup (both default false; either one requires the gmail.modify # scope — setup_email() re-consent if your token is readonly): # archive_ref_matched: true # mark read + archive replies matched by alias # # that applied a pipeline update (certainty only) # archive_all_classified: true # superset: also fuzzy/uncertain classified mail; # # 'unrelated' mail is never touched processed_label: "moonlighter/processed" # false (default) = sync is read-only; dedup is done in a local table. mark_processed: false # How many days back the sync searches, regardless of read/unread state. lookback_days: 30 interview_stages: - phone_screening - technical_interview - system_design - final_interview # Portal-feed jobs (RemoteOK, Remotive, WeWorkRemotely, HN Who Is Hiring) can # never be staleness-checked at their source; archive_stale_jobs archives them # once they age past this many days. 0 disables age-based archiving. # portal_max_age_days: 30