resume-parser-ats 1.1.1 → 1.2.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/CONTRIBUTING.md +272 -0
- package/README.md +360 -163
- package/bin/cli.js +27 -0
- package/package.json +7 -3
- package/resume-parser-ats/SKILL.md +218 -0
- package/resume-parser-ats/references/algorithm.md +126 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Contributing to Resume Parser
|
|
2
|
+
|
|
3
|
+
First off, thank you for considering contributing! 🎉
|
|
4
|
+
|
|
5
|
+
This project is a resume parsing agent skill, npm CLI tool, and MCP server. Contributions of all kinds are welcome: bug fixes, features, documentation improvements, test cases, and more.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Code of Conduct](#code-of-conduct)
|
|
10
|
+
- [Getting Started](#getting-started)
|
|
11
|
+
- [Development Setup](#development-setup)
|
|
12
|
+
- [Project Structure](#project-structure)
|
|
13
|
+
- [Making Changes](#making-changes)
|
|
14
|
+
- [Running Tests](#running-tests)
|
|
15
|
+
- [Code Style](#code-style)
|
|
16
|
+
- [Commit Messages](#commit-messages)
|
|
17
|
+
- [Pull Requests](#pull-requests)
|
|
18
|
+
- [Reporting Bugs](#reporting-bugs)
|
|
19
|
+
- [Feature Requests](#feature-requests)
|
|
20
|
+
|
|
21
|
+
## Code of Conduct
|
|
22
|
+
|
|
23
|
+
Be respectful, constructive, and inclusive. We're all here to make resume parsing better for everyone.
|
|
24
|
+
|
|
25
|
+
## Getting Started
|
|
26
|
+
|
|
27
|
+
1. **Fork** the repository on GitHub
|
|
28
|
+
2. **Clone** your fork locally:
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/YOUR_USERNAME/resume-parser-skill.git
|
|
31
|
+
cd resume-parser-skill
|
|
32
|
+
```
|
|
33
|
+
3. **Install** dependencies:
|
|
34
|
+
```bash
|
|
35
|
+
npm install
|
|
36
|
+
```
|
|
37
|
+
4. **Build** the project:
|
|
38
|
+
```bash
|
|
39
|
+
npm run build
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Development Setup
|
|
43
|
+
|
|
44
|
+
### Prerequisites
|
|
45
|
+
|
|
46
|
+
- **Node.js** >= 18 (tested on 18, 20, 22)
|
|
47
|
+
- **npm** >= 9
|
|
48
|
+
|
|
49
|
+
### Key Commands
|
|
50
|
+
|
|
51
|
+
| Command | Description |
|
|
52
|
+
|---------|-------------|
|
|
53
|
+
| `npm install` | Install dependencies |
|
|
54
|
+
| `npm run build` | Compile TypeScript to `dist/` |
|
|
55
|
+
| `npm test` | Run all evaluation tests |
|
|
56
|
+
| `npm run lint` | Lint source files |
|
|
57
|
+
| `npm run dev` | Run index.ts directly with ts-node |
|
|
58
|
+
| `npm run mcp` | Start the MCP server locally |
|
|
59
|
+
|
|
60
|
+
### Verify Everything Works
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Build and test
|
|
64
|
+
npm run build && npm test
|
|
65
|
+
|
|
66
|
+
# Verify CLI
|
|
67
|
+
node bin/cli.js --help
|
|
68
|
+
|
|
69
|
+
# Quick parse test
|
|
70
|
+
node bin/cli.js parse "John Doe
|
|
71
|
+
john@example.com
|
|
72
|
+
(555) 123-4567
|
|
73
|
+
Software Engineer"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Project Structure
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
resume-parser-skill/
|
|
80
|
+
├── resume-parser-ats/ # Agent skill directory (npx skills add)
|
|
81
|
+
│ ├── SKILL.md # Skill manifest & agent instructions
|
|
82
|
+
│ └── references/
|
|
83
|
+
│ └── algorithm.md # Full 4-step algorithm spec
|
|
84
|
+
├── src/ # TypeScript source code
|
|
85
|
+
│ ├── index.ts # Main entry, exports, fullPipeline()
|
|
86
|
+
│ ├── tools/
|
|
87
|
+
│ │ ├── parse-resume.ts # Step 1-4 parsing engine
|
|
88
|
+
│ │ ├── analyze-resume.ts # ATS scoring & analysis
|
|
89
|
+
│ │ └── suggest-improvements.ts # Suggestion generator
|
|
90
|
+
│ └── prompts/
|
|
91
|
+
│ ├── parser-prompt.ts # Parsing prompt templates
|
|
92
|
+
│ └── insights-prompt.ts # Insights prompt templates
|
|
93
|
+
├── bin/
|
|
94
|
+
│ └── cli.js # CLI entry point (npx resume-parser-ats)
|
|
95
|
+
├── mcp-server/
|
|
96
|
+
│ └── server.ts # MCP server implementation
|
|
97
|
+
├── test/evals/ # Test suites
|
|
98
|
+
│ ├── parse-resume.test.mjs
|
|
99
|
+
│ ├── analyze-resume.test.mjs
|
|
100
|
+
│ └── suggest-improvements.test.mjs
|
|
101
|
+
├── AGENTS.md # Agent configuration (skills spec)
|
|
102
|
+
├── package.json
|
|
103
|
+
├── tsconfig.json
|
|
104
|
+
└── README.md
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Making Changes
|
|
108
|
+
|
|
109
|
+
### Branch Naming
|
|
110
|
+
|
|
111
|
+
Use descriptive branch names:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
feature/add-bullet-point-parsing
|
|
115
|
+
fix/education-date-extraction
|
|
116
|
+
docs/mcp-setup-guide
|
|
117
|
+
test/strict-mode-edge-cases
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Code Changes
|
|
121
|
+
|
|
122
|
+
1. **Create a branch** from `master`:
|
|
123
|
+
```bash
|
|
124
|
+
git checkout -b feature/your-feature
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
2. **Make your changes** — follow the existing code patterns
|
|
128
|
+
|
|
129
|
+
3. **Update tests** — add or modify tests in `test/evals/`
|
|
130
|
+
|
|
131
|
+
4. **Update documentation** — if you add a feature, update:
|
|
132
|
+
- `SKILL.md` if it affects agent-facing instructions
|
|
133
|
+
- `README.md` if it affects user-facing docs
|
|
134
|
+
- `references/algorithm.md` if it changes the parsing algorithm
|
|
135
|
+
|
|
136
|
+
5. **Verify** — build and test:
|
|
137
|
+
```bash
|
|
138
|
+
npm run build && npm test
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Important Files to Update
|
|
142
|
+
|
|
143
|
+
| If you change... | Also update |
|
|
144
|
+
|---|---|
|
|
145
|
+
| Parsing logic in `src/tools/parse-resume.ts` | `resume-parser-ats/references/algorithm.md` |
|
|
146
|
+
| Output format of any tool | `resume-parser-ats/SKILL.md` and `README.md` |
|
|
147
|
+
| CLI commands or flags | `bin/cli.js` help text and `README.md` |
|
|
148
|
+
| MCP tool definitions | `mcp-server/server.ts` and `README.md` |
|
|
149
|
+
| Scoring or grading | `resume-parser-ats/SKILL.md` scoring tables |
|
|
150
|
+
|
|
151
|
+
## Running Tests
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Run all 86 tests
|
|
155
|
+
npm test
|
|
156
|
+
|
|
157
|
+
# Run specific test suite
|
|
158
|
+
node --test test/evals/parse-resume.test.mjs
|
|
159
|
+
node --test test/evals/analyze-resume.test.mjs
|
|
160
|
+
node --test test/evals/suggest-improvements.test.mjs
|
|
161
|
+
|
|
162
|
+
# Run a single test with verbose output
|
|
163
|
+
node --test test/evals/parse-resume.test.mjs --test-name-pattern "Step 1"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Tests use Node.js built-in test runner (`node:test`) and assert module (`node:assert/strict`). No additional test framework needed.
|
|
167
|
+
|
|
168
|
+
### Writing New Tests
|
|
169
|
+
|
|
170
|
+
Add test cases in the appropriate file under `test/evals/`:
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
import { describe, it } from "node:test";
|
|
174
|
+
import assert from "node:assert/strict";
|
|
175
|
+
import { parseResume } from "../../dist/src/tools/parse-resume.js";
|
|
176
|
+
|
|
177
|
+
describe("My New Feature", () => {
|
|
178
|
+
it("should handle the new case correctly", () => {
|
|
179
|
+
const result = parseResume({ rawText: "..." });
|
|
180
|
+
assert.equal(result.success, true);
|
|
181
|
+
assert.equal(result.data.profile.name, "Expected Name");
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Code Style
|
|
187
|
+
|
|
188
|
+
- **TypeScript** for all source code (`src/` and `mcp-server/`)
|
|
189
|
+
- **ES modules** with CommonJS compilation output
|
|
190
|
+
- **2-space indentation**
|
|
191
|
+
- Run `npm run lint` before committing — ESLint with TypeScript plugin
|
|
192
|
+
|
|
193
|
+
Key conventions:
|
|
194
|
+
- Use Zod for input validation schemas
|
|
195
|
+
- Always return `{ success: boolean, data: T, metadata: {...} }` format
|
|
196
|
+
- Include `warnings` array in metadata for non-fatal issues
|
|
197
|
+
- Feature scoring uses additive positive and negative scores
|
|
198
|
+
|
|
199
|
+
## Commit Messages
|
|
200
|
+
|
|
201
|
+
Follow [Conventional Commits](https://www.conventionalcommits.org/):
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
feat: add bullet-point parsing for experience sections
|
|
205
|
+
fix: handle edge case in date extraction for seasonal dates
|
|
206
|
+
docs: add MCP setup guide for Claude Desktop
|
|
207
|
+
test: add strict mode edge cases for phone parsing
|
|
208
|
+
refactor: simplify section grouping logic
|
|
209
|
+
chore: update dependencies
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Prefixes: `feat:`, `fix:`, `docs:`, `test:`, `refactor:`, `perf:`, `chore:`, `ci:`
|
|
213
|
+
|
|
214
|
+
## Pull Requests
|
|
215
|
+
|
|
216
|
+
1. **Push** your branch to your fork:
|
|
217
|
+
```bash
|
|
218
|
+
git push origin feature/your-feature
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
2. **Open a Pull Request** against the `master` branch
|
|
222
|
+
|
|
223
|
+
3. **Describe your changes** — what, why, and how to test
|
|
224
|
+
|
|
225
|
+
4. **Ensure CI passes** — all tests must pass across Node 18, 20, 22
|
|
226
|
+
|
|
227
|
+
5. **Respond to review feedback** promptly
|
|
228
|
+
|
|
229
|
+
### PR Checklist
|
|
230
|
+
|
|
231
|
+
- [ ] Code compiles (`npm run build` succeeds)
|
|
232
|
+
- [ ] All tests pass (`npm test`)
|
|
233
|
+
- [ ] Lint passes (`npm run lint`)
|
|
234
|
+
- [ ] New features have tests
|
|
235
|
+
- [ ] Documentation updated (SKILL.md, README.md, algorithm.md as needed)
|
|
236
|
+
- [ ] Commit messages follow conventional commits format
|
|
237
|
+
|
|
238
|
+
## Reporting Bugs
|
|
239
|
+
|
|
240
|
+
Open a [GitHub Issue](https://github.com/dhanushk-offl/resume-parser-skill/issues/new) with:
|
|
241
|
+
|
|
242
|
+
1. **What you did** — exact command or input
|
|
243
|
+
2. **What happened** — actual output or error
|
|
244
|
+
3. **What you expected** — desired output
|
|
245
|
+
4. **Environment** — Node.js version, OS, how you're using it (CLI, library, MCP, skill)
|
|
246
|
+
|
|
247
|
+
## Feature Requests
|
|
248
|
+
|
|
249
|
+
Open a [GitHub Issue](https://github.com/dhanushk-offl/resume-parser-skill/issues/new) with:
|
|
250
|
+
|
|
251
|
+
1. **Use case** — what problem does this solve?
|
|
252
|
+
2. **Proposed solution** — how should it work?
|
|
253
|
+
3. **Alternatives considered** — other approaches you thought of
|
|
254
|
+
4. **Which interface** — does this affect the skill, CLI, library, or MCP?
|
|
255
|
+
|
|
256
|
+
## Release Process
|
|
257
|
+
|
|
258
|
+
Maintainers only:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Bump version
|
|
262
|
+
npm version patch # or minor, major
|
|
263
|
+
|
|
264
|
+
# Push with tags
|
|
265
|
+
git push --follow-tags
|
|
266
|
+
|
|
267
|
+
# CI automatically publishes to npm and creates a GitHub release
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
Thank you for contributing! 💛
|
package/README.md
CHANGED
|
@@ -1,279 +1,459 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# 📄 Resume Parser
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
<strong>Deep resume parsing • ATS compatibility scoring • Actionable improvement insights</strong>
|
|
5
|
-
</p>
|
|
5
|
+
**Deep resume parsing • ATS compatibility scoring • Actionable improvement insights**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Made with ❤️ by <strong>Dhanush Kandhan</strong>
|
|
9
|
-
</p>
|
|
7
|
+
An agent skill, CLI tool, npm library, and MCP server that deeply parses resumes using the **OpenResume 4-step algorithm**, extracts structured information (Name, Email, Phone, Education, Work Experience, Skills, Projects), evaluates ATS compatibility, and provides prioritized, actionable suggestions.
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
Made with ❤️ by **Dhanush Kandhan**
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/resume-parser-ats)
|
|
12
|
+
[](https://github.com/dhanushk-offl/resume-parser-skill/actions/workflows/ci.yml)
|
|
13
|
+
[](./LICENSE)
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
14
18
|
|
|
15
19
|
## ✨ Features
|
|
16
20
|
|
|
17
21
|
- **🔍 Deep Parsing** — Extracts 10+ fields from raw text or PDF using a feature-scoring engine
|
|
18
|
-
- **📊 ATS Scoring** — Grades your resume A+ through F with
|
|
22
|
+
- **📊 ATS Scoring** — Grades your resume A+ through F with per-field confidence ratings
|
|
19
23
|
- **💡 Smart Suggestions** — Prioritized, categorized fixes (critical → low) with before/after examples
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
24
|
+
- **🤖 Agent Skill** — Install via `npx skills add` for pi, Claude Code, Codex, Gemini CLI, and more
|
|
25
|
+
- **🖥️ CLI** — Use directly from the command line
|
|
26
|
+
- **📡 MCP Server** — Plug into Claude Desktop, ChatGPT, and other MCP-compatible apps
|
|
27
|
+
- **📖 Library** — Import as an npm package for programmatic use
|
|
28
|
+
- **⚙️ Configurable** — Lenient, moderate, or strict ATS evaluation modes
|
|
29
|
+
- **🔒 Privacy-first** — Runs entirely locally, no external API calls
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 🚀 Quick Start
|
|
34
|
+
|
|
35
|
+
Choose how you want to use Resume Parser:
|
|
23
36
|
|
|
24
|
-
|
|
37
|
+
| Method | Install | Best for |
|
|
38
|
+
|--------|---------|----------|
|
|
39
|
+
| **Agent Skill** | `npx skills add dhanushk-offl/resume-parser-skill` | AI agents (pi, Claude Code, Codex, Gemini CLI) |
|
|
40
|
+
| **CLI** | `npm install -g resume-parser-ats` | Quick one-off resume analysis |
|
|
41
|
+
| **Library** | `npm install resume-parser-ats` | Building apps, batch processing |
|
|
42
|
+
| **MCP Server** | `npm install resume-parser-ats` | Claude Desktop, ChatGPT, Cursor |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 🤖 1. Agent Skill
|
|
47
|
+
|
|
48
|
+
Install as an agent skill for automatic activation in AI coding assistants:
|
|
25
49
|
|
|
26
50
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
npx skills add dhanushk-offl/resume-parser-skill
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Once installed, the skill activates automatically when you:
|
|
55
|
+
|
|
56
|
+
- Ask to parse, review, or analyze a resume
|
|
57
|
+
- Ask "is my resume ATS-friendly?"
|
|
58
|
+
- Ask for resume improvement suggestions
|
|
59
|
+
- Upload or reference a resume PDF
|
|
60
|
+
|
|
61
|
+
**Works with:** pi, Claude Code, OpenAI Codex, Gemini CLI, Cursor, Continue, and all [Agent Skills](https://agentskills.io) compatible tools.
|
|
30
62
|
|
|
31
|
-
|
|
32
|
-
npm install
|
|
63
|
+
### What the Agent Gets
|
|
33
64
|
|
|
34
|
-
|
|
35
|
-
|
|
65
|
+
| Tool | Description |
|
|
66
|
+
|------|-------------|
|
|
67
|
+
| `parse_resume` | Parse a resume PDF/text → structured data |
|
|
68
|
+
| `analyze_resume` | Parse + compute ATS compatibility score with per-field confidence |
|
|
69
|
+
| `suggest_improvements` | Parse + analyze + generate prioritized improvement suggestions |
|
|
70
|
+
|
|
71
|
+
### Example Agent Prompts
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
"Is my resume ATS-friendly? Here's the PDF path: ./my-resume.pdf"
|
|
75
|
+
"Parse this resume and extract the contact info"
|
|
76
|
+
"Analyze my resume for ATS compatibility with strict grading"
|
|
77
|
+
"What can I improve on my resume to get past ATS filters?"
|
|
36
78
|
```
|
|
37
79
|
|
|
38
|
-
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🖥️ 2. CLI
|
|
39
83
|
|
|
40
|
-
|
|
84
|
+
Install globally for command-line use:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm install -g resume-parser-ats
|
|
88
|
+
```
|
|
41
89
|
|
|
42
90
|
```bash
|
|
43
91
|
# Parse a resume and output structured data
|
|
44
|
-
|
|
92
|
+
resume-parser-ats parse resume.pdf
|
|
45
93
|
|
|
46
94
|
# Parse + analyze ATS compatibility
|
|
47
|
-
|
|
95
|
+
resume-parser-ats analyze resume.pdf
|
|
48
96
|
|
|
49
|
-
# Full pipeline: parse + analyze +
|
|
50
|
-
|
|
97
|
+
# Full pipeline: parse + analyze + suggestions
|
|
98
|
+
resume-parser-ats insights resume.pdf
|
|
51
99
|
|
|
52
100
|
# Parse from raw text
|
|
53
|
-
|
|
101
|
+
resume-parser-ats parse "John Doe\njohn@email.com\nSoftware Engineer"
|
|
54
102
|
|
|
55
103
|
# Adjust ATS strictness
|
|
56
|
-
|
|
104
|
+
resume-parser-ats analyze resume.pdf --strictness strict
|
|
57
105
|
|
|
58
106
|
# Focus on specific areas
|
|
59
|
-
|
|
107
|
+
resume-parser-ats insights resume.pdf --focus ats,formatting
|
|
108
|
+
|
|
109
|
+
# Output as JSON
|
|
110
|
+
resume-parser-ats insights resume.pdf --json
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Or use without installing:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx resume-parser-ats parse resume.pdf
|
|
60
117
|
```
|
|
61
118
|
|
|
62
|
-
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 📖 3. Library (npm Package)
|
|
122
|
+
|
|
123
|
+
Install as a dependency for programmatic use:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm install resume-parser-ats
|
|
127
|
+
```
|
|
63
128
|
|
|
64
129
|
```typescript
|
|
65
130
|
import { parseResume, analyzeResume, suggestImprovements } from "resume-parser-ats";
|
|
66
131
|
|
|
67
|
-
//
|
|
68
|
-
const parsed = parseResume({
|
|
69
|
-
|
|
70
|
-
|
|
132
|
+
// Parse — extract structured data
|
|
133
|
+
const parsed = parseResume({ filePath: "./resume.pdf" });
|
|
134
|
+
// or: parseResume({ rawText: "John Doe\njohn@email.com\n..." })
|
|
135
|
+
|
|
136
|
+
console.log(parsed.data.profile.name); // "Jane Doe"
|
|
137
|
+
console.log(parsed.data.profile.email); // "jane@example.com"
|
|
71
138
|
console.log(parsed.data.education[0]?.school); // "MIT"
|
|
72
139
|
|
|
73
|
-
//
|
|
140
|
+
// Analyze — ATS compatibility scoring
|
|
74
141
|
const analysis = analyzeResume({
|
|
75
|
-
|
|
142
|
+
filePath: "./resume.pdf",
|
|
76
143
|
parsedResume: parsed.data,
|
|
77
|
-
strictness: "
|
|
144
|
+
strictness: "strict",
|
|
78
145
|
});
|
|
146
|
+
|
|
79
147
|
console.log(analysis.data.atsScore); // 72
|
|
80
148
|
console.log(analysis.data.atsGrade); // "B-"
|
|
149
|
+
console.log(analysis.data.fieldAnalyses);
|
|
150
|
+
console.log(analysis.data.formatIssues);
|
|
81
151
|
|
|
82
|
-
//
|
|
152
|
+
// Suggest — prioritized improvement recommendations
|
|
83
153
|
const suggestions = suggestImprovements({
|
|
84
|
-
|
|
154
|
+
filePath: "./resume.pdf",
|
|
85
155
|
parsedResume: parsed.data,
|
|
86
156
|
analysisResult: analysis.data,
|
|
87
|
-
focusAreas: ["ats", "content", "formatting"
|
|
157
|
+
focusAreas: ["ats", "content", "formatting"],
|
|
88
158
|
});
|
|
89
|
-
|
|
90
|
-
console.log(suggestions.data.
|
|
159
|
+
|
|
160
|
+
console.log(suggestions.data.quickWins);
|
|
161
|
+
console.log(suggestions.data.suggestions);
|
|
91
162
|
```
|
|
92
163
|
|
|
93
|
-
###
|
|
164
|
+
### Full Pipeline
|
|
94
165
|
|
|
95
|
-
```
|
|
96
|
-
|
|
166
|
+
```typescript
|
|
167
|
+
import { fullPipeline } from "resume-parser-ats";
|
|
168
|
+
|
|
169
|
+
const { parsed, analyzed, suggestions } = fullPipeline({
|
|
170
|
+
filePath: "./resume.pdf",
|
|
171
|
+
strictness: "moderate",
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
console.log(`ATS Score: ${analyzed.data.atsScore}/100 (${analyzed.data.atsGrade})`);
|
|
97
175
|
```
|
|
98
176
|
|
|
99
|
-
|
|
177
|
+
### TypeScript Types
|
|
100
178
|
|
|
101
|
-
|
|
102
|
-
|------|-------------|
|
|
103
|
-
| `parse_resume` | Parse a resume PDF or raw text and return structured data |
|
|
104
|
-
| `analyze_resume` | Parse + compute ATS compatibility score with per-field confidence |
|
|
105
|
-
| `suggest_improvements` | Parse + analyze + generate prioritized improvement suggestions |
|
|
179
|
+
All types are exported:
|
|
106
180
|
|
|
107
|
-
|
|
181
|
+
```typescript
|
|
182
|
+
import type {
|
|
183
|
+
ParseResumeInput,
|
|
184
|
+
ParseResumeOutput,
|
|
185
|
+
AnalyzeResumeInput,
|
|
186
|
+
AnalyzeResumeOutput,
|
|
187
|
+
SuggestImprovementsInput,
|
|
188
|
+
SuggestImprovementsOutput,
|
|
189
|
+
ParsedResume,
|
|
190
|
+
TextItem,
|
|
191
|
+
LineItem,
|
|
192
|
+
SectionItem,
|
|
193
|
+
} from "resume-parser-ats";
|
|
194
|
+
```
|
|
108
195
|
|
|
109
|
-
|
|
196
|
+
---
|
|
110
197
|
|
|
111
|
-
|
|
198
|
+
## 📡 4. MCP Server
|
|
112
199
|
|
|
113
|
-
|
|
114
|
-
- Text content
|
|
115
|
-
- X/Y positions (relative to bottom-left origin)
|
|
116
|
-
- Bold metadata
|
|
117
|
-
- Newline markers
|
|
200
|
+
Use Resume Parser as a Model Context Protocol (MCP) server to give AI assistants direct access to the parsing tools.
|
|
118
201
|
|
|
119
|
-
###
|
|
202
|
+
### Claude Desktop
|
|
120
203
|
|
|
121
|
-
|
|
204
|
+
Add to your Claude Desktop config file:
|
|
122
205
|
|
|
123
|
-
|
|
206
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
207
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
124
208
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"mcpServers": {
|
|
212
|
+
"resume-parser": {
|
|
213
|
+
"command": "npx",
|
|
214
|
+
"args": ["-y", "resume-parser-ats", "--mcp"]
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
128
219
|
|
|
129
|
-
|
|
220
|
+
Restart Claude Desktop. You can now ask Claude to parse and analyze resumes:
|
|
130
221
|
|
|
131
|
-
|
|
222
|
+
```
|
|
223
|
+
"Can you analyze my resume for ATS compatibility? The file is at ~/Documents/my-resume.pdf"
|
|
224
|
+
```
|
|
132
225
|
|
|
133
|
-
|
|
134
|
-
|---|---|---|---|
|
|
135
|
-
| Contains only letters/spaces/periods | +3 | Matches email regex | +4 |
|
|
136
|
-
| Is bolded | +2 | Contains @ symbol | +4 |
|
|
137
|
-
| Is ALL UPPERCASE | +2 | Looks like a name (no @) | -1 |
|
|
138
|
-
| Contains @ (probably email) | -4 | Contains digits (no @) | -2 |
|
|
139
|
-
| Contains numbers (probably phone) | -4 | — | — |
|
|
226
|
+
### ChatGPT / Codex (OpenAI)
|
|
140
227
|
|
|
141
|
-
|
|
228
|
+
Add to your OpenAI MCP configuration:
|
|
142
229
|
|
|
143
|
-
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"mcpServers": {
|
|
233
|
+
"resume-parser": {
|
|
234
|
+
"command": "npx",
|
|
235
|
+
"args": ["-y", "resume-parser-ats", "--mcp"]
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
144
240
|
|
|
145
|
-
|
|
241
|
+
### Cursor
|
|
146
242
|
|
|
147
|
-
|
|
148
|
-
|
|
243
|
+
Add to `~/.cursor/mcp.json`:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"mcpServers": {
|
|
248
|
+
"resume-parser": {
|
|
249
|
+
"command": "npx",
|
|
250
|
+
"args": ["-y", "resume-parser-ats", "--mcp"]
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
149
254
|
```
|
|
150
255
|
|
|
151
|
-
|
|
256
|
+
### Other MCP-Compatible Apps
|
|
152
257
|
|
|
153
|
-
|
|
258
|
+
The server uses stdio transport. For any MCP-compatible application, configure:
|
|
154
259
|
|
|
155
|
-
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"mcpServers": {
|
|
263
|
+
"resume-parser": {
|
|
264
|
+
"command": "npx",
|
|
265
|
+
"args": ["-y", "resume-parser-ats", "--mcp"]
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
156
270
|
|
|
157
|
-
|
|
158
|
-
import { parseResume, analyzeResume } from "resume-parser-ats";
|
|
159
|
-
import fs from "fs";
|
|
271
|
+
If you have `resume-parser-ats` installed globally:
|
|
160
272
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
console.log(`${file}: ATS Score ${analysis.data.atsScore}/100 (${analysis.data.atsGrade})`);
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"mcpServers": {
|
|
276
|
+
"resume-parser": {
|
|
277
|
+
"command": "resume-parser-ats",
|
|
278
|
+
"args": ["--mcp"]
|
|
279
|
+
}
|
|
280
|
+
}
|
|
170
281
|
}
|
|
171
282
|
```
|
|
172
283
|
|
|
173
|
-
###
|
|
284
|
+
### MCP Tools Available
|
|
174
285
|
|
|
175
|
-
|
|
286
|
+
| Tool | Description | Parameters |
|
|
287
|
+
|------|-------------|------------|
|
|
288
|
+
| `parse_resume` | Parse resume PDF/text → structured data | `filePath`, `rawText` |
|
|
289
|
+
| `analyze_resume` | Parse + ATS scoring | `filePath`, `rawText`, `strictness` |
|
|
290
|
+
| `suggest_improvements` | Parse + analyze + suggestions | `filePath`, `rawText`, `focusAreas` |
|
|
176
291
|
|
|
177
|
-
|
|
178
|
-
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## 🧠 How It Works: The 4-Step Algorithm
|
|
295
|
+
|
|
296
|
+
The parser implements the **OpenResume algorithm**, the same methodology used by real ATS systems:
|
|
179
297
|
|
|
180
|
-
|
|
298
|
+
### Step 1 — Read Text Items from PDF
|
|
181
299
|
|
|
182
|
-
|
|
183
|
-
// result.analyzed — ATS score + field analysis
|
|
184
|
-
// result.suggestions — prioritized actions
|
|
300
|
+
Extract every text item with position, bold, and newline metadata:
|
|
185
301
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
${JSON.stringify(result.analyzed.data)}
|
|
189
|
-
Suggest improvements in a friendly, encouraging tone.`;
|
|
302
|
+
```typescript
|
|
303
|
+
{ text: "John Doe", x1: 72, x2: 144, y: 720, bold: true, newLine: true }
|
|
190
304
|
```
|
|
191
305
|
|
|
192
|
-
###
|
|
306
|
+
### Step 2 — Group Text Items into Lines
|
|
307
|
+
|
|
308
|
+
Merge adjacent items when their horizontal gap is less than average character width. Group by Y-coordinate to reconstruct the natural reading order.
|
|
309
|
+
|
|
310
|
+
### Step 3 — Group Lines into Sections
|
|
311
|
+
|
|
312
|
+
Detect section titles using two heuristics:
|
|
313
|
+
1. **Primary**: Only text item in line + bold + ALL UPPERCASE
|
|
314
|
+
2. **Fallback**: Keyword match (EDUCATION, EXPERIENCE, SKILLS, etc.)
|
|
315
|
+
|
|
316
|
+
### Step 4 — Extract Attributes via Feature Scoring
|
|
193
317
|
|
|
194
|
-
|
|
318
|
+
Each attribute has feature sets with scoring functions. The text item with the **highest total score** wins:
|
|
195
319
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
320
|
+
| Attribute | Core Pattern | Example |
|
|
321
|
+
|-----------|-------------|---------|
|
|
322
|
+
| Name | Only letters/spaces/periods | `John Doe` |
|
|
323
|
+
| Email | Email format | `john@email.com` |
|
|
324
|
+
| Phone | `(xxx) xxx-xxxx` | `(555) 123-4567` |
|
|
325
|
+
| Location | `City, ST` | `New York, NY` |
|
|
326
|
+
| School | Contains "University" etc. | `MIT` |
|
|
327
|
+
| Degree | Contains "B.S.", "M.A." etc. | `B.S. Computer Science` |
|
|
200
328
|
|
|
201
|
-
|
|
329
|
+
**Name scoring example**: Only letters (+3), bolded (+2), uppercase (+2), has @ (-4), has digit (-4)
|
|
330
|
+
|
|
331
|
+
See [`resume-parser-ats/references/algorithm.md`](resume-parser-ats/references/algorithm.md) for the full specification.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 📊 ATS Compatibility Scoring
|
|
336
|
+
|
|
337
|
+
| Dimension | Weight | What it checks |
|
|
338
|
+
|-----------|--------|---------------|
|
|
339
|
+
| Name extraction | 20 pts | Can the parser identify a full name? |
|
|
340
|
+
| Email extraction | 20 pts | Is there a valid email address? |
|
|
341
|
+
| Phone extraction | 10 pts | Is there a parseable phone number? |
|
|
342
|
+
| Section detection | 15 pts | Are sections properly structured? |
|
|
343
|
+
| Education parsing | 10 pts | Are school, degree, and date parsed? |
|
|
344
|
+
| Experience parsing | 15 pts | Are company, title, and date parsed? |
|
|
345
|
+
| Skills parsing | 10 pts | Are skills extracted correctly? |
|
|
346
|
+
|
|
347
|
+
### Grading Scale
|
|
348
|
+
|
|
349
|
+
| Grade | Score | Meaning |
|
|
350
|
+
|-------|-------|---------|
|
|
351
|
+
| A+ | 90-100 | Excellent — ATS will parse everything correctly |
|
|
352
|
+
| A | 85-89 | Great — minor issues only |
|
|
353
|
+
| B+ | 80-84 | Good — most fields parse correctly |
|
|
354
|
+
| B | 75-79 | Adequate — some sections need improvement |
|
|
355
|
+
| B- | 70-74 | Below average — multiple parsing issues |
|
|
356
|
+
| C+ | 65-69 | Needs work — significant ATS problems |
|
|
357
|
+
| C | 60-64 | Poor — many fields fail to parse |
|
|
358
|
+
| D | 50-59 | Bad — critical fields missing |
|
|
359
|
+
| F | 0-49 | Failing — unrecognizable as a resume |
|
|
360
|
+
|
|
361
|
+
### Issue Severity Levels
|
|
362
|
+
|
|
363
|
+
- 🔴 **CRITICAL** — Name or email cannot be parsed (ATS will discard)
|
|
364
|
+
- 🟠 **HIGH** — Sections missing, dates unparseable, phone not found
|
|
365
|
+
- 🟡 **MEDIUM** — Skills not clean, formatting merge issues
|
|
366
|
+
- 🟢 **LOW** — Minor inconsistencies, optional fields missing
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 📊 Use Cases
|
|
202
371
|
|
|
203
|
-
|
|
372
|
+
### 🎯 Job Seeker — ATS Optimization
|
|
204
373
|
|
|
205
|
-
|
|
206
|
-
- Flag common issues (missing dates, non-standard section headers)
|
|
207
|
-
- Provide standardized improvement templates
|
|
374
|
+
Before applying, see what an ATS actually extracts:
|
|
208
375
|
|
|
209
|
-
|
|
376
|
+
```bash
|
|
377
|
+
resume-parser-ats insights my-resume.pdf --strictness strict --json
|
|
378
|
+
```
|
|
210
379
|
|
|
211
|
-
|
|
380
|
+
### 🏢 Recruiter — Bulk Resume Screening
|
|
212
381
|
|
|
213
382
|
```typescript
|
|
214
|
-
import { parseResume } from "resume-parser-ats";
|
|
383
|
+
import { parseResume, analyzeResume } from "resume-parser-ats";
|
|
384
|
+
import fs from "fs";
|
|
215
385
|
|
|
216
|
-
const
|
|
217
|
-
|
|
386
|
+
const files = fs.readdirSync("resumes/");
|
|
387
|
+
for (const file of files) {
|
|
388
|
+
const parsed = parseResume({ filePath: `resumes/${file}` });
|
|
389
|
+
const analysis = analyzeResume({ parsedResume: parsed.data, strictness: "moderate" });
|
|
390
|
+
console.log(`${file}: ${analysis.data.atsScore}/100 (${analysis.data.atsGrade})`);
|
|
391
|
+
}
|
|
218
392
|
```
|
|
219
393
|
|
|
394
|
+
### 📈 Career Platform — Resume Health Dashboard
|
|
395
|
+
|
|
396
|
+
Parse on upload → store ATS score → visualize → suggest improvements → track progress.
|
|
397
|
+
|
|
398
|
+
### 🎓 University Career Center — Student Reviews
|
|
399
|
+
|
|
400
|
+
Batch-parse resumes, flag common issues, generate improvement templates.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
220
404
|
## 🏗️ Architecture
|
|
221
405
|
|
|
222
406
|
```
|
|
223
|
-
resume-parser/
|
|
224
|
-
├──
|
|
225
|
-
├──
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
├──
|
|
229
|
-
├──
|
|
230
|
-
│ ├── index.ts # Main entry point + fullPipeline()
|
|
407
|
+
resume-parser-skill/
|
|
408
|
+
├── resume-parser-ats/ # Agent skill (npx skills add)
|
|
409
|
+
│ ├── SKILL.md # Skill manifest & instructions
|
|
410
|
+
│ └── references/
|
|
411
|
+
│ └── algorithm.md # Full algorithm specification
|
|
412
|
+
├── src/ # TypeScript source
|
|
413
|
+
│ ├── index.ts # Exports + fullPipeline()
|
|
231
414
|
│ ├── tools/
|
|
232
|
-
│ │ ├── parse-resume.ts
|
|
233
|
-
│ │ ├── analyze-resume.ts
|
|
234
|
-
│ │ └── suggest-improvements.ts
|
|
415
|
+
│ │ ├── parse-resume.ts # Step 1-4 parsing engine
|
|
416
|
+
│ │ ├── analyze-resume.ts # ATS scoring & analysis
|
|
417
|
+
│ │ └── suggest-improvements.ts # Suggestion generator
|
|
235
418
|
│ └── prompts/
|
|
236
|
-
│ ├── parser-prompt.ts
|
|
237
|
-
│ └── insights-prompt.ts
|
|
238
|
-
├── mcp-server/
|
|
239
|
-
│ └── server.ts # MCP server implementation
|
|
419
|
+
│ ├── parser-prompt.ts # Parsing prompt templates
|
|
420
|
+
│ └── insights-prompt.ts # Insights prompt templates
|
|
240
421
|
├── bin/
|
|
241
|
-
│ └── cli.js
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
422
|
+
│ └── cli.js # CLI entry point
|
|
423
|
+
├── mcp-server/
|
|
424
|
+
│ └── server.ts # MCP server implementation
|
|
425
|
+
├── test/evals/ # Test suites (86 tests)
|
|
426
|
+
├── AGENTS.md # Agent configuration
|
|
427
|
+
├── CONTRIBUTING.md # Contributing guide
|
|
428
|
+
├── package.json
|
|
429
|
+
└── tsconfig.json
|
|
247
430
|
```
|
|
248
431
|
|
|
432
|
+
---
|
|
433
|
+
|
|
249
434
|
## 🧪 Testing
|
|
250
435
|
|
|
251
436
|
```bash
|
|
252
|
-
# Run all tests
|
|
437
|
+
# Run all 86 tests
|
|
253
438
|
npm test
|
|
254
439
|
|
|
255
|
-
# Run
|
|
256
|
-
node --test test/evals/parse-resume.test.
|
|
257
|
-
node --test test/evals/analyze-resume.test.
|
|
258
|
-
node --test test/evals/suggest-improvements.test.
|
|
259
|
-
```
|
|
440
|
+
# Run a specific suite
|
|
441
|
+
node --test test/evals/parse-resume.test.mjs
|
|
442
|
+
node --test test/evals/analyze-resume.test.mjs
|
|
443
|
+
node --test test/evals/suggest-improvements.test.mjs
|
|
260
444
|
|
|
261
|
-
|
|
445
|
+
# Filter by test name
|
|
446
|
+
node --test test/evals/parse-resume.test.mjs --test-name-pattern "Step 1"
|
|
447
|
+
```
|
|
262
448
|
|
|
263
|
-
|
|
264
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
265
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
266
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
267
|
-
5. Open a Pull Request
|
|
449
|
+
---
|
|
268
450
|
|
|
269
451
|
## ☁️ CI/CD
|
|
270
452
|
|
|
271
|
-
This project uses GitHub Actions for continuous integration and npm publishing:
|
|
272
|
-
|
|
273
453
|
| Workflow | Trigger | What it does |
|
|
274
454
|
|----------|---------|-------------|
|
|
275
|
-
| **Build & Test** | Push/PR to `master` | Lint, build, and test across Node 18
|
|
276
|
-
| **Publish to npm** | Tag push `v*`
|
|
455
|
+
| **Build & Test** | Push/PR to `master` | Lint, build, and test across Node 18, 20, 22 |
|
|
456
|
+
| **Publish to npm** | Tag push `v*` | Builds and publishes to npmjs with provenance |
|
|
277
457
|
|
|
278
458
|
To publish a new version:
|
|
279
459
|
|
|
@@ -282,13 +462,30 @@ npm version patch # or minor, major
|
|
|
282
462
|
git push --follow-tags
|
|
283
463
|
```
|
|
284
464
|
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## 🤝 Contributing
|
|
468
|
+
|
|
469
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for:
|
|
470
|
+
|
|
471
|
+
- Development setup
|
|
472
|
+
- Project structure guide
|
|
473
|
+
- Code style and testing conventions
|
|
474
|
+
- Commit message format
|
|
475
|
+
- Pull request checklist
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
285
479
|
## 📄 License
|
|
286
480
|
|
|
287
481
|
MIT License — Copyright (c) 2025 **Dhanush Kandhan**. See [LICENSE](./LICENSE) for details.
|
|
288
482
|
|
|
289
483
|
---
|
|
290
484
|
|
|
291
|
-
<
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
485
|
+
<div align="center">
|
|
486
|
+
|
|
487
|
+
Made with ❤️ by **Dhanush Kandhan**
|
|
488
|
+
|
|
489
|
+
If this project helped you, consider giving it a ⭐ on [GitHub](https://github.com/dhanushk-offl/resume-parser-skill)!
|
|
490
|
+
|
|
491
|
+
</div>
|
package/bin/cli.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* resume-parser-ats parse <file|text> Parse a resume and output structured data
|
|
8
8
|
* resume-parser-ats analyze <file|text> Parse + analyze ATS compatibility
|
|
9
9
|
* resume-parser-ats insights <file|text> Full pipeline: parse + analyze + suggestions
|
|
10
|
+
* resume-parser-ats --mcp Start MCP server for Claude/ChatGPT/Cursor
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
const path = require("path");
|
|
@@ -35,6 +36,7 @@ Options:
|
|
|
35
36
|
--strictness <level> ATS strictness: lenient, moderate, strict (default: moderate)
|
|
36
37
|
--focus <areas> Focus areas: ats,content,formatting,structure (default: all)
|
|
37
38
|
--json Output raw JSON instead of formatted report
|
|
39
|
+
--mcp Start MCP server (for Claude Desktop, ChatGPT, Cursor, etc.)
|
|
38
40
|
--help Show this help message
|
|
39
41
|
|
|
40
42
|
Examples:
|
|
@@ -42,12 +44,37 @@ Examples:
|
|
|
42
44
|
resume-parser-ats analyze resume.pdf --strictness strict
|
|
43
45
|
resume-parser-ats insights resume.pdf --focus ats,formatting --json
|
|
44
46
|
resume-parser-ats parse "John Doe\\njohn@email.com\\nSoftware Engineer"
|
|
47
|
+
|
|
48
|
+
MCP Server:
|
|
49
|
+
resume-parser-ats --mcp
|
|
50
|
+
|
|
51
|
+
Add to Claude Desktop config:
|
|
52
|
+
{
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"resume-parser": {
|
|
55
|
+
"command": "npx",
|
|
56
|
+
"args": ["-y", "resume-parser-ats", "--mcp"]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
45
60
|
`);
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
function main() {
|
|
49
64
|
const args = process.argv.slice(2);
|
|
50
65
|
|
|
66
|
+
// Handle --mcp flag: start MCP server
|
|
67
|
+
if (args.includes("--mcp")) {
|
|
68
|
+
try {
|
|
69
|
+
require("../dist/mcp-server/server.js");
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.error("Error: MCP server not built. Run `npm run build` first.");
|
|
72
|
+
console.error(err.message);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
51
78
|
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
52
79
|
printUsage();
|
|
53
80
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resume-parser-ats",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "An agent skill that deeply parses resumes, extracts structured data, and provides actionable insights to improve ATS compatibility and readability.",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
"dist/",
|
|
20
20
|
"bin/",
|
|
21
|
+
"resume-parser-ats/",
|
|
21
22
|
"README.md",
|
|
22
|
-
"LICENSE"
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"CONTRIBUTING.md"
|
|
23
25
|
],
|
|
24
26
|
"keywords": [
|
|
25
27
|
"resume",
|
|
@@ -27,7 +29,9 @@
|
|
|
27
29
|
"ATS",
|
|
28
30
|
"agent-skill",
|
|
29
31
|
"resume-parser",
|
|
30
|
-
"career"
|
|
32
|
+
"career",
|
|
33
|
+
"skills",
|
|
34
|
+
"npx-skills"
|
|
31
35
|
],
|
|
32
36
|
"author": "dhanush",
|
|
33
37
|
"license": "MIT",
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resume-parser-ats
|
|
3
|
+
description: >
|
|
4
|
+
Deeply parses resume PDFs using the OpenResume 4-step algorithm, extracts structured information
|
|
5
|
+
(Name, Email, Phone, Education, Work Experience, Skills, etc.), evaluates ATS compatibility,
|
|
6
|
+
and provides actionable improvement suggestions. Use when a user asks to parse, review, or
|
|
7
|
+
analyze a resume, check ATS-friendliness, or get resume improvement suggestions.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Resume Parser — ATS Intelligence
|
|
11
|
+
|
|
12
|
+
You are a resume parsing and ATS analysis specialist. When activated, deeply parse resumes and provide structured, actionable insights.
|
|
13
|
+
|
|
14
|
+
## When to Activate
|
|
15
|
+
|
|
16
|
+
- User asks to parse, review, or analyze a resume
|
|
17
|
+
- User asks "is my resume ATS-friendly?"
|
|
18
|
+
- User asks for resume improvement suggestions
|
|
19
|
+
- User uploads or references a resume PDF
|
|
20
|
+
- User wants to compare what an ATS sees vs. their intended content
|
|
21
|
+
|
|
22
|
+
## Tools Available
|
|
23
|
+
|
|
24
|
+
For programmatic use, install the npm package:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install resume-parser-ats
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### `parse_resume` — Extract structured data from a resume
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx resume-parser-ats parse <file.pdf>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
import { parseResume } from "resume-parser-ats";
|
|
38
|
+
const result = parseResume({ filePath: "/path/to/resume.pdf" });
|
|
39
|
+
// or: parseResume({ rawText: "John Doe\njohn@email.com..." })
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Input**: `{ filePath?: string, rawText?: string }`
|
|
43
|
+
**Output**: Structured data with profile, education, experience, skills, projects.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
### `analyze_resume` — Parse + ATS compatibility scoring
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx resume-parser-ats analyze <file.pdf> --strictness strict
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
import { analyzeResume } from "resume-parser-ats";
|
|
55
|
+
const result = analyzeResume({ filePath: "/path/to/resume.pdf", strictness: "moderate" });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Input**: `{ filePath?, rawText?, strictness?: "lenient"|"moderate"|"strict" }`
|
|
59
|
+
**Output**: ATS score (0-100), letter grade (A+ to F), per-field confidence, section detection, format issues.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### `suggest_improvements` — Parse + analyze + prioritized suggestions
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx resume-parser-ats insights <file.pdf> --strictness strict --focus ats,formatting
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
import { suggestImprovements } from "resume-parser-ats";
|
|
71
|
+
const result = suggestImprovements({ filePath: "/path/to/resume.pdf", focusAreas: ["ats", "content"] });
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Input**: `{ filePath?, rawText?, strictness?, focusAreas?: string[] }`
|
|
75
|
+
**Output**: Overall score, grade, quick wins, prioritized suggestions (critical → low), section analysis.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Manual Parsing Algorithm
|
|
80
|
+
|
|
81
|
+
Use this algorithm when the npm package is unavailable or for understanding the parsing logic:
|
|
82
|
+
|
|
83
|
+
### Step 1: Read Text Items from PDF
|
|
84
|
+
|
|
85
|
+
Extract all text items from the PDF. Each item includes:
|
|
86
|
+
- `text` — text content
|
|
87
|
+
- `x1`, `x2` — left/right X positions (origin at bottom-left)
|
|
88
|
+
- `y` — Y position from bottom
|
|
89
|
+
- `bold` — whether text is bold
|
|
90
|
+
- `newLine` — whether this item starts a new line
|
|
91
|
+
|
|
92
|
+
### Step 2: Group Text Items into Lines
|
|
93
|
+
|
|
94
|
+
1. **Merge adjacent items**: When `Distance = RightTextItem.X₁ - LeftTextItem.X₂` is less than average character width, merge them
|
|
95
|
+
2. **Average character width**: Total character widths / total character count (exclude bold and newline elements)
|
|
96
|
+
3. **Group by Y-coordinate**: Same Y = same line
|
|
97
|
+
|
|
98
|
+
### Step 3: Group Lines into Sections
|
|
99
|
+
|
|
100
|
+
**Section title detection** (must satisfy ALL 3):
|
|
101
|
+
1. It is the only text item in the line
|
|
102
|
+
2. It is bolded
|
|
103
|
+
3. Its letters are all UPPERCASE
|
|
104
|
+
|
|
105
|
+
**Fallback**: Keyword match against known headers:
|
|
106
|
+
PROFILE, SUMMARY, OBJECTIVE, ABOUT, EDUCATION, ACADEMIC, DEGREES, EXPERIENCE, WORK EXPERIENCE, EMPLOYMENT, PROFESSIONAL EXPERIENCE, SKILLS, TECHNICAL SKILLS, COMPETENCIES, PROJECTS, PORTFOLIO, CERTIFICATIONS, LICENSES, HONORS, AWARDS, VOLUNTEER, COMMUNITY, LEADERSHIP, PUBLICATIONS, RESEARCH, INTERESTS, ACTIVITIES, HOBBIES
|
|
107
|
+
|
|
108
|
+
Lines before any section title go into PROFILE.
|
|
109
|
+
|
|
110
|
+
### Step 4: Extract Attributes via Feature Scoring
|
|
111
|
+
|
|
112
|
+
Each attribute has feature sets (matching function + score). The text item with the **highest total score** wins.
|
|
113
|
+
|
|
114
|
+
| Attribute | Core Feature | Regex |
|
|
115
|
+
|-----------|-------------|-------|
|
|
116
|
+
| Name | Only letters/spaces/periods | `/^[a-zA-Z\s\.]+$/` |
|
|
117
|
+
| Email | Email format | `/\S+@\S+\.\S+/` |
|
|
118
|
+
| Phone | Phone format | `/\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}/` |
|
|
119
|
+
| Location | City, ST format | `/[A-Z][a-zA-Z\s]+, [A-Z]{2}/` |
|
|
120
|
+
| URL | URL format | `/\S+\.[a-z]+\/\S+/` |
|
|
121
|
+
|
|
122
|
+
**Name scoring example**: Only letters (+3), bolded (+2), uppercase (+2), has @ (-4), has digit (-4), has comma (-4), has slash (-4)
|
|
123
|
+
|
|
124
|
+
**Subsection detection** (for Education, Work Experience):
|
|
125
|
+
- Primary: vertical line gap > typical line gap × 1.4
|
|
126
|
+
- Fallback: text item is bolded
|
|
127
|
+
|
|
128
|
+
See [references/algorithm.md](references/algorithm.md) for the full specification.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## ATS Compatibility Scoring
|
|
133
|
+
|
|
134
|
+
| Dimension | Weight |
|
|
135
|
+
|-----------|--------|
|
|
136
|
+
| Name extraction | 20 pts |
|
|
137
|
+
| Email extraction | 20 pts |
|
|
138
|
+
| Phone extraction | 10 pts |
|
|
139
|
+
| Section detection | 15 pts |
|
|
140
|
+
| Education parsing | 10 pts |
|
|
141
|
+
| Experience parsing | 15 pts |
|
|
142
|
+
| Skills parsing | 10 pts |
|
|
143
|
+
|
|
144
|
+
**Grading**: A+ (90-100), A (85-89), B+ (80-84), B (75-79), B- (70-74), C+ (65-69), C (60-64), D (50-59), F (0-49)
|
|
145
|
+
|
|
146
|
+
## Issue Severity Levels
|
|
147
|
+
|
|
148
|
+
- **CRITICAL**: Name or email cannot be parsed → ATS will likely discard
|
|
149
|
+
- **HIGH**: Key sections missing, dates unparseable, phone not found
|
|
150
|
+
- **MEDIUM**: Skills not extracted cleanly, formatting merge issues
|
|
151
|
+
- **LOW**: Minor inconsistencies, optional fields missing
|
|
152
|
+
|
|
153
|
+
## Output Format
|
|
154
|
+
|
|
155
|
+
Always provide results in this structured format:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
## 📊 Resume Parsing Report
|
|
159
|
+
|
|
160
|
+
### ATS Compatibility Score: XX/100 (Grade: X)
|
|
161
|
+
|
|
162
|
+
### ✅ Successfully Parsed Fields
|
|
163
|
+
| Field | Parsed Value | Confidence |
|
|
164
|
+
|-------|-------------|------------|
|
|
165
|
+
| Name | John Doe | High |
|
|
166
|
+
|
|
167
|
+
### ⚠️ Issues Found
|
|
168
|
+
| # | Severity | Field | Issue | Suggestion |
|
|
169
|
+
|---|----------|-------|-------|------------|
|
|
170
|
+
| 1 | CRITICAL | Email | ... | ... |
|
|
171
|
+
|
|
172
|
+
### 📝 Priority Fixes
|
|
173
|
+
1. **[Fix Title]**: Description of what to change and why
|
|
174
|
+
- Before: `current state`
|
|
175
|
+
- After: `suggested state`
|
|
176
|
+
|
|
177
|
+
### 📋 Section-by-Section Analysis
|
|
178
|
+
#### Profile
|
|
179
|
+
- Analysis notes...
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Important Rules
|
|
183
|
+
|
|
184
|
+
1. **Always run all 4 parsing steps** — do not skip steps
|
|
185
|
+
2. **Always provide the ATS compatibility score** — this is the primary metric
|
|
186
|
+
3. **Every suggestion must be actionable** — not "improve formatting" but "Move the date to the same line as the company name"
|
|
187
|
+
4. **Prioritize Name and Email extraction** — if they fail, flag as CRITICAL
|
|
188
|
+
5. **Explain WHY** each suggestion matters in ATS terms
|
|
189
|
+
6. **Compare parsed output vs. likely intended content** — surface discrepancies
|
|
190
|
+
7. **Never modify the original file** — this is a read-only analysis tool
|
|
191
|
+
8. **If a PDF cannot be parsed**, fall back to raw text and note the limitation
|
|
192
|
+
9. **Flag when text items break unexpectedly** (e.g., phone numbers split across items)
|
|
193
|
+
|
|
194
|
+
## Programmatic Access
|
|
195
|
+
|
|
196
|
+
### As an npm Library
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npm install resume-parser-ats
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { parseResume, analyzeResume, suggestImprovements } from "resume-parser-ats";
|
|
204
|
+
|
|
205
|
+
const result = parseResume({ filePath: "resume.pdf" });
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### As an MCP Server
|
|
209
|
+
|
|
210
|
+
Start the MCP server for use with Claude Desktop, ChatGPT, Cursor, and other MCP-compatible apps:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
resume-parser-ats --mcp
|
|
214
|
+
# or
|
|
215
|
+
npx resume-parser-ats --mcp
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
See README for full MCP configuration instructions.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# OpenResume 4-Step Parsing Algorithm
|
|
2
|
+
|
|
3
|
+
This document provides the full technical reference for the resume parsing algorithm.
|
|
4
|
+
|
|
5
|
+
## Step 1: Read Text Items from PDF
|
|
6
|
+
|
|
7
|
+
Extract all text items from the PDF using `pdfjs-dist`. Each text item includes:
|
|
8
|
+
|
|
9
|
+
| Field | Type | Description |
|
|
10
|
+
|-------|------|-------------|
|
|
11
|
+
| `text` | string | The text content |
|
|
12
|
+
| `x1` | number | Left X position |
|
|
13
|
+
| `x2` | number | Right X position |
|
|
14
|
+
| `y` | number | Y position (from page bottom) |
|
|
15
|
+
| `bold` | boolean | Whether the text is bold |
|
|
16
|
+
| `newLine` | boolean | Whether this item starts a new line |
|
|
17
|
+
|
|
18
|
+
X,Y coordinates are relative to the bottom-left corner (origin 0,0).
|
|
19
|
+
|
|
20
|
+
## Step 2: Group Text Items into Lines
|
|
21
|
+
|
|
22
|
+
1. **Merge adjacent items** when `Distance = RightTextItem.X₁ - LeftTextItem.X₂` is less than average character width
|
|
23
|
+
2. Average character width = total character widths / total character count (exclude bold and newline elements)
|
|
24
|
+
3. **Group by Y-coordinate** to form lines (same Y = same line)
|
|
25
|
+
|
|
26
|
+
This reconstructs the line-by-line reading order that may be lost in PDF extraction.
|
|
27
|
+
|
|
28
|
+
## Step 3: Group Lines into Sections
|
|
29
|
+
|
|
30
|
+
### Section Title Detection (primary heuristic — must satisfy ALL 3):
|
|
31
|
+
|
|
32
|
+
1. It is the only text item in the line
|
|
33
|
+
2. It is bolded
|
|
34
|
+
3. Its letters are all UPPERCASE
|
|
35
|
+
|
|
36
|
+
### Fallback Heuristic: Keyword matching
|
|
37
|
+
|
|
38
|
+
Known section titles: PROFILE, SUMMARY, OBJECTIVE, ABOUT, EDUCATION, ACADEMIC, DEGREES, EXPERIENCE, WORK EXPERIENCE, EMPLOYMENT, PROFESSIONAL EXPERIENCE, SKILLS, TECHNICAL SKILLS, COMPETENCIES, PROJECTS, PORTFOLIO, CERTIFICATIONS, LICENSES, HONORS, AWARDS, VOLUNTEER, COMMUNITY, LEADERSHIP, PUBLICATIONS, RESEARCH, INTERESTS, ACTIVITIES, HOBBIES
|
|
39
|
+
|
|
40
|
+
- Group all lines under their closest preceding section title
|
|
41
|
+
- Lines before any section title go into the PROFILE section
|
|
42
|
+
|
|
43
|
+
## Step 4: Extract Resume Attributes using Feature Scoring
|
|
44
|
+
|
|
45
|
+
Each attribute has **feature sets** (matching function + score). Run every text item through all feature sets for an attribute. The text item with the **highest total feature score** is extracted as that attribute.
|
|
46
|
+
|
|
47
|
+
### Subsection Detection (for Education, Work Experience, etc.)
|
|
48
|
+
|
|
49
|
+
- **Primary**: vertical line gap > typical line gap × 1.4
|
|
50
|
+
- **Fallback**: text item is bolded
|
|
51
|
+
|
|
52
|
+
### Feature Scoring Tables
|
|
53
|
+
|
|
54
|
+
#### Name
|
|
55
|
+
|
|
56
|
+
| Feature | Score |
|
|
57
|
+
|---------|-------|
|
|
58
|
+
| Contains only letters, spaces or periods | +3 |
|
|
59
|
+
| Is bolded | +2 |
|
|
60
|
+
| Contains all uppercase letters | +2 |
|
|
61
|
+
| Contains @ (may be email) | -4 |
|
|
62
|
+
| Contains number (may be phone) | -4 |
|
|
63
|
+
| Contains , (may be address) | -4 |
|
|
64
|
+
| Contains / (may be URL) | -4 |
|
|
65
|
+
|
|
66
|
+
#### Email
|
|
67
|
+
|
|
68
|
+
| Feature | Score |
|
|
69
|
+
|---------|-------|
|
|
70
|
+
| Matches email regex `\S+@\S+\.\S+` | +5 |
|
|
71
|
+
| Contains @ | +2 |
|
|
72
|
+
|
|
73
|
+
#### Phone
|
|
74
|
+
|
|
75
|
+
| Feature | Score |
|
|
76
|
+
|---------|-------|
|
|
77
|
+
| Matches phone regex `\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}` | +5 |
|
|
78
|
+
|
|
79
|
+
#### Location
|
|
80
|
+
|
|
81
|
+
| Feature | Score |
|
|
82
|
+
|---------|-------|
|
|
83
|
+
| Matches city,state regex `[A-Z][a-zA-Z\s]+, [A-Z]{2}` | +5 |
|
|
84
|
+
|
|
85
|
+
#### URL
|
|
86
|
+
|
|
87
|
+
| Feature | Score |
|
|
88
|
+
|---------|-------|
|
|
89
|
+
| Matches URL regex `\S+\.[a-z]+\/\S+` | +5 |
|
|
90
|
+
|
|
91
|
+
#### School
|
|
92
|
+
|
|
93
|
+
| Feature | Score |
|
|
94
|
+
|---------|-------|
|
|
95
|
+
| Contains school keyword (College, University, School, Institute, Academy) | +4 |
|
|
96
|
+
|
|
97
|
+
#### Degree
|
|
98
|
+
|
|
99
|
+
| Feature | Score |
|
|
100
|
+
|---------|-------|
|
|
101
|
+
| Contains degree keyword (Associate, Bachelor, Master, Doctorate, B.S., B.A., M.S., M.A., Ph.D.) | +4 |
|
|
102
|
+
|
|
103
|
+
#### GPA
|
|
104
|
+
|
|
105
|
+
| Feature | Score |
|
|
106
|
+
|---------|-------|
|
|
107
|
+
| Matches GPA regex `[0-4]\.\d{1,2}` | +5 |
|
|
108
|
+
|
|
109
|
+
## ATS Compatibility Scoring Framework
|
|
110
|
+
|
|
111
|
+
| Dimension | Weight |
|
|
112
|
+
|-----------|--------|
|
|
113
|
+
| Name extraction | 20 pts |
|
|
114
|
+
| Email extraction | 20 pts |
|
|
115
|
+
| Phone extraction | 10 pts |
|
|
116
|
+
| Section detection | 15 pts |
|
|
117
|
+
| Education parsing | 10 pts |
|
|
118
|
+
| Experience parsing | 15 pts |
|
|
119
|
+
| Skills parsing | 10 pts |
|
|
120
|
+
|
|
121
|
+
### Issue Severity Levels
|
|
122
|
+
|
|
123
|
+
- **CRITICAL**: Name or email cannot be parsed (ATS will likely discard)
|
|
124
|
+
- **HIGH**: Key sections missing, dates unparseable, phone not found
|
|
125
|
+
- **MEDIUM**: Skills not extracted cleanly, formatting merge issues
|
|
126
|
+
- **LOW**: Minor inconsistencies, optional fields missing
|