Category: AI

  • Automating Job Applications with Markdown: From 60 Minutes to 20 Minutes

    Automating Job Applications with Markdown: From 60 Minutes to 20 Minutes

    Who This Is For: This workflow is designed for developers and technical professionals who are comfortable with command-line tools, enjoy working in code editors like VSCode, and who prefer markdown for writing (or are willing to give it a try). If you’re already using git for version control and don’t mind a bit of setup for long-term efficiency gains, this approach could save you significant time during your job search.

    Introduction 💡

    Job applications are tedious. Between customizing resumes, writing cover letters, tweaking formatting, and tracking applications, I was spending hours on administrative work instead of finding and responding to great opportunities–or working on side projects which I find infinitely more interesting.

    A little while ago I wrote a blog post on writing with markdown, which has greatly sped up my writing process. I’ve been using it for several weeks now and have made a bunch of automation improvements which enable me to quickly create a job application, customize a resume, draft a new cover letter, and track each application’s progress.

    I also took this opportunity to give Claude Code a test drive and see how it could help me build out some new automation scripts. In the past I’ve found agents like Cursor to be too aggressive–cranking out code faster than I can wrap my head around it. If I’m trying to learn something I want to go slow, ask questions, and understand what’s being built. Agents can’t reason but they’re good at replicating patterns, so I want to make sure it stays on track. (I’ll write more on Claude Code later–but so far I really like it!)

    The result of this collaboration is my new workflow, which I wanted to share with others: Markdown Writer. It’s still a work in progress, but if you like working in an IDE and are comfortable with a CLI you might find this a good way to manage your job applications.

    Why not use existing job tracking tools? TBH, I didn’t even research what’s available–I just knew I wanted to stay in my IDE where I’m most comfortable and productive. As developers, we often build our own tools not because existing solutions don’t exist, but because we have specific workflows and preferences. I wanted something that felt like coding: version-controlled, scriptable, and integrated with my daily development environment. Plus I wanted a small project to experiment with AI.

    Get Set Up ⚙️

    I use VSCode because it has great integration of file/project navigation, editing, helpful extensions, terminal integration, key bindings, snippets, and custom command integration. However this will also work with your favorite code editor and either zsh or bash in your terminal.

    This project is available as a GitHub template repository, making it easy to create your own private copy with one click. Simply visit the Markdown Writer repository and click “Use this template” to create a new repository in your GitHub account.

    If you prefer to clone and experiment first, you can use the repository directly:

    git clone git@github.com:nickhart/markdown-writer.git

    However, for ongoing use, I recommend creating your own repository from the template so you can customize it and track your applications privately. When there are updates to the main Markdown Writer repository, you can use the included script (scripts/sync.sh) to copy updates from the upstream repository to your own, or manually copy specific files you want to update.

    Requirements 📋

    Installing ⬇️

    git clone git@github.com:nickhart/markdown-writer.git
    cd markdown-writer
    ./setup.sh

    NOTE PDF formatting is supported, but requires installation of a LaTeX package. Out of the box Markdown Writer works great for creating DOCX files.

    Configuring 🔧

    Edit .writing.yml with your information. You can see an example .writing.yml here.

    Edit your resume and cover letter templates:

    • templates/resume/default.md
    • templates/cover_letter/default.md

    If you wish to customize your document formatting you can edit the styles in the files located below. Be sure to modify the standard styles (Heading, Heading 2, Body, etc…), then save the changes to reference.docx. Pandoc will use these reference files and use the styles in them when generating your formatted resume or cover letter.

    • templates/resume/reference.docx
    • templates/cover_letter/reference.docx

    You should now be ready to go. The system supports multiple resume templates. For many people “default” might suffice, but I find myself applying to a few different kinds of roles and have one tailored more towards mobile, frontend or fullstack… so I have resume templates with each of those names.

    Workflow 🔄

    Applying To a New Job 📝

    When I want to apply to a new job from the terminal I run

    job-apply Acme "Engineering Manager" default "http://acme.com/jobs/engineering-manager/1234"

    Or if I want to use a specific resume template other than default:

    job-apply Acme "Engineering Manager" fullstack "http://acme.com/jobs/engineering-manager/1234"

    This creates a new job application in the applications/active/acme_engineering_manager_20250624 directory. It copies my “default” resume template and standard cover letter and performs the variable substitution using my .writing.yml. It downloads the job description at the provided URL and saves it as an html file (job_description.html). It creates a metadata file (application.yml) which contains the company name, role, job description URL, and date created.

    Then I go in and tweak the resume as needed (perhaps just the title, maybe the intro blurb), and then crank out a few brief paragraphs for the cover letter. Usually I want to customize the intro to the cover-letter, but often I’ve already got some good content from prior cover letters which addresses particular needs/requirements in the job description. The organization of the applications makes it super easy for me to find a prior cover letter, lift a few sentences and add them into my new cover letter.

    Then I run job-format acme_engineering_manager_20250624 and it automatically formats my markdown resume and cover letter into DOCX format, using reference template files with my preferred styles and page format. The formatted versions go into a formatted subdirectory of the application. The .gitignore automatically excludes the formatted docs from being committed–but if one wished they could tweak that and commit the formatted files too.

    From here it’s a matter of uploading the DOCX files to the job application and filling out the rest of the application information.

    Some applications require some essay-style questions, in which case I add another markdown file to the application folder (eg: application_questions.md) and use my same editing process. I don’t bother formatting these into DOCX but it’s nice to have a record of my responses and then it’s easy to copy/paste them into the application form.

    Submitting and Tracking the Application 📤

    When I’m satisfied with the application I have a helpful command to commit it to my repo:

    job-commit acme_engineering_manager_20250624

    Once I’ve submitted the application, and as it moves through the review process I have a command to update its status:

    job-status acme_engineering_manager_20250624 submitted
    job-status acme_engineering_manager_20250624 interview
    job-status acme_engineering_manager_20250624 offered
    job-status acme_engineering_manager_20250624 rejected

    Each of these statuses has its own sub-folder inside the applications folder in the project root. The job-status command moves the application from one folder to another and updates the status in the application.yml metadata file.

    If I get to the interview stage (w00t!) I take notes in a markdown file which I keep in the application’s folder, eg:

    applications/
      interview/
        acme_engineering_manager_20250624/
          recruiter_notes.md
          hiring_manager_notes.md
          interview_loop_notes.md

    I also have a job-log command which will show a summary of all my applications, or just ones in a certain status. Right now the summary is terse, but I intend to make it a bit fancier in case someone in the state unemployment office decides to challenge me. It will be trivial to take the metadata and generate a log of each job application in DOCX format to prove I’ve exceeded their “three job activities a week” requirement.

    VSCode Integration 🛠️

    I mentioned in my prior post about how I like to use VSCode for my markdown writing. For those who are also using VSCode it will recommend some extensions that I find handy:

    • Markdown All in One
    • Code Spell Checker
    • markdownlint
    • Word Count
    • YAML

    The VSCode configuration adds some helpful settings for Markdown and YAML editing, as well as allowlisting some common words that the spell checker might flag.

    It also adds some commands to the command palette. With a simple cmd-shift-p to open the command palette, select Run Tasks, and choose one of my commands like Create Job Application. It’ll prompt me for the company name, role, which resume template (or use default), and the URL for the job description. It’ll run the command in a terminal and show me the output!

    Wrapping Up and Next Steps 🚀

    In my last post on this topic it was taking me an hour to do what now takes me 20 minutes–and most of that time is me thinking about what I want to write and entering it into a markdown file. I still only apply to a few jobs a day, but I can focus on applying to the roles that really interest me, take the time to craft a thoughtful cover letter, and then have more time to work on my other projects or write a blog post.

    I will continue to use the Markdown Writer to craft my job applications. I also use it for blog posts and format the results into HTML which I can copy/paste into Wordpress. No doubt I will continue to refine this aspect of my writing workflow.

    And if you’re curious about some of the other features I’m planning for my job application workflow, take a look at the TODO!

  • 5 Ways AI Helped Me Handle My Mother’s Passing

    5 Ways AI Helped Me Handle My Mother’s Passing

    AI and End of Life

    This article is not about Skynet and AI ending all life on Earth. 😂

    I recently lost my mother. And my job. It’s been a stressful and difficult time, and something I had never really prepared for. I had lots of questions and tasks: managing her estate, dealing with her taxes, dealing with my taxes, organizing her contacts, planning a celebration of life, preparing to livestream the celebration, and even figuring out what I wanted to say for a eulogy.

    As an AI enthusiast I instinctively turned to AI to help me navigate these many activities and challenges. I found AI to be an invaluable tool. I’m going to detail how I have been using it over the past few months to assist with end of life tasks.

    Data Mining for Contacts 🗃️

    As I began planning a celebration of life I wanted to make sure I invited all of my mother’s friends and connections. She wasn’t very organized about her contacts and addressbook—some were in her phone, some were in an email account she shared with my late father, and others were in her gmail account. Still more were scribbled on various notes throughout her office 🤦‍♂️.

    She corresponded with many people who weren’t recorded in her contacts/addressbook, so I knew I needed to scan her emails to find email addresses of personal contacts. I exported and downloaded all of her emails from both accounts, and exported her iPhone contacts. Her MBOX files were gigabytes of data so I knew I couldn’t just upload them to ChatGPT and expect AI to data mine it for me.

    I’ve been a Python developer since before the turn of the century, and it’s one of my favorite tools for processing and transforming data. MBOX files and email headers aren’t that complicated to parse, but I wanted to experiment with AI and see if it could speed up my development process.

    I asked ChatGPT for its help to write a Python script to process the MBOX files, look for email addresses and store them in a SQLite DB. I also wanted to record some contextual metadata with each occurrence of an email address. Was it from a sender or to a recipient? Were there telltale signs of a listserv in the email headers? How many interactions were there with each email address? I chose SQLite because it’s simple and fast for querying the data (and I wasn’t yet sure what I wanted to query).

    I then made a second script to process the SQLite DB and filter for email addresses that matched certain criteria. The script was able to parse a separate list of contacts from an addressbook CSV file, cross reference any email address with it and fill in the person’s name if it wasn’t parsed from the email. And then it output a new CSV with each contact, their first and last name, how many occurrences were found, and whether the address was categorized as personal or listserv. The script also had some filtering parameters to limit the output to only personal addresses, or require a minimum number of occurrences.

    Along the way I found discrepancies and anomalies in the output. I worked with ChatGPT to refine the scripts, for instance when I discovered a pattern of email addresses that were re-sent through yahoogroups.com (eg: code>someone%40comcast.net@yahoogroups.com).

    Eventually I arrived at a tool that worked pretty well for my needs. It was able to sort through gigabytes of data and arrive at a list of about 160 contacts which appeared to be real people with whom my mom had interacted with online over the past 25 years. This list became the basis for the invitations I would later send out for her celebration of life.

    I’ve published my ContactsScraper on GitHub in case anyone else may find it useful.

    Financial Planning 💸

    DISCLAIMER: Talk to your attorney and accountant/tax preparer. Do not rely on AI to make any legal or financial decisions.

    I inherited a small IRA from my mother, so had lots of questions about what to do here. What is a required minimum distribution? How much is it? What would this do to my taxes? How much debt could I afford to pay off without bumping myself into another tax bracket? Can I afford a new roof for my house? ChatGPT helped me answer a bunch of these questions and model several different scenarios. Then I called my accountant and discussed my plans with her and she confirmed what I had modeled.

    I provided as much specific information as I could about my finances and my mother’s IRA to ChatGPT. I’m not going to post any of that information here or any of the results, for obvious reasons. However, I found this to be a valuable process.

    As I iterated on the financial models new questions and considerations came to mind. How much interest am I paying on this chunk of credit card debt? How much in additional taxes will I pay by taking a larger IRA distribution, and how does that compare to the interest saved? What if I underpay my taxes? Below are some examples of prompts that I used to figure out how best to use this modest windfall.

    Prompt 1: Basic IRA Withdrawal vs. Credit Card Debt Tradeoff 💬

    “I have an inherited IRA worth $100,000 and $50,000 in credit card debt at 19% interest. I’m considering taking a distribution from the IRA to pay off the debt. What are the tax consequences of taking out $50,000 in a single year? Should I spread the withdrawals over multiple years to reduce the tax impact?”

    Prompt 2: Modeling Partial Withdrawal Strategy 💬

    “Assume I’m in the 22% federal tax bracket. If I take $25,000 from my inherited IRA this year and another $25,000 next year, how does that compare (in terms of taxes and interest saved) to taking the full $50,000 this year to eliminate my high-interest debt immediately?”

    Prompt 3: Safe Harbor and Withholding Adjustments 💬

    “If I take a $40,000 distribution from my inherited IRA and don’t adjust my withholding, could I owe an underpayment penalty? What’s the safe harbor threshold for avoiding a penalty, and how might I adjust my estimated tax payments to stay in the clear?”

    This sort of financial modeling is something I usually try to do myself with spreadsheets. Depending on the complexity and my familiarity with the topic it might require an hour of research before I even start writing the spreadsheet. Then as I enter data and model the answer I’ll spend hours more tweaking the spreadsheet columns, cell formatting, formulas, and trying to build a model that would help me visualize and understand different financial scenarios.

    In less than half the time it would have taken me to build a bunch of custom spreadsheets by hand ChatGPT helped me by generating charts and graphs, as well as asking clarifying questions that helped me provide better input. ChatGPT was like a financial planner that helped me get hands on with exploring various options.

    Creative Support ✍️

    “A eugoogalizor, one who speaks at funerals. Or did you think I’d be too stupid to know what a eugoogoly was?” – Derek Zoolander

    I’ve never written a eulogy before. I spoke at my dad’s funeral but aside from an anecdote I had thought of the day before it was largely spontaneous and I didn’t write it down. I wanted to plan a more comprehensive and heartfelt eulogy for my mother’s celebration of life.

    Let me be clear: I did not use generative AI to write my mom’s eulogy. I did use it to give some broad examples of how to approach it, and what elements to incorporate. It helped me establish an outline and plan to fill 5-10 minutes of time. At a high level:

    • Welcome & Thanks
      • acknowledge out of town family and those who couldn’t be here
      • special thanks to volunteers and key providers of support
    • A Difficult Year
      • talk about some of the struggles she’d been fighting through
      • acknowledge her grace and cheerful disposition through it all
    • Her Favorite Things
      • talk about some of the decor and memorabilia and how it relates to her
      • walk through the themes and give an anecdote or two–aim for some levity
    • Who She Was to Others
      • mention her career and impact
      • mention her volunteer work
    • Personal Reflection
      • talk about what she did for our family
      • the values I learned from her
      • how I will remember her
    • Closing
      • toast to her memory
      • invite others to speak
  • Did I Write This… or Did AI?

    Did I Write This… or Did AI?

    I’ve been spending a lot of time on LinkedIn lately as I navigate the highly competitive job market. I won’t lie–I have used ChatGPT in my job search. Full disclosure: AI did not write this article. I did. (Dall-E did provide the featured image.)

    Before I dive into AI I want to talk about writing. Not everyone is a great writer in English. I recently received a glowing recommendation on LinkedIn from a former employee for whom English is a second language. Part of me wished he wrote it with typos and all because it might appear more genuine. Except that knowing how AI works I am certain he put some effort into crafting a prompt with details about how he experienced working with me, mentoring, and career coaching. AI spit out the final product, but he gave it the inputs.

    I grew up in the United States in a middle class family where both parents had Masters Degrees in education. My father was a published author. I’ve always enjoyed reading and writing, done well in school and taken creative writing classes in college. I take pride in the fact that I can write well and communicate with the written word–whether it’s an email, Slack message, Confluence page, year end review, or commit message.

    Not everyone is so fortunate. So it seems to me that a tool like ChatGPT can help take some raw input and produce polished output. This can really level the playing field for some people!

    As a job seeker I find ChatGPT to be an invaluable tool. First and foremost I use it to review my cover letter and resume for typos and word choice. It’s like having a collaborative editor. But sometimes there is a little writers block and it can be useful to provide the job description, some notes on how your experience is a good fit for the role, and then take the result and make it one’s own. Much of the time the output sounds too polished, too generic, and too insincere. However, I’ve found it’s a starting point.

    Take the AI-generated content and make it your own. Think of it as a framework and add in your own experiences and wording. In a resume or cover letter nothing will substitute for your own experience and voice.

    This brings me to my last observation. I’ve seen a lot of LinkedIn posts from recruiters and hiring managers to the effect of “if I think you used AI I’m going to reject your application.” I can’t help but think how unfair that is to talented people for whom English is a second language, or who perhaps don’t have the same flair for expressing themselves in writing in English.

    AI is a tool. We’re all still learning how to use it and navigate this radically changed landscape–whether it’s writing code or cover letters. Let’s try to assume good intent. Sure some people will probably use AI to do their homework, but others might use it to help level the playing field a bit and make sure their resume makes it through the scanners… and you never know if that polished cover letter you threw out was crafted with care by a talented writer.