My V2 resume opened with "39 years old, 10 years of experience". I have 14. The
PDF had been sleeping on OVH for four years, linked from index.php:1019,
and nobody had reopened it. I wanted to fix three lines. I ended up with 36 iterations,
dual ATS/recruiter scoring, a QR code that misaligned everything, and a V3 that
overwrites V2 to keep the link alive.
Here is how it actually went.
The first trap: Claude cannot see my PDF
First reflex: "show me the render, I will tell you what to fix". Except Claude
was running on a remote server, over SSH, no browser. No localhost reachable from my
side. The PDF generated in /tmp/cv-build/cv.html was only visible to
Claude — and Claude cannot look at an image.
The sentence that unblocked everything: "you do realize you're on a server and I can't access your localhost". From there, the workflow flipped:
- Claude generates
cv.html+cv-v{n}.pdfwithgoogle-chrome --headless=new --print-to-pdf - Immediate upload to OVH via
lftp(credentials inscripts/.ftp.env, gitignored) - I click the public link, note what's broken, send back in plain language
- Claude diffs the previous version and fixes it
That is the thing Claude cannot do alone: judge a visual render. He has no eye. I do. The loop exploits that: he codes, I look, I yell, he fixes.
Dual scoring: ATS first, human second
A modern resume goes through two filters before reaching a desk: an ATS (Applicant Tracking System) parser that extracts structured fields, and a human who scans in 7 seconds. The two do not score the same things.
I asked Claude to play both roles on every iteration:
| Criterion | ATS / AI recruiter | Human recruiter |
|---|---|---|
| Section names | Canonical (EXPERIENCE, SKILLS…) | Readable, hierarchical |
| Domain keywords | Density, presence in EXPERTISE line | No stuffing, embedded in prose |
| Action verbs | Bullet start ("Designed", "Migrated") | Not too bullet-point, with flow |
| Metrics | Presence of numbers | Credibility, context |
| PDF readability | Extractable font, reading order | Whitespace, visual hierarchy |
| Soft skills | Often ignored | Mandatory, but no clichés |
Target: ≥ 90/100 on both scores. No averaging — both must hit. A resume that maxes out ATS but stuffs keywords gets dropped by humans. A resume that charms humans but ignores canonicity never clears the auto filter. The instruction "score it and keep looping until it gets an excellent grade" structured the whole session.
The pyramid: from general to specific
A resume is not read left to right. It is read in a zigzag, top to bottom, with an eye that disengages as soon as a block fails to draw it in. The rule we set: pyramid flow, from broadest to most specific.
- Profile — narrative prose, career summary in 4 sentences, embedded soft skills
- EXPERTISE LINE — single callout with densified keywords for the ATS
- Technical skills — chips colored by mastery level (soft teal = mastered, white = supporting)
- Experience — timeline with action verbs and metrics
- Projects — concrete, clickable link, visible stack
The profile got rewritten five times. The final version is prose, not bullets in disguise. Soft skills are slipped in — "methodical approach", "digging problems down to their root", "autonomous and used to vulgarizing". No "passionate since childhood". No "rigorous team player". ATS clichés burn human credibility for zero gain with the machine.
The feedback that flipped the render
Across 36 iterations, some remarks had disproportionate impact. Here they are in the order they landed:
1. Kubernetes, Terraform, PostGIS — never touched
Claude's first draft cherry-picked buzzwords. I had to cut hard: "Kubernetes drop it, never used it, PostGIS I don't even know what that is, Terraform nope". A resume that lies about the stack collapses at the first technical interview. Claude has no way to know what you actually touched — that filtering is your job.
2. "Methods 14 years" — irrelevant
Adding a duration on Agile/Scrum is filler. Removed. The resume gains in useful density.
3. The header QR code shifted everything
I asked for a QR code to the portfolio. Claude put it in the header. Result:
"this misaligns everything, ugly". Moved to page 3 footer, 15mm, accent teal,
generated as inline SVG with the Node qrcode package. Discreet,
functional, in the right spot.
4. "Go / PHP / Vue.js" wrapping with an orphan word
The title broke and left "Go /" alone on its line. Hideous. Fix:
<span style="white-space:nowrap">Go / PHP</span> / <span style="white-space:nowrap">Vue.js</span>
The kind of detail you spot in 30 seconds visually but miss while eyeballing HTML. Human eye catches it. Agent doesn't.
5. Location field too long
"Besançon · Mobile Franche-Comté / Switzerland · Full remote" overflowed the
right header block. Didn't want to shorten the info — let Claude play with CSS Grid:
grid-template-columns: auto minmax(0, 62mm) + max-width: 88mm
for clean wrapping.
6. Profile with the same green background as the rest
I wanted the callout style for the EXPERTISE line only. Differentiated: the prose stays neutral, green callout only for the keyword line.
Overwriting V2 → V3 to keep the link alive
The file on OVH was named HUGONNOT Odilon CV - Developpeur WebV2.pdf. The
link in index.php:1019 pointed to it. Rather than modify HTML, redeploy,
and risk breaking an external reference (LinkedIn, archived emails, recruiters who
saved the PDF), I overwrote V2 with V3's content.
cp /tmp/cv-build/cv-v36.pdf "assets/images/projects/HUGONNOT Odilon CV - Developpeur WebV2.pdf"
cp /tmp/cv-build/cv-v36.pdf "assets/images/projects/HUGONNOT Odilon CV - Developpeur WebV3.pdf"
lftp -e "set ftp:passive-mode true; put -O /www/assets/images/projects 'HUGONNOT Odilon CV - Developpeur WebV2.pdf'; put -O /www/assets/images/projects 'HUGONNOT Odilon CV - Developpeur WebV3.pdf'; bye" \
-u "$FTP_USER,$FTP_PASS" "$FTP_HOST"
V2 keeps its name and URL. The content is fresh. Old shares keep working, new ones point to V3. No migration, no redirect to maintain. The kind of hack a human finds obvious that an agent does not propose spontaneously — because it lacks the context of the external shares I never mentioned.
What the loop produced
The result is here:
Three strict pages:
- Page 1 — Header + Profile + Technical skills
- Page 2 — Full experience timeline
- Page 3 — Clickable projects + bottom-grid (Education, Languages, Interests) + QR code
Layout forced via page-break-before: always on sections 03 and 04. No
phantom page, no big white hole. Each page stands alone, and the eye never disengages
at the bottom looking for the rest elsewhere.
Conclusion
The agent cannot see. That is the limit. Across 36 iterations, roughly 30 fixes came from me — from the eye, not the code. Claude excels at turning a human remark ("this misaligns everything", "the orphan title", "Kubernetes never touched") into a CSS diff or a block rewrite in seconds. But aesthetic judgment, career coherence, stack honesty — those stay my job.
The real productivity gain is not "AI made my resume". It is "I can test 36 variants in two hours instead of one per day". Iteration bandwidth widens. Judgment quality stays on me. And that is exactly how it should be.