All notable changes to ApplyPilot will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Parallel workers for discovery/enrichment -
applypilot run --workers Nenables ThreadPoolExecutor-based parallelism for Workday scraping, smart extract, and detail enrichment. Default is sequential (1); power users can scale up. - Apply utility modes -
--gen(generate prompt for manual debugging),--mark-applied,--mark-failed,--reset-failedflags onapplypilot apply - Dry-run mode -
applypilot apply --dry-runfills forms without clicking Submit - 5 new tracking columns -
agent_id,last_attempted_at,apply_duration_ms,apply_task_id,verification_confidencefor better apply-stage observability - Manual ATS detection -
manual_atslist inconfig/sites.yamlskips sites with unsolvable CAPTCHAs (e.g. TCS iBegin) - Qwen3
/no_thinkoptimization - automatically saves tokens when using Qwen models config.DEFAULTS- centralized dict for magic numbers (min_score,max_apply_attempts,poll_interval,apply_timeout,viewport)
- Config YAML not found after install - moved
config/into the package atsrc/applypilot/config/so YAML files (employers, sites, searches) ship withpip install - Search config format mismatch - wizard wrote
searches:key but discovery code expectedqueries:with tier support. Aligned wizard output and example config - JobSpy install isolation - removed python-jobspy from package dependencies due to
broken numpy==1.26.3 exact pin in jobspy metadata. Installed separately with
--no-deps - Scoring batch limit - default limit of 50 silently left jobs unscored across runs. Changed to no limit (scores all pending jobs in one pass)
- Missing logging output - added
logging.basicConfig(INFO)so per-job progress for scoring, tailoring, and cover letters is visible during pipeline runs
- Blocked sites externalized - moved from hardcoded sets in launcher.py to
config/sites.yamlunderblocked:key - Site base URLs externalized - moved from hardcoded dict in detail.py to
config/sites.yamlunderbase_urls:key - SSO domains externalized - moved from hardcoded list in prompt.py to
config/sites.yamlunderblocked_sso:key - Prompt improvements - screening context uses
target_rolefrom profile, salary section includescurrency_conversion_noteand dynamic hourly rate examples acquire_job()fixed - writesagent_idandlast_attempted_atto proper columns instead of misusingapply_errorprofile.example.json- addedcurrency_conversion_noteandtarget_rolefields
- 6-stage pipeline: discover, enrich, score, tailor, cover letter, apply
- Multi-source job discovery: Indeed, LinkedIn, Glassdoor, ZipRecruiter, Google Jobs
- Workday employer portal support (46 preconfigured employers)
- Direct career site scraping (28 preconfigured sites)
- 3-tier job description extraction cascade (JSON-LD, CSS selectors, AI fallback)
- AI-powered job scoring (1-10 fit scale with rationale)
- Resume tailoring with factual preservation (no fabrication)
- Cover letter generation per job
- Autonomous browser-based application submission via Playwright
- Interactive setup wizard (
applypilot init) - Cross-platform Chrome/Chromium detection (Windows, macOS, Linux)
- Multi-provider LLM support (Gemini, OpenAI, local models via OpenAI-compatible endpoints)
- Pipeline stats and HTML results dashboard
- YAML-based configuration for employers, career sites, and search queries
- Job deduplication across sources
- Configurable score threshold filtering
- Safety limits for maximum applications per run
- Detailed application results logging