An automation tool for the job-application loop: it discovers open roles, tailors a resume to each job description, generates a PDF, and fills out the ATS application form (Greenhouse, Ashby, Lever, and others) — including dropdowns, comboboxes, and open-ended questions.
Demo video: https://www.youtube.com/watch?v=SM7EIgbBiiY
- Discovers open roles across job boards (
discover.py,yc_discover.py) - Tailors the resume to each job description and generates a fresh PDF
(
tailor.py,gen_pdf.py,make_cv.py) - Fills the application in its own browser window, so the operator's main browser stays free
- Survives interruptions: queue processing picks up where it left off
- Follows up: drafts follow-up emails for submitted applications
(
followup.py) - Hosted UI (
webapp.py): a job-queue page for reviewing discovered postings, plus a live-view auto-apply flow that streams the browser session and lets a reviewer intervene mid-fill
data/profile.yamlholds the candidate's facts and voice notes — the single source of truth for identity, work history, and preferences- Playwright opens the job URL in a dedicated Chromium instance with a persistent browser profile, so logins and cookies carry over between runs
- The form is extracted from the page DOM. Known fields (name, contact info, work authorization, EEO) are filled deterministically from the profile; an LLM drafts answers for open-ended questions
- The agent fills the form and attempts to submit. The final application state should be reviewed — see "Review before relying on auto-submit" below.
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
playwright install chromiumdocker compose build
docker compose run --rm agent python3 main.py <job_url>For the hosted job-queue UI:
docker compose -f docker-compose.dokploy.yml up -dCreate data/profile.yaml with the candidate's details (name, contact info,
work history, education, work authorization, EEO answers, and voice notes).
This file is gitignored — it is never committed, since it holds personal
information. There is no template checked in; see the field references in
main.py (apply_deterministic_answers) and tailor.py for the expected
schema.
export LLM_API_KEY=...
# optional:
export LLM_BASE_URL=...
export LLM_MODEL=...Any OpenAI-compatible endpoint works (OpenAI, Groq, etc.).
python main.py <job_url>
python main.py --queue data/jobs.txt # one URL per line
./apply.sh # launcher script, same as above
python discover.py --dry-run # preview matching postings without writing the queue
python webapp.py # hosted job-queue + live-view UI on :8765The agent fills the form and attempts to submit it, including a fallback that bypasses the click handler if the initial submit does not confirm. This is not gated behind a human-review pause. Before pointing this at postings that matter, verify the fields it fills are correct for the candidate in question — in particular:
- Work authorization and EEO fields are filled deterministically from
data/profile.yaml. Confirm those values are accurate for the candidate before running against a real posting. - Open-ended questions are LLM-generated and should be spot-checked.
- Some ATS forms use custom widgets (autocomplete location fields, radio groups for work authorization) that are not always filled reliably — check the run's log output for fields reported as still empty.
- Multiple candidates are not yet supported as a first-class feature — the
tool currently assumes one operator, one candidate, and one profile. See
MULTI_CANDIDATE_PLAN.mdfor the plan to support a staffing-firm, multi-candidate workflow. - Do not point this at LinkedIn Easy Apply (Terms of Service) or CAPTCHA-walled application flows.
- Workday: log in once in the agent's browser window; the persistent profile remembers the session on later runs. Full Workday auto-apply is not supported yet — matching postings are routed to a manual-review queue.
- Browser profiles, resumes, and application data (
data/,outputs/,.browser-profile/,resumes/) are gitignored and must stay that way — they contain session cookies and personal information.