EzzApply is a local job-application workflow that helps you:
- collect public job links
- scan and rank them against your profile
- queue the good matches
- generate a tailored resume draft and cover letter draft
- export final PDF files
It is designed to run on your own laptop. Your profile, resume, scans, runs, and generated outputs stay in this project folder.
There are two main ways to use the project:
-
Single-job flowPaste one full job description intodata/job_description.txtand run the pipeline for that one role. -
Scan-and-batch flowPaste multiple public job links intodata/job_links.txt, scan them, queue the useful ones, and process them in bulk.
Recommended bulk flow:
python -m app.cli scan-and-queue
python -m app.cli batchBefore running anything, EzzApply reads these base files:
data/profile.yamldata/base_resume.texdata/cover_letter_template.texdata/job_description.txtdata/job_links.txt
Optional queue folder:
data/job_descriptions/
scans/<scan_id>/- ranked scan results
- extracted job descriptions
- raw fetch/extraction artifacts
runs/<run_id>/- baseline analysis
- recruiter-style analysis
- tailored resume draft
- cover letter draft
- final
.texand.pdfoutputs
app/ Python application code
data/ Your editable inputs
profile.yaml
base_resume.tex
cover_letter_template.tex
job_description.txt
job_links.txt
job_descriptions/
runs/ One folder per application run
scans/ One folder per link scan
schemas/ JSON schema for Codex output
templates/ Local web UI templates
tests/ Automated tests
Minimum requirements:
- Python 3.12
- Windows PowerShell or another terminal
- internet access for job-page fetching
- Codex CLI available locally
- a LaTeX compiler for PDF export
Recommended on Windows:
- Conda for environment management
- MiKTeX for LaTeX export
- VS Code with the OpenAI / ChatGPT extension installed and logged in
git clone <your-repo-url>
cd ezzapplyUsing Conda:
conda create -n ezzapply python=3.12 -y
conda activate ezzapply
pip install -r requirements.txtWithout Conda:
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txtEzzApply uses Codex locally for the AI stages.
The app looks for codex in these common places:
- your
PATH - the OpenAI / ChatGPT VS Code extension install
~/.codex/bin/codex.exe- Windows app aliases
Recommended setup on Windows:
- Install VS Code
- Install the OpenAI / ChatGPT extension
- Sign in
- Confirm
codexis available
Quick check:
codex --helpIf that command does not work, EzzApply will not be able to run analyze, tailor-resume, or cover-letter.
On Windows, MiKTeX is the easiest option:
winget install --id MiKTeX.MiKTeX -e --source winget --accept-package-agreements --accept-source-agreementsEzzApply can also work with other LaTeX setups if latexmk, pdflatex, xelatex, or lualatex is available.
Quick check:
latexmk --versionIf no compiler is found, the app can still generate text and LaTeX drafts, but PDF export will fail.
You should update these files before running the pipeline seriously:
Put your structured profile here, including things like:
- name
- contact information
- target roles
- skills
- truthful guardrails
must_keepdo_not_claim- extra context you want the prompts to use
This is your source resume in LaTeX. The tailoring stage uses this as the starting point for resume rewriting.
Update it with:
- your current resume content
- your latest experience and education
- your thesis or recent projects
- the correct LaTeX document structure
If your resume depends on a custom class file, keep that file in the repo too. In this project that is:
data/muratcan_cv.cls
This is the LaTeX template used when generating the final cover letter.
Make sure it matches your preferred layout and still contains the body placeholder used by the app.
This is for the single-job workflow. Paste one full job description here if you want to process one role directly.
Optional metadata headers:
Role: AI Engineer
Company: Example Company
URL: https://example.com/jobs/123
This is for the scan workflow. Add one public job URL per line.
Example:
https://company1.com/jobs/applied-ai-engineer
https://company2.com/careers/ml-engineer
https://company3.com/openings/llm-engineer
Notes:
- blank lines are ignored
- lines starting with
#are ignored - one URL per line only
- direct public job-description pages work best
- login-walled or JS-only pages may be marked as failed during scan
Before using the full pipeline, these checks are helpful:
Run the tests:
python -m pytest -q tests -p no:cacheprovider --basetemp .tmp\pytestOpen CLI help:
python -m app.cli --helpCheck the available commands:
python -m app.cli scan --help
python -m app.cli batch --helpThis is the easiest workflow if you use Perplexity, Google, or job boards to collect links first.
One link per line.
python -m app.cli scan-and-queueThis command:
- reads
data/job_links.txt - deduplicates the links
- fetches public pages
- extracts role, company, location, and description
- scores each job against your base profile and resume
- writes scan artifacts into
scans/<scan_id>/ - queues all ranked jobs into
data/job_descriptions/
python -m app.cli batchThis command:
- reads every
.txtfile fromdata/job_descriptions/ - runs the full pipeline per job
- skips further AI work for jobs with
fit_score < 70 - archives processed source files into the run folder
- stops on the current file if a job does not finish cleanly
Important:
batchprocesses every.txtfile currently indata/job_descriptions/- if you only want a specific set of roles, clean that folder first
Paste one job description into data/job_description.txt, then run:
python -m app.cli allIf you want to use a specific queued file instead:
python -m app.cli all --job-file "data/job_descriptions\\your-job-file.txt"If you want manual control and review between stages:
python -m app.cli new
python -m app.cli analyze
python -m app.cli tailor-resume
python -m app.cli cover-letter
python -m app.cli review
python -m app.cli approve-drafts
python -m app.cli exportManual scan:
python -m app.cli scanManual queueing from a specific scan:
python -m app.cli scan-queue <scan_id> <job_id_1> <job_id_2>One-command scan plus queue:
python -m app.cli scan-and-queuepython -m app.cli status
python -m app.cli review
python -m app.cli exportCurrent model setup:
model: gpt-5.4
analyze -> model_reasoning_effort="low"
tailor_resume -> model_reasoning_effort="medium"
cover_letter -> model_reasoning_effort="medium"
timeout: 600 seconds
minimum_fit_score_to_continue: 70
Prompt inputs by stage:
analyze- job description
- base resume
- full profile
- deterministic baseline analysis
tailor_resume- job description
- base resume
- analyze result
- profile guardrails
cover_letter- job description
- updated tailored resume
- analyze result
- profile guardrails
Each scan creates:
scans/<scan_id>/input_urls.txtscans/<scan_id>/results.jsonscans/<scan_id>/summary.mdscans/<scan_id>/raw/
Each run creates:
runs/<run_id>/run.jsonruns/<run_id>/stage_outputs/00_job_input.txtruns/<run_id>/stage_outputs/01_baseline_analysis.mdruns/<run_id>/stage_outputs/02_recruiter_analysis.mdruns/<run_id>/stage_outputs/03_resume_changes.mdruns/<run_id>/stage_outputs/04_draft_resume.texruns/<run_id>/stage_outputs/05_draft_cover_letter_body.txtruns/<run_id>/stage_outputs/06_draft_cover_letter.tex
After approval and export, the run folder also contains final resume and cover-letter outputs.
You can also use the local FastAPI UI:
python -m uvicorn app.main:app --host 127.0.0.1 --port 8000Then open:
http://127.0.0.1:8000
The web app lets you:
- view runs and scans
- edit
profile.yaml - edit the cover letter template
- paste job links
- launch scans
- queue scanned jobs
- EzzApply only scans public job detail pages. It does not use browser automation to bypass login walls.
- Low-fit jobs are marked
rejected_low_fitafteranalyzeand do not continue to resume or cover-letter generation. - If Codex fails, the saved prompt files in the run folder can still be inspected and reused manually.
- If PDF export fails but LaTeX drafts exist, the AI stages may still have succeeded.
- On Windows, very long job titles or URLs can create long paths. The app now trims archived filenames and uses shorter archive paths when needed.
If you want the smoothest first run on a new laptop:
- Update
data/profile.yaml - Update
data/base_resume.tex - Update
data/cover_letter_template.tex - Make sure
codex --helpworks - Make sure
latexmk --versionorpdflatex --versionworks - Put 2 to 5 public job links into
data/job_links.txt - Run
python -m app.cli scan-and-queue - Review
scans/<scan_id>/summary.md - Run
python -m app.cli batch - Review outputs inside
runs/<run_id>/