{"id":49581691,"url":"https://github.com/humancto/mr-jobs","last_synced_at":"2026-05-03T20:40:06.537Z","repository":{"id":349639141,"uuid":"1167479473","full_name":"humancto/mr-jobs","owner":"humancto","description":"AI-powered job hunting command center. Discovers jobs from 7+ sources, scores them against your resume with AI, generates tailored applications, auto-fills forms via browser automation, and tracks your pipeline. Self-hosted, open source.","archived":false,"fork":false,"pushed_at":"2026-04-06T21:25:26.000Z","size":231,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-06T23:21:35.355Z","etag":null,"topics":["ai","automation","browser-automation","career","claude","docker","fastapi","job-application","job-board","job-hunting","job-search","job-tracker","llm","machine-learning","open-source","openai","playwright","python","resume","self-hosted"],"latest_commit_sha":null,"homepage":"https://humancto.github.io/mr-jobs/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/humancto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-26T10:40:23.000Z","updated_at":"2026-04-06T21:25:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/humancto/mr-jobs","commit_stats":null,"previous_names":["humancto/mr-jobs"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/humancto/mr-jobs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humancto%2Fmr-jobs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humancto%2Fmr-jobs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humancto%2Fmr-jobs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humancto%2Fmr-jobs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/humancto","download_url":"https://codeload.github.com/humancto/mr-jobs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humancto%2Fmr-jobs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32584646,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","automation","browser-automation","career","claude","docker","fastapi","job-application","job-board","job-hunting","job-search","job-tracker","llm","machine-learning","open-source","openai","playwright","python","resume","self-hosted"],"created_at":"2026-05-03T20:40:04.917Z","updated_at":"2026-05-03T20:40:06.520Z","avatar_url":"https://github.com/humancto.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MR.Jobs\n\n**Your AI job hunting command center.**\n\nDiscovers. Scores. Tailors. Applies. Tracks. -- All running locally on your machine.\n\n---\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Python 3.11+](https://img.shields.io/badge/Python-3.11+-green.svg)](https://www.python.org/downloads/)\n[![Docker Ready](https://img.shields.io/badge/Docker-Ready-2496ED.svg)](https://www.docker.com/)\n[![PRs Welcome](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](https://github.com/humancto/mr-jobs/pulls)\n\n---\n\nMR.Jobs is a self-hosted, AI-powered job hunting automation system. It continuously discovers jobs from 7+ sources, scores every listing against your actual resume, generates tailored application materials, auto-fills forms via browser automation, and tracks your entire pipeline with follow-up reminders and ghost detection -- all from a real-time local dashboard.\n\n```\n  DISCOVER          SCORE            TAILOR           APPLY            TRACK\n  ──────────     ──────────      ──────────      ──────────      ──────────\n  7+ sources     AI scores       Tailored        Playwright      Follow-ups\n  scanning       0-100 vs        resume per      fills forms     \u0026 ghost\n  continuously   your resume     top match       automatically   detection\n```\n\n---\n\n## Dashboard\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/screenshots/dashboard.png\" alt=\"MR.Jobs Dashboard\" width=\"800\" /\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003cem\u003eThe MR.Jobs dashboard -- real-time job intelligence at a glance\u003c/em\u003e\u003c/p\u003e\n\n|                                                      |                                                        |\n| ---------------------------------------------------- | ------------------------------------------------------ |\n| ![Setup Wizard](docs/screenshots/wizard.png)         | ![Job Scoring](docs/screenshots/scoring.png)           |\n| _First-run setup wizard -- no YAML editing required_ | _AI-powered job scoring with detailed reasoning_       |\n| ![Resume Tailoring](docs/screenshots/tailoring.png)  | ![Follow-up Tracking](docs/screenshots/follow-ups.png) |\n| _Per-job resume tailoring and cover letters_         | _Follow-up reminders and ghost detection_              |\n\n---\n\n## Features\n\n### Discovery Engine -- 7+ Sources\n\nMR.Jobs casts the widest possible net, pulling listings from direct ATS APIs, aggregated job boards, community threads, and any custom career page you point it at.\n\n| Source              | Module                        | Coverage                                                           | API Key Required |\n| ------------------- | ----------------------------- | ------------------------------------------------------------------ | ---------------- |\n| Greenhouse API      | `utils/discovery.py`          | Direct company job boards (Anthropic, Stripe, Figma, Vercel, etc.) | No               |\n| Lever API           | `utils/discovery.py`          | Direct company job boards                                          | No               |\n| python-jobspy       | `utils/jobspy_source.py`      | Indeed, LinkedIn, Glassdoor, ZipRecruiter, Google Jobs             | No               |\n| RemoteOK            | `utils/rss_source.py`         | Remote-first tech jobs                                             | No               |\n| HN Who is Hiring    | `utils/hn_source.py`          | Monthly Y Combinator hiring threads via Algolia API                | No               |\n| Adzuna              | `utils/adzuna_source.py`      | Adzuna job aggregator (200k+ listings)                             | Yes (free)       |\n| Custom Career Pages | `utils/career_page_source.py` | Any URL -- Playwright scrapes and AI extracts listings             | No               |\n\nEvery source is independently optional. If one source fails or is unconfigured, all others continue running normally.\n\n### AI Scoring -- Resume-Aware Matching\n\nEvery discovered job is scored 0-100 by an AI that reads your full resume text, not just keyword matching. The scoring engine produces:\n\n- **Match score** (0-100) based on role fit, skills overlap, location, and career trajectory\n- **Apply recommendation** (yes/no) with detailed reasoning\n- **Skill overlap analysis** -- which of your skills match the job requirements\n- **Red flags** -- mismatches in seniority, tech stack, or requirements\n- **Cover letter** -- a tailored draft generated alongside the score\n- **Favorite company bonus** -- +10 points for companies you flag as top targets\n\nThe minimum score threshold is configurable (default: 65). Jobs below the threshold are automatically skipped.\n\n### AI Resume Tailoring\n\nFor high-match jobs (score 80+), MR.Jobs generates tailored application materials specific to each posting:\n\n- **Tailored professional summary** -- 2-3 sentences optimized for the specific role\n- **Achievement bullets** -- your real accomplishments rewritten to emphasize relevance\n- **Keyword alignment** -- important terms from the job posting matched to your experience\n- **Emphasis guidance** -- which parts of your background to highlight or de-emphasize\n- **Custom cover letter** -- a specific, non-templated letter referencing both the job requirements and your matching experience\n\nAll tailored content is based exclusively on experience that actually exists in your resume. Nothing is fabricated.\n\n### Browser Automation\n\nPlaywright drives a visible Chromium browser to fill application forms:\n\n- **Greenhouse adapter** -- purpose-built for Greenhouse ATS forms\n- **Lever adapter** -- handles Lever-specific application flows\n- **Generic AI form filler** -- uses AI to analyze and fill any ATS or custom application form\n- **Custom question handling** -- AI interprets and answers freeform questions using your profile data\n- **Dry-run mode by default** -- forms are filled but never submitted unless you explicitly pass `--live`\n- **Headed browser** -- you can see every action as it happens and intervene at any time\n\n### Pipeline Tracking\n\nA SQLite database (WAL mode for concurrent access) tracks every job from discovery through final outcome:\n\n- **Status pipeline**: discovered - matched - applied - interviewing - offer / rejected / withdrawn / archived\n- **Follow-up reminders**: automatically set 7 days after application, configurable per job\n- **Ghost detection**: flags applications with no response after 14 days\n- **ACTION REQUIRED card**: the dashboard highlights overdue follow-ups and ghost alerts front and center\n- **Email monitoring**: optional IMAP integration scans your inbox for responses from known ATS domains (Greenhouse, Lever, Workday, iCIMS, Ashby, and more)\n- **Real-time updates**: WebSocket connection pushes every change to the dashboard instantly -- no polling\n\n### Pluggable AI Backends\n\nClaude CLI (included with a Claude Pro/Max subscription) is the default backend. You can swap to any of the following, and each AI component can be configured independently:\n\n| Backend           | Configuration                | Notes                                               |\n| ----------------- | ---------------------------- | --------------------------------------------------- |\n| Claude CLI        | Default -- no setup required | Uses `claude -p` subprocess                         |\n| OpenAI            | API key + model name         | GPT-4o, GPT-4-turbo, or any OpenAI model            |\n| Ollama            | Local URL + model name       | Llama 3, Mistral, or any Ollama-supported model     |\n| OpenAI-compatible | Custom base URL              | Any API matching the OpenAI chat completions format |\n\nComponents that can be independently routed: scoring, cover letter generation, resume tailoring, form analysis, email classification, and profile analysis.\n\n### Setup Wizard\n\nOn first launch, MR.Jobs presents a guided setup wizard in the browser. No manual YAML editing is required to get started:\n\n1. Enter your personal information\n2. Upload your resume (PDF)\n3. Select target roles and skills\n4. Add target companies\n5. Configure preferences and thresholds\n\nThe wizard writes `profile.yaml` for you. Advanced users can still edit the file directly.\n\n---\n\n## Quick Start\n\n### Option 1: Docker (Recommended)\n\n```bash\ngit clone https://github.com/humancto/mr-jobs.git\ncd mrjobs\ndocker compose up\n```\n\nOpen [http://localhost:8080](http://localhost:8080) and complete the setup wizard.\n\nTo pass a Claude auth token for the default AI backend:\n\n```bash\nCLAUDE_AUTH_TOKEN=your_token docker compose up\n```\n\n### Option 2: Local Install\n\n```bash\ngit clone https://github.com/humancto/mr-jobs.git\ncd mrjobs\nbash setup.sh\npython3 main.py server --port 8080\n```\n\nOpen [http://localhost:8080](http://localhost:8080) and complete the setup wizard.\n\nThe setup script installs Python dependencies, the Claude Code CLI, and Playwright's Chromium browser.\n\n**Prerequisites:**\n\n- Python 3.11+\n- Node.js 18+ (for Claude Code CLI)\n\n### Option 3: CLI Only\n\n```bash\n# Complete the setup wizard first, or copy and edit profile.yaml manually\ncp profile.yaml.example profile.yaml\n\n# Discover and score jobs\npython3 main.py discover\n\n# Fill application forms without submitting\npython3 main.py apply --dry-run\n\n# View pipeline statistics\npython3 main.py stats\n```\n\n---\n\n## Configuration\n\nMR.Jobs is configured through `profile.yaml`. The setup wizard generates this file, or you can create it manually from `profile.yaml.example`.\n\n```yaml\npersonal:\n  first_name: Jane\n  last_name: Doe\n  email: jane@example.com\n  phone: \"+1-555-000-0000\"\n  location: San Francisco, CA\n  linkedin: https://linkedin.com/in/janedoe\n  github: https://github.com/janedoe\n\nresume_path: ./resume.pdf\n\npreferences:\n  roles:\n    - Software Engineer\n    - Backend Engineer\n    - Platform Engineer\n  keywords:\n    - Python\n    - distributed systems\n    - AI\n  min_match_score: 65\n  remote_only: false\n  locations:\n    - San Francisco\n    - Remote\n  exclude_companies:\n    - SomeCompany\n\nskills:\n  primary: [Python, Go, Rust, distributed systems]\n  secondary: [Kubernetes, Docker, AWS, PostgreSQL]\n\nideal_job_description: \u003e\n  A senior backend or platform engineering role at a technology\n  company building distributed systems or AI infrastructure.\n\nfavorite_companies: [anthropic, stripe, figma, vercel]\n\ntarget_boards:\n  greenhouse: [anthropic, stripe, figma, vercel, datadog]\n  lever: [anyscale]\n\nsearch:\n  enabled: true\n  queries: [Software Engineer, Backend Engineer]\n  locations: [San Francisco, CA, Remote]\n  distance_miles: 50\n  results_per_query: 25\n\ncustom_career_pages: []\n\nrate_limits:\n  max_applications_per_day: 25\n  min_delay_seconds: 60\n  max_delay_seconds: 180\n\nschedule:\n  discover_interval_hours: 6\n  score_interval_minutes: 30\n  enabled: true\n\nemail:\n  enabled: false\n  imap_server: imap.gmail.com\n  email: \"\"\n  app_password: \"\"\n  check_interval_hours: 12\n\nai:\n  default_backend: claude_cli\n  backends:\n    claude_cli:\n      timeout: 120\n    # openai:\n    #   api_key: ${OPENAI_API_KEY}\n    #   model: gpt-4o\n    # ollama:\n    #   base_url: http://localhost:11434\n    #   model: llama3\n  components:\n    scoring: claude_cli\n    cover_letter: claude_cli\n    resume_tailoring: claude_cli\n    form_analysis: claude_cli\n    email_classification: claude_cli\n    profile_analysis: claude_cli\n```\n\n---\n\n## CLI Reference\n\n| Command                               | Description                                                    |\n| ------------------------------------- | -------------------------------------------------------------- |\n| `python3 main.py server`              | Launch the web dashboard and background scheduler on port 8080 |\n| `python3 main.py server --port 3000`  | Launch on a custom port                                        |\n| `python3 main.py discover`            | Run all discovery sources and score found jobs                 |\n| `python3 main.py apply --dry-run`     | Discover, score, and fill forms without submitting             |\n| `python3 main.py apply --live`        | Discover, score, and submit real applications                  |\n| `python3 main.py single \u003curl\u003e`        | Fill a single job application form (dry run)                   |\n| `python3 main.py single \u003curl\u003e --live` | Submit a single real application                               |\n| `python3 main.py rescore`             | Re-score all unscored jobs in the database                     |\n| `python3 main.py stats`               | Print pipeline statistics to the terminal                      |\n| `python3 main.py reset`               | Delete all tracked jobs and start fresh                        |\n\n---\n\n## API Reference\n\nThe dashboard server exposes a REST API at `http://localhost:8080`. All endpoints return JSON.\n\n### Jobs\n\n| Method   | Endpoint           | Description                                                                 |\n| -------- | ------------------ | --------------------------------------------------------------------------- |\n| `GET`    | `/api/jobs`        | List jobs with optional filters: `status`, `company`, `min_score`, `search` |\n| `GET`    | `/api/jobs/{id}`   | Get full details for a single job                                           |\n| `PATCH`  | `/api/jobs/{id}`   | Update job status or notes                                                  |\n| `DELETE` | `/api/jobs/{id}`   | Remove a job from tracking                                                  |\n| `POST`   | `/api/jobs/ignore` | Add jobs to the ignore list                                                 |\n\n### Stats\n\n| Method | Endpoint              | Description                              |\n| ------ | --------------------- | ---------------------------------------- |\n| `GET`  | `/api/stats`          | Aggregate counts by status               |\n| `GET`  | `/api/stats/timeline` | Daily discovery and application activity |\n| `GET`  | `/api/stats/scores`   | Score distribution across all jobs       |\n| `GET`  | `/api/companies`      | List of all companies with job counts    |\n| `GET`  | `/api/statuses`       | Valid status values for filtering        |\n\n### Actions\n\n| Method | Endpoint            | Description                                           |\n| ------ | ------------------- | ----------------------------------------------------- |\n| `POST` | `/api/discover`     | Trigger a full discovery run across all sources       |\n| `POST` | `/api/score-all`    | Score all unscored jobs                               |\n| `POST` | `/api/rescore/{id}` | Re-score a specific job                               |\n| `POST` | `/api/ingest`       | Ingest externally discovered jobs (`{\"jobs\": [...]}`) |\n| `POST` | `/api/apply/{id}`   | Apply to a specific job via browser automation        |\n| `POST` | `/api/apply-batch`  | Apply to multiple jobs in sequence                    |\n| `POST` | `/api/check-email`  | Check email for application status updates            |\n| `POST` | `/api/purge`        | Purge jobs by criteria                                |\n\n### Follow-ups and Tailoring\n\n| Method | Endpoint                           | Description                                    |\n| ------ | ---------------------------------- | ---------------------------------------------- |\n| `GET`  | `/api/follow-ups`                  | List overdue follow-ups and ghost alerts       |\n| `POST` | `/api/jobs/{id}/follow-up`         | Set or update a follow-up reminder             |\n| `POST` | `/api/jobs/{id}/dismiss-follow-up` | Dismiss a follow-up reminder                   |\n| `POST` | `/api/jobs/{id}/tailor`            | Generate tailored resume content for a job     |\n| `GET`  | `/api/jobs/{id}/tailor`            | Retrieve previously generated tailored content |\n\n### Profile and Setup\n\n| Method  | Endpoint             | Description                                         |\n| ------- | -------------------- | --------------------------------------------------- |\n| `GET`   | `/api/profile`       | Read the current profile configuration              |\n| `PATCH` | `/api/profile`       | Update profile fields                               |\n| `POST`  | `/api/setup`         | Complete the first-run setup wizard                 |\n| `POST`  | `/api/profile/score` | AI analysis of profile strength and market position |\n| `GET`   | `/api/resumes`       | List uploaded resumes                               |\n| `POST`  | `/api/resumes`       | Upload a new resume (PDF)                           |\n\n### Scheduler\n\n| Method | Endpoint                       | Description                                                          |\n| ------ | ------------------------------ | -------------------------------------------------------------------- |\n| `GET`  | `/api/scheduler/status`        | Current scheduler state and next run times                           |\n| `POST` | `/api/scheduler/trigger/{job}` | Manually trigger a scheduled job (discover, score, email, follow_up) |\n\n---\n\n## Architecture\n\n```\n                    ┌──────────────────────┐\n                    │   MR.Jobs Dashboard   │\n                    │   localhost:8080      │\n                    └─────────┬────────────┘\n                              │ REST + WebSocket\n                    ┌─────────┴────────────┐\n                    │   FastAPI Server      │\n                    │   dashboard/server.py │\n                    └─────────┬────────────┘\n                              │\n           ┌──────────┬───────┴───────┬───────────┐\n           │          │               │            │\n     ┌─────┴───┐ ┌───┴────┐  ┌──────┴─────┐ ┌───┴──────┐\n     │ Discover │ │ Score  │  │   Track    │ │ Schedule │\n     │ Engine   │ │ Engine │  │   Engine   │ │  Engine  │\n     └─────┬───┘ └───┬────┘  └──────┬─────┘ └───┬──────┘\n           │          │              │            │\n           │     Pluggable LLM      │       APScheduler\n           │     Backends           │       - Discovery: 6h\n           │     (brain.py + llm.py)│       - Scoring: 30m\n           │          │              │       - Email: 12h\n           │          │              │       - Follow-ups: 6h\n           │          │              │\n    ┌──────┴──────────┴──────────────┴──────┐\n    │              SQLite (WAL)              │\n    │           applications.db             │\n    └───────────────────────────────────────┘\n```\n\n**Discovery Engine** pulls from all configured sources in parallel, deduplicates by normalized (title, company), and stores raw listings. **Score Engine** reads each job description and the candidate's resume, then calls the configured AI backend to produce scores, reasoning, and cover letters. **Track Engine** manages the SQLite database with WAL mode for safe concurrent access from CLI and dashboard. **Schedule Engine** uses APScheduler to run discovery, scoring, email checks, and follow-up detection on configurable intervals.\n\n---\n\n## File Structure\n\n```\nmrjobs/\n  main.py                          CLI entry point and command orchestrator\n  profile.yaml                     User configuration (created by setup wizard)\n  profile.yaml.example             Example configuration for reference\n  applications.db                  SQLite database (auto-created, WAL mode)\n  scheduler.py                     APScheduler background job definitions\n  requirements.txt                 Python dependencies\n  setup.sh                         Local installation script\n  Dockerfile                       Container image definition\n  docker-compose.yml               One-command Docker deployment\n\n  dashboard/\n    server.py                      FastAPI server, REST API, WebSocket hub\n    templates/\n      index.html                   Dashboard UI (Alpine.js + Tailwind CSS + Chart.js)\n    static/\n      app.js                       Dashboard application logic\n      style.css                    Dark mission-control theme\n\n  utils/\n    brain.py                       ClaudeBrain -- AI scoring and reasoning interface\n    llm.py                         Pluggable LLM backend system (Claude, OpenAI, Ollama)\n    tracker.py                     SQLite CRUD, schema migration, event broadcasting\n    discovery.py                   Source registry, deduplication, parallel discovery\n    resume_tailor.py               AI resume tailoring per job posting\n    resume_parser.py               PDF text extraction with caching\n    jobspy_source.py               python-jobspy (Indeed, LinkedIn, Glassdoor, ZipRecruiter, Google)\n    rss_source.py                  RemoteOK JSON API\n    hn_source.py                   HN \"Who is Hiring\" via Algolia API\n    adzuna_source.py               Adzuna API integration\n    career_page_source.py          Playwright + AI career page scraping\n    mcp_source.py                  MCP tool helpers and search query generation\n    email_checker.py               IMAP email monitoring and classification\n    events.py                      EventBus singleton (sync emit to async broadcast)\n    answers.py                     Form answer pattern matching\n\n  adapters/\n    greenhouse.py                  Greenhouse ATS form automation\n    generic.py                     AI-driven generic form filler (any ATS)\n\n  service/\n    install.sh                     macOS LaunchAgent installer (run as background service)\n    uninstall.sh                   LaunchAgent uninstaller\n```\n\n---\n\n## Safety Features\n\nMR.Jobs is designed to keep you in control at every step:\n\n- **Dry run by default** -- the `apply` command fills forms but never submits unless you explicitly pass `--live`\n- **Daily application limits** -- configurable cap (default: 25 per day) prevents runaway submissions\n- **Rate limiting** -- randomized delays between applications (60-180s default) to avoid detection\n- **Deduplication** -- jobs are deduplicated by normalized (title, company) across all sources and runs\n- **Headed browser** -- Playwright runs in visible mode so you can watch every action and intervene\n- **Confirmation required** -- the dashboard requires explicit confirmation before submitting real applications\n- **Source isolation** -- each discovery source runs in its own try/except block; one failure never breaks the others\n- **No data leaves your machine** -- everything runs locally; the only external calls are to job board APIs and your configured AI backend\n\n---\n\n## Background Scheduling\n\nWhen running in server mode, MR.Jobs automatically schedules background jobs:\n\n| Job             | Default Interval | Description                                        |\n| --------------- | ---------------- | -------------------------------------------------- |\n| Discovery       | Every 6 hours    | Scans all configured sources for new listings      |\n| Scoring         | Every 30 minutes | Scores any unscored jobs in the database           |\n| Email Check     | Every 12 hours   | Scans inbox for application responses (if enabled) |\n| Follow-up Check | Every 6 hours    | Flags overdue follow-ups and ghost applications    |\n\nAll intervals are configurable in `profile.yaml` under the `schedule` section. The scheduler can be disabled entirely by setting `schedule.enabled: false`.\n\nYou can manually trigger any scheduled job from the dashboard or via the API:\n\n```bash\ncurl -X POST http://localhost:8080/api/scheduler/trigger/discover\ncurl -X POST http://localhost:8080/api/scheduler/trigger/score\n```\n\n---\n\n## Contributing\n\nContributions are welcome. Here is how to get started:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/your-feature`)\n3. Make your changes, following the existing code style\n4. Test your changes locally (`python3 main.py discover` for discovery changes, launch the server for API/dashboard changes)\n5. Commit with a clear message describing what and why\n6. Open a pull request against `main`\n\n**Guidelines:**\n\n- Each discovery source must be independently optional -- wrap source calls in try/except\n- New API endpoints should emit events via `EventBus` for real-time dashboard updates\n- SQLite access must use WAL mode (`PRAGMA journal_mode=WAL`)\n- AI subprocess calls must strip the `CLAUDECODE` environment variable to prevent nested session errors\n- Keep the dashboard responsive -- long operations should run as background tasks via `asyncio.create_task`\n\nIssues are welcome for bug reports, feature requests, and questions.\n\n---\n\n## License\n\nMIT\n\n---\n\n## Acknowledgments\n\n- Built with [Claude](https://claude.ai) by Anthropic\n- [python-jobspy](https://github.com/Bunsly/JobSpy) for aggregated job search across Indeed, LinkedIn, Glassdoor, ZipRecruiter, and Google\n- [Playwright](https://playwright.dev/) for reliable browser automation\n- [FastAPI](https://fastapi.tiangolo.com/) for the REST API and WebSocket server\n- [Alpine.js](https://alpinejs.dev/) and [Tailwind CSS](https://tailwindcss.com/) for the dashboard UI\n- [APScheduler](https://apscheduler.readthedocs.io/) for background job scheduling\n- The open source community\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumancto%2Fmr-jobs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhumancto%2Fmr-jobs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumancto%2Fmr-jobs/lists"}