Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

AutoApply

A personal, human-in-the-loop job application agent for Greenhouse, Lever and Ashby. It finds jobs, filters and scores them against your profile, tailors a truthful one-page resume per job, prepares answers to each application form, and fills the real form in a browser. You review every application; V1 has you click Submit, V2 (opt-in) submits only forms that pass every check. Design notes: BUILD_GUIDE.md.

Status: complete. 1–7 + week 2 of the build plan are implemented and tested (170 offline tests; live checks on real Greenhouse, Lever and Ashby forms, never submitted). What has not run yet is anything needing your API key: profile extraction, scoring, tailoring and LLM answer drafts are tested with fake models only. See "First run" below.


Setup (everything stays on E:)

Python 3.12 with a virtual environment in this folder. pip's cache, temp files, Playwright's Chromium and pytest's temp files all live in .cache/; C: is not used.

python -m venv .venv
$env:PIP_CACHE_DIR="E:\Job_Hunterrr\.cache\pip"; $env:TMP="E:\Job_Hunterrr\.cache\tmp"; $env:TEMP=$env:TMP
.venv\Scripts\python -m pip install -e ".[dev]"
$env:PLAYWRIGHT_BROWSERS_PATH="E:\Job_Hunterrr\.cache\ms-playwright"; .venv\Scripts\python -m playwright install chromium
copy .env.example .env    # then put your ANTHROPIC_API_KEY in .env
copy config\prefs.example.yaml config\prefs.yaml        # then fill in us_citizen / needs_sponsorship
copy config\answers.example.yaml config\answers.yaml    # then fill in your answers

(All of this is already done in this folder.) Activate with .venv\Scripts\Activate.ps1 to use the short autoapply command; otherwise .venv\Scripts\python -m autoapply ....

First run (once, ~30 minutes)

  1. API key: put ANTHROPIC_API_KEY=... in .env.
  2. Profile: autoapply profile extract path\to\resume.pdf, read the warnings, then edit data/profile.json by hand (add projects/bullets your resume cut for space; more raw material = better tailoring). autoapply render --base shows it in the resume template, for free.
  3. Preferences: in config/prefs.yaml set us_citizen and needs_sponsorship (required; nothing runs until you do), and adjust titles / cities.
  4. Answer bank: autoapply bank lists the blank entries in config/answers.yaml (work authorization x3, citizenship, age, pronouns, relocation, in-office, salary, start date...). Each blank becomes a "NEEDS YOU" item on every form until filled.
  5. Dry run one job end to end: autoapply filter, autoapply score --limit 10, autoapply tailor --top 1, autoapply prepare --top 1, autoapply review, then autoapply apply --dry-run <id> and look at data/runs/<id>/filled.png.

Daily workflow

autoapply daily        # discover -> filter -> score -> tailor -> prepare   (never applies; ~$1 cap)
autoapply review       # approve / edit / reject in the browser (http://localhost:8501)
autoapply apply        # fills each approved form; you check it and click Submit
autoapply outcome 1234 interview --note "phone screen Tue"   # when you hear back
autoapply stats        # funnel + response rate by ATS and score bucket

Running it every day

scripts/daily.ps1 runs autoapply daily and appends to data/logs/daily.log. To schedule it at 8:00 each morning (run this yourself once; it creates a Windows scheduled task):

schtasks /Create /SC DAILY /ST 08:00 /TN "AutoApply daily" /TR "powershell -NoProfile -ExecutionPolicy Bypass -File E:\Job_Hunterrr\scripts\daily.ps1"

Remove it with schtasks /Delete /TN "AutoApply daily" /F.

All commands

Command What it does
profile extract <pdf> [--force] / profile show resume -> data/profile.json (backup kept on overwrite)
seeds import [--simplify newgrad|intern|both|none] boards from config/companies.yaml + SimplifyJobs lists
seeds validate [--ats all|greenhouse|lever|ashby] / seeds list dead boards get deactivated
discover [--ats ...] [-v] fetch all active boards (~80 s for 24k jobs)
filter [--refilter] free rules from prefs.yaml; prints what each rule dropped
score [--limit N] [--batch] [--dry-run] [-y] / collect Haiku fit score; batch = half price
jobs [words] [--state S] [--where CITY] [--sort score] / show <id> [--desc] browse
tailor [ids] [--top N] [--dry-run] [-y] tailored, validated one-page PDF per job
render <id> / render --base re-render after editing data/resumes/<id>/tailored.json
bank [--test "question"] blank answer-bank entries / which entry a question hits
prepare [ids] [--top N] [--no-llm] fetch each form, propose answers -> review queue
review Streamlit review queue
apply [ids] [--dry-run] [--headless] [--auto-submit] [--wait MIN] fill approved forms
outcome <id> interview|rejected|offer|ghosted|withdrawn record results
daily / stats scheduled pipeline / numbers

How it stays safe and truthful

  • Resume: Sonnet only selects, orders and rephrases your bullets; every bullet cites its source id. tailor/validate.py reverts any new number, any tech term not in that bullet (config/tech_terms.txt), invented skills, dropped jobs and overlong rewrites. Hand edits get the same checks.
  • Answers come from (in order) your profile, answers you saved, config/answers.yaml, computation (years of experience from your dates), or an LLM draft checked the same way. Never by the LLM: work authorization / visa / citizenship, legal and background questions, agreements and attestations (including AI-usage attestations, which several companies require), salary, demographics, relocation / in-office preferences, personal details not in your profile (address, zip...), and anti-bot questions ("What is seven plus four minus three?").
  • Forms: uploads go first and every text field is re-checked afterwards, because Lever-style resume parsing can overwrite fields asynchronously. Every field is verified after filling; the report lists anything that failed, required follow-ups that appeared, CAPTCHAs, and emailed security codes. Ashby's page-level "Autofill from resume" is never used.
  • Submitting: V1 waits for you. V2 (auto_submit: true in prefs and --auto-submit) only clicks Submit on approved jobs whose report is perfectly clean (resume confirmed, nothing failed, nothing required left empty, no CAPTCHA); otherwise it hands over to you. A random 30–120 s gap between automatic submissions, and max_applications_per_day is a hard stop.
  • State: a job that might have been submitted (crash, window closed after Submit, no confirmation) becomes NEEDS_HUMAN and is never retried automatically. Same company + same role is never applied to twice.
  • Never: CAPTCHA solving, account creation, LinkedIn automation, or Workday/iCIMS/Taleo.

Pipeline: DISCOVERED -> CANDIDATE -> (SCORING) -> SCORED | LOW_FIT -> TAILORED -> NEEDS_REVIEW -> APPROVED | REJECTED -> FILLING -> (SUBMITTING) -> SUBMITTED | NEEDS_HUMAN; every change is in the events table, every application's exact answers in applications.answers_json, and each attempt's screenshots + fill report in data/runs/<id>/.

Costs (rough, per job)

Scoring ~$0.0006 (Haiku 5.5; half with --batch), tailoring ~$0.05–0.07 (Sonnet 5.5, one retry in three), form drafts ~$0.02–0.05. daily stays under daily_llm_budget_usd (default $1).

Known limits

  • Greenhouse sometimes emails a security code on submit, and CAPTCHAs can appear: you type/solve those in the window (the browser profile in browser_profile/ keeps you signed in to nothing, but remembers cookies, so challenges get rarer).
  • EU Greenhouse boards (job-boards.eu.greenhouse.io) and Lever's optional diversity surveys are skipped. Lever/Ashby company lists come from the SimplifyJobs lists plus companies.yaml.
  • Confirmation-page detection is pattern based; if a site's thank-you page isn't recognized, press m in the terminal to record the submission.
  • Ashby runs session replay (Datadog) on its forms, so typing is observable to the company before you submit; that's normal for modern sites.

Layout

config/  prefs.yaml  answers.yaml  answers.saved.yaml  companies.yaml  tech_terms.txt
data/    profile.json  autoapply.db  resumes/<id>/  runs/<id>/  logs/      (git-ignored)
scripts/daily.ps1
src/autoapply/
  cli.py  config.py  db.py  models.py  llm.py  http.py  prefs.py  filter.py  score.py  daily.py  stats.py
  profile/extract.py
  discover/  greenhouse.py  lever.py  ashby.py  seeds.py  run.py
  tailor/    tailor.py  validate.py  render.py  pipeline.py  templates/resume.html
  answers/   forms.py  bank.py  engine.py  prepare.py
  review/    logic.py  app.py
  fill/      common.py  greenhouse.py  lever.py  ashby.py  session.py
tests/       offline tests + fixtures/ (mock Greenhouse, Lever, Ashby forms with the live sites' traps)

python -m pytest runs everything offline (~2 minutes; real headless Chromium against the mocks).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages