Skip to main content

DivApply: AI-assisted end-to-end job application pipeline

Project description

DivApply

DivApply is a local-first job application assistant. It can find jobs, enrich postings, score fit, tailor resumes, write cover letters, export PDFs, and optionally help with browser-based applications.

It is designed to stay factual: it works from your profile, resume, saved preferences, and optional coursework notes. It should not invent jobs, credentials, degrees, tools, dates, metrics, or experience.

What It Does

discover -> enrich -> score -> tailor -> cover -> pdf -> apply
  • Finds jobs from configured searches and direct sources.
  • Expands postings with full descriptions and application links.
  • Scores jobs against your real experience and required criteria.
  • Separates required qualifications from preferred/nice-to-have items.
  • Generates one-page tailored resumes and cover letters.
  • Exports safe job tracking data.
  • Can run browser apply flows only when you confirm it.

Quick Start

Use Python 3.12 for the smoothest setup. The maintained Windows setup for this project currently uses Python 3.12.13. Python 3.14 may be installed on the same PC, but JobSpy-backed discovery is still expected to run from the Python 3.12 environment because of upstream dependency pins.

Recommended CLI install with pip:

python --version  # expected on the maintained Windows setup: Python 3.12.13
python -m pip install --upgrade pip
python -m pip install --upgrade "divapply[full]"
python -m pip install --no-deps "https://files.pythonhosted.org/packages/d5/2b/18863fcd3c544a69d81e351381a50036a33c21b61cc1c6de2a8f25931237/python_jobspy-1.1.82-py3-none-any.whl#sha256=93d638b35ffd30a714253e065907f68c5bac624e3937a3ad2ba09f618a072ee9"
python -m playwright install chromium
divapply init
divapply edit
divapply doctor

Virtualenv install, if you want the dependencies isolated:

python --version  # expected on the maintained Windows setup: Python 3.12.13
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install --upgrade "divapply[full]"
python -m pip install --no-deps "https://files.pythonhosted.org/packages/d5/2b/18863fcd3c544a69d81e351381a50036a33c21b61cc1c6de2a8f25931237/python_jobspy-1.1.82-py3-none-any.whl#sha256=93d638b35ffd30a714253e065907f68c5bac624e3937a3ad2ba09f618a072ee9"
python -m playwright install chromium
divapply init
divapply edit
divapply doctor

Alternative development install from the current GitHub main branch:

python --version  # expected on the maintained Windows setup: Python 3.12.13
python -m pip install --upgrade "divapply[full] @ git+https://github.com/InnitDivine/DivApply.git"
python -m pip install --no-deps "https://files.pythonhosted.org/packages/d5/2b/18863fcd3c544a69d81e351381a50036a33c21b61cc1c6de2a8f25931237/python_jobspy-1.1.82-py3-none-any.whl#sha256=93d638b35ffd30a714253e065907f68c5bac624e3937a3ad2ba09f618a072ee9"

Use divapply without extras for the lightest install. Use divapply[coursework] for PDF transcript import, divapply[jobspy-runtime] for the secure JobSpy runtime dependency floor, or divapply[full] for both coursework and JobSpy runtime dependencies. Because the current python-jobspy package pins markdownify<0.14.0, which conflicts with the CVE-2025-46656 fix in markdownify>=0.14.1, install DivApply's secure dependency floor first, then install the exact hash-verified JobSpy 1.1.82 wheel shown above with --no-deps. Run python -m divapply.jobspy_runtime to verify every installed JobSpy dependency bound. Until upstream relaxes that pin, pip check may still report the intentional Markdownify metadata conflict even when pip-audit and DivApply's runtime validator pass.

On Windows, DivApply installs plain divapply/divapply.cmd launchers instead of relying on a generated divapply.exe, so managed PCs that block generated console-script executables can still run divapply directly from cmd.

Auto-apply mode also needs Node.js 18+ and an agent CLI such as Codex or Claude Code. It uses DIVAPPLY_BROWSER when configured, otherwise it defaults to Playwright Chromium, which is installed by the quick-start command. Firefox is optional and only needed if you explicitly run divapply apply --browser firefox.

Clone Setup

Use this if you want the repo files locally.

git clone https://github.com/InnitDivine/DivApply.git
cd DivApply
.\install.ps1

Update an existing clone:

git pull
python -m pip install --upgrade -e ".[full]"
python -m pip install --no-deps "https://files.pythonhosted.org/packages/d5/2b/18863fcd3c544a69d81e351381a50036a33c21b61cc1c6de2a8f25931237/python_jobspy-1.1.82-py3-none-any.whl#sha256=93d638b35ffd30a714253e065907f68c5bac624e3937a3ad2ba09f618a072ee9"

First Run

divapply init
divapply edit

This creates your local app folder and setup files:

  • profile.json - applicant facts such as personal details, compensation, work history, education, and verified skills
  • resume.txt - master resume facts
  • searches.yaml - job searches and filters
  • .env - API keys and runtime settings
  • divapply.db - local jobs database

These files are private and ignored by git.

Use divapply edit as the normal setup screen after initialization. It opens a local-only browser editor for:

  • Personal/contact details
  • Compensation and verified skills
  • Work history, education, certifications, references, projects, and real metrics
  • Search roles, schedule/work-type filters, locations, query tiers, job boards, and filters

The editor saves applicant facts to profile.json and job-search intent to searches.yaml, so most users do not need to hand-edit JSON or YAML.

Keep profile.json factual: identity, work authorization, pay answers, work history, education, verified skills, references, and reusable application answers. Do not put preferred job titles, employers, locations, reject lists, or search strategy in the profile; put those in searches.yaml so scoring is driven by the current search instead of stale profile prose.

Daily Workflow

divapply doctor
divapply run
divapply status
divapply export jobs --out jobs.csv

Useful targeted runs:

divapply run discover enrich
divapply run score tailor cover
divapply explain https://example.com/job

Use dry runs before any real browser submission:

divapply apply --dry-run
divapply apply --gen --url https://example.com/job
divapply apply --yes

Auto-apply launches a dedicated Chromium browser session for each worker, navigates to application pages, fills supported form fields from your profile and resume facts, uploads generated documents when available, answers screening questions through the selected agent backend, and shows progress in the live terminal dashboard.

The apply agent is launched without host shell access and with an exact browser-tool allowlist. CAPTCHA solving fails closed with RESULT:CAPTCHA; DivApply never puts a CAPTCHA-service key or host-command recipe in the agent prompt. Gmail automation is unavailable because the former integration is archived and its latest dependency tree has known High-severity advisories. Email-only applications and email verification therefore fail closed with RESULT:FAILED:email_required.

Cost-safe defaults are intentionally conservative: real auto-apply runs default to one job and one worker, and higher limits, multiple workers, unlimited continuous polling, or unbounded runs require --allow-expensive. Start with divapply apply --dry-run --limit 1, then use divapply apply --yes --limit 1 for the lowest-cost real run.

Saved job-site logins are local-only and belong in ~/.divapply/credentials.yaml, not profile.json or Git:

divapply credentials --username you@example.com
divapply credentials --site workdayjobs.com --username you@example.com
divapply credentials --show

Omit --password and DivApply prompts for it without echoing it. Use site-specific entries for employers that need a different login.

To avoid signing in repeatedly, open the same persistent browser profile used by auto-apply, sign in once, complete any two-factor challenge, then close the browser:

divapply browser-login --url https://www.myworkday.com/
divapply browser-login --url https://imh.wd108.myworkdayjobs.com/IntermountainCareers

Future divapply apply --workers 1 runs reuse the worker-0 profile cookies for the configured browser. Use the same --browser and --worker values for login and apply when overriding the configured browser.

DivApply creates blank, dedicated worker profiles; it never copies your personal Chrome profile or another worker's cookies. Chrome worker profiles created by older DivApply releases are intentionally refused because they may contain copied personal browser credentials. Preserve an old profile as a backup, create a fresh dedicated profile, and sign in intentionally:

Move-Item "$HOME\.divapply\chrome-workers\worker-0" "$HOME\.divapply\chrome-workers\worker-0.legacy-backup"
divapply browser-login --browser chrome --worker 0 --url https://www.myworkday.com/

The apply agent cannot execute page JavaScript or arbitrary browser code. DivApply records applied only when the agent's final three nonempty lines provide a matching submission origin, visible confirmation evidence, and exact RESULT:APPLIED; this remains a conservative model-reported check, so verify important submissions with the employer.

If Google says "This browser or app may not be secure", use real Chrome for both login and apply:

divapply browser-login --browser chrome --url https://www.myworkday.com/
divapply apply --browser chrome --backend codex --model gpt-5.4-mini --dry-run --limit 1 --workers 1

To make real Chrome the default saved-cookie browser, set DIVAPPLY_BROWSER=chrome in ~/.divapply/.env. Then both divapply browser-login and divapply apply use the Chrome worker profile unless you explicitly pass a different --browser.

Auto-apply has a bounded 45-minute per-job timeout by default, plus a 5-minute no-output timeout. Multi-step ATS flows can take several minutes; for fail-fast testing, set a shorter timeout for that session:

$env:DIVAPPLY_APPLY_TIMEOUT="900"
divapply apply --backend codex --model gpt-5.4-mini --dry-run --limit 1 --workers 1

Search Config

searches.yaml controls what DivApply looks for.

Example:

queries:
  - query: "student assistant"
    tier: 1
  - query: "front desk"
    tier: 2
  - query: "customer service"
    tier: 3
locations:
  - location: "Exampletown, UT"
    remote: false
  - location: "Remote"
    remote: true
country: "USA"
boards:
  - indeed
  - linkedin
defaults:
  results_per_site: 50
  hours_old: 168

Tier 1 should be your best, most specific searches. Tier 2 should be strong adjacent matches. Tier 3 should be broad fallback searches. Keep job titles in queries, places in locations, schedule intent in require_part_time, and boards in boards. DivApply derives normal location filtering from locations; manual filters such as location.accept_patterns, reject_patterns, exclude_titles, excluded_keywords, and customer-service-specific hour filters are optional escape hatches only when a board repeatedly returns results that need cleanup before scoring.

Older search configs still load, but divapply selfcheck warns on legacy aliases so you can migrate gradually: search_terms -> queries, job_boards or sites -> boards, nearby_locations -> locations, reject_locations -> location.reject_patterns, target_titles -> include_titles, avoid_titles -> exclude_titles, and avoid_keywords -> excluded_keywords.

Resume Rules

Treat resume.txt as the source of truth.

  • Keep it broad, truthful, and complete.
  • Add only real work, projects, education, certifications, tools, and dates.
  • Generated resumes are job-specific views of the master resume.
  • Coursework can help matching, but it is not copied into resumes unless it belongs there.

Validation modes:

divapply run score tailor --validation strict
divapply run score tailor --validation normal
divapply run score tailor --validation lenient

Scoring

DivApply blends:

  • Required/preferred keyword matching
  • Local similarity scoring
  • LLM judgment

Required gaps matter more than preferred gaps. Missing preferred certifications should not block a good job match. Missing required non-substitutable items, such as a required license, degree, or clearance, can cap the score.

Provider and transport failures do not become valid low scores: affected jobs remain retryable. LLM requests use separate network timeouts, at most three attempts, finite retry delays, and a 10-minute default total caller budget; advanced overrides are documented in docs/OPERATIONS.md and .env.example.

Inspect a job:

divapply explain https://example.com/job

Exports

divapply export jobs --out jobs.csv
divapply export jobs --out jobs.json --format json

Exports include safe fields such as title, company, source site, URLs, fit score, lifecycle dates, and redacted apply errors. They do not print your full profile, resume, transcript text, or secrets.

Answer Bank

Save reusable factual answers for application forms:

divapply answers add "How many years of Python experience do you have?" "2 years."
divapply answers list
divapply answers match "Years using Python?"

Answers are local-only and must stay supported by your profile or resume.

Coursework

Optional coursework data can improve matching without exposing transcript text.

divapply import-coursework path\to\transcript.json
divapply coursework-summary

Supported formats: JSON, CSV, text, and PDF if pypdf is installed.

Safety

  • Real auto-apply requires confirmation.
  • Use --dry-run first on new sites.
  • Do not upload private files to git.
  • Review generated resumes before sending them.
  • Do not let the browser agent enter SSNs, bank info, payment details, ID uploads, or biometric verification.
  • Treat Gmail MCP opt-in as account access: enable it only when email application/verification automation is required.
  • CAPTCHA and unsupported authentication challenges stop the run instead of expanding agent permissions.
  • Browser workers use dedicated profiles only; personal or legacy unmarked Chrome profiles are never launched automatically.

Privacy details: docs/PRIVACY.md

Common Commands

divapply init
divapply add-url JOB_URL
divapply edit
divapply doctor
divapply selfcheck
divapply run
divapply run -w 4
divapply credentials --username you@example.com
divapply browser-login --url https://www.myworkday.com/
divapply status
divapply track applied JOB_URL
divapply followups
divapply analytics
divapply dashboard
divapply explain JOB_URL
divapply rescore
divapply export jobs --out jobs.csv
divapply answers list
divapply backup
divapply cleanup
divapply apply --dry-run
divapply apply --yes
divapply migrate
divapply prune --dry-run
divapply sync --dry-run

divapply dashboard opens an interactive local dashboard. Applied jobs include an Archive button so you can hide submitted applications without deleting their history. Archiving also removes generated resume and cover-letter files for that job. Use divapply dashboard --static when you only want to write a standalone HTML file.

divapply cleanup previews stale local dashboard benchmark/perf HTML files and backup-style .bak files. Run divapply cleanup --yes to delete the previewed files, or add --include-backups when you also want old divapply-backup-*.zip archives removed from the local backups folder.

Apply logs use private user-only files and expire after 30 days by default; set DIVAPPLY_LOG_RETENTION_DAYS=0 to retain them. Recovery backups exclude logs and credentials by default. Add --include-logs and/or --include-secrets only when explicitly needed.

Development

git clone https://github.com/InnitDivine/DivApply.git
cd DivApply
.\install.ps1 -Dev
python --version  # expected on the maintained Windows setup: Python 3.12.13
python -m pip install -e .
divapply --version
python -m divapply --version
python -m pytest -q
ruff check .

Release notes: CHANGELOG.md

Publishing notes: PUBLISHING.md

Operations notes: docs/OPERATIONS.md

AI assistance disclosure: docs/AI_ASSISTANCE.md

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

divapply-0.5.2.tar.gz (274.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

divapply-0.5.2-py3-none-any.whl (300.5 kB view details)

Uploaded Python 3

File details

Details for the file divapply-0.5.2.tar.gz.

File metadata

  • Download URL: divapply-0.5.2.tar.gz
  • Upload date:
  • Size: 274.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for divapply-0.5.2.tar.gz
Algorithm Hash digest
SHA256 349e4bc80015af1729bf193245c8053e5cb2601182c4c200e354b606d8bff1a7
MD5 254d7300d060f10606b393287ac624f7
BLAKE2b-256 84961677eef1554e85bf47cce6cf94758e145941442f57c5d812b76d3e44f361

See more details on using hashes here.

Provenance

The following attestation bundles were made for divapply-0.5.2.tar.gz:

Publisher: publish.yml on InnitDivine/DivApply

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file divapply-0.5.2-py3-none-any.whl.

File metadata

  • Download URL: divapply-0.5.2-py3-none-any.whl
  • Upload date:
  • Size: 300.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for divapply-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a9357d083a9e392cdc9ebace0eb518754e6c53041d773111adccc29a811e83f0
MD5 04ce8fb11791b566cb784acfbce50d6f
BLAKE2b-256 be0dae1ed4ad065d4a66b6e985d0b55e858398b475eba1151fcf5c26a8d50542

See more details on using hashes here.

Provenance

The following attestation bundles were made for divapply-0.5.2-py3-none-any.whl:

Publisher: publish.yml on InnitDivine/DivApply

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page