Inspiration
Time and again, we noticed the same frustrating pattern: a genuinely well-matched application would go out, and the candidate would never even get a shot at showing up in front of a human decision-maker. Meanwhile, a clearly lower-fit applicant would sometimes get through, because a person judged them better, but because of which filter their resume happened to pass through. It felt like a lose-lose: the employer missed a strong candidate, and the candidate never got a fair look.
We eventually found the mechanism behind that pattern in a 2026 Stanford FAccT paper, "Algorithmic Monocultures in Hiring" (Bommasani, Bana, Creel, Jurafsky, Liang, arXiv:2605.27371). Over 90% of U.S. employers now screen applicants with algorithmic tools, and most buy from the same handful of vendors. When one vendor's model screens the same applicant at multiple employers, rejections stop being independent events. Sending the same resume through the same filter 200 times isn't 200 chances, it's one chance, repeated 200 times.
P(\text{at least one callback in } n \text{ applications}) = 1 - (1-p)^n
Under correlated ("monocultured") screening, that curve flattens: the paper's modeling suggests it takes roughly 25 applications under monoculture conditions to reach the same ~99.9% shot at a single callback that just 10 applications would give under independent screening. That gap (NOT resume quality) is the real thing costing people interviews. That reframing is what EzzApply is built around.
What it does
EzzApply is an job application pipeline built around one reframed objective: get the application in front of a human, not just make it well-written.
Given your resume/profile and the roles you care about, EzzApply:
- discovers matching job listings for you (currently via Custom Built-in DB), runs a two-stage fit analysis a deterministic baseline score plus an AI recruiter-style read, so you can
- see which roles are worth a tailored shot,
- lets you pick which listings to apply to,
- generates a tailored resume and a cover letter for each one, exported straight to PDF, and
- keeps applications, revisions, and results in a dashboard; and
- lets the user select resume text, request a change, review the proposed edit, and accept or reject it.
Two things keep that tailoring honest rather than just "AI-flavored":
- Guardrails, not vibes. Every generation stage is bound by a must_keep list (facts that must survive tailoring) and a do_not_claim list (things the model may never invent). Resumes are composed from small, exact, verified text edits, and not a freehand rewrite.
- A persona that's actually yours. EzzApply diffs what the AI proposes against what you actually keep, extracts recurring style signals, and feeds that back in as a persona.yaml on your next generation, so your third cover letter needs fewer edits than your first.
The layer we're building next: the Human-Reach Engine extends the same "reach a human" objective to the delivery side: detecting which ATS vendor a given posting runs on (a listing at Company A might route through Greenhouse, another at Company B through Workday) and tracking, across your own application history, how concentrated your exposure to any single vendor is getting, so we can nudge you toward variance, or a referral/direct-outreach path, before you unknowingly stack five applications behind the same filter.
How we built it
Frontend: initially scaffolded in Lovable, now a React + TypeScript app using TanStack, Vite, Tailwind CSS, and Radix UI, deployed on Vercel.
Backend: Python + FastAPI with background workers. The async job queue, application revisions, feedback history, and learning signals now live in Postgres using FOR UPDATE SKIP LOCKED claims so multiple workers (and machines sharing one Codex credential) can pull from the same queue safely. Auth is handled by Supabase.
AI layer: Codex CLI (gpt-5.6) is the sole production provider today. Every call runs in an isolated, ephemeral, read-only sandbox and must return a strict, stage-specific JSON schema validated with Pydantic. Stable instructions are kept separate from dynamic payload for prompt-cache efficiency. Separate typed prompts handle analysis, resume tailoring, cover-letter generation, applying explicit feedback, persona learning, and profile-suggestion learning. A shared Postgres-backed admission controller enforces a global in-flight cap and per-user fairness, with heartbeats/leases so a long model call doesn't get reclaimed mid-turn, and cooldown-then-probe backoff on rate limits.
Documents: resumes and cover letters are composed deterministically. The AI proposes exact, non-overlapping text changes; the backend applies, validates, and assembles the final LaTeX; PDFs are compiled from that. Uploaded and generated files sit in private S3-compatible storage. MinIO locally, Cloudflare R2 in production.
Challenges we ran into
- Truthfulness vs. optimization. Letting a model freely rewrite a resume is fast, but it's also how fabricated claims sneak in. We settled on exact, anchored edits plus backend-side validation including re-checking every must_keep fact survived before anything reaches export.
- Reliable AI execution under shared rate limits. Codex calls are long-running and share one execution budget across users. We built real admission control (global cap, per-user limit, leases, cooldown/probe on rate limits) rather than firing requests and hoping.
- Moving the queue to Postgres. Our early SQLite-based queue worked for a single machine, but a shared Codex credential across workers needed real row-level locking (FOR UPDATE SKIP LOCKED) and a place to store execution slots, cooldown state, and per-attempt telemetry. Postgres solved that, but it meant migrating checkpoint and fingerprint-reuse logic that used to be SQLite-specific.
- LaTeX determinism. AI-proposed edits have to preserve document structure and still compile. We push the model toward small anchored changes and keep composition and compilation fully deterministic and backend-owned.
- Treating job descriptions, resumes, and feedback as untrusted input. None of it can be allowed to override truthfulness rules or redirect what the model is asked to do.
Accomplishments that we're proud of
We didn't discover the algorithmic-monoculture problem. The Stanford FAccT paper did. But based on our own prior-art research, we believe EzzApply is the first applicant-facing product working to operationalize it: turning "which ATS is likely screening me, and how concentrated is my exposure" into something a job seeker can eventually see and act on, rather than a finding that only lives in a paper or an employer-side audit tool.
We're also proud that this is an end-to-end working system, not a single prompt behind a form. Structured resume import, fit analysis, truthful generation, deterministic PDF export, revision history, and a real feedback loop, backed by a production-shaped concurrency system (shared execution slots, per-user fairness, cooldown handling, resumable checkpoints).
What we learned
Products ship at extraordinary speed now with the advent of AI, which puts more pressure on founders to stay close to the actual problem rather than the roadmap. We pivot often. Adding and, just as often, removing features to keep the product matched to what the market needs, and we try to act on real user feedback quickly rather than defending a plan for its own sake.
Technically, we learned that generation quality is only one part of a dependable AI product. The surrounding system (verified inputs, strict output contracts, deterministic validation, retries, checkpoints) matters just as much. And more than anything: the document isn't the finish line. A well-written resume has limited value if it keeps entering the same automated screening path without ever reaching a person. That's the insight that moved our roadmap from "generate a better document" toward "get the document in front of a human."
What's next for EzzApply
Concurrency. We're validating the Codex admission-control system in production before expanding it. Starting from one shared in-flight call, running canaries, and raising the cap to two only after quality, timeout, and rate-limit thresholds are met. EzzApply stays Codex-first through this validation; direct API providers or open-source fallback models are a later, gated expansion, not a current production claim.
The Human-Reach Engine, detailed in our Idea Brief: our job data already records ATS-related metadata per posting, but portfolio-level vendor concentration, a differentiation score, and routing guidance aren't shipped features yet. The plan is to detect the ATS behind a posting where public signals allow it, surface when a user's recent applications are concentrated in one ATS ecosystem, vary resume structure and evidence emphasis across applications routed through the same vendor, and suggest alternatives. A referral, direct outreach when repeated portal submission looks unlikely to reach a person. This will always be framed as a transparent exposure signal, not a rejection or acceptance prediction.
Further out, we want opt-in interview/outcome tracking, so EzzApply can eventually learn which document and routing choices actually helped someone reach a hiring team, rather than optimizing for generation quality alone.
Built With
- alembic
- amazon-ec2
- cloudflare
- codex
- docker
- fastapi
- gpt-5.6
- jobhive
- minio
- node.js
- playwright
- postgresql
- psycopg
- pyarrow
- pydantic
- python
- selectolax
- sqlalchemy
- supabase
- trafilatura

Log in or sign up for Devpost to join the conversation.