@getkrafter/resume-toolkit 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +4 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/krafter/client.d.ts +54 -0
- package/dist/krafter/client.d.ts.map +1 -0
- package/dist/krafter/client.js +130 -0
- package/dist/krafter/client.js.map +1 -0
- package/dist/krafter/errors.d.ts +26 -0
- package/dist/krafter/errors.d.ts.map +1 -0
- package/dist/krafter/errors.js +45 -0
- package/dist/krafter/errors.js.map +1 -0
- package/dist/lib/ats-scorer.d.ts +12 -0
- package/dist/lib/ats-scorer.d.ts.map +1 -0
- package/dist/lib/ats-scorer.js +83 -0
- package/dist/lib/ats-scorer.js.map +1 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +8 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/resume-scorer.d.ts +62 -0
- package/dist/lib/resume-scorer.d.ts.map +1 -0
- package/dist/lib/resume-scorer.js +236 -0
- package/dist/lib/resume-scorer.js.map +1 -0
- package/dist/lib/resume-transformer.d.ts +13 -0
- package/dist/lib/resume-transformer.d.ts.map +1 -0
- package/dist/lib/resume-transformer.js +113 -0
- package/dist/lib/resume-transformer.js.map +1 -0
- package/dist/lib/text-utils.d.ts +57 -0
- package/dist/lib/text-utils.d.ts.map +1 -0
- package/dist/lib/text-utils.js +282 -0
- package/dist/lib/text-utils.js.map +1 -0
- package/dist/lib/types.d.ts +31 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/mcp/server.d.ts +31 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +70 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/krafter.d.ts +14 -0
- package/dist/mcp/tools/krafter.d.ts.map +1 -0
- package/dist/mcp/tools/krafter.js +228 -0
- package/dist/mcp/tools/krafter.js.map +1 -0
- package/dist/mcp/tools/scoring.d.ts +46 -0
- package/dist/mcp/tools/scoring.d.ts.map +1 -0
- package/dist/mcp/tools/scoring.js +135 -0
- package/dist/mcp/tools/scoring.js.map +1 -0
- package/package.json +67 -0
- package/skills/score/SKILL.md +185 -0
- package/skills/tailor/SKILL.md +211 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: score
|
|
3
|
+
description: Score a resume for quality and ATS keyword match. Deterministic — same input always produces the same score.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Score a Resume
|
|
7
|
+
|
|
8
|
+
You are guiding the user through resume scoring using the `@getkrafter/resume-toolkit` scoring engine. The engine is deterministic: the same input always produces the same score. Your job is to collect the resume, optionally a job description, and then call the scoring tool and present the results clearly.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Step 1 — Collect the Resume
|
|
13
|
+
|
|
14
|
+
Ask the user for their resume. Accept any of these formats:
|
|
15
|
+
|
|
16
|
+
- **Paste text directly** — The user pastes their resume content into the chat.
|
|
17
|
+
- **File path** — The user provides a path to a PDF, DOCX, or plain text file.
|
|
18
|
+
- **Krafter integration** — If MCP is connected with Krafter tools available, offer: "I can fetch your resume from Krafter -- which one would you like to score?" Then call `list_resumes` to show their resumes and let them pick one. (You will use `score_krafter_resume` in Step 5 instead of `score_resume`.)
|
|
19
|
+
|
|
20
|
+
Prompt:
|
|
21
|
+
|
|
22
|
+
> How would you like to provide your resume?
|
|
23
|
+
> - Paste the text here
|
|
24
|
+
> - Give me a file path (PDF, DOCX, or .txt)
|
|
25
|
+
> - *(If Krafter is connected)* I can pull it from your Krafter account
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Step 2 — Ask for a Job Description (Optional)
|
|
30
|
+
|
|
31
|
+
After receiving the resume, ask:
|
|
32
|
+
|
|
33
|
+
> Would you like to paste a job description? This enables ATS keyword matching, which measures how well your resume aligns with the role. Otherwise, I will run a general quality score.
|
|
34
|
+
|
|
35
|
+
If the user provides a job description, store it as `jdText`. If they skip, proceed without it.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Step 3 — Extract Text from Files
|
|
40
|
+
|
|
41
|
+
If the user provided a file path (not pasted text, not Krafter):
|
|
42
|
+
|
|
43
|
+
1. Read the file using your file-reading capabilities.
|
|
44
|
+
2. Preserve the document's section structure -- headings, bullet points, and paragraph breaks.
|
|
45
|
+
3. Maintain the original reading order.
|
|
46
|
+
4. Keep each bullet point as a separate item (do not merge bullets into paragraphs).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Step 4 — Build ResumeData
|
|
51
|
+
|
|
52
|
+
Parse the extracted or pasted text into the scoring format:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
{
|
|
56
|
+
rawText: string; // All text concatenated
|
|
57
|
+
bullets: string[]; // Individual bullet points
|
|
58
|
+
sections: string[]; // Section heading names, lowercased
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Detection rules:
|
|
63
|
+
|
|
64
|
+
- **Bullets**: Lines starting with `-`, `*`, a bullet character, or a number followed by `.` or `)` (e.g., `1.`, `2)`). Strip the marker; keep only the text.
|
|
65
|
+
- **Sections**: Lines that are short (under 50 characters), non-bullet, and formatted as ALL CAPS (e.g., `EXPERIENCE`) or Title Case (e.g., `Work Experience`). Lowercase them when storing.
|
|
66
|
+
- **rawText**: The entire text concatenated as-is.
|
|
67
|
+
|
|
68
|
+
You do NOT need to do this manually. The `score_resume` MCP tool handles parsing internally. You provide `resumeText` as raw text and the tool does the rest. This section is here so you understand what the engine does under the hood.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Step 5 — Call the Scoring Tool
|
|
73
|
+
|
|
74
|
+
**Standard path** (pasted text or file):
|
|
75
|
+
|
|
76
|
+
Call the `score_resume` MCP tool:
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"resumeText": "<the full resume text>",
|
|
80
|
+
"jdText": "<job description text, or omit if not provided>"
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Krafter path** (user selected a Krafter resume):
|
|
85
|
+
|
|
86
|
+
Call the `score_krafter_resume` MCP tool:
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"id": "<the resume ID from list_resumes>",
|
|
90
|
+
"jdText": "<job description text, or omit if not provided>"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Step 6 — Present the Results
|
|
97
|
+
|
|
98
|
+
The tool returns a `ResumeScore` object:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
{
|
|
102
|
+
total: number; // 0-100, overall weighted score
|
|
103
|
+
mode: 'with-jd' | 'without-jd';
|
|
104
|
+
breakdown: {
|
|
105
|
+
quantification: { score, weight, weightedScore };
|
|
106
|
+
verbStrength: { score, weight, weightedScore };
|
|
107
|
+
ats: { score, weight, weightedScore };
|
|
108
|
+
bulletStructure: { score, weight, weightedScore };
|
|
109
|
+
sectionCompleteness: { score, weight, weightedScore };
|
|
110
|
+
};
|
|
111
|
+
ats: { // null when mode is without-jd
|
|
112
|
+
score: number;
|
|
113
|
+
matched: string[];
|
|
114
|
+
missing: string[];
|
|
115
|
+
details: { bigramsMatched, unigramsMatched, bigramsMissing, unigramsMissing };
|
|
116
|
+
} | null;
|
|
117
|
+
flags: string[]; // Diagnostic messages
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Follow this presentation order:
|
|
122
|
+
|
|
123
|
+
### 6a. Overall Score
|
|
124
|
+
|
|
125
|
+
Display the total score prominently with the correct mode label:
|
|
126
|
+
|
|
127
|
+
- **without-jd**: "General Quality Score: **{total}/100**"
|
|
128
|
+
- **with-jd**: "Score against {job title or 'this role'}: **{total}/100**"
|
|
129
|
+
|
|
130
|
+
If the mode is `without-jd`, add this note:
|
|
131
|
+
|
|
132
|
+
> Tip: Provide a job description to also measure keyword match, which changes the scoring weights and gives a more targeted assessment.
|
|
133
|
+
|
|
134
|
+
### 6b. Breakdown Table
|
|
135
|
+
|
|
136
|
+
Present each dimension in a table:
|
|
137
|
+
|
|
138
|
+
| Dimension | Score | Weight | Interpretation |
|
|
139
|
+
|-----------|-------|--------|----------------|
|
|
140
|
+
|
|
141
|
+
Use these human-readable dimension names:
|
|
142
|
+
|
|
143
|
+
- `quantification` -> "Measurable Results"
|
|
144
|
+
- `verbStrength` -> "Action Verbs"
|
|
145
|
+
- `ats` -> "ATS Keyword Match" (only shown when mode is `with-jd`)
|
|
146
|
+
- `bulletStructure` -> "Bullet Quality"
|
|
147
|
+
- `sectionCompleteness` -> "Section Coverage"
|
|
148
|
+
|
|
149
|
+
For the Interpretation column, give a brief plain-English reading of what the score means for that specific resume. Do not just restate the number. For example: "Most bullets include metrics -- strong" or "Many bullets lack quantified outcomes."
|
|
150
|
+
|
|
151
|
+
### 6c. Weakest Dimensions -- Actionable Advice
|
|
152
|
+
|
|
153
|
+
Identify the 2-3 dimensions with the lowest scores. For each:
|
|
154
|
+
|
|
155
|
+
1. Explain what the dimension measures in one sentence.
|
|
156
|
+
2. Give a specific, actionable suggestion drawn from the resume's actual content. Reference real bullets or sections from the resume where possible.
|
|
157
|
+
3. Provide a concrete before/after example if the content allows it.
|
|
158
|
+
|
|
159
|
+
### 6d. ATS Keyword Analysis (with-jd mode only)
|
|
160
|
+
|
|
161
|
+
If ATS results are present:
|
|
162
|
+
|
|
163
|
+
- State the ATS match percentage.
|
|
164
|
+
- List the **top 5 missing keywords** from `ats.missing` (or fewer if there are fewer than 5).
|
|
165
|
+
- Briefly suggest where in the resume each missing keyword could naturally be incorporated.
|
|
166
|
+
|
|
167
|
+
### 6e. Flags
|
|
168
|
+
|
|
169
|
+
Present any items from the `flags` array as conversational advice. These are not errors -- they are observations. Frame them helpfully:
|
|
170
|
+
|
|
171
|
+
- "No job description provided" -> Already handled by the tip in 6a; skip this flag.
|
|
172
|
+
- Other flags -> Weave them into your narrative naturally. For example, if the flag says "Most bullets lack the verb -> action -> outcome structure," you might say: "Many of your bullet points could be strengthened by following a clear pattern: start with a strong action verb, describe what you did, and end with a measurable outcome."
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Tone Guidance
|
|
177
|
+
|
|
178
|
+
Follow these rules for all commentary:
|
|
179
|
+
|
|
180
|
+
- **Be constructive, not judgmental.** Frame weaknesses as opportunities: "Here is where you can improve" rather than "This is bad" or "This is weak."
|
|
181
|
+
- **Lead with strengths.** Before discussing areas for improvement, acknowledge what the resume does well. Even a low-scoring resume has something worth highlighting.
|
|
182
|
+
- **Give specific, actionable suggestions.** Do not say "Add more metrics." Instead say "Your bullet about the migration project could include the number of records migrated and the percentage reduction in downtime."
|
|
183
|
+
- **Use encouraging language.** Prefer "you can" and "consider" over "you should" and "you need to."
|
|
184
|
+
- **Never be dismissive.** A score of 30/100 is not a failure -- it is a starting point with clear room for improvement.
|
|
185
|
+
- **Keep it concise.** Aim for a focused, scannable response. Use the table for the breakdown and prose for the narrative. Do not repeat information from the table in the narrative.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tailor
|
|
3
|
+
description: Analyze resume gaps against a job description and suggest targeted rewrites. Truth-preserving — never fabricates experience.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /tailor -- JD-Targeted Resume Optimization
|
|
7
|
+
|
|
8
|
+
Analyze a resume against a specific job description, identify keyword gaps, and suggest truth-preserving rewrites that improve ATS match rate.
|
|
9
|
+
|
|
10
|
+
## CRITICAL: Truth-Preserving Mandate
|
|
11
|
+
|
|
12
|
+
NEVER suggest adding experience, skills, or achievements the user doesn't have.
|
|
13
|
+
Every rewrite suggestion MUST include a confidence note reminding the user to only
|
|
14
|
+
apply changes that reflect their actual experience. "Only add X if you actually
|
|
15
|
+
did/used X" is required on every suggestion that introduces a new keyword.
|
|
16
|
+
|
|
17
|
+
If a keyword gap cannot be addressed with existing experience, flag it as
|
|
18
|
+
unresolvable -- do NOT fabricate or stretch the truth.
|
|
19
|
+
|
|
20
|
+
## Workflow
|
|
21
|
+
|
|
22
|
+
Follow these steps in order. Use the "flag and continue" model throughout: deliver
|
|
23
|
+
the FULL report without pausing to interview the user mid-analysis.
|
|
24
|
+
|
|
25
|
+
### Step 1 -- Collect the Resume
|
|
26
|
+
|
|
27
|
+
Ask the user for their resume. Accept any of these formats:
|
|
28
|
+
|
|
29
|
+
- **Paste**: "Paste your resume text below."
|
|
30
|
+
- **File path**: Read the file from disk (`.txt`, `.md`, or similar text formats).
|
|
31
|
+
- **Krafter resume ID**: If the user provides a Krafter resume ID (UUID format), use the `get_resume` tool to fetch it. The ID may come from a URL like `https://app.getkrafter.com/resume/<id>`.
|
|
32
|
+
|
|
33
|
+
Store the raw resume text for tool input. If fetched from Krafter, also store the
|
|
34
|
+
resume ID for later use with `score_krafter_resume`.
|
|
35
|
+
|
|
36
|
+
### Step 2 -- Collect the Job Description (REQUIRED)
|
|
37
|
+
|
|
38
|
+
Prompt: "Paste the job description you're targeting. This is required for tailoring."
|
|
39
|
+
|
|
40
|
+
The job description is **mandatory** for the `/tailor` skill. If the user tries to
|
|
41
|
+
proceed without one, remind them that tailoring requires a JD to compare against.
|
|
42
|
+
|
|
43
|
+
Store the raw JD text as `jdText`.
|
|
44
|
+
|
|
45
|
+
### Step 3 -- Parse the Resume
|
|
46
|
+
|
|
47
|
+
Build the internal `ResumeData` structure from the raw resume text:
|
|
48
|
+
|
|
49
|
+
- Split into lines.
|
|
50
|
+
- Lines starting with bullet markers (`-`, `*`, numbered lists) are extracted as **bullets** (strip the marker).
|
|
51
|
+
- Short ALL-CAPS or Title-Case lines (under 50 characters) are extracted as **section headings**.
|
|
52
|
+
- Everything feeds into `rawText`.
|
|
53
|
+
|
|
54
|
+
If the resume came from Krafter (Step 1), skip manual parsing -- the tools handle
|
|
55
|
+
transformation internally via `toResumeData`.
|
|
56
|
+
|
|
57
|
+
### Step 4 -- Run Scoring Tools
|
|
58
|
+
|
|
59
|
+
Run **both** scoring tools to get the full picture:
|
|
60
|
+
|
|
61
|
+
**For pasted/file resumes:**
|
|
62
|
+
|
|
63
|
+
1. `score_ats` with `{ resumeText, jdText }` -- returns `ATSResult` with:
|
|
64
|
+
- `score` (0-100)
|
|
65
|
+
- `matched` keywords (array)
|
|
66
|
+
- `missing` keywords (array)
|
|
67
|
+
- `details.bigramsMatched`, `details.unigramsMatched`, `details.bigramsMissing`, `details.unigramsMissing`
|
|
68
|
+
|
|
69
|
+
2. `score_resume` with `{ resumeText, jdText }` -- returns `ResumeScore` with:
|
|
70
|
+
- `total` (0-100)
|
|
71
|
+
- `mode` ("with-jd")
|
|
72
|
+
- `breakdown` per dimension (quantification, verbStrength, ats, bulletStructure, sectionCompleteness)
|
|
73
|
+
- `ats` (embedded ATSResult)
|
|
74
|
+
- `flags` (diagnostic messages)
|
|
75
|
+
|
|
76
|
+
**For Krafter resumes:**
|
|
77
|
+
|
|
78
|
+
1. `score_krafter_resume` with `{ id, jdText }` -- returns the full `ResumeScore` including the embedded `ATSResult`.
|
|
79
|
+
2. Optionally also call `score_ats` directly if you need the standalone ATS breakdown.
|
|
80
|
+
|
|
81
|
+
### Step 5 -- Gap Analysis
|
|
82
|
+
|
|
83
|
+
For **each missing keyword/term** from the ATS result:
|
|
84
|
+
|
|
85
|
+
1. **Search the resume** for related experience that could be reframed. Look for:
|
|
86
|
+
- Synonyms or adjacent concepts (e.g., "container orchestration" relates to "Kubernetes")
|
|
87
|
+
- Implicit skills (e.g., "built CI/CD pipelines" implies familiarity with automation tools)
|
|
88
|
+
- Bullets that describe the activity without naming the specific technology
|
|
89
|
+
|
|
90
|
+
2. **If related experience exists**: mark as a **resolvable gap** -- the user's resume
|
|
91
|
+
already contains evidence that could be reworded to surface the missing keyword.
|
|
92
|
+
|
|
93
|
+
3. **If no related experience exists**: mark as an **unresolvable gap** -- the keyword
|
|
94
|
+
requires experience the resume does not reflect.
|
|
95
|
+
|
|
96
|
+
### Step 6 -- Generate Rewrite Suggestions
|
|
97
|
+
|
|
98
|
+
For each **resolvable gap**, produce a Before/After rewrite suggestion:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
### [Missing Keyword]
|
|
102
|
+
|
|
103
|
+
**Before:** Led team of 8 engineers to deliver platform
|
|
104
|
+
**After:** Led team of 8 engineers to deliver microservices platform using Kubernetes
|
|
105
|
+
**Confidence:** Only add "Kubernetes" if you actually used it in this role
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Rules for rewrites:
|
|
109
|
+
- Show the **exact original bullet** as "Before".
|
|
110
|
+
- Show a **minimal edit** as "After" -- change as few words as possible to incorporate the keyword naturally.
|
|
111
|
+
- Include a **Confidence** note on every single rewrite that introduces a new keyword. The note MUST say "Only add [keyword] if you actually [did/used/worked with] [keyword]".
|
|
112
|
+
- Prefer surfacing keywords that are already implicit rather than adding entirely new claims.
|
|
113
|
+
- If a single bullet could address multiple missing keywords, show one rewrite per keyword -- do not overload a single suggestion.
|
|
114
|
+
|
|
115
|
+
### Step 7 -- Flag Unresolvable Gaps
|
|
116
|
+
|
|
117
|
+
For each **unresolvable gap**, produce a gap notice:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
### [Missing Keyword]
|
|
121
|
+
|
|
122
|
+
**Gap:** [Keyword] -- This JD requires [keyword] experience. Consider adding this
|
|
123
|
+
if you have relevant experience, even from side projects, coursework, or
|
|
124
|
+
certifications.
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Frame these as opportunities, not failures. Suggest concrete places the user
|
|
128
|
+
could gain or demonstrate the skill (side projects, certifications, open source
|
|
129
|
+
contributions).
|
|
130
|
+
|
|
131
|
+
### Step 8 -- Present the Full Report
|
|
132
|
+
|
|
133
|
+
Compile everything into a single, structured report. Do NOT pause to ask
|
|
134
|
+
questions -- deliver the complete analysis in one response.
|
|
135
|
+
|
|
136
|
+
#### Report Structure
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
## Tailoring Report: [Job Title from JD]
|
|
140
|
+
|
|
141
|
+
### Current Scores
|
|
142
|
+
- **Overall Quality:** X/100 (mode: with-jd)
|
|
143
|
+
- **ATS Keyword Match:** Y/100
|
|
144
|
+
- **Breakdown:**
|
|
145
|
+
- Quantification: X/100 (weight: 25%)
|
|
146
|
+
- Verb Strength: X/100 (weight: 20%)
|
|
147
|
+
- ATS Match: X/100 (weight: 30%)
|
|
148
|
+
- Bullet Structure: X/100 (weight: 15%)
|
|
149
|
+
- Section Completeness: X/100 (weight: 10%)
|
|
150
|
+
|
|
151
|
+
### Matched Keywords (What's Working)
|
|
152
|
+
List all matched keywords from the ATS result. Group by bigrams and unigrams
|
|
153
|
+
if the list is long. This shows the user what they're already doing well.
|
|
154
|
+
|
|
155
|
+
### Diagnostic Flags
|
|
156
|
+
List any flags from the scorer (e.g., "Fewer than 40% of bullets contain
|
|
157
|
+
measurable results", "No summary/profile section found").
|
|
158
|
+
|
|
159
|
+
### Suggested Rewrites (Resolvable Gaps)
|
|
160
|
+
[One subsection per resolvable gap, using the Before/After/Confidence format
|
|
161
|
+
from Step 6]
|
|
162
|
+
|
|
163
|
+
### Unresolvable Gaps
|
|
164
|
+
[One subsection per unresolvable gap, using the Gap format from Step 7]
|
|
165
|
+
|
|
166
|
+
### Projected Impact
|
|
167
|
+
Implementing these changes could improve your ATS match from X% to ~Y%.
|
|
168
|
+
|
|
169
|
+
Calculate the projected Y% by assuming all resolvable gap keywords would become
|
|
170
|
+
matched. The formula:
|
|
171
|
+
- Current matched = number of matched terms
|
|
172
|
+
- Projected matched = current matched + number of resolvable gaps
|
|
173
|
+
- Total JD terms = matched + missing
|
|
174
|
+
- Projected score = round((projected matched points / total points) * 100)
|
|
175
|
+
|
|
176
|
+
Use bigram weight (1.5) and unigram weight (1.0) for accurate projection.
|
|
177
|
+
|
|
178
|
+
### Action Items
|
|
179
|
+
Numbered list of concrete next steps:
|
|
180
|
+
1. Apply the suggested rewrites (after verifying accuracy)
|
|
181
|
+
2. Address any structural issues flagged by the scorer
|
|
182
|
+
3. Consider ways to fill unresolvable gaps (courses, projects, certifications)
|
|
183
|
+
4. Re-run /score after making changes to verify improvement
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Tone and Formatting
|
|
187
|
+
|
|
188
|
+
- Be constructive and actionable -- frame everything as improvement opportunity
|
|
189
|
+
- Use the Before/After format consistently for every suggestion
|
|
190
|
+
- Always include the Confidence note -- no exceptions
|
|
191
|
+
- Use bullet points and clear hierarchy for scanability
|
|
192
|
+
- Keep language professional but encouraging
|
|
193
|
+
- Frame gaps as opportunities, not failures or shortcomings
|
|
194
|
+
- Be specific: name the exact bullet, the exact keyword, and the exact change
|
|
195
|
+
|
|
196
|
+
## Edge Cases
|
|
197
|
+
|
|
198
|
+
- **Very short resume (< 50 words):** Flag that the resume is too short for meaningful tailoring. Suggest building out content first, then re-running `/tailor`.
|
|
199
|
+
- **JD is too short or vague:** Flag that the JD lacks specific keywords. Provide what analysis you can, but note the limited data.
|
|
200
|
+
- **Perfect ATS match (100%):** Congratulate the user. Focus the report on the other quality dimensions (quantification, verb strength, bullet structure) instead.
|
|
201
|
+
- **Zero matched keywords:** This usually means a major career pivot or wrong resume. Flag it clearly and suggest whether tailoring is the right approach vs. a full rewrite.
|
|
202
|
+
- **Krafter resume fetch fails:** Fall back to asking the user to paste the resume text directly.
|
|
203
|
+
|
|
204
|
+
## Tool Reference
|
|
205
|
+
|
|
206
|
+
| Tool | Input | Output |
|
|
207
|
+
|------|-------|--------|
|
|
208
|
+
| `score_ats` | `{ resumeText: string, jdText: string }` | `ATSResult { score, matched[], missing[], details }` |
|
|
209
|
+
| `score_resume` | `{ resumeText: string, jdText?: string }` | `ResumeScore { total, mode, breakdown, ats, flags[] }` |
|
|
210
|
+
| `score_krafter_resume` | `{ id: string, jdText?: string }` | `ResumeScore { total, mode, breakdown, ats, flags[] }` |
|
|
211
|
+
| `get_resume` | `{ id: string }` | Krafter resume object (JSON) |
|