job-hunt Job Hunter
⚡ Full-process Automatic Execution Constraints (Highest Priority, Valid Throughout)
Only applicable to the full-process mode of without parameters.
After the user provides the resume and confirms the screenshots, all remaining steps are automatically executed continuously until the shortlist is output.
- Between Step 3 fetcher return → Step 7: No text output is allowed. Text output = turn end = wait for user = process interruption
- Immediately call the tool (Skill / Bash / Read / Write) required for the next step after each step ends, without inserting any text
- The return results of sub-skills (fetcher / analyzer / tailor) are internal data, must not be echoed, repeated, or reported to the user, and should be directly used for the next step
- Prohibited to ask the user "whether to continue" or "whether to start the next step" between steps
Violating the above constraints = process interruption, complete collapse of user experience.
Subcommand Routing
Determine the execution path based on user input:
| User Input | Execution |
|---|
| without parameters | Full process (Step 1→7) |
| Only execute screenshot import (Step 1+2+3) |
| Only execute analysis (Step 1+4) |
| Execute sorting (Step 5) + customization (Step 6) |
| Output current run status (Step 7b) |
| Force clean all caches and products (Step 8) |
Step 1: Determine Working Directory and Initialization
= The current directory where Claude starts (absolute path of
).
Obtain with Bash:
, use the result as
.
=
<data_dir>/jobHuntSkillData
(all data files are uniformly placed in this directory, do not write directly to
).
Ensure the following directories exist (create with Bash
):
<data_dir>/.work/jd-pool/
<data_dir>/output/
Generate
(format:
, using current local time).
Create directory
<data_dir>/output/<run_id>/
.
Initialize
<data_dir>/output/<run_id>/state.json
:
json
{
"run_id": "<run_id>",
"phase": "init",
"stages": {
"fetched": [],
"analyzed": [],
"analysis_errors": [],
"tailored": []
},
"last_error": null,
"checkpoint_at": "<current ISO 8601 time>"
}
In all subsequent steps involving paths, use instead of . Pass the value of
as the
parameter to sub-skills.
Subcommand special handling: If the current subcommand is
,
or
, before generating a new run_id, first scan the existing run directories (format
) under
. If they exist,
reuse the latest run_id (do not create a new directory, read the existing state.json and continue using it); if not, create a new run_id according to the above process.
Step 2: Obtain Resume
(Executed for full-process, fetch, analyze subcommands)
Check if
<data_dir>/.work/resume.md
exists:
If it exists: Inform the user:
"A resume saved from last time has been detected, continue using it.
If you need to replace the resume, directly send me the new resume (supports file / path / pasted text), and I will help you replace it and re-evaluate.
If you continue to use the current resume, tell me 'Continue'."
Stop execution and wait for user reply:
- User sends new resume → process according to the "If not exists" method below, overwrite and save , enter Step 2.5 for re-evaluation
- User says "Continue" or other non-resume content → skip this step, skip Step 2.5, directly enter Step 3
If it does not exist: Prompt the user to provide a resume:
"Please provide your resume, supporting the following two methods:
① Send a .md format resume file, or tell me the local path of the file (e.g.,
)
②
Directly paste the resume text into the message box and send (fastest and most stable, select all and copy from any PDF/Word reader)
Direct upload of PDF/Word and other layout files is not supported - cross-environment parsing of such formats is prone to distortion or failure. Please use method ② to paste text directly."
Process according to the user's provided method:
-
Send file (.md) / file path (.md): Read the file content using Read tool or Bash
-
Send file / file path (other formats, such as .pdf / .docx / .doc / .txt / .rtf, etc.): Do not attempt any form of parsing, directly inform the user:
"PDF / Word and other layout file uploads are not supported temporarily (cross-environment parsing is prone to distortion). Please use:
① Open the resume with any PDF/Word reader, select all (Cmd/Ctrl+A) → copy (Cmd/Ctrl+C) → paste here and send
② Or save the resume as .md format and resend"
Stop execution and wait for the user to re-operate
-
Paste text: Execute according to the "Pasted Text Processing Flow" below
⛔ Ethical Hard Constraint: No matter what format the user provides, absolutely prohibit fabricating, imagining, or inferring resume content out of thin air. If the format cannot be recognized, stop the process and let the user re-upload, never generate a fake resume.
.md File Branch Processing: After reading the content, directly write to
<data_dir>/.work/resume.md
, inform the user "✅ Resume saved.", enter Step 2.5.
Pasted Text Processing Flow
Only execute when the user takes the "paste text" branch:
Step 1: Save Original Backup
Write the
original content pasted by the user (without any modification) into
<data_dir>/.work/resume.raw.md
. This is a rollback backup for any subsequent cleaning.
Step 2: Heuristic Detection of Whether Format is Already OK
Judge whether the pasted text is "already structured Markdown", which must simultaneously meet the following conditions:
- Contains ≥ 2 section markers (line starts with , or ordered list numbers like / )
- Contains ≥ 2 list markers (line starts with or or followed by a space)
- Average non-empty line length ≥ 15 characters (indicating no forced line breaks per word)
- No large number of "single-word isolated lines" (more than 5 consecutive lines with only 1-3 characters per line)
All conditions met: Directly write the original content into
<data_dir>/.work/resume.md
, inform the user "✅ Resume saved (good format, used directly).", enter Step 2.5.
No inquiry, no cleaning.
Any condition not met: Enter Step 3.
Step 3: Ask User for Selection
Key Constraints:
- Must output the complete original resume text pasted by the user (no omissions, not a preview, not a summary, not truncated to first N words)
- The A/B question comes after the resume original text
- The A/B question must be the last paragraph of the entire message, so that the user's last line of sight falls on
- Do not write any explanatory text above the resume original text (such as "The following is your resume" "Received" and other opening remarks)
- Display the resume original text in a code block (wrapped with ```) to avoid Markdown rendering interfering with the original format
Output format strictly as follows:
```
<Complete original resume text pasted by the user, unchanged>
```
---
📝 The above is the resume content you pasted. It seems there are some format issues - there may be line breaks, missing section markers, etc., which are common when copying from PDF/Word.
Two processing methods:
A. **Help me organize it** —— Only modify the format: merge broken lines of the same paragraph, restore project symbols, add section titles; **do not change a single word**
B. **Keep my original format** —— I want it this way, don't change it
👉 Reply A or B
Stop execution and wait for user reply.
Prohibited:
- Truncate resume content (even if the resume is very long, post it in full)
- Append any text after the A/B question
- Add any title/explanation above the resume original text (start directly with the code block)
Step 4: Process According to User's Selection
- User replies A (or semantic equivalents: "organize", "clean", "help me fix", "whatever", etc.) → enter Step 5 for structure normalization
- User replies B (or semantic equivalents: "don't change", "keep as is", "retain", "don't modify", etc.) → write the original content into
<data_dir>/.work/resume.md
, inform the user "✅ Saved according to your original format.", enter Step 2.5
- User replies ambiguous content (such as "?" "What do you mean") → briefly re-explain the meaning of A/B once, then wait for reply
- User directly sends a new resume → treat as re-pasting, return to Step 1
Step 5: Execute Structure Normalization (Only A Path)
Strictly only modify the format, do not change a single word. List of allowed and absolutely prohibited operations:
✅ Allowed:
| Operation | Description |
|---|
| Merge broken lines of the same sentence | Responsible for Douyin\nshort videos\nfrontend development
→ Responsible for Douyin short videos frontend development
. Judgment standard: the previous line does not end with sentence-ending punctuation () and the next line does not look like the start of a new section/list item |
| Merge split titles/names | → ; → |
| Remove consecutive blank lines | 3 or more consecutive blank lines → keep 1 |
| Restore project symbols | Isolated at the beginning of paragraphs → replace with |
| Restore section title hierarchy | Identify common section keywords such as "Personal Information", "Work Experience", "Project Experience", "Educational Background", "Professional Skills", "Self-evaluation", add in front |
| Standardize indentation | tab characters → 2 spaces; excessive spaces at the beginning of lines unified to multiples of 2 spaces |
| Fix encoding exceptions | Delete invisible characters such as zero-width spaces |
| Delete out-of-order fragments caused by obvious multi-column layout | Only when it is 100% certain that it is a multi-column problem and can be correctly restored; do not modify if uncertain |
❌ Absolutely Prohibited:
- Add, delete, or rewrite any text content (even a single word)
- Correct typos (if the user writes "Hangzhou" as "杭洲", keep "杭洲")
- Translate, summarize, simplify, or expand
- Infer and fill in missing information based on context
- Add sections, skills, or experiences not mentioned by the user
- Change the order, time, or numbers of events
Violating any of the ❌ items triggers an ethical hard constraint alert, must stop and inform the user.
After cleaning is completed:
- Write the cleaned result into
<data_dir>/.work/resume.md
- Briefly inform the user of the cleaning amount: "📝 Resume format organized: merged N broken lines / restored M project symbols / added K section titles. The original version has been backed up (say 'restore original version' if unsatisfied)."
- Enter Step 2.5
User Regrets Afterwards (Any Stage)
When the user says semantic equivalent instructions such as "restore original version", "use original version", "use the version I pasted", "don't use the cleaned version" in subsequent processes:
- Check if
<data_dir>/.work/resume.raw.md
exists
- Does not exist → inform "Original backup version not found (maybe this resume was not cleaned). If you need to replace it, directly re-paste or send a new resume."
- Exists → use Bash to copy and overwrite
- Inform the user "✅ Switched back to the original version."
- Re-enter Step 2.5 for evaluation
Step 2.5: Resume Quality Evaluation
(Only executed when the user provides a new resume in this session; skip directly to Step 3 if reusing cache)
Read
<data_dir>/.work/resume.md
, find all
evaluable units, score them one by one, and output the results.
⛔ Must filter first, then evaluate. The following three rules are mandatory prerequisites, cannot be skipped or bypassed:
- Before any evaluation action, must complete the complete screening process of Rule 1→2→3
- Must not infer the work content of the experience based on company name, position name, or department name for evaluation —— The evaluation object can only be the action verbs and result descriptions written clearly in the resume
- Only the text content that passes Rule 3 can appear in the "Paragraph-by-Paragraph Analysis"; blocks/lines that fail the screening must not appear
Three judgment rules, executed in order:
Rule 1: Skip the entire block (ignore content, skip directly)
The following blocks are skipped entirely regardless of what is written, not evaluated:
- Personal Information / Basic Information / Contact Information
- Professional Skills / Skill Strengths / Technical Abilities / Tool Usage / Technology Stack
- Educational Background / Educational Experience / Academic Qualification
- Self-evaluation / Personal Profile / Job Intention
- Certificates / Awards / Honors
Block names are not limited to the above words, as long as the semantics belong to the above types (such as "My Skills", "Tools Mastered", "Awards Received"), they are also skipped entirely.
⚠️ Processing of merged blocks: If the block name contains both work and education (such as "Work and Educational Experience", "Educational and Work Background"), do not skip entirely, enter Rule 2 to judge line by line. Lines belonging to educational entries (including school name, major name, degree, school time) will also be skipped according to Rule 2.
All other blocks (Work Experience, Project Experience, Internship Experience, Entrepreneurship Experience, Part-time Experience, or any custom-named experience blocks) enter Rule 2.
Rule 2: Skip title lines within blocks
In experience blocks, judge each line individually. If this line meets both of the following two points, skip it:
- No action verbs (responsible for, led, designed, promoted, built, optimized, completed, implemented, led, etc.)
- No result descriptions (improved, reduced, increased, decreased, reached, exceeded, saved, or specific numbers/percentages)
⚠️ Important: Verbal words contained in position names and department names do not count as action verbs. For example, "Operation Group", "Brand Department", "Design Section", "Management Position" —— these are name tags of organizational units, not descriptions of personal behaviors, and do not trigger evaluation. Judgment basis: whether this word describes "what this person did" or "what this department/position is called".
Examples:
- "ByteDance · Product Manager · 2021.03—2023.06" → ❌ Skip (no verbs, no results)
- "A Cultural Media Company 2023.7~2025.11 New Media-Operation Group" → ❌ Skip ("Operation" is the department name, not an action description)
- "An Internet Technology Company 2022.6~2023.6 Marketing Department-Brand Group" → ❌ Skip ("Brand" is the department name, not an action description)
- "XX University 2018.9~2022.6 Journalism and Communication-Bachelor" → ❌ Skip (educational entry, no action, no result)
- "Project Name: xxx Platform | Role: Leader | 2022.01—2022.06" → ❌ Skip (no verbs, no results)
⚠️ Empty Block Rule (Check immediately after executing Rule 2)
If all lines in an experience block are skipped after Rule 2 processing (i.e., no line in the block contains action verbs or result descriptions), then this block does not enter the three-dimensional scoring below, must not generate any evaluation entries for this block, and must not borrow content from other blocks to fill it.
Typical scenario: The "Work and Educational Experience" block only has three lines of header information: company name + time + department name. After all are skipped by Rule 2, this block does not participate in paragraph-by-paragraph scoring.
📛 But empty work/internship experiences cannot disappear silently, must be prominently warned:
When skipping such blocks, record the empty entries belonging to work/internship experiences (company name + time period, e.g., "A Cultural Media Company 2023.7~2025.11"). If there is at least one such entry, must output the "Empty Experience Warning" block at the top of the evaluation output (see output format below).
Reason: Empty work experience is the most fatal shortcoming of a resume, and the tailor stage cannot make any rewrites for it (ethical red line prohibits fabricating content). If these empty experiences cover the user's main working years, completing them is more important than any resume customization —— must let the user see it clearly instead of letting it disappear silently. Empty educational entries are not within this warning scope (educational experience does not require action/results).
Rule 3: Evaluate the remaining content
The sentences/entries remaining after screening through the first two rules are evaluable units, enter the three-dimensional scoring below.
⚠️ When a title line and description are mixed in the same line, judge according to Rule 2: as long as it contains action verbs or result descriptions, evaluate it.
- "During my tenure as a Product Manager at ByteDance, I led the launch of the xx project, increasing DAU by 40%" → ✅ Evaluate (contains verb + result)
Evaluation Dimensions
⛔ Only content that passes Rule 3 above can enter this step. If all lines in a block (such as "Work and Educational Experience") are skipped by Rule 2, no evaluation entries are generated for this block as a whole —— even if you can judge that it is a work experience, do not evaluate it because no actions or results are written in the resume.
Each section of descriptive content is scored according to the following three dimensions (✅ Qualified / ⚠️ Weak / ❌ Missing):
| Dimension | ✅ Qualified | ⚠️ Weak | ❌ Missing |
|---|
| Scenario/Problem (S/P) | Has clear business background or problem to solve | Background is vague and mentioned in passing | No scenario description at all |
| Action (A) | Specifically describes "what I did", with methods/means | Only writes responsibilities, no action details | Missing |
| Result (R) | Has quantified numbers, or clear business value | Result is vague (e.g., "good effect") | No result description |
Additional checks:
- Whether a large number of passive verbs such as "responsible for", "participated in", "assisted" are used (minus points, recommended to change to active verbs)
- Whether there are obvious quantifiable but blank indicators (the tailor stage will insert placeholder)
Output Format
📋 Resume Quality Evaluation
<【Only output this block at the top if empty work/internship experiences are detected; otherwise, omit the entire block】
⚠️ Important Reminder: You have <N> empty work experiences
· <Company Name> · <Time Period>
· <Company Name> · <Time Period>
These sections only have company names and time, no work content or achievements written. This is the biggest shortcoming of your resume:
- When calculating the matching degree, these experiences will be skipped entirely due to no content, and the matching score will be significantly lower
- When customizing the resume, AI will not fabricate content for you (ethical red line), these sections can only be kept as is and cannot be optimized
👉 Completing the "what I did + what results I achieved" for these sections is more important than any resume customization. It is strongly recommended to choose A to supplement this part first.
>
Overall: <One-sentence summary, e.g., "Action descriptions are relatively sufficient, but result quantification is generally missing, it is recommended to supplement first">
Paragraph-by-Paragraph Analysis:
【Company Name · Position Name】
Scenario/Problem ✅ Action ⚠️ Result ❌
Problem: <Specific description of weak points>
Suggestion: <One-sentence rewriting direction>
【Project Name · Role】
Scenario/Problem ⚠️ Action ✅ Result ⚠️
Problem: <Description>
Suggestion: <Suggestion>
(...Other paragraphs)
⚡ Top 1-2 Priority Changes:
1. <Highest priority>
2. <Second priority>
🔧 Professional Skills Section Diagnosis:
<Independent of the above STAR evaluation, special inspection of the skills section (semantic recognition section, applicable to any name; if no title, identify by content characteristics: continuously arranged skill words/tool names/framework names). Check one by one according to the following four types of problems, output specific entries if there are problems, omit the type if no problem; if there are no problems in the entire skills section, omit the entire "🔧 Professional Skills Section Diagnosis" section:>
- **Vague/Empty Claims**: "Proficient" "Skilled in" followed by no specific scenarios or tools, or broad statements such as "proficient in all frontend technologies".
Provide **rewriting examples** for each problematic entry, e.g.:
"Proficient in Python" → "Skilled in Python (Flask/pandas, used for xx data processing)"
- **Missing Tool Names/Too Broad**: Only writes ability directions, no specific tools/platforms/frameworks. E.g., "Familiar with data analysis" "Understand frontend development".
Provide suggested completion directions for each entry, e.g.:
"Familiar with data analysis" → "Familiar with data analysis (SQL / Tableau / Power BI)"
- **No Level Stratification**: All entries use the same level word (all "familiar" or all "proficient"), unable to reflect the depth of ability.
If there is this problem, prompt to re-classify according to "Skilled / Familiar / Understand" or the user's actual situation.
- **明显与目标岗位偏差**: <Leave blank, give suggestions in combination with specific JD in the tailor stage; no JD context in Step 2.5, do not evaluate this item>
<Only output the "🔧 Professional Skills Section Diagnosis" section if at least one of the above four types has substantial problems; if the skills section is written reasonably (level words are stratified, have tool names, no large number of empty claims), omit the entire section and do not output any placeholder text.>
---
How to continue?
A. I will revise my resume myself and send it to you for re-evaluation after revision
B. Do not revise for now, continue with the current resume
User Selection Processing
Choose A (Revise Resume):
- Inform the user: "Okay, directly send me the new resume after revision (supports file / path / pasted text)."
- Stop execution and wait for the user to send the resume again
- After receiving, process in the same way as Step 2, overwrite and save
- Re-execute Step 2.5 (loop until the user chooses B)
Choose B (Continue):
- Inform the user: "Okay, continue."
- Execute Step 3
Step 3: Job Collection and Import
(Executed for full-process, fetch subcommands)
Prompt the user:
"Please upload the jobs you are interested in, supporting the following methods:
【Method 1】Directly send screenshots of job detail pages (any recruitment platform, Boss/Zhilian/Liepin/Lagou, etc.)
You can send multiple at a time, 📌 One screenshot = one job
If the job information is long, use a long screenshot, and the screenshot must at least contain the job name (company name is optional)
【Method 2】Tell me the directory path where the screenshots are located (e.g., /Users/xxx/Desktop/jobs)
I will automatically read all images and .jobs.json files in this directory (no recursive subdirectories)
【Method 3】Export the .jobs.json file with a browser plugin and drag it in with one click (supports Boss Zhipin / 51job / Zhilian Recruitment / Liepin)
👉 No plugin installed? Check the README installation instructions"
After sending the above prompt, stop execution and wait for the user to send screenshots or messages. Do not enter the loop in advance.
Judge user input type:
| Input | Processing Branch |
|---|
| Image attachments (one or more) | Branch A: Screenshot Parsing |
| File path ending with | Branch C: JSON Import |
| Directory path | Branch B: Scan Directory (mixed images + .jobs.json) |
Branch A: Screenshot Parsing
Call the Skill tool, load the
skill, pass in:
- : <value of data_dir>
- : <current run_id>
- : <batch of screenshots>
The fetcher processes internally (including grouping confirmation interaction), and writes to jd-pool after completion.
Branch B: Scan Directory
Verify the directory exists with Bash:
If it does not exist, inform the user "Directory does not exist, please confirm the path and resend." and wait again.
List image files and .jobs.json files in the directory with Bash (only read the current directory, no recursive subdirectories):
find "<directory>" -maxdepth 1 -type f \( -iname "*.png" -o -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.webp" -o -iname "*.jobs.json" \) | sort
If the result is empty, inform the user "No images or .jobs.json files found in this directory, please confirm and resend." and wait again.
Inform the user which files were found: "Found <N> screenshots + <M> .jobs.json files, starting processing."
Process by file type:
- Images → Branch A (call fetcher)
- Each .jobs.json → Branch C (call import_jobs.py)
Branch C: JSON Import
Call import_jobs.py with Bash:
bash
if command -v python3 >/dev/null 2>&1; then PYBIN=python3; \
elif command -v python >/dev/null 2>&1; then PYBIN=python; \
else echo "PYTHON_MISSING"; exit 1; fi
"$PYBIN" "$HOME/.claude/skills/job-hunt/import_jobs.py" "<data_dir>" "<json_path>"
Expected stdout:
OK: Imported N jobs -> ...
→ Success, continue
- → Inform the user "Failed to process .jobs.json: <reason>. Please check the file and resend." and wait again
- → Inform the user "Python 3 is required to process .jobs.json, please install and try again." and stop
Common Follow-up
Regardless of Branch A/B/C, after all processing is completed:
Use the Bash tool to scan all
files under
<data_dir>/.work/jd-pool/
(exclude
), read the files where
in the frontmatter equals the current run_id (extension-import is also included), extract their
fields as the batch ID list; append the ID list to
's
, update
and
to
.
If the subcommand is
: Inform the user "✅ JD import completed, total <N> jobs. Run /job-hunt analyze to start analysis." and stop.
【Full Process】⚠️ No text output is allowed between the completion of this step and Step 7 (including echoing or repeating the output content of sub-skills). After updating state.json, the next action must be a Skill tool call (execute Step 4), no text can be inserted in between.
Step 4: Analysis (job-hunt-analyzer)
(Executed for full-process, analyze subcommands)
Determine the list of JDs to be analyzed:
- Scan all files under
<data_dir>/.work/jd-pool/
(exclude files ending with )
- Read the frontmatter of each file, filter files with , extract their fields
- Exclude IDs that have been recorded as failed in
state.json.stages.analysis_errors
If the list is empty, inform the user "No JDs to be analyzed in jd-pool, please upload screenshots first." and stop.
Call the Skill tool, load the
skill, pass in:
- : <absolute path>
- :
<data_dir>/.work/resume.md
- : <list of JD IDs to be analyzed>
- :
{"soft_preferences": {"prefer_industries": [], "avoid_industries": [], "prefer_company_size": []}, "ranking": {"match_weight": 1.0, "preference_weight": 0.0}}
- : <current run_id>
After the analyzer returns, use the Bash tool to update
's
to
.
【Full Process】⚠️ Do not echo or repeat the return content of the analyzer. Immediately execute Step 5 after updating state.json, no text output allowed.
Step 5: Sorting
(Executed before full-process or tailor subcommand, no LLM call)
⚠️ This step uses Bash / Read tools throughout, no text output allowed (including sorting process, intermediate results, ranking list).
Use Bash to read
<data_dir>/.work/jd-pool/*.analysis.md
, extract the
field from each file, sort in descending order to get the ordered list of JD IDs.
All analyzed JDs participate in sorting, no truncation.
Use Bash to write the sorting result into the
's
field, and keep it in memory for direct use in Step 6. When resuming from a breakpoint in Step 6, if there is no sorting result in memory, read from
state.json.stages.sorted_ids
.
【Full Process】⚠️ Immediately call the Skill tool to execute Step 6 after updating state.json, no text output allowed.
Step 6: Customize Resume (job-hunt-tailor)
(Executed for full-process or tailor subcommands)
Check if
<data_dir>/.work/resume.md
exists, if not, execute Step 2 to obtain the resume first before continuing.
Take the complete sorted JD ID list from Step 5.
Exclude those already in
's
(skip when resuming from breakpoint).
Call the Skill tool, load the
skill, pass in:
- : <absolute path>
- :
<data_dir>/.work/resume.md
- : <complete sorted JD ID list>
- : <current run_id>
After the tailor returns, use the Bash tool to update
's
to
.
【Full Process】⚠️ Do not echo or repeat the return content of the tailor. Immediately execute Step 7 after updating state.json, no text output allowed.
Step 7: Generate shortlist.html
(Last step of full-process, only generate HTML, no MD file)
Execution Order (Strictly Follow This Order):
- Use Bash tool: Detect Python, call to generate shortlist.html
- Use Bash tool: Update 's to
- Final Step: Output a short completion message in the chat (only contains HTML link + operation prompt, no longer output ranking MD overview, because the HTML view is for viewing these contents)
Execute command:
bash
# 1. Detect available Python command
if command -v python3 >/dev/null 2>&1; then
PYBIN=python3
elif command -v python >/dev/null 2>&1; then
# Fallback (common on Windows where only python exists, no python3)
PYBIN=python
else
PYBIN=""
fi
# 2. Call script, or output downgrade marker if no Python
if [ -n "$PYBIN" ]; then
"$PYBIN" "$HOME/.claude/skills/job-hunt/build_html.py" "<data_dir>" "<run_id>"
else
echo "PYTHON_MISSING"
fi
Bash Output Parsing Rules (determine the final completion message sent to the user):
| Script stdout Content | Status |
|---|
| (regardless of subsequent or ) | HTML generated successfully, prompt user to copy the link to open in browser |
| Template file missing (rarely occurs, prompt reinstallation) |
| Python 3 not installed on the system, guide user to install (process fails because only HTML is generated now) |
| (stderr) | Other errors, inform user to troubleshoot |
Script Design Principles:
- LLM does not construct JSON at all, the script scans jd-pool / tailored directory to read all fields by itself
- Elegant handling of empty files: if tailored file does not exist → the field is empty string
- Elegant downgrade when template is missing: if template.html does not exist → print and exit 0, main process does not interrupt
After updating
's
to
,
must output the final message in the chat —— select the corresponding copy based on the marker output by Bash.
Final Message Copy (4 Branches):
-
HTML Generated Successfully (Python script outputs
):
✅ All completed! <N> customized resumes generated in total.
🌐 HTML View: file://<absolute path of data_dir>/output/<run_id>/shortlist.html
💡 Copy the above file:// link to the browser address bar to open and view the complete resume view. The page supports:
· View all jobs sorted by matching degree
· Edit resumes directly on the webpage (automatically saved to browser local storage)
· Export to PDF with one click (consistent Chinese fonts across platforms)
· Switch to view resumes / changes / opening remarks for each job
Where
is filled with the length of
state.json.stages.tailored
array.
-
HTML Template Missing (Python script outputs
):
⚠️ Process completed, but HTML view not generated.
Reason: ~/.claude/skills/job-hunt/template.html not found.
Solution: Please reinstall the skill (run install.sh or npx skills add).
Customized resumes for each job have been written to: <absolute path of data_dir>/output/<run_id>/tailored/
-
Python Not Available (Bash outputs
):
⚠️ Process completed, but HTML view not generated.
Reason: Your system does not have Python 3.
📦 Install Python 3 to generate HTML view:
• Mac: Run `xcode-select --install` in terminal (one-time, takes a few minutes)
• Windows: Visit https://python.org/downloads/ to download and install
⚠️ Be sure to check "Add Python to PATH" during installation
• Linux: Usually pre-installed; if not, run `sudo apt install python3` or `sudo yum install python3`
After installation, run this command to generate HTML:
python3 ~/.claude/skills/job-hunt/build_html.py "<absolute path of data_dir>" "<run_id>"
Customized resumes for each job have been written to: <absolute path of data_dir>/output/<run_id>/tailored/
-
Other Errors (script outputs
in stderr):
⚠️ HTML generation failed. Error message: <stderr content>
Customized resumes for each job have been written to: <absolute path of data_dir>/output/<run_id>/tailored/
Please check the files or re-run.
⚠️ Key Constraints:
- Do not wrap the file:// link with backticks —— plain text links are easier for users to select all with three clicks and copy to the browser
- The completion message must be the last paragraph of the entire reply, not placed in the middle
- No longer generate shortlist.md, and no longer output MD content overview in the chat —— the HTML view is for the user to view, repeated output is redundant and takes up screen space
Step 7b (status subcommand): Output Running Status
Scan all subdirectories under
, find directories named in the format
, read the
of the latest one, and output according to the following format:
Job-Hunt Status Report
==================
Run ID: <run_id>
Current Phase: <phase>
Working Directory: <data_dir>
Progress Statistics:
Imported JDs: <number of stages.fetched> pieces
Completed Analysis: <number of stages.analyzed> pieces
Analysis Failures: <number of stages.analysis_errors> pieces
Generated Three-piece Set: <number of stages.tailored> pieces
Last Updated: <checkpoint_at>
If there are no run records, inform the user "Have not run /job-hunt yet, please run the full process first."
Step 8 (clean subcommand): Force Clean
Delete all files under
<data_dir>/.work/jd-pool/
(including .analysis.md).
Delete all run directories under
.
Delete
<data_dir>/.work/resume.md
(if exists).
Count and inform the user how many files/directories have been cleaned.