daliparthi/personal-job-agent

Local job-search agent for Workday career sites: finds matching postings, tailors your resume with rules (no AI), side-by-side review dashboard, assisted auto-apply.

Python

0

2 commits

updated Oct 1, 2026

See the code

See what people are saying

README

Workday Job Agent

Disclaimer: use at your own risk. A master resume / CV contains personally identifiable information (name, contact details, employment history), so this tool has not been dry-run with a real resume. It was tested only with made-up sample resumes. Results with your own resume may differ, so check the parsed master_resume/resume_data.yaml and every tailored resume before you use or submit it.

The tailored resume is a starting point for further editing, not a finished document. Review it, edit it (on the dashboard or in the downloaded .docx), and make sure everything in it is accurate before you apply.

Runs on your PC every day at 11:00 AM Eastern. Everything is plain code: no AI service, no API key, and nothing per-resume to pay for. It:

  1. Searches 109 large employers' Workday career sites (companies.yaml) for your keywords, using Workday's own public job-search API, and skips your current employer.
  2. Classifies every posting: Full-Time / Contract / Temporary / Part-Time / Internship (from Workday's own job-type field), Remote / Hybrid / On-site, and salary range (parsed from the pay-transparency text).
  3. Filters by job type, remote-only, minimum salary, posting age, US state, title words, match score and your own mandatory / optional keywords (see below).
  4. Tailors your master resume for each remaining posting with rules (details below), and renders an ATS-friendly .docx (single column, standard headings, real bullets). It never adds anything that isn't in your resume.
  5. Opens a dashboard where you review each job description side by side with its tailored resume, with the ATS keyword match before → after, matched and missing keywords highlighted, and job-type badges. You can edit or re-tailor the resume, skip the job, or approve it.
  6. On approval, a browser window opens and fills in the Workday application (sign-in or account creation, resume upload, contact details, screening questions from your answer rules, EEO questions). By default it stops on the Review page for you to click Submit. Set auto_submit: true to have it submit for you.
  7. Archives each application to applications/<Company>/<date>_<Job title>_<Req ID>/: the tailored resume that was sent, the job description (.html + .txt), and application.json (salary, type, scores, link).

Mandatory and optional keywords

search.keywords decides what to search Workday for (job titles). These two lists decide which of the postings found you see. They're checked against each posting's title and full description:

Must have (mandatory_keywords)The posting must mention every keyword, or it goes to Filtered out with the reason (e.g. "missing mandatory keyword: Snowflake") and is never tailored.
Nice to have (optional_keywords)Can be left empty. Postings that mention more of them are listed first, and the Keywords column shows how many (e.g. 2/3). Set at least N to also require some of them.
  • Matching is by whole word, and any spelling the skills list knows counts: AWS finds "Amazon Web Services", PostgreSQL finds "Postgres", and Java does not match "JavaScript".
  • Use | inside one keyword for either-or: AWS | Azure | GCP is satisfied by any one of them.
  • Refine on the dashboard: type a keyword and press Enter (or paste a comma-separated list) to add it as a chip, and click × (or Backspace) to remove one. The list updates as you type. Save for daily runs keeps them for the 11 AM run and re-checks the jobs you haven't acted on. A tailored job that no longer qualifies moves to Filtered out with its resume kept, and comes back if you loosen the filters.
  • On each job's review page, Your search keywords shows which ones the posting mentions (✓ / ✗), and they are outlined in the description.

You can also set starting values in config.yaml → filters:.

Location filters (USA)

The Location row on the dashboard:

United States only (us_only, on by default)Drops postings outside the US.
States (states)Pick states from the list (they show as chips, × removes one). Empty = every state. A posting with several locations passes if any of them is in one of your states.
Always include remote jobs (include_remote, on by default)Keeps remote US postings even when they aren't in your states.

States are read from Workday's location text, whatever the company's format: US, CA, Santa Clara, CHARLOTTE, NC; ISELIN, NJ, California - San Francisco, Newark, New Jersey, USA-Texas-Austin. Washington, DC counts as DC, and Kansas City, MO as Missouri. Postings that fail show the reason under Filtered out, e.g. "state: NC, TX" or "outside the US (India)". Like the other filters, changes apply to the list instantly; Save for daily runs keeps them for the 11 AM run.

How the tailoring works

  1. Reading your resume. jobagent/resume_parser.py reads .docx/.pdf/.txt/.md: it finds the section headings, then bullets, job titles, companies, dates, locations, degrees and skills. The result is saved to master_resume/resume_data.yaml. Check that file once and fix anything that landed in the wrong place. Every tailored resume is built only from it.
  2. Reading the posting. jobagent/keywords.py finds the skills and tools the posting mentions. It uses a built-in list of about 580 skills with their other spellings (jobagent/skills.yaml, e.g. AWS = Amazon Web Services, K8s = Kubernetes, Postgres = PostgreSQL), plus every skill on your resume. Keywords are weighted by where they appear: job title > Required / Minimum qualifications > Preferred / Nice to have. The company blurb, benefits, EEO and salary text are ignored.
  3. Tailoring (jobagent/tailor.py):
    • Headline: your own most recent job title that matches the posting's role, plus your top 3 matching skills (e.g. Senior Data Engineer | PostgreSQL · Python · Kubernetes). It never uses a title you haven't held.
    • Summary: the best of your summary_variants, ending with "Skilled in …" listing your matching skills.
    • Skills: the posting's skills come first, written the way the posting writes them. If you list AWS and the posting says "Amazon Web Services", your resume shows Amazon Web Services (AWS); that's what simple ATS keyword scans look for. Matching skills that only appear in your bullets are listed under Additional Skills.
    • Experience: each role's bullets are ordered by relevance. Older roles can be trimmed to their best bullets.
    • Projects / certifications: most relevant first.
  4. Checks: the tailored resume is compared with your master resume. Any changed employer, title or dates, or a skill your master resume doesn't show, is flagged in yellow on the review page. Posting requirements you don't have are listed as gaps. Add them to resume_data.yaml only if they're true.

To get better matches, keep resume_data.yaml complete (extra bullets are fine; tailoring picks the best ones). Add alternative summaries under summary_variants:, and add tools the built-in list doesn't know to config.yaml → tailoring.extra_skills / tailoring.synonyms.

Requirements

  • Windows 10/11 (the daily schedule uses Windows Task Scheduler; the rest is plain Python)
  • Python 3.10 or newer
  • Microsoft Edge (built into Windows) for the auto-apply browser. To use Playwright's own Chromium instead, set apply.browser_channel: chromium and run .\.venv\Scripts\python.exe -m playwright install chromium.

Setup (once)

git clone <this repository's URL> workday-job-agent
cd workday-job-agent
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
copy .env.example .env                 # then edit .env
copy config.example.yaml config.yaml   # then edit config.yaml

.env, config.yaml, your resume, data\ and applications\ are in .gitignore, so your personal details are never committed.

  1. Resume: put your master resume (.docx, .pdf, .txt or .md) in master_resume\.
  2. .env: set WORKDAY_EMAIL and WORKDAY_PASSWORD. Workday has a separate account per company, so use a password you don't use elsewhere.
  3. config.yaml: set current_employer, search.keywords, your profile (name, phone, address), and fill in the answers: for screening questions (work authorization, sponsorship, …). Unanswered questions are left for you in the browser.
  4. Read your resume and check the result:
    .\.venv\Scripts\python.exe -m jobagent init
    
    It prints what it found (roles, dates, bullet counts, education). Open master_resume\resume_data.yaml and fix anything that's off. If you later replace your resume file, run init --reparse.
  5. First search (about 10 minutes across all 109 companies; later runs only fetch new postings):
    .\.venv\Scripts\python.exe -m jobagent run
    
  6. Schedule the daily 11 AM Eastern run (Windows Task Scheduler; runs late if the PC was asleep at 11):
    powershell -ExecutionPolicy Bypass -File scripts\install_schedule.ps1
    

Every day

At 11:00 the task searches, tailors, then opens http://127.0.0.1:5055. You can also open it any time with start_dashboard.bat.

  • Filter bar: toggle Full-Time / Contract / Temporary / Part-Time / Internship, Remote only, Min salary, Hide jobs with no salary listed. Changes apply to the list instantly. Save for daily runs also stops future runs from tailoring jobs you've filtered out.
  • Tabs: To review · In progress · Applied · Waiting to tailor · Not applied · Skipped · Filtered out (with the reason, and you can still tailor and apply).
  • Review page: job description on the left, tailored resume on the right. Approve & apply, Edit resume, Re-tailor… (choose skills to put first, or a max number of bullets per role), Download .docx, Mark as applied (if you applied yourself), Skip.
  • If the browser needs you (CAPTCHA, email verification link, a question with no rule), the dashboard shows a red banner saying what to do. Do it in the open browser window and the agent continues.

Commands

CommandWhat it does
python -m jobagent init [--reparse]Read the master resume into resume_data.yaml, check config
python -m jobagent run [--no-tailor]Search + filter + tailor now
python -m jobagent serve [--open]Start the dashboard
python -m jobagent dailyWhat the scheduled task runs
python -m jobagent apply-approvedApply to approved jobs (the dashboard starts this for you)
python -m jobagent validate-companiesCheck every Workday URL still answers
python -m jobagent add-company <url> --name "<Company>"Add a Workday site (also possible from the dashboard)

(Use .venv\Scripts\python.exe in place of python.)

Good to know

  • Adding companies: any company on Workday works. Paste its careers URL (https://<company>.wd<N>.myworkdayjobs.com/<Site>) into the dashboard's Add company box. Companies that use other systems (Greenhouse, Lever, iCIMS, Taleo, their own site) aren't covered.
  • What rules can't do: they don't rewrite your bullets into new sentences. They choose, order and re-word skill names. Your bullets appear as you wrote them, so write strong bullets in resume_data.yaml once.
  • Auto-apply is best-effort: every company adds its own questions and some add extra pages. The agent fills in what it can and hands the browser to you for anything else. It never guesses an answer and never solves CAPTCHAs. Keep auto_submit: false until you've watched a few applications go through.
  • Privacy: everything runs locally. Postings, resumes and the database live in data\, master_resume\ and applications\. The dashboard only listens on 127.0.0.1. Nothing is sent anywhere except Workday itself.
  • Logs: data\logs\ (jobagent.log, daily.log, apply.log, server.log).
  • Remove the schedule: Unregister-ScheduledTask -TaskName JobAgentDaily -Confirm:$false

License

MIT, provided as is, without warranty of any kind (see the disclaimer at the top).

Layout

jobagent/          workday.py (Workday API) · classify.py (type/remote/salary) · geo.py (US states) · keywords.py + skills.yaml
                   (posting keywords) · resume_parser.py (read your resume) · tailor.py (tailoring rules)
                   resume.py (data model, checks, .docx) · scoring.py · pipeline.py (daily run, archive)
                   applier.py (browser automation) · server.py + templates/ + static/ (dashboard) · __main__.py (CLI)
companies.yaml     Workday sites to search          config.yaml   your settings
master_resume/     your resume + resume_data.yaml   data/         database, tailored drafts, logs, browser profile
applications/      one folder per submitted application
ats
automation
flask
job-application
job-search
playwright
python
resume
resume-tailoring
workday

daliparthi/personal-job-agent

Local job-search agent for Workday career sites: finds matching postings, tailors your resume with rules (no AI), side-by-side review dashboard, assisted auto-apply.

Python

0

2 commits

updated Oct 1, 2026

See the code

See what people are saying

README

Workday Job Agent

Disclaimer: use at your own risk. A master resume / CV contains personally identifiable information (name, contact details, employment history), so this tool has not been dry-run with a real resume. It was tested only with made-up sample resumes. Results with your own resume may differ, so check the parsed master_resume/resume_data.yaml and every tailored resume before you use or submit it.

The tailored resume is a starting point for further editing, not a finished document. Review it, edit it (on the dashboard or in the downloaded .docx), and make sure everything in it is accurate before you apply.

Runs on your PC every day at 11:00 AM Eastern. Everything is plain code: no AI service, no API key, and nothing per-resume to pay for. It:

  1. Searches 109 large employers' Workday career sites (companies.yaml) for your keywords, using Workday's own public job-search API, and skips your current employer.
  2. Classifies every posting: Full-Time / Contract / Temporary / Part-Time / Internship (from Workday's own job-type field), Remote / Hybrid / On-site, and salary range (parsed from the pay-transparency text).
  3. Filters by job type, remote-only, minimum salary, posting age, US state, title words, match score and your own mandatory / optional keywords (see below).
  4. Tailors your master resume for each remaining posting with rules (details below), and renders an ATS-friendly .docx (single column, standard headings, real bullets). It never adds anything that isn't in your resume.
  5. Opens a dashboard where you review each job description side by side with its tailored resume, with the ATS keyword match before → after, matched and missing keywords highlighted, and job-type badges. You can edit or re-tailor the resume, skip the job, or approve it.
  6. On approval, a browser window opens and fills in the Workday application (sign-in or account creation, resume upload, contact details, screening questions from your answer rules, EEO questions). By default it stops on the Review page for you to click Submit. Set auto_submit: true to have it submit for you.
  7. Archives each application to applications/<Company>/<date>_<Job title>_<Req ID>/: the tailored resume that was sent, the job description (.html + .txt), and application.json (salary, type, scores, link).

Mandatory and optional keywords

search.keywords decides what to search Workday for (job titles). These two lists decide which of the postings found you see. They're checked against each posting's title and full description:

Must have (mandatory_keywords)The posting must mention every keyword, or it goes to Filtered out with the reason (e.g. "missing mandatory keyword: Snowflake") and is never tailored.
Nice to have (optional_keywords)Can be left empty. Postings that mention more of them are listed first, and the Keywords column shows how many (e.g. 2/3). Set at least N to also require some of them.
  • Matching is by whole word, and any spelling the skills list knows counts: AWS finds "Amazon Web Services", PostgreSQL finds "Postgres", and Java does not match "JavaScript".
  • Use | inside one keyword for either-or: AWS | Azure | GCP is satisfied by any one of them.
  • Refine on the dashboard: type a keyword and press Enter (or paste a comma-separated list) to add it as a chip, and click × (or Backspace) to remove one. The list updates as you type. Save for daily runs keeps them for the 11 AM run and re-checks the jobs you haven't acted on. A tailored job that no longer qualifies moves to Filtered out with its resume kept, and comes back if you loosen the filters.
  • On each job's review page, Your search keywords shows which ones the posting mentions (✓ / ✗), and they are outlined in the description.

You can also set starting values in config.yaml → filters:.

Location filters (USA)

The Location row on the dashboard:

United States only (us_only, on by default)Drops postings outside the US.
States (states)Pick states from the list (they show as chips, × removes one). Empty = every state. A posting with several locations passes if any of them is in one of your states.
Always include remote jobs (include_remote, on by default)Keeps remote US postings even when they aren't in your states.

States are read from Workday's location text, whatever the company's format: US, CA, Santa Clara, CHARLOTTE, NC; ISELIN, NJ, California - San Francisco, Newark, New Jersey, USA-Texas-Austin. Washington, DC counts as DC, and Kansas City, MO as Missouri. Postings that fail show the reason under Filtered out, e.g. "state: NC, TX" or "outside the US (India)". Like the other filters, changes apply to the list instantly; Save for daily runs keeps them for the 11 AM run.

How the tailoring works

  1. Reading your resume. jobagent/resume_parser.py reads .docx/.pdf/.txt/.md: it finds the section headings, then bullets, job titles, companies, dates, locations, degrees and skills. The result is saved to master_resume/resume_data.yaml. Check that file once and fix anything that landed in the wrong place. Every tailored resume is built only from it.
  2. Reading the posting. jobagent/keywords.py finds the skills and tools the posting mentions. It uses a built-in list of about 580 skills with their other spellings (jobagent/skills.yaml, e.g. AWS = Amazon Web Services, K8s = Kubernetes, Postgres = PostgreSQL), plus every skill on your resume. Keywords are weighted by where they appear: job title > Required / Minimum qualifications > Preferred / Nice to have. The company blurb, benefits, EEO and salary text are ignored.
  3. Tailoring (jobagent/tailor.py):
    • Headline: your own most recent job title that matches the posting's role, plus your top 3 matching skills (e.g. Senior Data Engineer | PostgreSQL · Python · Kubernetes). It never uses a title you haven't held.
    • Summary: the best of your summary_variants, ending with "Skilled in …" listing your matching skills.
    • Skills: the posting's skills come first, written the way the posting writes them. If you list AWS and the posting says "Amazon Web Services", your resume shows Amazon Web Services (AWS); that's what simple ATS keyword scans look for. Matching skills that only appear in your bullets are listed under Additional Skills.
    • Experience: each role's bullets are ordered by relevance. Older roles can be trimmed to their best bullets.
    • Projects / certifications: most relevant first.
  4. Checks: the tailored resume is compared with your master resume. Any changed employer, title or dates, or a skill your master resume doesn't show, is flagged in yellow on the review page. Posting requirements you don't have are listed as gaps. Add them to resume_data.yaml only if they're true.

To get better matches, keep resume_data.yaml complete (extra bullets are fine; tailoring picks the best ones). Add alternative summaries under summary_variants:, and add tools the built-in list doesn't know to config.yaml → tailoring.extra_skills / tailoring.synonyms.

Requirements

  • Windows 10/11 (the daily schedule uses Windows Task Scheduler; the rest is plain Python)
  • Python 3.10 or newer
  • Microsoft Edge (built into Windows) for the auto-apply browser. To use Playwright's own Chromium instead, set apply.browser_channel: chromium and run .\.venv\Scripts\python.exe -m playwright install chromium.

Setup (once)

git clone <this repository's URL> workday-job-agent
cd workday-job-agent
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
copy .env.example .env                 # then edit .env
copy config.example.yaml config.yaml   # then edit config.yaml

.env, config.yaml, your resume, data\ and applications\ are in .gitignore, so your personal details are never committed.

  1. Resume: put your master resume (.docx, .pdf, .txt or .md) in master_resume\.
  2. .env: set WORKDAY_EMAIL and WORKDAY_PASSWORD. Workday has a separate account per company, so use a password you don't use elsewhere.
  3. config.yaml: set current_employer, search.keywords, your profile (name, phone, address), and fill in the answers: for screening questions (work authorization, sponsorship, …). Unanswered questions are left for you in the browser.
  4. Read your resume and check the result:
    .\.venv\Scripts\python.exe -m jobagent init
    
    It prints what it found (roles, dates, bullet counts, education). Open master_resume\resume_data.yaml and fix anything that's off. If you later replace your resume file, run init --reparse.
  5. First search (about 10 minutes across all 109 companies; later runs only fetch new postings):
    .\.venv\Scripts\python.exe -m jobagent run
    
  6. Schedule the daily 11 AM Eastern run (Windows Task Scheduler; runs late if the PC was asleep at 11):
    powershell -ExecutionPolicy Bypass -File scripts\install_schedule.ps1
    

Every day

At 11:00 the task searches, tailors, then opens http://127.0.0.1:5055. You can also open it any time with start_dashboard.bat.

  • Filter bar: toggle Full-Time / Contract / Temporary / Part-Time / Internship, Remote only, Min salary, Hide jobs with no salary listed. Changes apply to the list instantly. Save for daily runs also stops future runs from tailoring jobs you've filtered out.
  • Tabs: To review · In progress · Applied · Waiting to tailor · Not applied · Skipped · Filtered out (with the reason, and you can still tailor and apply).
  • Review page: job description on the left, tailored resume on the right. Approve & apply, Edit resume, Re-tailor… (choose skills to put first, or a max number of bullets per role), Download .docx, Mark as applied (if you applied yourself), Skip.
  • If the browser needs you (CAPTCHA, email verification link, a question with no rule), the dashboard shows a red banner saying what to do. Do it in the open browser window and the agent continues.

Commands

CommandWhat it does
python -m jobagent init [--reparse]Read the master resume into resume_data.yaml, check config
python -m jobagent run [--no-tailor]Search + filter + tailor now
python -m jobagent serve [--open]Start the dashboard
python -m jobagent dailyWhat the scheduled task runs
python -m jobagent apply-approvedApply to approved jobs (the dashboard starts this for you)
python -m jobagent validate-companiesCheck every Workday URL still answers
python -m jobagent add-company <url> --name "<Company>"Add a Workday site (also possible from the dashboard)

(Use .venv\Scripts\python.exe in place of python.)

Good to know

  • Adding companies: any company on Workday works. Paste its careers URL (https://<company>.wd<N>.myworkdayjobs.com/<Site>) into the dashboard's Add company box. Companies that use other systems (Greenhouse, Lever, iCIMS, Taleo, their own site) aren't covered.
  • What rules can't do: they don't rewrite your bullets into new sentences. They choose, order and re-word skill names. Your bullets appear as you wrote them, so write strong bullets in resume_data.yaml once.
  • Auto-apply is best-effort: every company adds its own questions and some add extra pages. The agent fills in what it can and hands the browser to you for anything else. It never guesses an answer and never solves CAPTCHAs. Keep auto_submit: false until you've watched a few applications go through.
  • Privacy: everything runs locally. Postings, resumes and the database live in data\, master_resume\ and applications\. The dashboard only listens on 127.0.0.1. Nothing is sent anywhere except Workday itself.
  • Logs: data\logs\ (jobagent.log, daily.log, apply.log, server.log).
  • Remove the schedule: Unregister-ScheduledTask -TaskName JobAgentDaily -Confirm:$false

License

MIT, provided as is, without warranty of any kind (see the disclaimer at the top).

Layout

jobagent/          workday.py (Workday API) · classify.py (type/remote/salary) · geo.py (US states) · keywords.py + skills.yaml
                   (posting keywords) · resume_parser.py (read your resume) · tailor.py (tailoring rules)
                   resume.py (data model, checks, .docx) · scoring.py · pipeline.py (daily run, archive)
                   applier.py (browser automation) · server.py + templates/ + static/ (dashboard) · __main__.py (CLI)
companies.yaml     Workday sites to search          config.yaml   your settings
master_resume/     your resume + resume_data.yaml   data/         database, tailored drafts, logs, browser profile
applications/      one folder per submitted application
ats
automation
flask
job-application
job-search
playwright
python
resume
resume-tailoring
workday

Languages

Python

77.1%

JavaScript

12.7%

CSS

5.3%

HTML

3.7%

PowerShell

1.0%