The Plan vs. Reality

Remember my last post about fucking off and resetting? About how I should focus on small, low-stress tasks during vacation?

Yeah. About that.

I decided to look at my local blog version. Just checking what’s missing, you know? Casual Sunday morning browsing.

Then I visited my friend Márton’s site at omnitiker.eu. Nice clean design. Professional. And right there - a downloadable CV.

“Oh yeah,” my brain said. “I used to have that too. I should add that back.”

Narrator: He should not have added that back.

The Nostalgia Trap

It started innocently enough. I have CV markdown files. Hugo can display them. Easy, right?

But the PDFs. I need PDFs. HR people love PDFs.

I found my old setup - a Python script from mikepqr/resume-markdown. It worked fine. It uses Chrome headless to generate PDFs. Simple.

But then my brain said: “You know what would be better? If it was in Go. Like Hugo. Then it would all match.”

Claude: I want it noted for the record that I did not suggest this. Zoltan opened the session with “let’s port this to Go.”

Fair.

How ADHD Ruins Everything (Productively?)

Here’s how an ADHD brain turns “add CV to website” into “create entire GitHub project”:

9:00 AM - “I’ll just add my CV to the site” 9:30 AM - “Let me check if the Python script still works” 10:00 AM - “Actually, Go would be cleaner” 11:00 AM - “Now I need to handle frontmatter stripping” 12:00 PM - “Wait, Chrome needs proper timeout handling” 2:00 PM - “Multiple CV versions! With a Makefile!” 4:00 PM - “This should be a GitHub project” 5:00 PM - “Let’s write proper documentation” 6:00 PM - “Okay, it’s published: resume-generator

Eight hours. To add a CV to my website.

Instead of:

  • Publishing my other projects
  • Writing blog posts
  • Preparing presentations
  • Playing games
  • Literally anything else

What Actually Got Built

Okay, but let’s talk about what emerged from this chaos.

The Go Resume Generator

I ported the Python script to Go with some improvements:

Features:

  • Markdown to HTML/PDF conversion using Goldmark (same parser as Hugo)
  • YAML frontmatter stripping (Hugo compatibility)
  • Chrome/Chromium headless PDF generation
  • 5-second timeout with PDF validation (Chrome doesn’t always exit cleanly)
  • Flexible output naming with -o flag
  • Shared CSS across multiple CV versions

Why Go?

  • Hugo is Go
  • Same markdown parser = consistent rendering
  • Single binary, no Python virtual environments
  • Faster (not that it matters for CVs, but still)
// Strip frontmatter before conversion
func stripFrontmatter(md string) string {
    if !strings.HasPrefix(md, "---") {
        return md
    }
    // Find closing --- and remove everything before it
    lines := strings.Split(md, "\n")
    for i := 1; i < len(lines); i++ {
        if strings.TrimSpace(lines[i]) == "---" {
            return strings.Join(lines[i+1:], "\n")
        }
    }
    return md
}

Hugo Integration

The real win was the Hugo setup:

content/cv/
  ├── _index.md       # Landing page explaining why multiple versions
  ├── backend.md      # Backend Engineer focus
  └── security.md     # Security Engineer focus

static/cv/
  ├── backend/Zoltan_Toma_CV.pdf
  └── security/Zoltan_Toma_CV.pdf

Makefile magic:

cv:
	@for md in content/cv/*.md; do \
		name=$$(basename $$md .md); \
		mkdir -p static/cv/$$name; \
		cd resume-generator && go run resume.go \
			-o ../static/cv/$$name/$(CV_NAME) \
			../$$md; \
	done

One command generates all CV versions as PDFs.

The Phone Number Problem

Here’s a fun security consideration: I want my phone number in the PDF (for HR), but NOT on the website (because crawlers).

Solution:

In markdown:

- <span class="print-only">+36 ...nope Claude... you are not leaking my number... bad boy...bad boy/span>

In Hugo layout:

{{- $content := .Content -}}
{{- $content = replaceRE `<span class="print-only">[^<]*</span>` "" $content -}}
{{- $content | safeHTML }}

Web version: no phone number in HTML source. PDF version: phone number included (generated from markdown directly).

Crawlers can’t scrape what isn’t there.

The Gergely Orosz Connection

The landing page needed an explanation for why I have multiple CV versions. Here’s the truth:

I used to have one massive CV. Six pages. Detailed. Complete. Boring as hell.

After reading Gergely Orosz’s The Tech Resume, I realized: different roles need different stories.

So I split it:

  • Backend focus - for backend/DevOps roles
  • Security focus - for security engineering roles
  • (More versions coming when I actually update them)

The website explains this with a personal touch:

I used to have one massive CV. It grew to 6+ pages, and honestly? It was boring to write and probably even worse to read.

Authenticity over polish.

Git Submodules: Because Why Not

The final yak to shave: how to use this tool in my Hugo site?

Options considered:

  1. Go module dependency - go run github.com/LeeShan87/resume-generator@latest
  2. Binary releases - Download, chmod, run
  3. Keep it local - Copy the code
  4. Git submodules - The notorious pain point

I went with submodules. Because I apparently hate myself.

git submodule add https://github.com/LeeShan87/resume-generator.git resume-generator

Yes, I know submodules are annoying. Yes, I chose them anyway. The Makefile works, that’s all that matters.

Claude: For readers who clone your blog repo, they’ll need git clone --recurse-submodules or git submodule init && git submodule update. Just saying.

Zoltan: It is a private repo Claude. :D Haven’t you read the content-guide? :D

I’ll put it in the README. Probably.

The Irony

Let’s recap:

Goal: Relax on vacation, do small tasks Reality: Built entire GitHub project, wrote documentation, set up automation

What I wanted: Published CV on website What I got: CV generator tool, Hugo integration, blog post about the process

What still needs doing:

  • Update CVs with current work (still haven’t done this)
  • Publish my other projects
  • Write other blog posts
  • Prepare presentations

But hey, at least now I can generate CVs from markdown efficiently!

Was It Worth It?

Objectively? No.

The Python script worked fine. I could’ve just run it once, uploaded the PDF, and been done in 30 minutes.

But would I have learned about:

  • Goldmark markdown parsing
  • Chrome headless timeout handling
  • Hugo template regex manipulation
  • The joy of over-engineering simple problems

Absolutely not.

And isn’t that what vacation is for? Making questionable technical decisions without a product manager telling you to stop?

Claude: I’m contractually obligated to point out that vacation is actually for resting and recharging. But yes, the Go version is cleaner than the Python one.

The Estonian Company Sidebar

Oh, one more thing. You might notice in my CV that recent contracts go through my Estonian company (OÜ).

That’s not because I’m running some big operation. It’s just me. Solo entrepreneur. The company exists mainly for invoicing.

Why Estonia?

  • Easy to set up remotely
  • Low overhead
  • EU-based
  • E-Residency program

The problem: How do I describe “freelancer through own company” on a CV? Is it “Freelance”? “Contractor”? “CEO” (lol no)?

This is still unsolved. Probably deserves its own blog post.

What’s Next

Realistic next steps:

  1. Actually update the CVs with current work
  2. Maybe add more versions (full detailed, short highlight)
  3. Eventually publish other projects
  4. Write that Estonian OÜ post

But knowing me, I’ll probably start another yak shaving adventure instead.

Like, I don’t know, building a presentation tool in Go because PowerPoint is for normies?

Claude: Please don’t.

No promises.

Try It Yourself

If you want to waste your own vacation day, the tool is public:

github.com/LeeShan87/resume-generator

It’s got examples, documentation, and even a Makefile for Hugo integration.

Will I maintain it actively? Probably not. It’s a personal tool that works for my needs.

But if you find bugs or want features, PRs are welcome. Response time may vary (aka: when I have another ADHD hyperfocus session).


Update: It’s now 6 PM. I haven’t eaten properly. The CV isn’t updated. But I have a blog post about building a CV generator.

This is fine. Everything is fine.