Resume engine: why my resume builder refuses to build
For a while I was using AI to tailor my resume for every job, and it would pretty much always mess something up somewhere, a line would run onto a second page, a bullet would pick up a number I never gave it, a title would quietly get renamed to match the posting. So every resume turned into three or four rounds of me telling Claude Code to fix this, then fix that, then fix the thing it broke while fixing that, and at some point I stopped and asked myself why I was taking a process that should come out the same every time and leaving it up to RNG. A resume has rules I already know, one page, real titles, nothing I can't back up, and if I know the rules then there's no reason to hope the model remembers them on the first try when I could just write them down once and have a program check them every time.
You can't just tell the model
The thing I kept running into is that you can tell a model "don't make things up" or "keep it to one page" as many times as you want, and it'll agree with you every time, and then it'll hand you something that breaks both rules and tell you it looks great. It doesn't actually know how tall a page is, and it doesn't know which of its bullets came from me and which ones it filled in because they sounded right, and with no verification step it's going to assume it's right all the time. It's kind of like asking someone to pack your bag without a scale and then taking their word that it's under the weight limit, and the only way to actually know is to put it on the scale at the counter.
So the idea was to take the ambiguity out wherever I could, and let Python do the parts that have one right answer, since that's honestly what it's for.
What it does
Everything true about my career lives in one file, a master PROFILE.md, and each fact in it gets registered with an ID. When I want a resume for a job, the model's only job is the part it's actually good at, reading the posting and deciding which of my facts to lead with and how to phrase them, and it writes that down as a small spec file where every line has to point at one of those IDs. Then the Python takes over, and before it renders anything it checks that every summary line, bullet, skill line and degree cites a real fact, and if one doesn't, it refuses to build and tells you which line has no receipt. It works the same way an expense report does at a job, where you can describe the dinner however you want, but if there's no receipt attached it doesn't get paid.
After that it renders the DOCX and PDF, measures the actual page, and adjusts the spacing until the page is about 96% full, and it won't shrink the font below 10 pt to squeeze more in, so if the content doesn't fit it stops and tells you to cut something. I made that rule on purpose because the model's instinct when something overflows is to make everything smaller until it technically fits, and a resume in 8 pt font technically fits in the same way a suitcase you had to sit on technically closes.
The part I didn't expect to like as much as I do is the list it gives back of keywords it couldn't support. When I tailored for a part-time operations role at Democracy Prep, it covered 8 of the 10 keywords I cared about and flagged procurement and inventory management as things I had no evidence for, which is exactly the moment an AI would normally just write a vague bullet that sort of implies I've done procurement. Instead I get a question, and if the answer is yes then it goes into PROFILE.md first and gets cited from there, and if the answer is no then it stays off the resume.
Who built what
I should be clear that I didn't write this code myself. I designed it, I decided what the rules were and what "done" looks like, and Claude Code wrote the Python while I kept tightening the spec every time a build came out wrong. That's pretty much the same pattern as the resume itself, where the model does the writing and something deterministic checks it, which I think is the only way I actually trust either one.
What's still open is that the check only proves a line traces back to my profile, and it can't tell whether the profile is true, so the whole thing is only as honest as the person filling in PROFILE.md. For me that's fine, since that file is the one place I'm careful, but it's the reason the setup step asks you questions instead of guessing.
A friend wanted to use it on their own resume, so I made it work for anyone with a profile or an existing resume and put it up on GitHub at mdpierre/resume-engine, with a fictional example profile so you can see what it builds before putting your own stuff in.