1. The Core Bottleneck: What Engineering Problem Does It Break?
Job hunting automation usually lands in one of two broken extremes. The first relies on cloud-hosted recruitment SaaS platforms, requiring job seekers to hand unredacted resumes, salary expectations, and full career histories over to centralized third-party databases. The output is almost invariably boilerplate cover letters packed with generic AI hallucinations. The second extreme relies on brittle web scrapers coupled with raw, zero-shot LLM prompts, spitting out unformatted PDFs that immediately fail enterprise Applicant Tracking Systems (ATS).
Mads Lorentzen, a former geophysicist who lost his position, engineered this framework to run his own career pivot. Running 69 tailored applications through this exact CLI workflow yielded 20 first-round interviews and a signed contract as an AI engineer. The framework approaches job hunting as a deterministic, local compilation pipeline: user data remains strictly on the host file system, and raw generation is bound by an adversarial Drafter-Reviewer loop paired with a rigid TeX compilation check.
💡 Core Architectural Insight: Treating candidate records as a static local knowledge base and abstracting job application into an adversarial compiler pipeline: a Drafter Agent synthesizes, a Reviewer Agent audits, and a TeX engine validates the final artifacts.
2. Architecture and Data Flow Decomposition
The framework utilizes Claude Code CLI as its host execution runtime, backed by Bun-driven skill workers and native TeX compilation engines. The system decouples the workflow into three primary stages: candidate profile extraction (/setup), multi-portal web scraping (/scrape), and an adversarial application generation loop (/apply <url>).
[ User Files: documents/ ] ---> [ /setup: Reverse Profiler ] ---> [ profiles/ (Local Markdown) ]
│
[ Job Portals / APIs ] --------> [ /scrape: Bun CLI Skills ] ------------>│ (Context Routing)
▼
[ /apply Fit Evaluator ]
(Score: 1-10 & Gap)
│
┌────────────────────────────────────┘
▼
[ Drafter Agent (LaTeX) ] <─────────┐
│ │ Feedback Loop
▼ │ (Style & Truth Check)
[ Reviewer Agent (Critique) ] ──────┘
│ (Approved)
▼
[ LuaLaTeX (CV) / XeLaTeX (Cover Letter) ]
│
▼
[ ATS Parser (pypdf/pdftotext) ] ---> [ Ready PDF Outputs ]
The pipeline begins with /setup. It ingests raw PDFs, diplomas, LinkedIn exports, and previous applications from documents/, extracting verified career markers and formatting them into local Markdown state files without reaching out to external networks.
Executing /apply <url> triggers the decision engine. The Fit Evaluator benchmarks candidate history against target JD requirements, spitting out an explicit compatibility score (1 to 10) alongside an identified skill gap breakdown. If within parameters, the Drafter Agent pulls targeted project evidence to compose tailored LaTeX sources. The Reviewer Agent immediately intercepts the generation, auditing the source code for inflated claims, generic buzzwords, or verbatim JD plagiarism. Once the Reviewer signs off, the pipeline delegates compilation: lualatex builds the CV, and xelatex compiles the cover letter. Finally, an ATS parseability loop leverages pypdf to read the binaries back into memory, verifying that enterprise text extraction pipelines will not choke on malformed layers.
3. Technology Stack & Competitive Benchmark
| Technical Dimension | This Architecture (ai-job-search) | Traditional Practice | Commercial SaaS Solutions | Production Benefits |
|---|---|---|---|---|
| Data Architecture | Local CLI + File System State Engine | Browser Extensions + Cloud DB | Web-based stateless prompt form | Zero data leakage risk; sensitive credentials never leave the host machine |
| Output Quality Control | Adversarial Drafter-Reviewer Loop | Single-shot prompt generation | Hard-coded keyword injection | Completely strips AI buzzwords, repetitive patterns, and hallucinated records |
| Typesetting Engine | Native LuaLaTeX + XeLaTeX toolchains | HTML-to-PDF via Headless Chrome | Canvas renders or raw docx exports | Strict typography standards; zero font clipping or broken layout flows |
| ATS Compatibility | Built-in pypdf / pdftotext round-trip audit | No validation mechanism | Unverified vendor claims | Preempts ATS ingestion failures caused by hidden font encoding errors |
| Extensibility Model | Bun-isolated Skill scripts | Monolithic Python scraper scripts | Closed proprietary APIs | Job portal scrapers remain decoupled from the core LLM execution engine |
This engineering stack favors battle-tested native tooling over heavy abstractions. Instead of wrapping electron shells around basic web APIs, it exploits Claude Code for logic orchestration and Bun for runtime-free script execution. Separating synthesis from critique through distinct agents directly mitigates the generic hallucination patterns typical of consumer LLMs.
4. Hands-on Implementation: The Minimal Viable Pipeline
System Toolchains & Environment Setup
The runtime requires Python 3.10+, Bun, and a comprehensive TeX distribution. macOS setups install these dependencies cleanly via Homebrew:
# Install system dependencies and TeX compilation chain
brew install [email protected] bun poppler
brew install --cask mactex-no-gui
pip install pypdf
Setting Up an Isolated Private Repository
Because upstream contains personal candidate data, do not use a standard GitHub fork. Establish a private tracking repository and compile the bundled skill dependencies:
# Create an isolated private local workspace
mkdir my-private-job-search && cd my-private-job-search
git init
git remote add upstream https://github.com/MadsLorentzen/ai-job-search.git
git pull upstream main
# Install runtime dependencies across all search skill modules
for tool in jobbank-search jobdanmark-search jobindex-search jobnet-search linkedin-search freehire-search; do
(cd .agents/skills/$tool/cli && bun install)
done
Running the Automated Pipeline
The following commands execute profile ingestion, target discovery, and full application compilation inside the Claude Code interface:
# Launch Claude Code execution context
claude
# Step 1: Ingest documents/ directory and synthesize profile state into profiles/
/setup
# Step 2: Query job portals via CLI skills with query constraints
/scrape --keyword "AI Engineer" --location "Copenhagen"
# Step 3: Run the end-to-end evaluation, generation, and LaTeX compilation loop
/apply https://example.com/jobs/senior-ai-engineer-1024
Expected generation output tree:
applications/2026-06-example-senior-ai-engineer/
├── evaluation.md # Fit score, gap evaluation, and positioning strategy
├── cv.tex # Dynamically tailored CV source code
├── cv.pdf # Compiled binary via LuaLaTeX
├── cover_letter.tex # Target-tailored cover letter source code
├── cover_letter.pdf # Compiled binary via XeLaTeX
└── ats_check_report.txt # Extracted plain text verification report via pypdf
5. Production Gotchas & Operational Hazards
Running fully automated generation against native compilation engines introduces specific edge-case failures.
⚠️ Hazard Warning 1: TeX Font Expansion Engine Crashes The base CV template imports modern vector glyphs using
fontawesome5. When compiled with standardpdflatex, compilation aborts abruptly under contemporary MiKTeX or stripped-down distributions due to internal font-expansion buffer limitations. The CV target strictly requires compilation vialualatex. Conversely,cover.clsrelies internally onfontspec, makingxelatexan absolute hard requirement. Environments running minimal footprints like TinyTeX must manually provision both engine-specific packages before triggering/apply.⚠️ Hazard Warning 2: Accidental Exposure via GitHub Public Forks Standard forks on GitHub inherit the visibility of the upstream source: they are permanently public. Running
/setuppopulatesprofiles/with unencrypted, tracked files containing home addresses, identity details, previous compensation history, and references. Pushing this branch upstream exposes private candidate metrics to the open web. Users must bypass the UI Fork button, initialize an empty private repository locally, and pull the upstream code tree manually.⚠️ Hazard Warning 3: Context Window Degradation & Token Burn Executing multiple
/applyroutines inside a persistent Claude Code session retains verbose TeX source code, full JD strings, and multi-turn reviewer critique chains in working memory. After 5 sequential runs, input token counts balloon drastically, multiplying token expenditure while inducing instruction-drift in the Reviewer Agent. After compiling and exporting an application run, issue/clearto flush working memory and restore strict deterministic behavior.
