Files
ai-job-search/.claude/skills/job-application-assistant/06-cover-letter-templates.md
T
Ayobami Adegoke 6477987608 ci: add GitHub Actions workflow - LaTeX smoke compiles, skill lint, CLI typechecks, placeholder integrity (#59)
Every PR to this repo is currently verified by hand. This adds the checks
a machine can do:

- latex-smoke: compiles cv/main_example.tex (lualatex) and the new
  cover_letters/cover_example.tex (xelatex) in the texlive/texlive
  container, failing on any LaTeX error. Exact page-count assertions
  (CV=2, cover letter=1) run on the upstream repo only
- lint (tools/lint_skills.py, also runnable locally): every SKILL.md has
  parseable YAML frontmatter with name+description (frontmatter breakage
  happened before - 37a0eed), allowed-tools 'bun run <path>' targets
  exist, command files start with a '# /<name>' title, settings.json is
  valid JSON with a permissions.allow list
- cli-typecheck: bun install + tsc --noEmit for all five portal CLIs
  (matrix, fail-fast off)
- placeholder-integrity (upstream only): tracked template files still
  carry their placeholder tokens, catching accidental personal-data
  commits before they land

Fork-friendly by design: /setup personalizes CLAUDE.md, the skill files,
and main_example.tex in forks, so placeholder checks and exact page
counts are guarded with github.repository == upstream; compile success
and lint run everywhere. Live CLI smoke tests are deliberately excluded:
network-flaky, and linkedin-search is personal-use-only per its own ToS
warning - CI-automated requests would violate it. CLIs are typechecked
instead.

The cover letter previously had no tracked example (cover_*.tex is
gitignored), so cover_example.tex is new: a placeholder letter following
the documented 06 structure, demonstrating the correct itemize-outside-
lettercontent pattern. It doubles as the structural reference /apply
Step 2 looks for on fresh clones, which until now matched nothing. The
gitignore exception is ordered after Cover_*.tex because case-insensitive
filesystems match that pattern against cover_example.tex too.

Writing it surfaced a latent bug in the documented template itself:
06-cover-letter-templates.md's structure ends with \closing{Kind
regards,\} - but cover.cls appends its own \, and the doubled break
produces '! LaTeX Error: There's no line here to end.' on every compile
(nonstopmode swallows it, so it went unnoticed). Fixed in 06 and noted
in the example.
2026-07-08 17:09:33 +02:00

6.3 KiB

Cover Letter Templates and Tailoring Guide

Template: Custom cover.cls (XeLaTeX)

Cover letters use a custom LaTeX document class (cover.cls) with Lato/Raleway fonts.

Output file: cover_letters/cover_<company>_<role>.tex Compile with: XeLaTeX (cover.cls requires fontspec) Font directory: cover_letters/OpenFonts/fonts/

Compile command

cd cover_letters && xelatex -interaction=nonstopmode cover_<company>_<role>.tex

Expected output: Output written on cover_<company>_<role>.pdf (1 page, ...). Any page count other than 1 is a failure that must be fixed before presenting to the user.

Compile-and-Inspect Loop (MANDATORY)

After writing the cover letter and before presenting to the user, always compile and visually inspect the PDF. Iterate until the layout is clean:

  1. Run xelatex -interaction=nonstopmode cover_<company>_<role>.tex
  2. Confirm page count is exactly 1 and compile succeeded
  3. Read the PDF via the Read tool and visually check: signature fits at the bottom, no text cut off, bullet font matches body

Known template pitfall: itemize inside \lettercontent{}

The \lettercontent{} macro appends \\ to its argument. This breaks when the argument ends in \end{itemize} because \\ has no line to break after the environment closes, producing ! LaTeX Error: There's no line here to end. and no PDF output.

Wrong (breaks compile):

\lettercontent{Here is how my experience maps:
\begin{itemize}
    \item ...
\end{itemize}}

Correct — close \lettercontent{} before the list and wrap the list in the matching Raleway-Medium font so typography stays consistent:

\lettercontent{Here is how my experience maps:}

{\raggedright\fontspec[Path = OpenFonts/fonts/raleway/]{Raleway-Medium}\fontsize{11pt}{13pt}\selectfont
\begin{itemize}
    \item ...
\end{itemize}\par}
\vspace{6pt}

\lettercontent{[next paragraph]}

The font wrapper is mandatory — if you just move \begin{itemize} outside \lettercontent{} without the \fontspec block, bullets render in the default body font (Lato) and visually mismatch the rest of the letter.

Document Structure

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Cover Letter - [Company], [Role]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\documentclass[]{cover}
\usepackage{fancyhdr}

\pagestyle{fancy}
\fancyhf{}

\rfoot{Page \thepage \hspace{0pt}}
\thispagestyle{empty}
\renewcommand{\headrulewidth}{0pt}
\begin{document}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     TITLE NAME
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\namesection{}{\Huge{[YOUR_NAME]}}{  \href{mailto:[YOUR_EMAIL]}{[YOUR_EMAIL]} | [YOUR_PHONE] |  \urlstyle{same}\href{[YOUR_LINKEDIN_URL]}{LinkedIn}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     MAIN COVER LETTER CONTENT
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\currentdate{\today}
\lettercontent{Dear [Name/Team],}

\lettercontent{[Opening paragraph - role, connection to background, 2-3 sentences]}

\lettercontent{[Body paragraph - most relevant experience, then bullet list]

\begin{itemize}
    \item [Concrete achievement/skill 1]
    \item [Concrete achievement/skill 2]
    \item [Concrete achievement/skill 3]
\end{itemize}

[Connection to company - why this role, why this company specifically]}

\lettercontent{[Personal fit paragraph - behavioral strengths, team contribution, 2-3 sentences]}

\lettercontent{I look forward to hearing from you.}

\begin{flushright}
% No trailing \\ inside \closing{} - cover.cls appends its own \\, and a
% doubled break triggers "! LaTeX Error: There's no line here to end."
\closing{Kind regards,}

\signature{[YOUR_NAME]}
\end{flushright}
\end{document}

Key Commands Reference

Command Purpose
\namesection{}{Name}{contact info} Header with name and contact
\currentdate{date} Date field (use \today or explicit date)
\lettercontent{text} Body paragraph (adds spacing after)
\closing{text} Closing line
\signature{name} Printed name below signature

Tailoring Guidelines

Salutation

  • If you know the hiring manager's name: "Dear [First Last],"
  • If you know the team: "Dear [Company] hiring team,"
  • Generic: "Dear [Company]," (avoid "To whom it may concern")

Length - Hard 1-Page Limit

  • Target: 1 page including signature block
  • Maximum: never exceed 1 page
  • Word budget: 250-300 words of body text (not counting LaTeX markup). This is the safe maximum. 350 words will overflow.
  • Always count: opening paragraph + bullet list paragraph + closing paragraph = 3 blocks. Add a 4th only if the others are short.
  • When adding company-specific content, trim other content to compensate rather than adding net length

Line Spacing

  • Add \usepackage{setspace} and \setstretch{1.0} if the letter is long and needs to fit on one page
  • Use \vspace{.5cm} between major sections for readability (only if space permits)

Bullet Lists

  • Place \begin{itemize}...\end{itemize} outside a \lettercontent{} block (see "Known template pitfall" above), wrapped in the matching Raleway-Medium \fontspec so the bullet font matches the body
  • 3-5 bullets is ideal
  • Start each bullet with bold label or action verb
  • Use \textbf{Label:} for category-style bullets

LaTeX Special Characters

  • Underscore: \_
  • Ampersand: \&

Non-English Cover Letters

  • Same template structure, just write content in the posting's language
  • Adjust date format to local convention
  • Adjust closing to local convention (e.g. "Med venlig hilsen," for Danish)

Checklist Before Finalizing

  • No em-dashes (use commas or periods instead)
  • No cliches or empty filler
  • Every claim backed by specific example
  • Forward-looking framing: focuses on tasks you'll solve, not just past duties
  • Motivation section references this specific company's mission/values
  • Company name and role are correct throughout
  • Date is current
  • Fits on one page
  • Language matches the job posting language
  • Salutation is appropriate (named person if possible)
  • Headline is engaging and specific, not generic

Submission Guidelines (Best Practice)

  • Submit only the documents the employer requests
  • Export as PDF to preserve formatting
  • Name files clearly: "[Your Name] CV" and "[Your Name] Cover Letter"
  • Follow all employer instructions regarding anonymity or specific materials