Build an automatic cover letter writer with LLMs and BAML

Robot mascot for technology posts

If you don’t recall what BAML is, it is Basically A Made-Up Language that standardizes the way you can interact with LLM APIs. It essentially turns an API call to an LLM into a function call, with standardized outputs.

I’m sure you could work with the JSON objects that come back from calling ChatGPT’s API, but I am fairly convinced that you will go farther faster if you take the leap into BAML first.

That’s what I did in my prior post “BAMLing Through the Code: Overcoming Challenges with AI’s New Language”

Now I want to use it to do something useful. The plan is to read in a job description, read in a resume, and automatically produce a cover letter.

I am assuming you have a Python environment set up. If you need tips on that read my post Try Python: It’s not too hard.

I am also assuming you have API access to an LLM. I’m going to use ChatGPT. If you need help with that check out my post Get API Access to ChatGPT

First let’s set up BAML

Follow the boundaryml.com’s installation directions at:
Python — Boundary Documentation

If you get stuck on anything, leave me a comment or email thingsitriedblogger@gmail.com
I’d be happy to help you.

Since the BoundaryML folks seem to favor VS Code, I decided to bite the bullet and try it out. But I made the mistake of installing the hefty Visual Studio instead of the lightweight VS Code.

I went to do a hello-world.py and it wanted me to define a class. OMG, this is why most people thinking coding is too hard. It can be overwhelming just trying to get started.

Don’t give up. Lightweight tools like VS Code are fine. If you aren’t a serious coder, try one of these:

  • NotePad++
  • VS Code (not Visual Studio)
  • Thonny
  • IDLE
  • PyCharm
  • Jupyter notebook

I used to use Jupyter a lot, but I actually think I sort of outgrew it.

Now I usually use NotePad++, but today I am entering the VS Code world, and so far, I’m kind of liking it. I dig the “Ctrl + ~” shortcut to open an in-app terminal.

Once in VS Code, they recommend installing the BAML VSCODE/Cursor Extension and updating your VSCode user settings with some basic typeCheckingMode JSON.

With the help of ChatGPT, I was able to get past those hurdles. You can skip them if you don’t want to deal with those.

If you are in VS Code, you can open a terminal with the keyboard shortcut “Ctrl + ~” Now just do “pip install baml-py” at your terminal.

Ok. That was a little tougher than I thought. Python wasn’t working in my VS Code terminal. Turns out it wasn’t using the proper Python interpreter. I managed to get past that.

Here is help with setting up Python in VS Code from stackoverflow.

Now install some starter code with “baml-cli init”

Terminal where I set up BAML

That created a “baml_src” directory with three files:

  • clients.baml
  • generators.baml
  • resume.baml

Then generate a client with “baml-cli generate”

Then create a file called main.py at the same level as your baml-src and baml-client directorys.

Put some code in there to use BAML. They have some sample code for main.py at boundaryml.com:

Python — Boundary Documentation

I will say it is a little anti-climactic when it runs. There is no output. But—BAML is set up.

Now Let’s Have Some Fun with BAML

Here is some code that reads in a plain text resume and a plain text job description. The resume is parsed and sent along with the job description to ChatGPT with a prompt asking for a cover letter.

The returned cover letter is saved as cover_letter.txt.

Once again, feel free to leave me a comment or email thingsitriedblogger@gmail.com if you have any questions.

cover_letter_writer.py:

''' This is cover_letter_writer.py '''

# Ensure you have the latest OpenAI package installed
# pip install –upgrade openai
import openai
import os
from baml_client.sync_client import b
from baml_client.types import Resume

my_api_key = os.getenv("OPENAI_API_KEY")  # Fetch API key from environment

def extract_resume(raw_resume: str) -> Resume: 
  # BAML's internal parser guarantees ExtractResume
  # to be always return a Resume type
  response = b.ExtractResume(raw_resume)
  return response

# Function to generate a cover letter using OpenAI's latest API
def generate_cover_letter(name, email, experience, skills, job_description):
    prompt = f"""
    You are a professional career coach and expert in writing compelling cover letters. 
    Generate a personalized cover letter for the applicant based on the details below:

    Applicant Name: {name}
    Applicant Email: {email}
    Experience: {', '.join(experience)}
    Skills: {', '.join(skills)}
    
    Job Description:
    {job_description}

    Cover Letter:
    """
    
    # Call OpenAI API using the new format
    client = openai.OpenAI(api_key=my_api_key)  # Replace with your actual API key

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": "You are an expert cover letter writer."},
            {"role": "system", "content": "You are a confident qualified candidate."},            {"role": "user", "content": prompt}
        ],
        max_tokens=400
    )
    
    return response.choices[0].message.content.strip()
    


print("starting") 

# Open the job description and read its contents into a string
with open("job_description.txt", "r", encoding="utf-8") as file:
    job_description = file.read()
# Print the contents (optional)
#print(job_description)


# Extract resume into applicant details
with open("my_resume.txt", "r", encoding="utf-8") as file:
    resume_text = file.read()    
extracted_resume = extract_resume(resume_text)
applicant_details = {
    "name": extracted_resume.name,
    "email": extracted_resume.email,
    "experience": extracted_resume.experience,
    "skills": extracted_resume.skills
}


# Generate Cover Letter
cover_letter = generate_cover_letter(**applicant_details, job_description=job_description)

print(cover_letter)


# Open file in write mode and save the string
with open("cover_letter.txt", "w") as file:
    file.write(cover_letter)

job_description.txt:

This is job_description.txt

Job Title: Blogger – Things I Will Never Try
📍 Remote | Part-Time or Full-Time

About Us
"Things I Will Never Try" is a humor-infused lifestyle blog dedicated to exploring (and avoiding) the weirdest, wildest, and most questionable trends, activities, and products out there. From skydiving to snail facials, we dive deep into why some things just aren't worth the risk—so our readers don’t have to!

We’re looking for a creative, witty, and engaging Blogger who can turn skepticism into storytelling, crafting entertaining, opinionated, and well-researched posts about the things they absolutely refuse to try (but still love to write about).

Responsibilities
🖊️ Write 2-4 engaging blog posts per week on topics ranging from bizarre food trends to extreme sports (that you will never, ever try).
🔍 Research viral challenges, trends, and niche activities to explain why they’re just not for you.
🤣 Infuse articles with humor, sarcasm, and a healthy dose of skepticism.
📸 Source relevant images, memes, and gifs to enhance content.
📢 Promote blog posts on social media and interact with readers in the comments.
📈 Optimize content for SEO while keeping it fun and conversational.
🤝 Collaborate with guest writers and contributors for fresh takes on the "Nope, not doing that" lifestyle.

What We’re Looking For
✅ A strong, witty writing voice that can turn hesitation into hilarity.
✅ Passion for storytelling and online trends (even if you refuse to participate in them).
✅ Basic knowledge of SEO and WordPress (or willingness to learn).
✅ Social media savvy—able to craft posts that spark engagement.
✅ Ability to fact-check bizarre trends before completely roasting them.

Bonus Points If You:
🌶️ Have a knack for ranking the worst things ever (ex: "Top 10 Foods I Will Never Eat Again").
🎥 Can create short-form videos or memes to accompany your posts.
😂 Have personally regretted trying something once and vowed never again.
📣 Have experience writing for humor, lifestyle, or satire blogs.

Perks & Compensation
💰 Competitive freelance rates or part-time salary
📖 Creative freedom to say "No thanks, not doing that."
🚀 A fun, laid-back team that loves a good rant
📢 Exposure on a growing platform with a cult following of fellow skeptics

How to Apply
Think you’re the perfect fit? Send us:
📜 A short cover letter explaining three things you will never try and why
📝 Links to previous writing samples (or a funny Twitter thread you wrote)
📧 Email: jobs@thingsiwillnevertry.com

We can't wait to hear about what you'll absolutely refuse to do! 🚫😂

my_resume.txt:

This is my_resume.txt

Sami Reed
📍 San Diego, CA | 📧 thingsitriedblogger@gmail.com | 🌐 thingsitried.com

🌟 Summary
Creative and passionate blogger with a talent for engaging storytelling, restaurant reviews, and technology content. Founder of Things I Tried, a blog exploring new experiences, products, and trends with honest insights. Adept at SEO, social media growth, and audience engagement.

📝 Experience
Founder & Blogger | Things I Tried (2025 – Present)
Created and manage a successful blog covering product reviews, lifestyle experiences, and personal challenges.
Grew readership from zero to 200+ monthly visitors through SEO optimization, engaging content, and social media marketing.
Researched and wrote 30+ blog posts covering diverse topics, including restaurants, tech, and DIY projects.
Attempted collaboration with brands and sponsors to create authentic, informative content.
Utilized Google Analytics and SEO tools to optimize content for maximum reach and engagement.
Free Lance Content Writer | Various Clients (2021 – Present)
Wrote blog articles, social media posts, and website copy for clients in various industries, especially Lance, who I wrote for for free.
Created high-performing, SEO-optimized content that increased web traffic by a lot (I think).
Provided ghostwriting services for lifestyle and personal development blogs.
Social Media Manager | Self-Managed (2020 – Present)
Built and maintained a strong social media presence across Facebook, Instagram, BlueSky, and Mastodon.
Increased Instagram following to 1+ followers through engaging posts and audience interaction.
Designed branded graphics and short-form video content using Canva and Adobe Express.

If you would like to hire or work with me
email me at thingsitriedblogger@gmail.com

I would like to target $50/hr, but can negotiate.


Discover more from Things I Tried

Subscribe to get the latest posts sent to your email.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *