feat: add proposal for cover letter PDF conversion

Add OpenSpec proposal for converting markdown cover letters to PDF format using Swiss business letter standards.

The proposal includes:
- Swiss letter formatting with scrlttr2 and Swiss Norm configuration
- Environment validation for Pandoc and LaTeX
- Comprehensive error handling and user guidance
- Support for Swiss German formatting and address window positioning

This addresses step 7 "Generate PDFs" in the project workflow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-03 20:14:24 +01:00
co-authored by Claude
parent 8e1fd25fe1
commit 4d1fc47f1b
5 changed files with 845 additions and 0 deletions
@@ -0,0 +1,499 @@
Convert a markdown cover letter to a professionally formatted PDF using Swiss business letter standards.
# Instructions
You are converting a markdown cover letter to PDF format. The output will follow Swiss business letter standards (scrlttr2 with Swiss Norm) for proper formatting and address window positioning.
## Step 1: Check for Cover Letter
### Verify File Exists
1. Check if `cover-letter.md` exists in the current directory
2. If file exists → proceed to Step 2
3. If file does not exist → show error and stop
### Error: Cover Letter Not Found
```
❌ Cover letter not found
Could not find cover-letter.md in the current directory.
Please either:
1. Navigate to an application folder containing a cover letter:
cd applications/pending/[application-folder]/
/convert-cover-letter
2. Generate a cover letter first:
/write-cover-letter
Current directory: [show current working directory]
```
STOP. Do not proceed.
## Step 2: Environment Validation
**CRITICAL**: Check for required tools before attempting conversion.
Show progress: `🔍 Checking system requirements...`
### Check for Pandoc
Run: `which pandoc` or `pandoc --version`
**If Pandoc is NOT installed:**
```
❌ Pandoc not found
Pandoc is required for PDF conversion but is not installed on your system.
## Installation Instructions:
### Ubuntu/Debian:
sudo apt update
sudo apt install pandoc
### macOS (Homebrew):
brew install pandoc
### Arch Linux:
sudo pacman -S pandoc
### Windows:
winget install pandoc
### Other Systems:
Download from: https://pandoc.org/installing.html
---
After installation, run: pandoc --version
Then try /convert-cover-letter again.
```
STOP. Do not proceed with conversion.
**If Pandoc is installed:**
Show progress: `✓ Pandoc found (version X.X.X)`
### Check for LaTeX (pdflatex)
Run: `which pdflatex` or `pdflatex --version`
**If LaTeX is NOT installed:**
```
❌ LaTeX not found
LaTeX (pdflatex) is required for PDF generation but is not installed.
## Installation Instructions:
### Ubuntu/Debian:
sudo apt update
sudo apt install texlive-latex-base texlive-lang-german texlive-latex-extra
### macOS (Homebrew):
brew install texlive
# Note: This is a large download (~4GB). Alternative: MacTeX from https://www.tug.org/mactex/
### Arch Linux:
sudo pacman -S texlive-core texlive-latexextra
### Windows:
# Install MiKTeX from: https://miktex.org/download
# Or TeX Live from: https://www.tug.org/texlive/
---
**Required packages**:
- texlive-latex-base (core LaTeX)
- texlive-lang-german (Swiss German hyphenation and spelling)
- texlive-latex-extra (KOMA-Script including scrlttr2)
After installation, run: pdflatex --version
Then try /convert-cover-letter again.
```
STOP. Do not proceed with conversion.
**If LaTeX is installed:**
Show progress: `✓ LaTeX found (pdfTeX X.X.X)`
**All prerequisites met:**
Show progress: `✅ All requirements satisfied`
## Step 3: Read and Validate Cover Letter
Show progress: `📄 Reading cover-letter.md...`
### Read File Content
1. Read the entire `cover-letter.md` file
2. Separate frontmatter (YAML between `---` delimiters) from body content
3. Parse the YAML frontmatter
4. Extract the markdown body (everything after the second `---`)
### Validate Frontmatter Structure
**Required fields:**
- `from.name` - Sender's full name
- `from.street` - Sender's street address
- `from.city` - Sender's city with postal code (e.g., "CH-8000 Zürich")
- `to` - Array of recipient address lines (at least 2 lines)
- `subject` - Letter subject line
- `opening` - Letter opening salutation
- `closing` - Letter closing phrase
- `signature` - Name for signature
**Optional fields:**
- `from.phone` - Sender's phone number
- `from.email` - Sender's email address
- `date` - Letter date (defaults to current date if missing)
- `enclosures` - Array of enclosure items
### Error: Invalid YAML
**If frontmatter cannot be parsed as YAML:**
```
❌ Invalid frontmatter format
The YAML frontmatter in cover-letter.md could not be parsed.
Error details: [specific YAML parsing error]
Please check that:
1. Frontmatter is enclosed between --- markers
2. YAML syntax is correct (proper indentation, colons, hyphens)
3. No special characters are unescaped
Example of correct frontmatter:
---
from:
name: Max Mustermann
street: Musterstrasse 42
city: CH-8000 Zürich
phone: +41 44 123 45 67
email: max.mustermann@example.ch
to:
- Firma AG
- Personalabteilung
- Hauptstrasse 100
- CH-3000 Bern
subject: Bewerbung als Software-Entwickler
opening: Sehr geehrte Damen und Herren
closing: Freundliche Grüsse
signature: Max Mustermann
---
```
STOP.
### Error: Missing Required Fields
**If any required fields are missing:**
```
❌ Incomplete frontmatter
Your cover letter is missing required fields in the frontmatter:
Missing fields:
[List each missing field with description]
Required frontmatter structure:
---
from:
name: [Your full name]
street: [Your street address]
city: [Your city with postal code]
phone: [Your phone] (optional)
email: [Your email] (optional)
to:
- [Company name]
- [Department or contact person]
- [Street address]
- [City with postal code]
date: [DD.MM.YYYY] (optional, defaults to today)
subject: [Letter subject]
opening: [Greeting, e.g., "Sehr geehrte Damen und Herren"]
closing: [Sign-off, e.g., "Freundliche Grüsse"]
signature: [Your name for signature]
enclosures: (optional)
- [Document 1]
- [Document 2]
---
[Body content follows]
```
STOP.
**If all required fields are present:**
Show progress: `✓ Frontmatter validated`
## Step 4: Convert to PDF
Show progress: `🔄 Converting to PDF...`
### Prepare Pandoc Command
Build the conversion command:
```bash
pandoc cover-letter.md \
--from markdown \
--to latex \
--template=[path-to-swiss-letter.tex] \
--pdf-engine=pdflatex \
--output=cover-letter.pdf
```
**Template path**: Use the template at `src/.claude/templates/swiss-letter.tex` relative to the framework root.
### Execute Conversion
1. Run the Pandoc command
2. Capture stdout and stderr
3. Check exit code
### Handle Conversion Errors
**If pdflatex fails to compile:**
```
❌ PDF compilation failed
LaTeX encountered an error while compiling your cover letter.
Error output:
[Show relevant error lines from stderr]
Common causes:
1. Special characters not properly escaped (e.g., &, %, $, #, _)
2. Formatting issues in the markdown body
3. Very long lines or complex formatting
4. Missing LaTeX packages
Troubleshooting:
1. Check for special characters in your cover letter text
2. Try simplifying complex formatting
3. Verify that all required LaTeX packages are installed:
- texlive-latex-base
- texlive-lang-german
- texlive-latex-extra
The intermediate .tex file has been preserved at: [path-to-.tex-file]
You can inspect this file to identify the issue.
Need help? Share the error output above for assistance.
```
STOP.
**If file permissions error:**
```
❌ Permission denied
Could not write cover-letter.pdf to the current directory.
Please check:
1. You have write permissions in: [current directory]
2. The file is not open in another application
3. Sufficient disk space is available
Current directory permissions:
[Show output of: ls -ld .]
```
STOP.
**If disk space error:**
```
❌ Insufficient disk space
Could not create PDF file due to insufficient disk space.
Please:
1. Free up disk space
2. Or choose a different output location
Available disk space:
[Show output of: df -h .]
```
STOP.
**If conversion times out (> 30 seconds):**
```
❌ Conversion timeout
PDF generation took longer than expected (> 30 seconds).
This might indicate:
1. Very long or complex document
2. LaTeX compilation stuck on an error
3. System resource constraints
Please try:
1. Simplifying the cover letter content
2. Checking system resources
3. Running pdflatex manually for debugging
Manual debugging:
pandoc cover-letter.md --from markdown --to latex --template=[template-path] -o cover-letter.tex
pdflatex cover-letter.tex
```
STOP.
## Step 5: Success Output
**If conversion succeeded:**
```
✅ PDF generated successfully: cover-letter.pdf
## Conversion Summary:
📄 Input: cover-letter.md
📑 Output: cover-letter.pdf
📐 Format: Swiss business letter (scrlttr2, Swiss Norm)
## Document Details:
✓ Sender: [from.name]
✓ Recipient: [to[0]] (first line of address)
✓ Subject: [subject]
✓ Date: [date]
$if(enclosures)$
✓ Enclosures: [N] items
$endif$
## Formatting Applied:
- Swiss address window positioning (compatible with standard Swiss envelopes)
- Swiss German hyphenation and spelling
- Professional business letter layout
- Clickable email links
- Proper margins and spacing
## Next Steps:
1. **Review the PDF**: Open cover-letter.pdf and verify:
- All information is correct
- Layout looks professional
- Address fits in envelope window (if printing)
- No formatting issues or typos
2. **Print test** (if mailing):
- Print the PDF
- Check address position with a Swiss envelope window
- Verify text is clear and readable
3. **Digital submission**:
- Ready to attach to email applications
- Filename: cover-letter.pdf
4. **Rename for organization** (optional):
- Consider: [YourName]_Cover_Letter_[Company]_[Date].pdf
- Example: Max_Mustermann_Cover_Letter_TechCorp_2025-11-03.pdf
---
**Tip**: The generated PDF follows Swiss standards (SN) for business correspondence.
The address positioning is optimized for standard Swiss envelope windows.
```
## Step 6: Cleanup (Optional)
Pandoc may create intermediate files during conversion:
- `cover-letter.tex` - Intermediate LaTeX file
- `cover-letter.aux`, `cover-letter.log` - LaTeX compilation files
**If conversion was successful**: These files can be deleted (they're not needed)
**If conversion failed**: Preserve the .tex file for debugging
## Additional Features
### Custom Template
Users can customize the Swiss letter template:
**Location**: `src/.claude/templates/swiss-letter.tex`
**Customizable elements** (documented in template):
- Font size (currently 11pt)
- Margins and spacing
- Sender address alignment
- Header/footer content
- Color scheme (currently black/white)
**To customize**:
1. Edit `src/.claude/templates/swiss-letter.tex`
2. Re-run `/convert-cover-letter` to apply changes
3. Template comments explain each section
### Multiple Conversions
Users can run `/convert-cover-letter` multiple times:
- Overwrites existing `cover-letter.pdf` (no prompt needed)
- Use this after editing `cover-letter.md`
- Quick iteration on formatting and content
## Error Handling Summary
| Error Condition | User Action Required |
|-----------------|---------------------|
| No cover-letter.md | Navigate to application folder or run /write-cover-letter |
| Pandoc missing | Install Pandoc via package manager |
| LaTeX missing | Install texlive-latex-base, texlive-lang-german, texlive-latex-extra |
| Invalid YAML | Fix frontmatter syntax in cover-letter.md |
| Missing required fields | Add missing fields to frontmatter |
| LaTeX compilation error | Check for special characters, inspect .tex file |
| Permission denied | Check directory write permissions |
| Disk space | Free up disk space |
| Timeout | Simplify content or debug manually |
## Important Notes
### Swiss Letter Standards
The conversion follows Swiss Norm (SN) for business letters:
- **Address window**: Positioned for standard Swiss envelope windows
- **Date format**: DD.MM.YYYY (Swiss convention)
- **Layout**: KOMA-Script scrlttr2 with Swiss configuration
- **Language support**: Swiss German hyphenation and special characters (ä, ö, ü, ß)
### File Compatibility
**Input format**: Markdown with YAML frontmatter
**Output format**: PDF (via LaTeX)
**Template engine**: Pandoc with custom LaTeX template
### System Requirements
**Minimum**:
- Pandoc 2.0+
- LaTeX (TeX Live or MiKTeX)
- Basic LaTeX packages (texlive-latex-base, texlive-lang-german, texlive-latex-extra)
**Recommended**:
- Latest Pandoc version
- Full TeX Live installation (includes all packages)
- ~500MB disk space for full LaTeX installation
### Troubleshooting
**Common issues**:
1. **"File not found"** → Run command from application directory
2. **"Pandoc not found"** → Install Pandoc first
3. **"LaTeX error"** → Check for special characters in text
4. **"Missing font"** → Install texlive-fonts-recommended
5. **"Address doesn't fit window"** → Verify Swiss envelope type, check template settings
**For advanced users**:
- Intermediate .tex file shows LaTeX source
- Run `pdflatex cover-letter.tex` manually for detailed error output
- Edit swiss-letter.tex template for custom layouts
---
**Remember**: The goal is to produce a professional, Swiss-standard business letter PDF that is ready for submission with job applications. Quality and formatting accuracy are paramount.
+120
View File
@@ -0,0 +1,120 @@
% Swiss Business Letter Template for Pandoc
% This template follows Swiss standards (SN) for business correspondence
% Compatible with KOMA-Script scrlttr2 class
\documentclass[
fontsize=11pt,
paper=a4,
parskip=half, % Half line spacing between paragraphs
fromalign=right, % Sender address aligned right
fromphone, % Include phone number
fromemail, % Include email address
version=last % Use latest KOMA-Script features
]{scrlttr2}
% ==================== ENCODING & FONTS ====================
% UTF-8 input encoding for special characters (ä, ö, ü, ß)
\usepackage[utf8]{inputenc}
% T1 font encoding for proper hyphenation and special characters
\usepackage[T1]{fontenc}
% ==================== HYPERLINKS ====================
% Enable clickable email links in PDF
\usepackage{hyperref}
\hypersetup{
colorlinks=true,
urlcolor=black,
pdfborder={0 0 0}
}
% ==================== PANDOC COMPATIBILITY ====================
% Define tightlist command for Pandoc-generated lists
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
% ==================== SWISS LETTER CONFIGURATION ====================
% Load Swiss Norm (SN) for proper address window positioning
% This ensures the recipient address fits in standard Swiss envelope windows
\LoadLetterOption{SN}
% ==================== SENDER INFORMATION ====================
% Customize these fields by editing the markdown frontmatter
\setkomavar{fromname}{$from.name$}
\setkomavar{fromaddress}{$from.street$\\$from.city$}
$if(from.phone)$
\setkomavar{fromphone}{$from.phone$}
$endif$
$if(from.email)$
% Email is rendered as a clickable hyperlink
\setkomavar{fromemail}{\href{mailto:$from.email$}{$from.email$}}
$endif$
% ==================== LETTER METADATA ====================
$if(subject)$
\setkomavar{subject}{$subject$}
$endif$
$if(date)$
\setkomavar{date}{$date$}
$endif$
$if(signature)$
\setkomavar{signature}{$signature$}
$endif$
% ==================== ENCLOSURES ====================
$if(enclosures)$
% Separator between "Enclosures" label and list (e.g., "Anlagen:")
\setkomavar{enclseparator}{:}
$endif$
% ==================== CUSTOMIZATION OPTIONS ====================
% Remove backaddress line in envelope window (uncomment to enable)
\setkomavar{backaddress}{}
% You can customize additional elements here:
% - \setkomavar{location}{} - Text in the upper right corner
% - \setkomavar{place}{} - Place of writing (if different from address)
% - Font sizes, margins, spacing can be adjusted via KOMA-Script options
% ==================== DOCUMENT BODY ====================
\begin{document}
\begin{letter}{%
% Recipient address - each line from the 'to' frontmatter array
$for(to)$
$to$\\
$endfor$
}
% ==================== OPENING ====================
$if(opening)$
\opening{$opening$}
$else$
% Default opening if not specified
\opening{Sehr geehrte Damen und Herren}
$endif$
% ==================== LETTER BODY ====================
% The main content from your markdown file is inserted here
$body$
% ==================== CLOSING ====================
$if(closing)$
\closing{$closing$}
$else$
% Default closing if not specified
\closing{Freundliche Grüsse}
$endif$
% ==================== ENCLOSURES LIST ====================
$if(enclosures)$
% List of attached documents (e.g., CV, certificates)
\encl{$for(enclosures)$$enclosures$$sep$\\$endfor$}
$endif$
\end{letter}
\end{document}