applypilot 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. applypilot-0.2.0/.env.example +14 -0
  2. applypilot-0.2.0/.github/workflows/ci.yml +29 -0
  3. applypilot-0.2.0/.github/workflows/publish.yml +31 -0
  4. applypilot-0.2.0/.gitignore +41 -0
  5. applypilot-0.2.0/CHANGELOG.md +70 -0
  6. applypilot-0.2.0/CONTRIBUTING.md +149 -0
  7. applypilot-0.2.0/LICENSE +661 -0
  8. applypilot-0.2.0/PKG-INFO +219 -0
  9. applypilot-0.2.0/README.md +187 -0
  10. applypilot-0.2.0/profile.example.json +61 -0
  11. applypilot-0.2.0/pyproject.toml +54 -0
  12. applypilot-0.2.0/src/applypilot/__init__.py +3 -0
  13. applypilot-0.2.0/src/applypilot/__main__.py +5 -0
  14. applypilot-0.2.0/src/applypilot/apply/__init__.py +1 -0
  15. applypilot-0.2.0/src/applypilot/apply/chrome.py +321 -0
  16. applypilot-0.2.0/src/applypilot/apply/dashboard.py +203 -0
  17. applypilot-0.2.0/src/applypilot/apply/launcher.py +785 -0
  18. applypilot-0.2.0/src/applypilot/apply/prompt.py +624 -0
  19. applypilot-0.2.0/src/applypilot/cli.py +316 -0
  20. applypilot-0.2.0/src/applypilot/config/employers.yaml +305 -0
  21. applypilot-0.2.0/src/applypilot/config/searches.example.yaml +112 -0
  22. applypilot-0.2.0/src/applypilot/config/sites.yaml +181 -0
  23. applypilot-0.2.0/src/applypilot/config.py +260 -0
  24. applypilot-0.2.0/src/applypilot/database.py +424 -0
  25. applypilot-0.2.0/src/applypilot/discovery/__init__.py +0 -0
  26. applypilot-0.2.0/src/applypilot/discovery/jobspy.py +478 -0
  27. applypilot-0.2.0/src/applypilot/discovery/smartextract.py +1118 -0
  28. applypilot-0.2.0/src/applypilot/discovery/workday.py +543 -0
  29. applypilot-0.2.0/src/applypilot/enrichment/__init__.py +0 -0
  30. applypilot-0.2.0/src/applypilot/enrichment/detail.py +894 -0
  31. applypilot-0.2.0/src/applypilot/llm.py +158 -0
  32. applypilot-0.2.0/src/applypilot/pipeline.py +531 -0
  33. applypilot-0.2.0/src/applypilot/scoring/__init__.py +1 -0
  34. applypilot-0.2.0/src/applypilot/scoring/cover_letter.py +286 -0
  35. applypilot-0.2.0/src/applypilot/scoring/pdf.py +440 -0
  36. applypilot-0.2.0/src/applypilot/scoring/scorer.py +180 -0
  37. applypilot-0.2.0/src/applypilot/scoring/tailor.py +562 -0
  38. applypilot-0.2.0/src/applypilot/scoring/validator.py +315 -0
  39. applypilot-0.2.0/src/applypilot/view.py +406 -0
  40. applypilot-0.2.0/src/applypilot/wizard/__init__.py +0 -0
  41. applypilot-0.2.0/src/applypilot/wizard/init.py +381 -0
@@ -0,0 +1,14 @@
1
+ # ApplyPilot Environment Configuration
2
+ # Copy to ~/.applypilot/.env and fill in your values.
3
+
4
+ # LLM Provider (pick one)
5
+ GEMINI_API_KEY= # Gemini 2.0 Flash (recommended, cheapest)
6
+ # OPENAI_API_KEY= # OpenAI (GPT-4o-mini)
7
+ # LLM_URL=http://127.0.0.1:8080/v1 # Local LLM (llama.cpp, Ollama)
8
+ # LLM_MODEL= # Override model name
9
+
10
+ # Auto-Apply (optional)
11
+ CAPSOLVER_API_KEY= # For CAPTCHA solving during auto-apply
12
+
13
+ # Proxy (optional, for scraping)
14
+ # PROXY=host:port:user:pass
@@ -0,0 +1,29 @@
1
+ name: CI
2
+
3
+ on:
4
+ workflow_dispatch: # manual trigger only
5
+
6
+ jobs:
7
+ test:
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ python-version: ["3.11", "3.12", "3.13"]
12
+
13
+ steps:
14
+ - name: Checkout
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up Python ${{ matrix.python-version }}
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+
22
+ - name: Install dependencies
23
+ run: pip install -e ".[dev]"
24
+
25
+ - name: Lint
26
+ run: ruff check src/
27
+
28
+ - name: Test
29
+ run: pytest tests/ -v
@@ -0,0 +1,31 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ environment: pypi
12
+ permissions:
13
+ id-token: write # required for OIDC trusted publishing
14
+
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: "3.12"
23
+
24
+ - name: Install build tools
25
+ run: pip install build
26
+
27
+ - name: Build package
28
+ run: python -m build
29
+
30
+ - name: Publish to PyPI
31
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,41 @@
1
+ # User data (NEVER commit)
2
+ profile.json
3
+ resume.txt
4
+ resume.pdf
5
+ *.env
6
+ .env.*
7
+ !.env.example
8
+
9
+ # Runtime artifacts
10
+ *.db
11
+ tailored_resumes/
12
+ cover_letters/
13
+ chrome-workers/
14
+ apply-workers/
15
+ apply_logs/
16
+ logs/
17
+
18
+ # MCP configs (per-machine)
19
+ .mcp*.json
20
+
21
+ # Python
22
+ __pycache__/
23
+ *.py[cod]
24
+ *$py.class
25
+ *.egg-info/
26
+ dist/
27
+ build/
28
+ *.egg
29
+
30
+ # IDE
31
+ .vscode/
32
+ .idea/
33
+ *.swp
34
+ *.swo
35
+
36
+ # OS
37
+ .DS_Store
38
+ Thumbs.db
39
+
40
+ # Claude Code
41
+ .claude/
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ All notable changes to ApplyPilot will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.0] - 2026-02-17
9
+
10
+ ### Added
11
+ - **Parallel workers for discovery/enrichment** - `applypilot run --workers N` enables
12
+ ThreadPoolExecutor-based parallelism for Workday scraping, smart extract, and detail
13
+ enrichment. Default is sequential (1); power users can scale up.
14
+ - **Apply utility modes** - `--gen` (generate prompt for manual debugging), `--mark-applied`,
15
+ `--mark-failed`, `--reset-failed` flags on `applypilot apply`
16
+ - **Dry-run mode** - `applypilot apply --dry-run` fills forms without clicking Submit
17
+ - **5 new tracking columns** - `agent_id`, `last_attempted_at`, `apply_duration_ms`,
18
+ `apply_task_id`, `verification_confidence` for better apply-stage observability
19
+ - **Manual ATS detection** - `manual_ats` list in `config/sites.yaml` skips sites with
20
+ unsolvable CAPTCHAs (e.g. TCS iBegin)
21
+ - **Qwen3 `/no_think` optimization** - automatically saves tokens when using Qwen models
22
+ - **`config.DEFAULTS`** - centralized dict for magic numbers (`min_score`, `max_apply_attempts`,
23
+ `poll_interval`, `apply_timeout`, `viewport`)
24
+
25
+ ### Fixed
26
+ - **Config YAML not found after install** - moved `config/` into the package at
27
+ `src/applypilot/config/` so YAML files (employers, sites, searches) ship with `pip install`
28
+ - **Search config format mismatch** - wizard wrote `searches:` key but discovery code
29
+ expected `queries:` with tier support. Aligned wizard output and example config
30
+ - **JobSpy install isolation** - removed python-jobspy from package dependencies due to
31
+ broken numpy==1.26.3 exact pin in jobspy metadata. Installed separately with `--no-deps`
32
+ - **Scoring batch limit** - default limit of 50 silently left jobs unscored across runs.
33
+ Changed to no limit (scores all pending jobs in one pass)
34
+ - **Missing logging output** - added `logging.basicConfig(INFO)` so per-job progress for
35
+ scoring, tailoring, and cover letters is visible during pipeline runs
36
+
37
+ ### Changed
38
+ - **Blocked sites externalized** - moved from hardcoded sets in launcher.py to
39
+ `config/sites.yaml` under `blocked:` key
40
+ - **Site base URLs externalized** - moved from hardcoded dict in detail.py to
41
+ `config/sites.yaml` under `base_urls:` key
42
+ - **SSO domains externalized** - moved from hardcoded list in prompt.py to
43
+ `config/sites.yaml` under `blocked_sso:` key
44
+ - **Prompt improvements** - screening context uses `target_role` from profile,
45
+ salary section includes `currency_conversion_note` and dynamic hourly rate examples
46
+ - **`acquire_job()` fixed** - writes `agent_id` and `last_attempted_at` to proper columns
47
+ instead of misusing `apply_error`
48
+ - **`profile.example.json`** - added `currency_conversion_note` and `target_role` fields
49
+
50
+ ## [0.1.0] - 2026-02-17
51
+
52
+ ### Added
53
+ - 6-stage pipeline: discover, enrich, score, tailor, cover letter, apply
54
+ - Multi-source job discovery: Indeed, LinkedIn, Glassdoor, ZipRecruiter, Google Jobs
55
+ - Workday employer portal support (46 preconfigured employers)
56
+ - Direct career site scraping (28 preconfigured sites)
57
+ - 3-tier job description extraction cascade (JSON-LD, CSS selectors, AI fallback)
58
+ - AI-powered job scoring (1-10 fit scale with rationale)
59
+ - Resume tailoring with factual preservation (no fabrication)
60
+ - Cover letter generation per job
61
+ - Autonomous browser-based application submission via Playwright
62
+ - Interactive setup wizard (`applypilot init`)
63
+ - Cross-platform Chrome/Chromium detection (Windows, macOS, Linux)
64
+ - Multi-provider LLM support (Gemini, OpenAI, local models via OpenAI-compatible endpoints)
65
+ - Pipeline stats and HTML results dashboard
66
+ - YAML-based configuration for employers, career sites, and search queries
67
+ - Job deduplication across sources
68
+ - Configurable score threshold filtering
69
+ - Safety limits for maximum applications per run
70
+ - Detailed application results logging
@@ -0,0 +1,149 @@
1
+ # Contributing to ApplyPilot
2
+
3
+ Thank you for your interest in contributing to ApplyPilot. This guide covers everything you need to get started.
4
+
5
+ ## Development Setup
6
+
7
+ ### Prerequisites
8
+
9
+ - Python 3.11 or higher
10
+ - Git
11
+
12
+ ### Clone and Install
13
+
14
+ ```bash
15
+ git clone https://github.com/Pickle-Pixel/ApplyPilot.git
16
+ cd ApplyPilot
17
+ pip install -e ".[dev]"
18
+ playwright install chromium
19
+ ```
20
+
21
+ This installs ApplyPilot in editable mode with all development dependencies (pytest, ruff, etc.) and downloads the Chromium browser binary for Playwright.
22
+
23
+ ### Verify Installation
24
+
25
+ ```bash
26
+ applypilot --version
27
+ pytest tests/ -v
28
+ ruff check src/
29
+ ```
30
+
31
+ ## How to Contribute
32
+
33
+ ### Adding New Workday Employers
34
+
35
+ Workday employer portals are configured in `config/employers.yaml`. To add a new employer:
36
+
37
+ 1. Find the company's Workday career portal URL (usually `https://company.wd5.myworkdaysite.com/`)
38
+ 2. Identify the Workday instance number (wd1, wd3, wd5, etc.) and the tenant ID
39
+ 3. Add an entry to `config/employers.yaml`:
40
+
41
+ ```yaml
42
+ - name: "Company Name"
43
+ tenant: "company_tenant_id"
44
+ instance: "wd5"
45
+ url: "https://company.wd5.myworkdaysite.com/en-US/recruiting"
46
+ ```
47
+
48
+ 4. Test discovery: `applypilot discover --employer "Company Name"`
49
+ 5. Submit a PR with the new entry
50
+
51
+ ### Adding New Career Sites
52
+
53
+ Direct career site scrapers are configured in `config/sites.yaml`. To add a new site:
54
+
55
+ 1. Inspect the company's careers page and identify the job listing structure
56
+ 2. Add an entry to `config/sites.yaml` with CSS selectors:
57
+
58
+ ```yaml
59
+ - name: "Company Name"
60
+ url: "https://company.com/careers"
61
+ selectors:
62
+ job_list: ".job-listing"
63
+ title: ".job-title"
64
+ location: ".job-location"
65
+ link: "a.job-link"
66
+ description: ".job-description"
67
+ ```
68
+
69
+ 3. Test: `applypilot discover --site "Company Name"`
70
+ 4. Submit a PR
71
+
72
+ ### Bug Fixes and Features
73
+
74
+ 1. Check existing [issues](https://github.com/Pickle-Pixel/ApplyPilot/issues) to avoid duplicating work
75
+ 2. For new features, open an issue first to discuss the approach
76
+ 3. Fork the repo and create a feature branch from `main`
77
+ 4. Write your code with type hints and docstrings
78
+ 5. Add tests for new functionality
79
+ 6. Update the CHANGELOG.md under an `[Unreleased]` section
80
+ 7. Submit a PR
81
+
82
+ ## Running Tests
83
+
84
+ ```bash
85
+ # Run all tests
86
+ pytest tests/ -v
87
+
88
+ # Run a specific test file
89
+ pytest tests/test_scoring.py -v
90
+
91
+ # Run with coverage
92
+ pytest tests/ --cov=src/applypilot --cov-report=term-missing
93
+ ```
94
+
95
+ ## Linting and Code Style
96
+
97
+ ApplyPilot uses [Ruff](https://docs.astral.sh/ruff/) for linting and formatting.
98
+
99
+ ```bash
100
+ # Check for issues
101
+ ruff check src/
102
+
103
+ # Auto-fix what can be fixed
104
+ ruff check src/ --fix
105
+
106
+ # Format code
107
+ ruff format src/
108
+ ```
109
+
110
+ ### Code Style Guidelines
111
+
112
+ - **Type hints**: All function signatures must have type annotations
113
+ - **Docstrings**: All public functions and classes must have docstrings (Google style)
114
+ - **Naming**: snake_case for functions and variables, PascalCase for classes
115
+ - **Imports**: Sorted by Ruff (isort-compatible)
116
+ - **Line length**: 100 characters maximum
117
+
118
+ ## PR Guidelines
119
+
120
+ - **One feature per PR.** Keep changes focused and reviewable.
121
+ - **Include tests.** New features need test coverage. Bug fixes need a regression test.
122
+ - **Update CHANGELOG.md.** Add your changes under `[Unreleased]`.
123
+ - **Write a clear PR description.** Explain what changed and why.
124
+ - **Keep commits clean.** Squash fixup commits before requesting review.
125
+ - **CI must pass.** All linting and tests must be green.
126
+
127
+ ## Project Structure
128
+
129
+ ```
130
+ ApplyPilot/
131
+ ├── src/applypilot/ # Main package
132
+ │ ├── __init__.py
133
+ │ ├── cli.py # CLI entry points
134
+ │ ├── discover/ # Stage 1: job discovery scrapers
135
+ │ ├── enrich/ # Stage 2: description extraction
136
+ │ ├── score/ # Stage 3: AI scoring
137
+ │ ├── tailor/ # Stage 4: resume tailoring
138
+ │ ├── cover/ # Stage 5: cover letter generation
139
+ │ ├── apply/ # Stage 6: browser automation
140
+ │ └── utils/ # Shared utilities
141
+ ├── config/ # Default configuration files
142
+ ├── tests/ # Test suite
143
+ ├── docs/ # Documentation
144
+ └── pyproject.toml # Package configuration
145
+ ```
146
+
147
+ ## License
148
+
149
+ By contributing to ApplyPilot, you agree that your contributions will be licensed under the [GNU Affero General Public License v3.0](LICENSE).