This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
The task I dread most when applying for jobs is rewriting my cover letter and resume for every single job description. So I built the Lazy Job-Application Helper.
You paste your resume as plain text and paste a job description. Gemma, an open-weight model from Google, sends back four things:
- a tailored cover letter
- the keywords the job asks for that your resume doesn't show
- 3 to 5 rewritten resume bullets
- 5 likely interview questions
Everything is saved to a history page where you can reopen or delete it. Each account can only see its own applications.
It gives suggestions only. It doesn't write a whole resume, and it doesn't apply for you. The rule I cared about most is that the model may only use facts that are in your resume. It must never invent skills, tools or numbers, because a cover letter that claims experience you don't have is worse than no cover letter.
Demo
Video: https://www.youtube.com/watch?v=cR_yfAr1JYI
A few honest notes about the demo:
- I recorded it on my phone, and it runs locally (that's the
127.0.0.1in the address bar). - I paused the recording while Gemma was generating, so the video skips the wait. On the free tier a real run takes up to about 2 minutes.
- I did not deploy a public link on purpose. A public demo would let strangers spend my free API quota and send their resumes to a third party.
I tested it with mismatched sample resumes on purpose. When I gave it a DevOps resume and a Frontend (ReactJS + InertiaJS) job, it listed ReactJS, InertiaJS, Tailwind CSS and Vite as missing keywords. Its interview questions asked how a DevOps background prepares me for a frontend role. It did not pretend I had React experience, and that is exactly what I wanted.
The screenshot below shows the same idea the other way round: a front-end resume against a Java backend job. Java, Spring and Unix come back as missing keywords, and the rewritten bullets keep the real numbers from the resume.
Code
Lazy Job-Application Helper
Paste your resume and a job description. Gemma gives you a tailored cover letter, the keywords your resume is missing, a few resume bullet rewrites, and five likely interview questions. Everything is saved to a private history page.
Built for the DEV Hacktoberfest Open-Source AI Challenge: Week 3 ("Slow and Steady"). The theme is open-weight AI that does a dreaded task for you, and writing job applications is mine.
What it does
- Sign up and log in (Laravel Breeze).
- Paste your resume as plain text and paste the job description.
- A hosted Gemma model returns
- a tailored cover letter
- missing keywords (things the job asks for that your resume does not show)
- 3 to 5 rewritten resume bullets
- 5 interview questions
- Results are saved. You can view or delete them from the History page.
Suggestions only. It does not generate a full resume, and…
How I Built It
This was my first time calling an AI model from code.
- App: Laravel with Breeze (login), Blade and Tailwind CSS, with SQLite for development.
-
Model:
gemma-4-31b-it, served through the Gemini API on Google AI Studio's free tier. -
One class for all model calls:
ModelClient.phpreads the API key, URL and model name from.env. It asks for a JSON answer, pulls out the JSON, checks that all four fields are present, and retries once if the output is unreadable. It also retries on temporary API errors and shows a friendly message if the call fails. - Safety basics: keys stay out of git, submissions are rate limited, and other users' result pages return a 404.
Things that went wrong along the way:
- The first model name I used returned a 404. I asked the API which models my key could use and found the right one.
- Gemma 4 returns its "thinking" as a separate part of the reply. My first version would have shown that as the answer, so I filter it out.
- Google's API returned a 500 error once, which is why the retries exist.
- The Vite build failed on Termux until I added esbuild.
The prompt took four rounds, and I checked every round against the resume text by hand:
- First version: no invented skills, but it added filler like "successfully" and "to enhance team capabilities".
- Ban additions: no more filler, but the bullets were nearly copies of my resume.
- Keep numbers exact: the numbers survived, but one bullet still came out identical.
- Final version: pick the bullets most relevant to the job, start with a strong verb, put the result first, keep the same meaning, never copy word for word, and add no new facts.
With the final prompt, the rewritten bullets matched facts in the resume, including the numbers (+200, +24%, $5,000, 5,500 lines of code and a team of 4). The cost of being strict is that the rewrites stay fairly close to the original wording. I chose honest over flashy.
The cover letter and interview questions are less tightly controlled than the bullets. In some runs they still add soft phrases like "proven track record" or "extensive experience" that my resume doesn't state. That is why the result page tells you to check every line before using it.
I also used an AI assistant to help plan the build and debug errors, and I ran and tested every step myself.
Why Does Open Innovation Matter?
- I can't run a model this big myself. A 31B-parameter model is too large for the hardware I have. A hosted open-weight model let me use Gemma anyway, at no cost to me.
-
I'm not locked in to one model. All model calls go through one class and three
.envvalues. A different Gemma size is a.envchange, and a different provider means editing one file. - Open weights make a private option possible. Someone with a stronger machine could run Gemma locally, for example with Ollama, and keep their resume on their own computer. I did not build or test that, so I'm not claiming it.
The honest part: my version uses Google's hosted free tier. Resume text goes to Google, and on the free tier Google may use it to improve its models. That is why the form warns you not to paste phone numbers, addresses or ID numbers, and why I don't call this version private. For a tool that handles resumes, being able to move to a local model is the real reason open weights matter to me.
The Lazy Payoff
I timed myself writing a cover letter and new resume bullets for one job by hand. It took 10 minutes. The app returned its answer in about 2 minutes of waiting, and that answer also included the missing keywords and 5 interview questions I didn't write by hand.
This was one task, one person and one sample resume, and I didn't stopwatch the app, so treat it as a rough comparison. Nobody else has used it yet, and I still need to read and check everything it writes before using any of it.
Prize Categories
- Best Use of Gemma


Top comments (0)