# AI Job Search Custom Document Template Requirements: The Complete Guide

> Discover the essential requirements for custom document templates in AI Job Search. Learn about manifest files, source skeletons, compile commands, and folder structures for seamless integration.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: how-to-guide
- Published: 2026-08-25

---

**AI Job Search requires custom templates to include a [`TEMPLATE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/TEMPLATE.md) manifest, a placeholder-based source skeleton, a validated compile command, and strict folder structure under `templates/cv/` or `templates/cover_letters/` to integrate with the `/apply` workflow.**

The AI Job Search framework (MadsLorentzen/ai-job-search) allows you to replace its built-in LaTeX templates with your own custom document templates using LaTeX, Typst, or any command-line-to-PDF toolchain. To ensure reliable compilation and ATS-compatible output, the `/add-template` command enforces strict requirements defined in [`.claude/commands/add-template.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/add-template.md) that govern how the `/apply` workflow processes your documents.

## Template Type and Folder Structure Requirements

Every custom document template must declare its **Template Type** and follow a specific folder layout.

The framework recognizes two types:
- **CV** – Stored under `templates/cv/<name>/`
- **Cover letter** – Stored under `templates/cover_letters/<name>/`

The folder name `<name>` becomes the unique template identifier. According to the source code in [`.claude/commands/add-template.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/add-template.md), the type determines which guidance file receives the **ACTIVE-TEMPLATE** managed block—either [`05-cv-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/05-cv-templates.md) or [`06-cover-letter-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/06-cover-letter-templates.md).

### Required Folder Layout

```text
templates/
└─ cv/
   └─ <template-name>/
      ├─ template.<ext>          # Source skeleton (e.g., .tex, .typ)

      ├─ TEMPLATE.md             # Manifest file (required)

      ├─ moderncv.cls            # Optional: custom class files

      └─ fonts/                  # Optional: bundled font files

         └─ CustomFont-Regular.ttf

```

All auxiliary files—custom LaTeX classes, Typst packages, or bundled fonts—must reside within this folder. Paths inside your template must reference these local copies using relative paths.

## The TEMPLATE.md Manifest File

Every template folder must contain a [`TEMPLATE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/TEMPLATE.md) manifest that serves as the single source of truth for the registration logic. This file declares the metadata required for the `/apply` workflow to compile and validate documents.

The manifest must specify:

- **Type**: `CV` or `Cover letter`
- **Source extension**: File extension (e.g., `.tex`, `.typ`)
- **Engine/toolchain**: `lualatex`, `xelatex`, `pdflatex`, or `typst`
- **Compile command**: Full shell command using `<file>` as placeholder
- **Page limit**: Hard budget (default 2 pages for CVs, 1 for cover letters)
- **Fonts**: System-installed or bundled (with bundling noted explicitly)
- **Style rules**: Layout conventions the AI must preserve
- **Known pitfalls**: Compilation quirks or ATS compatibility issues

### Example TEMPLATE.md

```markdown

# Template: awesome-cv

- **Type:** CV
- **Source extension:** .tex
- **Engine/toolchain:** lualatex
- **Page limit:** 2 page(s)
- **Fonts:** OpenSans (bundled in fonts/)

## Compile command

    cd <output dir> && lualatex -interaction=nonstopmode <file>.tex

## Style rules

- Single-column layout, no sidebars.
- Section headings use `\section` with bold 12pt font.
- Dates must use ASCII hyphens (`2016-2020`).

## Known pitfalls

- Do not use `fontawesome` icons; they produce non-Unicode glyphs that break ATS parsing.

```

The `/add-template` command parses this manifest to generate the **ACTIVE-TEMPLATE** block inserted into the guidance files.

## Source Skeleton and Placeholder Tokens

The actual template file—named `template.<ext>` (e.g., `template.tex` or `template.typ`)—must contain **placeholder tokens** rather than personal data. This ensures the template remains shareable and profile-agnostic.

Required placeholder format uses square brackets with descriptive names:

- `[YOUR_NAME]`
- `[YOUR_EMAIL]`
- `[YOUR_PHONE]`
- `[COMPANY_NAME]`
- `[JOB_TITLE]`

During the `/apply` workflow, the framework copies your skeleton to a temporary file (`_compile_test.<ext>` for validation, or the final output file), replaces these tokens with actual profile data, and executes the compile command.

## Compile Command and Toolchain Validation

The manifest must declare a **full compile command** that the framework can execute via shell. The command must use `<file>` as a placeholder for the base filename.

**Valid compile command examples:**

```bash
lualatex -interaction=nonstopmode <file>.tex

```

```bash
typst compile <file>.typ

```

**Critical requirement:** The declared engine must match the actual command. For LaTeX sources, the engine (`lualatex`, `xelatex`, or `pdflatex`) is inferred from font usage. For Typst, the standard command is `typst compile`.

The framework performs a **test compile** during registration. It copies the skeleton to `_compile_test.<ext>`, fills placeholders with dummy data, and runs your declared command. The registration **aborts** if compilation fails or if the resulting PDF exceeds the declared page limit.

## Font Management and Page Limits

### Font Requirements

The manifest must list all main fonts. If your template bundles fonts (recommended for reproducibility), they must live in a `fonts/` subdirectory, and the manifest must note they are *bundled*. For system fonts, you must record the exact font name and warn users that the font must be present on their machine.

### Page Budget Enforcement

You must declare a hard page limit:
- **CVs**: Default 2 pages
- **Cover letters**: Default 1 page

The `/apply` step checks the compiled PDF against this limit using the metadata in your manifest. Templates exceeding the limit are rejected with an error.

## Registration and Activation Process

### Adding a New Template

Register your template using the CLI command:

```bash
claude /add-template templates/cv/awesome-cv

```

This command executes the validation pipeline defined in [`.claude/commands/add-template.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/add-template.md):
1. Parses [`TEMPLATE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/TEMPLATE.md) for metadata compliance
2. Copies the skeleton and replaces placeholders with test data
3. Executes the compile command in a temporary directory
4. Validates the PDF respects page limits
5. Inserts the **ACTIVE-TEMPLATE** managed block into the appropriate guidance file ([`.claude/skills/job-application-assistant/05-cv-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/05-cv-templates.md) or [`06-cover-letter-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/06-cover-letter-templates.md))

Only one **ACTIVE-TEMPLATE** block can exist at a time; switching templates replaces the existing block.

### Switching Templates Without Revalidation

To activate a previously registered template without re-running the test compile:

```bash
claude /add-template --use awesome-cv

```

This updates the **ACTIVE-TEMPLATE** block in the guidance files to point to the existing template folder.

### Idempotency

Re-running `/add-template` with the same template name updates the existing entry rather than creating duplicates. The framework overwrites the manifest and folder contents only after a successful test compile passes.

## Key Files in the Template System

| Path | Role |
|------|------|
| [`.claude/commands/add-template.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/add-template.md) | Full specification of the registration workflow and validation logic |
| [`.claude/skills/job-application-assistant/05-cv-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/05-cv-templates.md) | Holds the **ACTIVE-TEMPLATE** managed block for CVs; read by `/apply` |
| [`.claude/skills/job-application-assistant/06-cover-letter-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/06-cover-letter-templates.md) | Holds the **ACTIVE-TEMPLATE** block for cover letters |
| `templates/cv/<name>/TEMPLATE.md` | Manifest defining compilation rules and constraints |
| `templates/cv/<name>/template.<ext>` | LaTeX/Typst skeleton with placeholder tokens |
| `templates/cv/<name>/fonts/` | Optional bundled font directory |

## Summary

- **Folder structure**: Create `templates/cv/<name>/` or `templates/cover_letters/<name>/` with unique identifier names
- **Manifest file**: Every template requires a [`TEMPLATE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/TEMPLATE.md) declaring type, compile command, fonts, page limits, and style rules
- **Source skeleton**: Use `template.<ext>` with `[PLACEHOLDER]` tokens for all personal data
- **Compile validation**: The framework test-compiles with dummy data before registration; failures abort the process
- **Activation**: Valid templates insert an **ACTIVE-TEMPLATE** block into guidance files ([`.claude/skills/job-application-assistant/05-cv-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/05-cv-templates.md) or [`06-cover-letter-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/06-cover-letter-templates.md))
- **Idempotency**: Re-registering updates existing templates only after successful validation

## Frequently Asked Questions

### What happens if my custom template fails the test compile?

The `/add-template` command aborts registration and displays the error output from the compilation process. You must fix the source files, manifest, or compile command and rerun the command. The framework will not insert the **ACTIVE-TEMPLATE** block until the test compile succeeds and the PDF respects the declared page limit.

### Can I use Typst instead of LaTeX for custom templates?

Yes. The framework supports any command-line-to-PDF toolchain. For Typst, set the **Engine/toolchain** to `typst` and the **Compile command** to `typst compile <file>.typ` in your [`TEMPLATE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/TEMPLATE.md). Place your Typst source in `template.typ` with the same placeholder token format used for LaTeX templates.

### How does the framework handle fonts that aren't installed system-wide?

Place bundled font files in a `fonts/` subdirectory within your template folder and declare them as *bundled* in the manifest. The compile command should reference these local files. If using system fonts, the manifest must explicitly warn users that the template requires specific system-installed fonts to compile successfully.

### What is the ACTIVE-TEMPLATE block and why is it important?

The **ACTIVE-TEMPLATE** block is a managed content section inserted into [`.claude/skills/job-application-assistant/05-cv-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/05-cv-templates.md) or [`06-cover-letter-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/06-cover-letter-templates.md). It contains the metadata needed by the `/apply` workflow to locate your template, execute the correct compile command, and enforce style rules. Only one block can be active per document type; switching templates replaces this block to ensure the `/apply` command uses the correct source files and compilation settings.