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.
- applypilot-0.2.0/.env.example +14 -0
- applypilot-0.2.0/.github/workflows/ci.yml +29 -0
- applypilot-0.2.0/.github/workflows/publish.yml +31 -0
- applypilot-0.2.0/.gitignore +41 -0
- applypilot-0.2.0/CHANGELOG.md +70 -0
- applypilot-0.2.0/CONTRIBUTING.md +149 -0
- applypilot-0.2.0/LICENSE +661 -0
- applypilot-0.2.0/PKG-INFO +219 -0
- applypilot-0.2.0/README.md +187 -0
- applypilot-0.2.0/profile.example.json +61 -0
- applypilot-0.2.0/pyproject.toml +54 -0
- applypilot-0.2.0/src/applypilot/__init__.py +3 -0
- applypilot-0.2.0/src/applypilot/__main__.py +5 -0
- applypilot-0.2.0/src/applypilot/apply/__init__.py +1 -0
- applypilot-0.2.0/src/applypilot/apply/chrome.py +321 -0
- applypilot-0.2.0/src/applypilot/apply/dashboard.py +203 -0
- applypilot-0.2.0/src/applypilot/apply/launcher.py +785 -0
- applypilot-0.2.0/src/applypilot/apply/prompt.py +624 -0
- applypilot-0.2.0/src/applypilot/cli.py +316 -0
- applypilot-0.2.0/src/applypilot/config/employers.yaml +305 -0
- applypilot-0.2.0/src/applypilot/config/searches.example.yaml +112 -0
- applypilot-0.2.0/src/applypilot/config/sites.yaml +181 -0
- applypilot-0.2.0/src/applypilot/config.py +260 -0
- applypilot-0.2.0/src/applypilot/database.py +424 -0
- applypilot-0.2.0/src/applypilot/discovery/__init__.py +0 -0
- applypilot-0.2.0/src/applypilot/discovery/jobspy.py +478 -0
- applypilot-0.2.0/src/applypilot/discovery/smartextract.py +1118 -0
- applypilot-0.2.0/src/applypilot/discovery/workday.py +543 -0
- applypilot-0.2.0/src/applypilot/enrichment/__init__.py +0 -0
- applypilot-0.2.0/src/applypilot/enrichment/detail.py +894 -0
- applypilot-0.2.0/src/applypilot/llm.py +158 -0
- applypilot-0.2.0/src/applypilot/pipeline.py +531 -0
- applypilot-0.2.0/src/applypilot/scoring/__init__.py +1 -0
- applypilot-0.2.0/src/applypilot/scoring/cover_letter.py +286 -0
- applypilot-0.2.0/src/applypilot/scoring/pdf.py +440 -0
- applypilot-0.2.0/src/applypilot/scoring/scorer.py +180 -0
- applypilot-0.2.0/src/applypilot/scoring/tailor.py +562 -0
- applypilot-0.2.0/src/applypilot/scoring/validator.py +315 -0
- applypilot-0.2.0/src/applypilot/view.py +406 -0
- applypilot-0.2.0/src/applypilot/wizard/__init__.py +0 -0
- 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).
|