| name | resume-generator |
| description | Generate tailored Chinese and English resumes and cover letters from a job description. Use when the user asks to create a resume, CV, cover letter, or application materials for a specific job posting. Triggers on JD analysis, resume tailoring, cover letter writing, or job application preparation. |
Resume & Cover Letter Generator
IMPORTANT
Do NOT edit this file during resume generation.
If you need to update rules, tell the user instead.
Generate application materials from a JD using Python script + JSON config.
Architecture
LLM Role: Analyze JD -> Output JSON config (~2KB)
Script Role: Read template + Apply config -> Generate HTML
Personal info: Extracted by script from references/work-history.md, NOT by LLM
This design reduces token usage by 95% and execution time from 20min to 2min.
Photo Handling: Photo base64 is stored separately in assets/photo-base64.txt (~120KB) and auto-injected by the script. Template uses {{PHOTO_BASE64}} placeholder. Photo is required — generate.py will refuse to run without it.
Environment Setup (Auto, First Run)
Before the first resume generation, check and install dependencies:
python3 -c "from playwright.sync_api import sync_playwright; print('Playwright OK')" 2>/dev/null || \
(pip install playwright && playwright install chromium)
If Playwright cannot be installed (e.g. permission issues), warn the user that layout validation will be skipped and the resume may have overflow or orphan word issues.
Onboarding (First-Time Setup)
Before generating a resume, check if references/work-history.md exists.
If it does NOT exist, enter onboarding:
-
Collect work history:
- Tell the user: "请把你的工作经历以文本形式发给我。如果你的AI工具支持读取图片或PDF,也可以发这些格式。"
- Parse the user's response into structured work-history.md format (see
references/work-history-template.md for the schema)
-
Confirm locked companies:
- List all companies/positions found
- Ask: "以下是你的工作经历。请选择哪些必须出现在每份简历中(确保时间线完整,不留空白年份)。回复序号即可。"
- Save selections to
locked_companies in work-history.md frontmatter
-
Collect default links:
- Ask: "你有想默认展示在简历上的链接吗?(如LinkedIn、GitHub、个人网站)"
- Save to work-history.md
links section
-
Collect photo (required):
- Tell the user: "请发一张照片用于简历。"
- Save as
assets/photo-base64.txt
- If user insists on skipping, warn that the resume will have a blank photo area
-
Onboarding complete, ready for JD analysis.
JD Analysis (Optional Pre-Step)
When the user provides a JD but hasn't explicitly asked to generate a resume, or when the user asks "帮我分析一下这个JD" / "这个岗位适合我吗" / "analyze this JD", run a JD analysis first.
Analysis Flow
- Read
references/work-history.md
- Read the JD text provided by the user
- Output a structured analysis:
## JD 匹配度分析
**匹配度评分**: X/10
### 定位建议
(建议用什么角度/侧重点来写这份简历)
### 匹配优势
- 优势1:你的XX经历直接对应JD要求的XX
- 优势2:...
### 潜在差距
- 差距1:JD要求XX,你的经历中没有直接体现
- 差距2:...
### 弥补策略
(针对每个差距,如何用现有经历的不同角度来弥补)
### 推荐重点突出的经历
(按相关度排序,标注哪些 locked_companies 必须包含)
- Analysis 完成后,问用户:
- "要根据这个分析生成简历吗?" → 进入 Resume Generation 流程
- "要生成求职信吗?" → 进入 Cover Letter 流程
- 用户也可以先调整定位再生成
Analysis Rules
- 评分必须基于 work-history.md 中的真实经历,不能假设用户有未记录的能力
- 差距分析要诚实 — 如果匹配度低就直接说,不要强行美化
- 弥补策略只能用现有经历的不同表述角度,不能编造
- locked_companies 列表中的公司经历无论匹配度如何都必须出现在推荐中
Quick Workflow (Resume Generation)
- Read
references/work-history.md (the ONLY source of truth)
- Verify
assets/photo-base64.txt exists (if not, ask user for photo before proceeding)
- Analyze JD, determine positioning (or use JD Analysis result if already done)
- Generate JSON config file (write content-rich config first — see Page Fullness below)
- Run
python3 scripts/generate.py <config.json> <template.html> <output.html>
- Auto-validation runs (companies / title_lines / overflow / orphan words) — all FAIL block output
6b. If overflow: trim content by priority (see Page Fullness) and re-run step 5
6c. If orphan word detected: fix config text -> re-run step 5 until pass
- Provide output file path
JSON Config Schema
Write config to /tmp/{company}-config.json:
{
"company": "Target Company Name",
"title_lines": [
"职位1",
"职位2",
"职位3"
],
"about_text": "~100字个人简介,必须包含至少2个具体数据指标...",
"skills": [
"技能1",
"技能2",
"技能3",
"技能4",
"技能5",
"技能6",
"技能7"
],
"core_competencies": [
{"title": "核心能力1", "desc": "描述..."},
{"title": "核心能力2", "desc": "描述..."},
{"title": "核心能力3", "desc": "描述..."},
{"title": "核心能力4", "desc": "描述..."},
{"title": "核心能力5", "desc": "描述..."},
{"title": "核心能力6", "desc": "描述..."}
],
"experience": [
{
"company": "从work-history.md精确提取的公司名",
"period": "从work-history.md精确提取",
"role": "从work-history.md精确提取的职位",
"bullets": [
"根据JD重新撰写的要点...",
"**加粗标签**: 支持这种语法"
]
}
],
"highlight_keywords": {
"old_keyword": "new_keyword"
},
"sidebar_section_title": "基本信息"
}
Critical: What LLM Generates vs What Script Extracts
| Source | Fields |
|---|
| Script extracts from work-history.md | name, name_en, email, phone, links, education, company names, periods, roles |
| LLM generates in config | title_lines, about_text, skills, bullet content, core_competencies, highlight_keywords |
The LLM must still include company, period, and role in the experience config entries — the script uses these for timeline rendering. But these values MUST be copied exactly from work-history.md, never invented.
Page Fullness Principle
页面充实优先,溢出调整其次。 The resume should fill the A4 page well — no large blank areas at the bottom. Write content-rich config first, then trim only if overflow occurs.
Content priority for trimming (when overflow):
- First: shorten core_competencies desc text
- Then: reduce bullet count in least-relevant experience entries
- Last resort: reduce core_competencies from 6 to 4
Never start with minimal content to "play it safe" — always write full, rich content first.
Field Rules
| Field | Count | Rules |
|---|
title_lines | 3 | must be real job titles from work-history.md (e.g. Role or Role_EN values), NOT skill descriptions or inferred titles |
about_text | 100-150 chars | Tailored per JD, referencing work-history.md; only reframe existing facts, never fabricate. Must include at least 2 concrete metrics from experience (e.g. "170+ videos", "8+ platforms"), otherwise validate.py will block output. Write towards 150 chars for page fullness. |
skills | 7 | Pick the 7 most relevant from work-history.md skill pool |
experience | all locked | All locked_companies must appear. validate.py will FAIL if any is missing. Role must be real title from work-history.md. Bullets support **Label**: text syntax. Content tailored per JD angle, facts must not be fabricated. Each experience entry should have 3-5 bullets — don't write only 1-2 bullets per entry. Keep content comprehensive, minimize trimming. |
core_competencies | 6 | Each with title + desc. desc should be 15-25 characters (CN) or 8-15 words (EN) — don't write overly short descriptions. If overflow after generation, reduce to 4. |
highlight_keywords | optional | Replace highlighted keywords to match JD language |
sidebar_section_title | CN: "基本信息" | EN: "BASIC INFO" (hardcoded in template) |
Generate Command
generate.py will auto-call validate.py after generation, outputting a Validation Report.
python3 SKILL_DIR/scripts/generate.py \
/tmp/{company}-config.json \
SKILL_DIR/assets/template-cn.html \
/tmp/{company}-resume-cn.html
python3 SKILL_DIR/scripts/generate.py \
/tmp/{company}-config.json \
SKILL_DIR/assets/template-en.html \
/tmp/{company}-resume-en.html
Replace SKILL_DIR with the actual path to this skill directory.
Validation (auto-runs, no manual call needed)
generate.py auto-runs validate.py after completion, checking:
| Check | Method | Failure |
|---|
| Locked companies present | HTML string match against work-history.md locked_companies | FAIL |
| title_lines are real titles | config JSON vs work-history.md Role/Role_EN values | FAIL |
| about_text has 2+ metrics | Regex count of numbers | FAIL |
| Content exceeds A4 page | Playwright scrollHeight | FAIL, trim content |
| Orphan words (single word on last line) | Playwright word-level rendering | FAIL |
| Sparse lines (low fill rate) | Playwright pixel measurement | WARNING |
If VALIDATION FAILED appears, must fix config and regenerate — never send resume directly.
Orphan Word Fix
If orphan error appears:
- Report shows orphan word and its selector (e.g.
.job-list li, .core-item)
- Modify config text (add/remove words to change line breaks)
- Re-run generate until pass
Cover Letter (Scripted Flow)
Cover letters are generated via generate_cover_letter.py from a JSON config.
Shared template: assets/template-cover-letter.html (language switched via language field).
Workflow
- Read
references/work-history.md + JD
- Write config to
/tmp/{company}-cover-letter-config.json
- Run:
python3 SKILL_DIR/scripts/generate_cover_letter.py \
/tmp/{company}-cover-letter-config.json \
/tmp/{company}-cover-letter-{lang}.html
JSON Config Schema
{
"company": "Company Name",
"language": "en",
"date": "July 19, 2026",
"job_title": "Job Title from JD",
"hiring_team": "Company Hiring Team",
"greeting": "Dear Hiring Team,",
"intro": "I am writing to apply for...",
"sections": [
{
"title": "Why This Role",
"paragraphs": ["..."]
},
{
"title": "What I Bring",
"paragraphs": [
"**Key Skill:** Description of relevant experience...",
"**Another Skill:** More details..."
]
}
],
"closing": "I would welcome the opportunity...",
"sign_off": "Best regards,"
}
Field Rules
| Field | Required | Notes |
|---|
company | yes | Used in page title and hiring team default |
language | yes | "en" or "cn" — auto-switches labels |
date | yes | Display date |
job_title | yes | Exact role from JD |
hiring_team | optional | Defaults to "{company} Hiring Team" |
greeting | optional | Defaults to "Dear Hiring Team," / "尊敬的招聘团队:" |
intro | yes | Opening paragraph |
sections | yes | Array of {title, paragraphs}. Supports **Label:** text for bold. |
closing | optional | Closing paragraph (or array) |
sign_off | optional | Defaults to "Best regards," / "此致敬礼," |
Critical Rules
- NEVER invent work experience. Only use jobs in
references/work-history.md
- NEVER change dates or company names — copy exactly from work-history.md
- title_lines must be REAL job titles from work-history.md, NOT skill descriptions or inferred titles
- Never fabricate or extrapolate facts: Resume modifications must only reframe existing facts
- Template HTML/CSS is LOCKED — script only replaces text content
- locked_companies from work-history.md frontmatter MUST all appear in experience
Anti-Patterns
- No fabrication: Don't invent capabilities or metrics not in work-history.md
- No inferred titles: Don't use titles never actually held
- No content overflow: If content too long, trim rather than exceeding page
- No sparse pages: Don't write minimal content — page should be well-filled with no large blank areas at bottom
- No orphan words: All text must avoid single-word last lines
- No abbreviations in config: Use full forms (communications, department, management)
English Bullet Writing Style
DO
- Keep sentences short and direct
- One core point per bullet
- Weave numbers and results naturally into sentences
- Distribute info across bullets logically
DON'T
- Don't overuse em dashes to split long sentences
- Don't pile on modifiers
- Don't cram all info into one bullet
- Don't use overly formal/stiff structures
- Don't use informal abbreviations: comms -> communications, dept. -> department