mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 00:26:26 +00:00
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:
@@ -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}
|
||||
Reference in New Issue
Block a user