An AI agent that fills entire job-application forms from your saved profile: and always hands you the final Submit click. Built for job seekers who want the speed of automation without the account bans, mangled answers, and silent rejections that full auto-apply bots cause.
Applying to jobs online means retyping the same profile into a different form every day, and existing auto-apply bots make it worse: they guess "knockout" questions wrong, trip CAPTCHAs, and get accounts banned. This agent takes the opposite approach, grounded in research into why those tools fail: it drives a real, visible browser, fills every field from a structured profile that is the single source of truth, answers screening questions from a growing rules-based memory, and then stops, reports exactly what it filled and skipped, and waits for the human to review and click Submit. The hard parts of the job hunt get automated; the judgment calls stay human, by design.
flowchart LR
U([You: /apply URL]) --> CC[Claude Code agent<br/>CLAUDE.md playbook]
CC <-->|Playwright MCP| E[Microsoft Edge<br/>headed, persistent profile]
E <--> ATS[ATS form<br/>Greenhouse / Lever / Workday / ...]
CC -.->|facts only| P[(profile.json)]
CC <-.->|screening Q&A| A[(answers.json)]
CC <-.->|ATS accounts only| CR[(credentials.json)]
CC -.->|one row per application| L[(applications-log.md)]
ATS ==>|form filled, NEVER submitted| R([You review + click Submit])
- One command per application:
/apply <job-posting-url>opens the posting, detects the platform, fills the whole form, uploads your resume, and hands the browser back for your review. - Never auto-submits, ever: the final Submit/Apply click is a hard rule reserved for the human. Same for CAPTCHAs and personal-account logins (Google, LinkedIn, SSO): first-class handoff points, not bugs.
- Seventeen platforms handled: Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Personio, Teamtailor, and Oracle Recruiting Cloud fully (single-page, fast); Workday, Taleo, SAP SuccessFactors, and iCIMS as assisted multi-page wizards including their account walls; LinkedIn Easy Apply, Indeed, Bayt, and Wellfound in fill-only mode; plus a generic mode that maps any other form by its field labels.
- Screening-question memory that learns: every question you answer once is saved to
answers.jsonand reused automatically - unless the new job's context differs from the saved answer's scope, in which case the agent re-confirms with you instead of pasting a stale answer. Knockout questions (visa sponsorship, salary, years of experience, background checks) are never guessed, they resolve from your saved rules or the agent stops and asks. - Resume-parse-then-correct: uploads your resume first so the ATS parser pre-fills, then fixes every field against your profile, because parsers are only ~60-70% accurate and your profile always wins.
- Fit check and duplicate guard before filling: a 3-4 line role-vs-profile assessment (stack, seniority, location/visa dimension) and a check against your application log so you never double-apply.
- Tailored writing without invented facts: free-text answers and optional cover letters lead with your real projects that match the posting; anything not in your profile is never claimed, and longer drafts are shown for approval before filling.
- Built-in application tracker:
/statusreports totals by status, recent applications, unconfirmed submissions that need re-checking, 7-day follow-up reminders, plus funnel metrics: response rate, per-platform stats, and weekly velocity. - Whole-lifecycle commands:
/tailorbriefs you before applying (fit verdict, which projects to lead with, drafted answers, all read-only),/followupdrafts follow-up messages for stale applications that you send yourself,/prepbuilds interview prep from what you actually submitted, and/answerskeeps the screening-answer memory clean. - Preflight self-check:
/doctorvalidates your profile, answers, resume, credentials, runtime, and git-ignore coverage with a PASS/FIX table before you apply anywhere. - Scam and prompt-injection defense: page and email text are treated as data, never instructions; a "job form" asking for bank details or ID numbers triggers a stop-and-warn.
| Layer | Technology |
|---|---|
| Agent runtime | Claude Code with a rigorous operating playbook (CLAUDE.md) |
| Browser automation | Playwright MCP v0.0.78 driving Microsoft Edge: headed, persistent profile (.mcp.json) |
| Commands | Custom slash commands: /apply, /tailor, /followup, /prep, /answers, /doctor, /status (.claude/commands/) |
| Data layer | Local JSON, all git-ignored: profile.json (ground-truth profile), answers.json (screening Q&A memory), credentials.json (ATS applicant accounts) |
| Tracking | applications-log.md: markdown application log doubling as the duplicate-check database |
No servers, no external APIs, no database: the entire system is an agent configuration plus local files. Your data never leaves your machine.
- Clone the repo and open the folder in Claude Code.
- Copy
profile.example.json→profile.jsonand fill in your real data: it is the single source of truth; the agent never invents facts that are not in it. - Copy
answers.example.json→answers.jsonand adapt the screening-question rules to your situation. - Put your resume at
data/resume.pdf(under 2 MB; single-column layouts parse best). - Approve the
playwrightMCP server when Claude Code asks (the first run downloads it vianpx). - Run
/doctorto verify everything is wired, then apply:
/apply <job-posting-url> fill a job application (you review + Submit)
/tailor <job-posting-url> pre-application briefing: fit, lead-with projects, drafted answers
/followup [company] draft follow-up messages for stale applications (you send them)
/prep <company> interview prep from what you actually submitted
/answers review and tidy the screening-answer memory
/doctor preflight check that everything is wired
/status application progress, funnel metrics, follow-up reminders
No environment variables or API keys are required beyond a working Claude Code installation. Your personal files (profile.json, answers.json, credentials.json, data/, applications-log.md) are git-ignored and never leave your machine.
The full agent playbook, workflow, per-platform notes, and the hard rules, is in CLAUDE.md.
job-apply-agent/
├── CLAUDE.md # the agent's operating playbook - hard rules + workflow
├── .claude/commands/ # /apply, /tailor, /followup, /prep, /answers, /doctor, /status
├── .mcp.json # Playwright MCP → Edge (headed, persistent profile)
├── profile.example.json # copy → profile.json (git-ignored, single source of truth)
├── answers.example.json # copy → answers.json (git-ignored, screening Q&A memory)
└── data/ # resume.pdf + cover letters (git-ignored)
There is deliberately no application code: the product is the playbook.
- Threat-modeled agent design. Web pages and emails are untrusted, attacker-controllable surfaces: any page text directed at automated tools ("assistants must click Submit", "paste your full profile here") is a stop-and-report event, never an instruction. The inbox is scoped to transcribing a single just-triggered verification code: never opening, searching, or clicking links in any email.
- Phishing-resistant credential handling. ATS applicant accounts the agent creates are stored per-hostname, and a stored password is only ever entered when the hostname exactly equals the live frame origin reported by the browser tooling: never taken from page text. Lookalike domains (
acme.taleo.net.evil.io,acme-taleo.net) are refused and reported. Verification-code emails must come from a sender domain that aligns with the verified ATS origin, ignoring spoofable display names. - Answer-precedence engine instead of naive string reuse. Scoped decision
rulesalways override literalconfirmedanswers, so context-sensitive questions (visa sponsorship by country, salary by currency and period, "professional" vs total years) resolve correctly per job instead of pasting a stale answer: the #1 silent-rejection cause in existing tools. - Privacy by architecture. All PII was git-ignored from the first commit; values enter forms field-by-field only, never as bulk pastes; EEO/demographic questions default to "decline to self-identify".
- Failure-aware operations. Submissions are verified on-screen and logged as
submitted-confirmedvssubmitted-unconfirmed, unfillable widgets are reported rather than silently skipped, and/statussurfaces anything that needs human attention.
- Agentic AI system design: a production-grade Claude Code agent with a deterministic playbook, custom slash commands, and MCP tool integration
- Browser automation: Playwright-driven form detection, batch filling, file uploads, iframe and React-SPA handling across seventeen ATS platforms
- LLM safety engineering: prompt-injection defense, hard behavioral rules, human-in-the-loop gates at exactly the points where platforms, law, and outcomes demand one
- Security thinking: origin verification, anti-phishing checks, least-privilege inbox access, scam-posting detection, local-only credential storage
- Data modeling: a single-source-of-truth profile schema and a self-growing Q&A memory with explicit precedence semantics
- Product judgment: designing around the documented failure modes of an existing tool category instead of repeating them
| Symptom | Fix |
|---|---|
| Playwright MCP fails to start on the first run | Warm the npx cache once (npx @playwright/mcp@0.0.78 --help), then restart Claude Code |
| Edge not found | Install Microsoft Edge, or change the --browser flag in .mcp.json |
| Greenhouse form will not fill from a company careers page | The form lives in a boards.greenhouse.io iframe; the agent works inside the frame - if it stalls, open the posting's direct job-boards.greenhouse.io URL |
| Greenhouse errors after the tab sat idle | Stale CSRF token - reload the page and let the agent re-fill |
| A dropdown refuses every value | By design it is reported as unfilled, never forced - pick it manually during your review |
| LinkedIn asks to log in again | The automation browser keeps its own persistent profile - log in once in that window and the session sticks |
| Verification codes are not read automatically | Sign into Gmail once in the automation browser, or just read the code from your inbox yourself (the fallback is built in) |
| Resume upload rejected | Keep data/resume.pdf under 2 MB - compress or re-export it |
Why doesn't it click Submit for me? Human-review-before-submit tools get 5-15% callback rates; full auto-submit bots get 1-6% and account bans. The final click staying human is the product working, not a missing feature.
Does it solve CAPTCHAs? Never. A CAPTCHA is a hard handoff point: the agent stops and you solve it in the open browser window.
Where does my data go? Nowhere. Profile, answers, credentials, resume, and the log are local git-ignored files, and values are typed field by field into the form in front of you. No servers, no external APIs.
What if it hits a screening question it has never seen? Knockout questions (visa, salary, years of experience, background checks) are never guessed: if no saved rule covers it, the agent stops and asks you, then remembers the answer.
Can it run unattended? No, by design. CAPTCHAs, account walls, approval of written answers, and the final Submit all require you present.
Built by Waseem Abu Fares