An AI-powered job application automation system that generates tailored, professional cover letters by combining your competence profile with job postings.
- Quick Start (15 minutes)
- Project Structure
- Detailed Setup Guide
- How It Works
- File Reference
- Customization Guide
- Daily Workflow
- Troubleshooting
- Contributing
# 1. Clone the repository
git clone https://github.com/sweady1989/JobMatchAI
cd JobMatchAI
# 2. Copy example files to create your configuration
cp 3_latex/user_info.example.yml 3_latex/user_info.yml
# 3. Edit user_info.yml with your personal details
# (Use your favorite text editor)
# 4. Start n8n (requires Docker)
cd 4_n8n
docker compose up -d
# 5. Open http://localhost:5678 in your browser
# 6. Import the workflow: 4_n8n/application-letter-agent.json
# 7. Add your OpenAI API credentials in n8n
# 8. Add a job posting to candidates/example_user/0_inbox-jobs/
# 9. Run the workflow!JobMatchAI/
├── 0_queries&prompts/ # GPT prompts and LinkedIn search queries
│ ├── prompts/ # AI prompts for letter generation
│ │ └── 3_last_update_ATS_optimized_prompt.md # Main prompt
│ └── queries_linkedin/ # Job search query templates
│ └── search_queries_template.md
│
├── 3_latex/ # LaTeX document system
│ ├── src/
│ │ ├── templates/ # Cover letter and CV templates
│ │ ├── content/ # Generated .md files go here for processing
│ │ └── applications/ # Converted .tex files
│ ├── figures/ # Images (profile pics, signatures)
│ ├── output/ # Final PDFs appear here
│ ├── build/ # Build artifacts and logs
│ ├── parse_md_to_tex.py # Markdown → LaTeX converter
│ ├── user_info.example.yml # TEMPLATE: Copy to user_info.yml
│ └── Makefile # Build commands
│
├── 4_n8n/ # Workflow automation
│ ├── docker-compose.yml # Docker configuration
│ ├── application-letter-agent.json # Main workflow (import this!)
│ ├── IMPROVEMENT_GUIDE.md # Technical documentation
│ └── application_letter_cost_analysis.md # Cost tracking guide
│
├── candidates/ # Your application data
│ └── example_user/ # Example candidate folder (copy for yourself)
│ ├── 0_inbox-jobs/ # Job postings go here
│ │ ├── 0_template_jobs.md # Template for new jobs
│ │ └── 2025-01-15/ # Date-organized folders
│ │ └── 2025-01-15_company_role.md
│ ├── 1_profile/ # Your competence profile
│ │ └── competence-profile.md # EDIT THIS with your info
│ ├── 2_applications-mds/ # Generated letters appear here
│ │ └── 2025-01-15/
│ │ └── 2025-01-15_company_role_ENG.md
│ ├── 3_job_analysis/ # Job match analysis (optional)
│ └── .latest_job.json # Points to current job folder
│
├── 98_testfiles/ # Test and experiment files
├── Makefile # Top-level build commands
├── normalize_mds.py # Filename cleanup utility
└── README.md # This file
Install these tools before starting:
| Tool | macOS | Windows | Purpose |
|---|---|---|---|
| Git | brew install git |
Download | Version control |
| Docker Desktop | brew install --cask docker |
Download | Runs n8n workflow engine |
| Python 3 | brew install python |
Download | Runs conversion scripts |
| LaTeX (XeLaTeX) | brew install --cask mactex |
MiKTeX | Compiles PDF documents |
After installing, restart your terminal.
# Clone the repository
git clone https://github.com/sweady1989/JobMatchAI
cd JobMatchAI
# Create your personal configuration (this file is gitignored)
cp 3_latex/user_info.example.yml 3_latex/user_info.ymlNow edit 3_latex/user_info.yml with your real information:
- id: yourname # Used to select your profile
full_name: Your Full Name
email: [email protected]
phone: "+49 123 456 7890"
job_title: Your Target Role
linkedin_url: https://www.linkedin.com/in/yourprofile/
location: Your City, Country
# ... fill in all fieldsYour competence profile is the key to great application letters. The AI uses this to match your skills to job requirements.
- Navigate to
candidates/example_user/1_profile/competence-profile.md - Study the example structure - it shows you exactly what information to include
- Replace with your own information:
- Professional summary - 2-3 sentences about who you are
- Work experience - Include achievements with metrics ("Reduced costs by 30%")
- Education - Degrees, certifications, relevant courses
- Skills - Technical skills, tools, methodologies
- Notable projects - Highlight your best work
Tips for a strong profile:
- Be specific: "Reduced deployment time by 70%" beats "Improved efficiency"
- Use keywords from your target industry
- Include both technical skills and soft skills
- Update regularly as you gain new experience
n8n is the workflow automation engine that orchestrates the AI letter generation.
# Start n8n
cd 4_n8n
docker compose up -d- Open http://localhost:5678 in your browser
- Log in with credentials from
docker-compose.yml(change the default password!) - Click Import workflow → Select
application-letter-agent.json - Add your OpenAI API key:
- Click on the "create prompt-> send to model" node
- Click on "Credentials" → "Create new credential"
- Select "OpenAI API"
- Enter your API key from https://platform.openai.com/api-keys
- Update file paths in the workflow if you created a custom candidate folder:
path competence profilenode: Update the path to your profilereading json from "create-daily-folders"-workflownode: Update the path to your.latest_job.json
-
Create a date folder for today:
mkdir -p candidates/example_user/0_inbox-jobs/$(date +%Y-%m-%d) -
Copy the template:
cp candidates/example_user/0_inbox-jobs/0_template_jobs.md \ "candidates/example_user/0_inbox-jobs/$(date +%Y-%m-%d)/$(date +%Y-%m-%d)_company_jobtitle.md" -
Open the file and paste the job description
-
Fill in the metadata (company, location, salary if known)
-
Save the file
-
Update
.latest_job.jsonwith the path to your job folder:{ "jobs": [ { "jobFilePath": "/workspace/jobs/candidates/example_user/0_inbox-jobs/2025-01-15" } ] } -
In n8n, click Execute Workflow
-
Wait for the AI to generate your letter (usually 10-30 seconds)
-
Find the generated letter in
candidates/example_user/2_applications-mds/YYYY-MM-DD/
Convert the generated Markdown letter to a professional PDF:
# From the repository root
cd 3_latex
# Copy the generated letter to the content folder
cp ../candidates/example_user/2_applications-mds/2025-01-15/*.md src/content/
# Convert Markdown to LaTeX and compile PDF
make md2pdf
# Find your PDF in output/
ls output/
open output/ # macOS: opens the folderThe system uses a structured pipeline to generate professional application letters:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Job Posting │ │ Competence │ │ AI Prompt │
│ (Markdown) │ │ Profile │ │ (GPT rules) │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
└───────────────────────┼───────────────────────┘
│
▼
┌────────────────────────┐
│ n8n Workflow │
│ (Merges & sends to │
│ OpenAI API) │
└────────────┬───────────┘
│
▼
┌────────────────────────┐
│ Generated Letter │
│ (Markdown with │
│ LaTeX formatting) │
└────────────┬───────────┘
│
▼
┌────────────────────────┐
│ parse_md_to_tex.py │
│ (Converts to LaTeX) │
└────────────┬───────────┘
│
▼
┌────────────────────────┐
│ XeLaTeX Compile │
│ (Creates final PDF) │
└────────────────────────┘
-
AI Prompt (
0_queries&prompts/prompts/3_last_update_ATS_optimized_prompt.md)- Instructs GPT to write letters with specific sections
- Uses HTML comment labels:
<!-- PARAGRAPH_1_INTRODUCTION --> - Formats content in
\lettercontent{...}blocks for LaTeX
-
n8n Workflow (
4_n8n/application-letter-agent.json)- Reads your job posting and competence profile
- Merges them with the AI prompt
- Sends to OpenAI API
- Saves the generated letter
-
Markdown Parser (
3_latex/parse_md_to_tex.py)- Reads section labels from generated markdown
- Maps them to LaTeX template placeholders
- Auto-fills your personal info from
user_info.yml
-
LaTeX Templates (
3_latex/src/templates/)- Professional document layouts
- Placeholders like
{{PARAGRAPH_1_INTRODUCTION}}get replaced with content
| File | Purpose | How to Create |
|---|---|---|
3_latex/user_info.yml |
Your contact information | Copy from user_info.example.yml, edit with your data |
candidates/yourname/1_profile/competence-profile.md |
Your professional profile | Copy example folder, customize the profile |
candidates/yourname/0_inbox-jobs/DATE/*.md |
Job postings | Copy from 0_template_jobs.md, paste job description |
candidates/yourname/.latest_job.json |
Current job folder path | Edit to point to today's job folder |
| File | Purpose |
|---|---|
candidates/*/2_applications-mds/*.md |
AI-generated letters |
3_latex/src/applications/*.tex |
Converted LaTeX files |
3_latex/output/*.pdf |
Final PDF documents |
| File | Purpose |
|---|---|
4_n8n/docker-compose.yml |
n8n Docker settings (edit paths for your system) |
4_n8n/application-letter-agent.json |
n8n workflow (import into n8n) |
.gitignore |
Prevents committing personal data |
To set up the system for another person (family member, client):
-
Create their folder structure:
mkdir -p candidates/newperson/{0_inbox-jobs,1_profile,2_applications-mds,3_job_analysis} cp candidates/example_user/0_inbox-jobs/0_template_jobs.md candidates/newperson/0_inbox-jobs/ cp candidates/example_user/1_profile/competence-profile.md candidates/newperson/1_profile/ echo '{"jobs": []}' > candidates/newperson/.latest_job.json -
Edit their competence profile with their information
-
Add their info to
3_latex/user_info.yml:- id: newperson full_name: New Person Name # ... rest of fields
-
Duplicate the n8n workflow and update the file paths to point to the new folder
The AI prompt controls how letters are written. To customize:
- Open
0_queries&prompts/prompts/3_last_update_ATS_optimized_prompt.md - Study the structure:
- Language detection rules
- Section definitions (introduction, technical, experience, strategic fit, closing)
- Formatting requirements
- Make changes and test with a few job postings
- Update the prompt in the n8n workflow node as well
- Copy an existing template from
3_latex/src/templates/ - Modify the design (requires LaTeX knowledge)
- Update
parse_md_to_tex.pyto use your template
- Find a job posting - LinkedIn, company websites, job boards
- Save the job - Create a markdown file in your
0_inbox-jobs/DATE/folder - Update
.latest_job.json- Point to today's job folder - Run the workflow - Execute in n8n, wait for generation
- Review the letter - Check the generated markdown, edit if needed
- Generate PDF - Run
make md2pdfin the3_latex/folder - Send application - Use the PDF, track in your job search spreadsheet
Problem: Workflow fails with "file not found" errors
Solution:
- Check that Docker volume paths in
docker-compose.ymlare correct - Verify paths in workflow nodes match your folder structure
- Ensure the repository is mounted at
/workspace/jobsinside the container - Run
docker compose down && docker compose up -dto restart
Problem: make md2pdf fails with errors
Solution:
- Check
3_latex/build/*.logfor detailed error messages - Common issues:
- Missing LaTeX packages: Install with
tlmgr install packagename - Special characters: Escape
%,$,&,#in your content - Missing fonts: Install required fonts or change the template
- Missing LaTeX packages: Install with
Problem: Letters don't match the job or sound generic
Solution:
- Improve your competence profile with more specific details and metrics
- Ensure the job posting is complete (not just a title)
- Check that the AI prompt matches your industry/role
- Consider using GPT-4 instead of GPT-3.5 for better quality
Problem: Docker compose fails to start
Solution:
- Ensure Docker Desktop is running
- Check port 5678 is not in use:
lsof -i :5678(macOS/Linux) - Try
docker compose down && docker compose up -d - Check Docker logs:
docker compose logs
Problem: "API key invalid" or "quota exceeded"
Solution:
- Verify your API key at https://platform.openai.com/api-keys
- Check your usage limits at https://platform.openai.com/usage
- Update the credential in n8n if you regenerated the key
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
Important: Never commit personal data (real names, emails, phone numbers, job applications).
MIT License - See LICENSE file for details.
- Built with n8n workflow automation
- Powered by OpenAI GPT models
- PDF generation via LaTeX/XeLaTeX
