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.
This commit is contained in:
Ayobami Adegoke
2026-07-08 17:09:33 +02:00
committed by GitHub
parent 75fbfc56e4
commit 6477987608
6 changed files with 285 additions and 1 deletions
+61
View File
@@ -0,0 +1,61 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Cover Letter - [Company], [Role]
%
% Example cover letter with placeholder content. This is the structural
% reference for /apply (see 06-cover-letter-templates.md) and the CI smoke
% test for cover.cls: it must always compile with xelatex to exactly 1 page.
% It demonstrates the correct itemize pattern: the list sits OUTSIDE
% \lettercontent{} (whose trailing \\ errors on \end{itemize}) and is
% wrapped in Raleway-Medium so the bullet font matches the body.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\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@example.com}{your.email@example.com} | [+XX XXXXXXXXXX] | \urlstyle{same}\href{https://www.linkedin.com/in/yourprofile}{LinkedIn}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MAIN COVER LETTER CONTENT
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\currentdate{\today}
\lettercontent{Dear [Hiring Manager / Team],}
\lettercontent{[Opening paragraph: name the role and where you found it, state your strongest connection to it in one sentence, and preview why you are a fit. Keep it to 2--3 sentences.]}
\lettercontent{[Body paragraph: your most relevant experience, framed toward the tasks in the posting. Follow with 3--5 concrete bullets:]}
{\raggedright\fontspec[Path = OpenFonts/fonts/raleway/]{Raleway-Medium}\fontsize{11pt}{13pt}\selectfont
\begin{itemize}
\item \textbf{[Achievement 1]:} [concrete result with a number where possible]
\item \textbf{[Achievement 2]:} [skill or project mapped to a posting requirement]
\item \textbf{[Achievement 3]:} [evidence for a nice-to-have requirement]
\end{itemize}\par}
\vspace{6pt}
\lettercontent{[Connection paragraph: why this company specifically. Reference a verified specific: a product, a stated priority, a team. Never generic.]}
\lettercontent{[Personal fit paragraph: behavioral strengths and what you bring to the team, 2--3 sentences.]}
\lettercontent{I look forward to hearing from you.}
\begin{flushright}
% Note: no trailing \\ inside \closing{} - cover.cls appends its own \\, and a
% doubled break triggers "There's no line here to end."
\closing{Kind regards,}
\signature{[YOUR NAME]}
\end{flushright}
\end{document}