Skip to main content

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

Project description

DivApply

PyPI Python CI License

DivApply is a local-first job application assistant. It discovers jobs, enriches postings, scores fit, tailors resumes, writes cover letters, exports PDFs, and can optionally assist with browser-based applications.

discover -> enrich -> score -> tailor -> cover -> pdf -> apply

DivApply works from your profile, resume, search preferences, and optional coursework. It is designed to preserve facts—not invent employers, credentials, degrees, skills, dates, metrics, or experience.

Highlights

  • Configurable searches across job boards and direct employer sources.
  • Full-posting enrichment and canonical application links.
  • Hybrid keyword, local-similarity, and optional LLM scoring.
  • Required-versus-preferred qualification handling.
  • Factual, job-specific resumes and cover letters with fail-closed ATS text validation.
  • Local dashboard, lifecycle tracking, analytics, and safe exports.
  • Hidden coursework context without automatic transcript disclosure.
  • Confirmation-gated browser assistance with dedicated worker profiles.

Requirements

Feature Requirement
Core CLI Python 3.11+
Full JobSpy discovery Python 3.12 recommended; maintained Windows setup uses 3.12.13
Default browser and PDF workflows Playwright Chromium; auto-apply can also target supported installed browsers
AI scoring and documents Gemini, OpenAI, or a compatible local endpoint
Auto-apply Node.js 20+ and Codex CLI or Claude Code

Python 3.14 can remain installed for other work, but run DivApply from a Python 3.12 virtual environment while upstream JobSpy pins remain in place.

Install

Use an isolated virtual environment. This keeps DivApply and its browser dependencies out of your system Python.

Windows PowerShell

$Venv = "$HOME\.venvs\divapply"
py -3.12 -m venv $Venv
& "$Venv\Scripts\Activate.ps1"

python -m pip install --upgrade pip
python -m pip install --upgrade "divapply[full]"

$JobSpyWheel = "https://files.pythonhosted.org/packages/d5/2b/18863fcd3c544a69d81e351381a50036a33c21b61cc1c6de2a8f25931237/python_jobspy-1.1.82-py3-none-any.whl#sha256=93d638b35ffd30a714253e065907f68c5bac624e3937a3ad2ba09f618a072ee9"
python -m pip install --no-deps $JobSpyWheel
python -m divapply.jobspy_runtime
python -m playwright install chromium

divapply init
divapply doctor

If py -3.12 is unavailable, install Python 3.12 or use an existing 3.12 interpreter explicitly.

macOS and Linux

python3.12 -m venv ~/.venvs/divapply
source ~/.venvs/divapply/bin/activate

python -m pip install --upgrade pip
python -m pip install --upgrade 'divapply[full]'

JOBSPY_WHEEL='https://files.pythonhosted.org/packages/d5/2b/18863fcd3c544a69d81e351381a50036a33c21b61cc1c6de2a8f25931237/python_jobspy-1.1.82-py3-none-any.whl#sha256=93d638b35ffd30a714253e065907f68c5bac624e3937a3ad2ba09f618a072ee9'
python -m pip install --no-deps "$JOBSPY_WHEEL"
python -m divapply.jobspy_runtime
python -m playwright install chromium

divapply init
divapply doctor

Install choices

Package Includes
divapply Core CLI
divapply[coursework] Core CLI plus PDF coursework import
divapply[jobspy-runtime] Secure JobSpy dependency floor, without JobSpy itself
divapply[full] Coursework plus the secure JobSpy runtime dependencies

Why JobSpy uses a separate command

python-jobspy 1.1.82 declares markdownify<0.14.0, while the patched dependency floor requires markdownify>=0.14.1. DivApply therefore installs the secure floor first, then the exact hash-verified JobSpy wheel with --no-deps.

Because those published metadata ranges cannot overlap, pip check may report an intentional Markdownify conflict. Do not downgrade Markdownify to silence it. Use these supported checks instead:

python -m divapply.jobspy_runtime
divapply selfcheck
divapply doctor

First Run

divapply init
divapply edit
divapply selfcheck
divapply doctor

divapply init is an interactive setup wizard. divapply edit opens the normal local-only editor for your profile and searches.

User data lives under ~/.divapply:

  • profile.json — applicant facts, work history, education, verified skills, and reusable form answers.
  • resume.txt / resume.pdf — master resume evidence.
  • searches.yaml — target roles, markets, schedules, boards, tiers, and filters.
  • .env — API keys and runtime settings.
  • credentials.yaml — optional job-site login credentials.
  • divapply.db — local jobs, coursework, and application history.

These files are private and ignored by Git. Keep candidate facts in profile.json; keep job-search strategy in searches.yaml so old preferences do not become resume claims.

Core Workflow

Run the full non-submitting pipeline:

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

Run selected stages or inspect one posting:

divapply run discover enrich
divapply run score tailor cover pdf
divapply add-url JOB_URL
divapply add-url JOB_URL --prepare --min-score 5
divapply explain JOB_URL
divapply rescore

divapply run never submits applications. Submission is a separate, confirmation-gated divapply apply command.

Search Configuration

Most users should configure searches through divapply edit. The underlying searches.yaml remains human-readable:

defaults:
  results_per_site: 50
  hours_old: 168

locations:
  - label: local
    location: "Exampletown, UT"
    remote: false
  - label: remote
    location: "Remote"
    remote: true

queries:
  - query: "IT Support Specialist"
    tier: 1
    location_labels: [local, remote]
  - query: "Help Desk Technician"
    tier: 2
    location_labels: [local, remote]
  - query: "Health Information Technician"
    tier: 3
    location_labels: [local, remote]

boards:
  - indeed
  - linkedin

Tier 1 is the strongest target, tier 2 is an adjacent path, and tier 3 is a broader fallback. Titles belong in queries; places belong in locations; schedule, benefits, market, and application-mode policy should remain structured search configuration.

Configured official GovernmentJobs/SchoolJobs, JobAps, and CalCareers sources use deterministic current-vacancy adapters. A row is marked open only when the current official board exposes an exact job/application entry; expired filing deadlines are excluded. Rediscovery may restore a legacy or source-closed row, but it never overrides a job you archived yourself or one excluded by search policy.

Legacy aliases still load, but divapply selfcheck reports migration guidance.

Scoring and Resume Safety

DivApply blends required/preferred keyword evidence, local similarity, and optional LLM judgment. Required non-substitutable gaps—such as a mandatory license or clearance—can cap a score. Preferred credentials should not block an otherwise strong match.

Provider or transport failures remain retryable rather than becoming fake low scores. Inspect score evidence with:

divapply explain JOB_URL

Treat profile.json and your master resume as factual sources. Imported structured education fields are canonical for their academic values, and coursework may provide additional academic context. Generated documents may rephrase or prioritize supported facts, but must not turn coursework, labs, projects, or in-progress education into paid experience or earned credentials.

Resume PDFs use a one-column layout and are checked after rendering for selectable text, source-token coverage, and standard section order. A PDF that fails those machine-readability checks is not saved or offered for upload.

Validation modes are available when generating documents:

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

Coursework

Coursework can improve matching without exposing raw transcript text:

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

Supported formats are JSON, CSV, text, and PDF when the coursework extra is installed. Raw transcript text stays local. Selected completed-course facts may be included in scoring or tailoring prompts sent to your configured LLM, but coursework is not automatically copied into a resume.

Browser Login and Auto-Apply

Start with one dry-run job:

divapply apply --dry-run --limit 1

Optional usernames and passwords can be stored in the permission-protected local credentials.yaml file. This file is not an encrypted credential vault:

divapply credentials --username you@example.com

Save cookies separately in DivApply's dedicated browser profile by signing in interactively:

divapply browser-login --url https://www.myworkday.com/

Then run the smallest real batch:

divapply apply --yes --limit 1 --workers 1

Safety boundaries:

  • Real application runs require explicit confirmation.
  • Worker profiles are blank and dedicated; DivApply never clones your personal Chrome profile.
  • The apply agent receives an allowlisted browser surface, without host shell or arbitrary page-code execution.
  • CAPTCHA, unsupported authentication, and email-only flows fail closed. Gmail automation is unavailable.
  • RESULT:APPLIED requires matching submission-origin and visible-confirmation evidence, but remains model-reported; verify important submissions yourself.
  • Do not automate SSNs, banking details, payments, ID uploads, or biometric verification.

If a site rejects Playwright's browser, set DIVAPPLY_BROWSER=chrome in ~/.divapply/.env, then use the same browser for browser-login and apply.

Backups, Cleanup, and Privacy

divapply backup
divapply cleanup
divapply cleanup --yes

Backups include profile, resume, searches, database, local config, and generated documents. Logs and secrets are excluded unless you explicitly add --include-logs or --include-secrets.

divapply cleanup previews dashboard benchmark/performance files, .bak files, and non-PDF sidecars in generated-document folders. Add --include-backups only when you intentionally want matching divapply-backup-*.zip archives removed.

Apply logs use user-only permissions and expire after 30 days by default. See Privacy for data boundaries and Git hygiene.

Common Commands

divapply init
divapply add-url JOB_URL
divapply edit
divapply doctor
divapply selfcheck
divapply run
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 migrate
divapply prune --dry-run
divapply sync --dry-run

Run divapply --help or divapply COMMAND --help for full options.

Development

git clone https://github.com/InnitDivine/DivApply.git
cd DivApply
.\install.ps1 -Dev
.\.venv\Scripts\Activate.ps1

python -m pytest -q
ruff check .

On macOS or Linux:

./install.sh --dev
source .venv/bin/activate

python -m pytest -q
ruff check .

Documentation

License

DivApply is licensed under AGPL-3.0-only.

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.8.tar.gz (283.2 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.8-py3-none-any.whl (309.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: divapply-0.5.8.tar.gz
  • Upload date:
  • Size: 283.2 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.8.tar.gz
Algorithm Hash digest
SHA256 25f47a74cf000f01287dcda9d4f79f62e2641966ee20e799c7cfe8164d03b49c
MD5 78fd7a37b7bab4ceb7fc9a77cdd77848
BLAKE2b-256 9cbb9a189402a5b102e5e8cc07850470f7244c1ac0b9224a5e05e3896501c047

See more details on using hashes here.

Provenance

The following attestation bundles were made for divapply-0.5.8.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.8-py3-none-any.whl.

File metadata

  • Download URL: divapply-0.5.8-py3-none-any.whl
  • Upload date:
  • Size: 309.0 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.8-py3-none-any.whl
Algorithm Hash digest
SHA256 76488085a7e90eb11f721976dfd0cd4d376a7b513094c35b7b5db228d1631ee5
MD5 1ae4b016d1a0bf4bcdcd4d6a7948557b
BLAKE2b-256 2e6ce1fc820090b629061797b9e19382abd9ed0f600b95b302123e52da59dad4

See more details on using hashes here.

Provenance

The following attestation bundles were made for divapply-0.5.8-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