Install
openclaw skills install @chijiang/resume-editorBuild, edit, and format professional resumes with PDF import, styled HTML/PDF export, and multi-language support. Use this skill whenever a user mentions resumes, CVs, or curriculum vitae — whether they want to create one from scratch, import and edit an existing PDF resume, add or update sections (education, experience, projects, skills), export to a styled HTML or PDF document, generate multi-language versions, or apply professional formatting. Also triggers for requests like "help me update my CV", "format my resume", "translate my resume to Chinese", or "I need a professional-looking resume".
openclaw skills install @chijiang/resume-editorBuild professional resumes with AI-assisted content management, supporting PDF import/export, HTML styling, and multi-language output.
Canonical resume schema: See references/resume-schema.json and references/data-structure.md
Troubleshooting: See references/troubleshooting.md
Customization (themes, languages): See references/customization.md
pip install pymupdf==1.26.5pip install playwright==1.60.0 && playwright install chromiumSave resume JSON to resume.json in the current working directory unless the user specifies another path. When importing from PDF, save the extracted JSON alongside the source file.
Always keep the working file in the canonical schema used by the renderer. If imported data is rough or partially parsed, normalize it before presenting edits or exporting.
The scripts/extract_from_pdf.py script does basic text extraction, but it produces rough output. For best results, use your AI capabilities to read and understand the PDF content directly, then structure it into the resume JSON schema yourself. The script is available as a fallback:
python3 "$SKILL_DIR/scripts/extract_from_pdf.py" input.pdf output.json
After extraction (by any method), do not export immediately. First:
When adding or editing sections, gather complete information through natural conversation. The key areas to ask about:
For Education: institution, degree, period, location, GPA (if applicable), honors. For Work Experience: company, position, period, location, responsibilities, quantifiable achievements. For Projects: name, role, period, technologies, description, key achievements.
Keep asking follow-up questions if responses are brief or unclear. The goal is a complete, well-structured entry — not a minimal one.
Built-in themes hide personal.photo by default — most regions (US, UK, Canada, Australia, much of the EU) expect resumes without a photo and may discard photo-bearing resumes for legal reasons (anti-discrimination). Do not add a photo unprompted.
Ask about a photo only when the context suggests one is expected, for example:
When in doubt, ask once: "Do you want a portrait on this resume? Some markets expect one, others penalize it."
If the user wants a photo:
https:// URL, or data: base64 URI. Do not invent, fetch, or generate an image.personal.photo. Supported values are a relative path, absolute local file path, file:// URL, https:// URL, or data: URI. Relative paths resolve against the HTML output location, so the user should keep the photo next to the generated HTML.scripts/create_theme.py and enable it:
.resume-photo {
display: block;
width: 96px; height: 96px;
object-fit: cover;
border-radius: 50%; /* or 4px for a square headshot */
}
When the user requests meaningful edits, especially after import, prefer an edit-review-export flow:
resume.json.When the user dislikes the built-in look and wants a more personalized visual style:
modern, classic, minimal, creative).python3 "$SKILL_DIR/scripts/create_theme.py" custom-theme-name --base modern
user-themes/custom-theme-name/style.css based on the user's feedback.user-themes/custom-theme-name/template.html.--theme custom-theme-name.Prefer this path over editing built-in assets directly. It preserves the stock themes and gives the user a reusable personal template.
Important separation principle:
This separation makes the resume scannable for HR while providing depth for engineering interviews.
python3 "$SKILL_DIR/scripts/export_resume.py" --format html --theme modern --lang en resume.json output.html
python3 "$SKILL_DIR/scripts/export_resume.py" --format pdf --theme modern --lang en resume.json output.pdf
The PDF flow always renders a clean HTML intermediary first, then converts it to PDF. Do not use editable HTML as the final PDF source.
The PDF renderer blocks external network requests by design. Prefer local assets, data: URIs, or bundled files for anything that must appear in the PDF.
Available themes: modern, classic, minimal, creative
Custom themes: Any folder under user-themes/<name>/ with a style.css, or a direct path to a custom theme directory
Available languages: en, zh, ja, fr, de, es
--langonly switches UI labels (section titles like "Work Experience", the edit-mode toolbar strings, and thehtml langattribute). It does not translate resume body content. When a user asks to "translate my resume to X", translate the JSON content yourself first, then export with--lang Xso labels and content stay consistent.
For collaborative refinement with the user, generate an editable HTML that includes inline editing capabilities:
python3 "$SKILL_DIR/scripts/export_resume.py" --format html --theme modern --lang en --editable resume.json output.html
Workflow:
resume.json on disk through a local sync server that the export step starts automatically.resume.json yourself to pick up the changes. Do not ask the user to paste JSON.resume.json.--editable.Rich-text markup. Body fields support a small Markdown subset for emphasis. Both the agent (when authoring JSON) and the user (via the toolbar) use the same syntax, so they round-trip:
| Syntax | Effect |
|---|---|
**text** | bold |
*text* | italic |
_text_ | underline |
==text|#rrggbb== or ==text|namedcolor== | colored run |
Example: "Achieved **30%** growth with *custom* analytics.". The renderer applies a strict whitelist — invalid color specs are left as literal text, and HTML/script tags are escaped. Title-like fields (name, company, position, degree, institution, project-name, role, category-title, period, location, gpa, technologies, skill items) render plain to keep layouts clean.
Notes:
<output>.sync.json for explicit cleanup.--no-sync is passed (or the server failed to start), the Save button is disabled and the user falls back to Copy JSON; in that case ask them to paste.JSON.stringify(window.extractToJson ? extractToJson() : 'N/A') to read edits programmatically without Save.| Script | Purpose |
|---|---|
scripts/extract_from_pdf.py | Extract text from PDF resumes (fallback — prefer AI-based parsing) |
scripts/generate_html.py | Generate styled HTML from resume JSON |
scripts/generate_pdf.py | Convert HTML resume to PDF |
scripts/export_resume.py | Unified entrypoint for HTML/PDF export |
scripts/create_theme.py | Scaffold a reusable custom theme |
scripts/validate_resume.py | Validate a resume JSON against the canonical schema |
scripts/_edit_sync_server.py | Local-only HTTP server (background) that the editable toolbar POSTs edits to — writes them back to resume.json. Started automatically by generate_html.py when --editable is set and --no-sync is not. Not invoked directly. |