job_ops-mcp 0.3.0
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/.env.example +33 -0
- package/LICENSE +21 -0
- package/README.md +400 -0
- package/config/profile.example.yml +67 -0
- package/cv.example.md +53 -0
- package/dist/cli.js +385 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/core/browser.js +27 -0
- package/dist/core/browser.js.map +1 -0
- package/dist/core/content_hash.js +11 -0
- package/dist/core/content_hash.js.map +1 -0
- package/dist/core/csv.js +107 -0
- package/dist/core/csv.js.map +1 -0
- package/dist/core/cv_parse.js +201 -0
- package/dist/core/cv_parse.js.map +1 -0
- package/dist/core/html.js +10 -0
- package/dist/core/html.js.map +1 -0
- package/dist/core/jd_normalize.js +99 -0
- package/dist/core/jd_normalize.js.map +1 -0
- package/dist/core/jobs.js +106 -0
- package/dist/core/jobs.js.map +1 -0
- package/dist/core/llm.js +227 -0
- package/dist/core/llm.js.map +1 -0
- package/dist/core/modes.js +55 -0
- package/dist/core/modes.js.map +1 -0
- package/dist/core/outreach_safety.js +77 -0
- package/dist/core/outreach_safety.js.map +1 -0
- package/dist/core/profile.js +88 -0
- package/dist/core/profile.js.map +1 -0
- package/dist/core/providers/amazon.js +36 -0
- package/dist/core/providers/amazon.js.map +1 -0
- package/dist/core/providers/ashby.js +31 -0
- package/dist/core/providers/ashby.js.map +1 -0
- package/dist/core/providers/google.js +46 -0
- package/dist/core/providers/google.js.map +1 -0
- package/dist/core/providers/greenhouse.js +55 -0
- package/dist/core/providers/greenhouse.js.map +1 -0
- package/dist/core/providers/http.js +36 -0
- package/dist/core/providers/http.js.map +1 -0
- package/dist/core/providers/index.js +53 -0
- package/dist/core/providers/index.js.map +1 -0
- package/dist/core/providers/lever.js +32 -0
- package/dist/core/providers/lever.js.map +1 -0
- package/dist/core/providers/playwright_generic.js +53 -0
- package/dist/core/providers/playwright_generic.js.map +1 -0
- package/dist/core/providers/types.js +2 -0
- package/dist/core/providers/types.js.map +1 -0
- package/dist/core/providers/workday.js +44 -0
- package/dist/core/providers/workday.js.map +1 -0
- package/dist/core/render.js +253 -0
- package/dist/core/render.js.map +1 -0
- package/dist/core/reports.js +257 -0
- package/dist/core/reports.js.map +1 -0
- package/dist/core/resources.js +40 -0
- package/dist/core/resources.js.map +1 -0
- package/dist/core/scan_engine.js +164 -0
- package/dist/core/scan_engine.js.map +1 -0
- package/dist/core/scheduler.js +117 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/db.js +60 -0
- package/dist/db.js.map +1 -0
- package/dist/http/app.js +35 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/dashboard.js +131 -0
- package/dist/http/dashboard.js.map +1 -0
- package/dist/mcp/define.js +35 -0
- package/dist/mcp/define.js.map +1 -0
- package/dist/mcp/server.js +103 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/apply_prefill.js +167 -0
- package/dist/mcp/tools/apply_prefill.js.map +1 -0
- package/dist/mcp/tools/batch_evaluate.js +143 -0
- package/dist/mcp/tools/batch_evaluate.js.map +1 -0
- package/dist/mcp/tools/evaluate_job.js +181 -0
- package/dist/mcp/tools/evaluate_job.js.map +1 -0
- package/dist/mcp/tools/generate_materials.js +126 -0
- package/dist/mcp/tools/generate_materials.js.map +1 -0
- package/dist/mcp/tools/get_report.js +24 -0
- package/dist/mcp/tools/get_report.js.map +1 -0
- package/dist/mcp/tools/ops.js +321 -0
- package/dist/mcp/tools/ops.js.map +1 -0
- package/dist/mcp/tools/outreach.js +481 -0
- package/dist/mcp/tools/outreach.js.map +1 -0
- package/dist/mcp/tools/render_pdf.js +27 -0
- package/dist/mcp/tools/render_pdf.js.map +1 -0
- package/dist/mcp/tools/scan_portals.js +35 -0
- package/dist/mcp/tools/scan_portals.js.map +1 -0
- package/dist/mcp/tools/scheduler.js +32 -0
- package/dist/mcp/tools/scheduler.js.map +1 -0
- package/dist/mcp/tools/stories.js +172 -0
- package/dist/mcp/tools/stories.js.map +1 -0
- package/dist/mcp/tools/tracker.js +183 -0
- package/dist/mcp/tools/tracker.js.map +1 -0
- package/dist/mcp/tools/visa.js +219 -0
- package/dist/mcp/tools/visa.js.map +1 -0
- package/dist/migrations/001_initial.sql +505 -0
- package/dist/migrations/002_llm_and_digest.sql +42 -0
- package/dist/server.js +55 -0
- package/dist/server.js.map +1 -0
- package/fonts/dm-sans-latin-ext.woff2 +0 -0
- package/fonts/dm-sans-latin.woff2 +0 -0
- package/fonts/space-grotesk-latin-ext.woff2 +0 -0
- package/fonts/space-grotesk-latin.woff2 +0 -0
- package/modes/career_packet.md +91 -0
- package/modes/negotiation_playbook.md +64 -0
- package/modes/outreach_tone.md +80 -0
- package/modes/report_format.md +83 -0
- package/modes/rubric.md +119 -0
- package/modes/tailoring_rules.md +102 -0
- package/package.json +67 -0
- package/portals.example.yml +95 -0
- package/templates/cover-template.html +64 -0
- package/templates/cv-template.html +421 -0
- package/templates/cv-template.tex +123 -0
package/.env.example
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# mcp-jsa configuration
|
|
2
|
+
|
|
3
|
+
# Network
|
|
4
|
+
MCP_JSA_PORT=7891
|
|
5
|
+
MCP_JSA_HOST=127.0.0.1
|
|
6
|
+
|
|
7
|
+
# Project root — where cv.md, config/profile.yml, portals.yml live.
|
|
8
|
+
# Defaults to the directory this server runs from.
|
|
9
|
+
# To reuse the existing career-ops/ data, point it there:
|
|
10
|
+
# MCP_JSA_PROJECT_ROOT=/Users/you/Documents/Career Ops/career-ops
|
|
11
|
+
MCP_JSA_PROJECT_ROOT=
|
|
12
|
+
|
|
13
|
+
# Data + outputs (resolved relative to the server install dir, not project root)
|
|
14
|
+
MCP_JSA_DATA_DIR=./data
|
|
15
|
+
MCP_JSA_OUTPUT_DIR=./output
|
|
16
|
+
|
|
17
|
+
# LLM provider — only used on api/batch paths in later milestones.
|
|
18
|
+
# chat-mode (default) runs zero LLM calls server-side; the chat client is the brain.
|
|
19
|
+
MCP_JSA_LLM_PROVIDER=gemini # gemini | deepseek | none
|
|
20
|
+
MCP_JSA_LLM_MODEL=
|
|
21
|
+
GEMINI_API_KEY=
|
|
22
|
+
DEEPSEEK_API_KEY=
|
|
23
|
+
|
|
24
|
+
# Scheduler — off by default. Enable specific jobs via scheduler_enable MCP tool.
|
|
25
|
+
MCP_JSA_SCHEDULER_ENABLED=false
|
|
26
|
+
|
|
27
|
+
# Visa scoring — set to `false` if you don't need visa/H1B signal (US citizens, non-US
|
|
28
|
+
# users, etc.). When false, visa_fit is dropped from the rubric, weights renormalize to
|
|
29
|
+
# resume 0.6 / taste 0.4, the visa_signal / import_h1b / import_linkedin tools are hidden,
|
|
30
|
+
# and visa columns are stripped from tool responses. Default: true.
|
|
31
|
+
MCP_JSA_VISA_SCORING=true
|
|
32
|
+
|
|
33
|
+
# Playwright — usually no config needed once `npm run playwright:install` is done.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mohith Kattukuttiyil Das
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# job_ops-mcp
|
|
2
|
+
|
|
3
|
+
A self-hosted **Model Context Protocol** server for the full job-search loop — portal
|
|
4
|
+
scanning, JD evaluation, tailored resume + cover PDFs, outreach drafting, story bank,
|
|
5
|
+
negotiation brief — all driven from your MCP-aware chat client (Claude Desktop, Cursor,
|
|
6
|
+
any client that speaks streamable-HTTP MCP).
|
|
7
|
+
|
|
8
|
+
The chat is the brain. This server executes the mechanical work and hands every artifact
|
|
9
|
+
back as an `http://localhost:7891/...` link.
|
|
10
|
+
|
|
11
|
+
> **Status:** early. Works. APIs may still move pre-1.0.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quickstart
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 1. Scaffold your working directory (cv.md, profile.yml, portals.yml + SQLite DB)
|
|
19
|
+
npx job_ops-mcp init
|
|
20
|
+
|
|
21
|
+
# 2. Open cv.md, config/profile.yml, portals.yml and replace every <TODO> placeholder.
|
|
22
|
+
|
|
23
|
+
# 3. Confirm everything is wired
|
|
24
|
+
npx job_ops-mcp doctor
|
|
25
|
+
|
|
26
|
+
# 4. Boot the server (Chromium auto-installs on first run)
|
|
27
|
+
npx job_ops-mcp start
|
|
28
|
+
# ▷ job_ops-mcp listening on http://127.0.0.1:7891
|
|
29
|
+
|
|
30
|
+
# 5. Get a copy-paste config block for your MCP client
|
|
31
|
+
npx job_ops-mcp connect
|
|
32
|
+
|
|
33
|
+
# 6. Paste a job URL or pasted JD into your chat — the chat calls evaluate_job, draws on
|
|
34
|
+
# your rubric + career_packet + tailoring rules, and walks the rest of the workflow.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
That's the loop. Everything else (warm-intro finder, story bank, negotiation brief,
|
|
38
|
+
batch rater, scheduler, …) is wired in but optional.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## What it does
|
|
43
|
+
|
|
44
|
+
Two systems merged into one MCP server:
|
|
45
|
+
|
|
46
|
+
- **Evaluation + materials side** — port of [santifer/career-ops](https://github.com/santifer/career-ops):
|
|
47
|
+
6-block A–F (+G legitimacy) report, archetype detection, ATS-friendly HTML→PDF resume
|
|
48
|
+
+ cover generation, story bank, negotiation playbook.
|
|
49
|
+
- **Pipeline side** — port of a personal Postgres + n8n pipeline ("JSA"): Greenhouse /
|
|
50
|
+
Ashby / Lever / Workday pollers + closed-board Playwright scrapers, content-hash
|
|
51
|
+
dedupe, batch LLM rater with strict-JSON parsing, warm-intro / founder DM drafter,
|
|
52
|
+
visa signal from DOL OFLC H1B data.
|
|
53
|
+
|
|
54
|
+
Everything lives in a single Node process with a single SQLite file. No external
|
|
55
|
+
Postgres, no n8n, no cloud anything. Bring your own LLM key (Gemini free tier by
|
|
56
|
+
default, DeepSeek optional) if you want the API/batch paths; chat-mode tools work
|
|
57
|
+
without one.
|
|
58
|
+
|
|
59
|
+
> **Not affiliated with or endorsed by santifer's career-ops.** This is an independent
|
|
60
|
+
> project that ports + adapts the publicly-released MIT-licensed templates and rubric
|
|
61
|
+
> shape into the MCP transport surface. See the [Attribution](#attribution) section.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Tools (36 — one MCP `tools/list` call away)
|
|
66
|
+
|
|
67
|
+
| Group | Tools |
|
|
68
|
+
|---|---|
|
|
69
|
+
| **Evaluation** | `evaluate_job`, `batch_evaluate`, `get_top_jobs`, `evaluate_training`, `evaluate_project` |
|
|
70
|
+
| **Materials** | `generate_materials`, `render_pdf`, `get_report` |
|
|
71
|
+
| **Tracker** | `get_tracker`, `update_status`, `mark_ready_to_apply` |
|
|
72
|
+
| **Sourcing** | `scan_portals` (Greenhouse + Ashby + Lever + Workday + Amazon + Google + generic Playwright) |
|
|
73
|
+
| **Outreach** | `find_warm_intros`, `find_founders`, `draft_outreach`, `draft_followup`, `draft_reply`, `get_outreach_queue`, `update_outreach`, `get_followups_due` |
|
|
74
|
+
| **Interview / offer** | `extract_stories`, `get_story_bank`, `negotiation_brief` |
|
|
75
|
+
| **Research** | `deep_research`, `enrich_company`, `daily_digest` |
|
|
76
|
+
| **Profile + ops** | `get_career_packet`, `update_career_packet`, `cost_estimate` |
|
|
77
|
+
| **Apply (preview only — never submits)** | `apply_prefill` |
|
|
78
|
+
| **Visa (optional, can be hidden)** | `visa_signal`, `import_h1b`, `import_linkedin` |
|
|
79
|
+
| **Scheduler (opt-in cron, off by default)** | `scheduler_status`, `scheduler_enable`, `scheduler_disable` |
|
|
80
|
+
|
|
81
|
+
Six MCP **resources** carry the editable behaviour — rubric, report_format,
|
|
82
|
+
tailoring_rules, outreach_tone, negotiation_playbook, career_packet — all loaded from
|
|
83
|
+
`modes/*.md` and live-reloaded on edit. Tune scoring or tone without touching code.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Designed to be made yours
|
|
88
|
+
|
|
89
|
+
The defaults assume nothing about your location, citizenship, role, or industry. Every
|
|
90
|
+
behaviour-shaping piece is a markdown file you can rewrite:
|
|
91
|
+
|
|
92
|
+
| You can change… | By editing… |
|
|
93
|
+
|---|---|
|
|
94
|
+
| Scoring dimensions + weights | `modes/rubric.md` |
|
|
95
|
+
| 6-block report shape | `modes/report_format.md` |
|
|
96
|
+
| Resume/cover tailoring rules | `modes/tailoring_rules.md` |
|
|
97
|
+
| Outreach tone + char caps | `modes/outreach_tone.md` |
|
|
98
|
+
| Negotiation scripts + framework | `modes/negotiation_playbook.md` |
|
|
99
|
+
| Your bullet/project bank | `modes/career_packet.md` (or via `update_career_packet`) |
|
|
100
|
+
| Tracked companies + filters | `portals.yml` |
|
|
101
|
+
| Identity + target roles | `config/profile.yml` |
|
|
102
|
+
|
|
103
|
+
### Non-US users / non-sponsorship cases
|
|
104
|
+
|
|
105
|
+
Visa scoring is **fully optional**. Set:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
export MCP_JSA_VISA_SCORING=false
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
When off:
|
|
112
|
+
|
|
113
|
+
- `score_total = round(0.6 · resume_fit + 0.4 · taste_fit)` (server-side authoritative)
|
|
114
|
+
- The `visa_signal`, `import_h1b`, `import_linkedin` tools are hidden from `tools/list`
|
|
115
|
+
- `score_visa_fit` is stripped from `get_top_jobs` items and the eval-report HTML badge
|
|
116
|
+
- The rubric resource gets a "VISA SCORING DISABLED" override prefix the chat reads
|
|
117
|
+
|
|
118
|
+
Other features are unaffected. If you're a US citizen, a non-US user, or anyone scoring
|
|
119
|
+
roles where sponsorship is a non-issue — turn it off; the rest of the system works.
|
|
120
|
+
|
|
121
|
+
### Non-US markets
|
|
122
|
+
|
|
123
|
+
`portals.yml` ships with example shapes for Greenhouse / Ashby / Lever / Workday / Amazon
|
|
124
|
+
/ Google / generic Playwright. Drop in the boards relevant to your market. `modes/rubric.md`
|
|
125
|
+
+ `modes/negotiation_playbook.md` + `config/profile.yml` are all yours to localize
|
|
126
|
+
(language, comp ranges, geography priors).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Environment variables
|
|
131
|
+
|
|
132
|
+
| Var | Default | Purpose |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `MCP_JSA_PORT` | `7891` | HTTP port (MCP + file server + tracker dashboard) |
|
|
135
|
+
| `MCP_JSA_HOST` | `127.0.0.1` | Bind host |
|
|
136
|
+
| `MCP_JSA_PROJECT_ROOT` | cwd | Where `cv.md` / `config/profile.yml` / `portals.yml` live |
|
|
137
|
+
| `MCP_JSA_DATA_DIR` | `<install>/data` | SQLite + WAL location |
|
|
138
|
+
| `MCP_JSA_OUTPUT_DIR` | `<install>/output` | Rendered artifacts (PDFs, report HTML) |
|
|
139
|
+
| `MCP_JSA_VISA_SCORING` | `true` | Set `false` to drop visa surface entirely (see above) |
|
|
140
|
+
| `MCP_JSA_LLM_PROVIDER` | `gemini` | Used only by `api`/batch paths: `gemini`, `deepseek`, `none` |
|
|
141
|
+
| `MCP_JSA_LLM_MODEL` | _empty_ | Provider-specific model id |
|
|
142
|
+
| `GEMINI_API_KEY` / `DEEPSEEK_API_KEY` | _empty_ | Provider credentials |
|
|
143
|
+
| `MCP_JSA_SCHEDULER_ENABLED` | `false` | Whether opt-in cron runs at all |
|
|
144
|
+
|
|
145
|
+
A working starter is at `.env.example`.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Wiring it to Claude Desktop
|
|
150
|
+
|
|
151
|
+
`npx job_ops-mcp connect` prints the exact config block. The short version:
|
|
152
|
+
|
|
153
|
+
```jsonc
|
|
154
|
+
{
|
|
155
|
+
"mcpServers": {
|
|
156
|
+
"job_ops-mcp": {
|
|
157
|
+
"command": "npx",
|
|
158
|
+
"args": ["-y", "job_ops-mcp", "start"],
|
|
159
|
+
"env": {
|
|
160
|
+
"MCP_JSA_PORT": "7891",
|
|
161
|
+
"MCP_JSA_PROJECT_ROOT": "/absolute/path/to/your/job-search/dir"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
(Drop into `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS,
|
|
169
|
+
`%APPDATA%/Claude/claude_desktop_config.json` on Windows. Restart Claude Desktop.)
|
|
170
|
+
|
|
171
|
+
Generic MCP clients that take a streamable-HTTP URL: point them at
|
|
172
|
+
`http://127.0.0.1:7891/mcp` after `npx job_ops-mcp start` is running.
|
|
173
|
+
|
|
174
|
+
### LibreChat
|
|
175
|
+
|
|
176
|
+
`npx job_ops-mcp connect` also prints a `librechat.yaml` block. Two shapes:
|
|
177
|
+
|
|
178
|
+
- **LibreChat as a host process:** `type: streamable-http`, `url: http://127.0.0.1:7891/mcp`.
|
|
179
|
+
- **LibreChat in Docker:** swap to `http://host.docker.internal:7891/mcp` AND allowlist
|
|
180
|
+
the address under `mcpSettings.allowedAddresses` (LibreChat blocks private/internal
|
|
181
|
+
addresses by default as SSRF protection). On Linux, also add
|
|
182
|
+
`extra_hosts: ["host.docker.internal:host-gateway"]` to the LibreChat service in your
|
|
183
|
+
`docker-compose.yml`.
|
|
184
|
+
|
|
185
|
+
(Refs:
|
|
186
|
+
[librechat.ai/docs/.../mcp_servers](https://www.librechat.ai/docs/configuration/librechat_yaml/object_structure/mcp_servers),
|
|
187
|
+
[features/mcp](https://www.librechat.ai/docs/features/mcp).)
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Working `evaluate_job` payloads
|
|
192
|
+
|
|
193
|
+
### Step 1 — paste a JD or URL
|
|
194
|
+
|
|
195
|
+
```jsonc
|
|
196
|
+
{
|
|
197
|
+
"method": "tools/call",
|
|
198
|
+
"params": {
|
|
199
|
+
"name": "evaluate_job",
|
|
200
|
+
"arguments": {
|
|
201
|
+
"input": "https://jobs.ashbyhq.com/example/123",
|
|
202
|
+
"mode": "chat",
|
|
203
|
+
"title": "Builder PM",
|
|
204
|
+
"company": "Frontier AI Tools Co"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Returns the rubric, the report format, the active career packet, and a `job_id`. The
|
|
211
|
+
chat client uses those to score + draft the 6 blocks.
|
|
212
|
+
|
|
213
|
+
### Step 2 — finalize
|
|
214
|
+
|
|
215
|
+
```jsonc
|
|
216
|
+
{
|
|
217
|
+
"method": "tools/call",
|
|
218
|
+
"params": {
|
|
219
|
+
"name": "evaluate_job",
|
|
220
|
+
"arguments": {
|
|
221
|
+
"job_id": "<from step 1>",
|
|
222
|
+
"mode": "chat",
|
|
223
|
+
"report": {
|
|
224
|
+
"archetype_detected": "Agentic / LLMOps hybrid",
|
|
225
|
+
"block_role_summary": "…",
|
|
226
|
+
"block_cv_match": "…",
|
|
227
|
+
"block_level": "…",
|
|
228
|
+
"block_comp": "…",
|
|
229
|
+
"block_personalize": "…",
|
|
230
|
+
"block_interview": "…",
|
|
231
|
+
"block_legitimacy": "…",
|
|
232
|
+
"keywords": ["builder pm", "agentic workflows", "…"]
|
|
233
|
+
},
|
|
234
|
+
"scores": {
|
|
235
|
+
"resume_fit": 86, "taste_fit": 92, "visa_fit": 88, "score_total": 88,
|
|
236
|
+
"reasoning": "Strong match on agentic workflows + PRDs + SQL/Python.",
|
|
237
|
+
"concerns": "Evals experience is adjacent rather than LLM-eval-specific.",
|
|
238
|
+
"role_category": "pm",
|
|
239
|
+
"seniority": "senior"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Server persists, renders HTML at `/files/reports/<id>.html`, returns the URL.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Advanced / outreach features (optional)
|
|
251
|
+
|
|
252
|
+
### Importing your LinkedIn network → warm-intro finder
|
|
253
|
+
|
|
254
|
+
Download your LinkedIn data export (Settings → Data Privacy → Get a copy of your data →
|
|
255
|
+
Connections), then:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Through your MCP chat:
|
|
259
|
+
import_linkedin path="/absolute/path/to/Connections.csv"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Now `find_warm_intros(company="…")` returns the people you actually know who work there
|
|
263
|
+
(filtered to non-recruiters, sorted by engineering / leadership weight).
|
|
264
|
+
|
|
265
|
+
### Importing DOL OFLC H1B data → visa-friendliness signal
|
|
266
|
+
|
|
267
|
+
Download a quarterly LCA disclosure CSV from <https://www.dol.gov/agencies/eta/foreign-labor/performance>,
|
|
268
|
+
then:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
# Through your MCP chat:
|
|
272
|
+
import_h1b path="/absolute/path/to/LCA_Disclosure_Data_FY2025_Q1.csv"
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`visa_signal(company="…")` then returns a friendliness band (`strong | mixed | weak |
|
|
276
|
+
none`) computed from filings count + recency. **Internal only** — never surfaced in any
|
|
277
|
+
resume, cover letter, or outreach (see the visa hard rule).
|
|
278
|
+
|
|
279
|
+
If you disabled visa scoring (`MCP_JSA_VISA_SCORING=false`), these tools don't appear in
|
|
280
|
+
`tools/list` at all.
|
|
281
|
+
|
|
282
|
+
### Scheduler (opt-in cron)
|
|
283
|
+
|
|
284
|
+
Off by default. To run scans + batch rates on a schedule:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# In your MCP chat:
|
|
288
|
+
scheduler_enable jobs=["scan_portals_4h", "batch_evaluate_30m", "daily_digest_morning"]
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Job cadence is fixed (4h / 30m / hourly with an 8AM digest window). Toggle off with
|
|
292
|
+
`scheduler_disable`. Survives only as long as the server process is alive.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Hard rules baked in
|
|
297
|
+
|
|
298
|
+
1. **Never surface visa / work-auth** in any resume, cover letter, or outreach. Visa data
|
|
299
|
+
is internal scoring only.
|
|
300
|
+
2. **Never invent claims** not in `career_packet`. The materials generator validates LLM
|
|
301
|
+
output against the packet before persisting.
|
|
302
|
+
3. **Human-in-the-loop everywhere.** No tool auto-submits an application or auto-sends a
|
|
303
|
+
DM. `apply_prefill` is preview-only — it opens the form in Chromium, drafts values,
|
|
304
|
+
takes a screenshot, and stops. You submit manually.
|
|
305
|
+
4. **Strict-JSON parsing on the api path** with a recorded `PARSE_ERROR` fallback —
|
|
306
|
+
never silent zeros.
|
|
307
|
+
5. **Tracker / application / outreach writes are serialized** behind a single write lock.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Layout
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
job_ops-mcp/
|
|
315
|
+
├── modes/ # MCP resources (edit me to tune the brain)
|
|
316
|
+
├── templates/ # CV HTML/LaTeX templates + cover-letter template
|
|
317
|
+
├── fonts/ # Space Grotesk, DM Sans (woff2 subsets)
|
|
318
|
+
├── cv.example.md # → cv.md after init
|
|
319
|
+
├── config/profile.example.yml # → config/profile.yml after init
|
|
320
|
+
├── portals.example.yml # → portals.yml after init
|
|
321
|
+
├── src/ # TypeScript source (not published)
|
|
322
|
+
│ ├── cli.ts # init / start / doctor / connect
|
|
323
|
+
│ ├── server.ts # HTTP + MCP boot
|
|
324
|
+
│ ├── core/ # llm, providers, jobs, reports, render, scan_engine, …
|
|
325
|
+
│ ├── http/ # express app + dashboard
|
|
326
|
+
│ ├── mcp/ # define + register + tools/
|
|
327
|
+
│ └── migrations/*.sql # SQLite migrations
|
|
328
|
+
└── data/, output/ # gitignored runtime state
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Attribution
|
|
334
|
+
|
|
335
|
+
- The HTML CV template, font set, and ATS unicode-normalization logic are ported from
|
|
336
|
+
[santifer/career-ops](https://github.com/santifer/career-ops) (MIT licensed). The
|
|
337
|
+
6-block A–F report shape, scoring rubric framing, and outreach tone rules are also
|
|
338
|
+
inspired by that project. **Not affiliated with or endorsed by career-ops** — this is
|
|
339
|
+
an independent fork of those publicly-released ideas into the MCP transport.
|
|
340
|
+
- The 3-dimension scoring formula (resume / taste / visa), the schema shape
|
|
341
|
+
(companies / jobs / outreach / enrichment / career_packet views), and the strict-JSON
|
|
342
|
+
rater rubric are distilled from a personal pipeline ("JSA") that predates this
|
|
343
|
+
project.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Releasing (maintainer notes)
|
|
348
|
+
|
|
349
|
+
Releases ship to npm via the GitHub Actions workflow at
|
|
350
|
+
[`.github/workflows/publish.yml`](.github/workflows/publish.yml). The workflow fires
|
|
351
|
+
**only on pushing a version tag** (`v*.*.*`) — never on a push to `main` — so merging
|
|
352
|
+
work never auto-publishes.
|
|
353
|
+
|
|
354
|
+
### One-time setup
|
|
355
|
+
|
|
356
|
+
1. **Generate an npm automation token** at [npmjs.com](https://www.npmjs.com/) →
|
|
357
|
+
click your avatar → **Access Tokens** → **Generate New Token** → choose
|
|
358
|
+
**"Automation"** (NOT *Read-Only* and NOT *Publish*; Automation tokens bypass 2FA,
|
|
359
|
+
which CI needs).
|
|
360
|
+
2. **Add it to GitHub.** In the repo → **Settings** → **Secrets and variables** →
|
|
361
|
+
**Actions** → **New repository secret** → name **`NPM_TOKEN`**, value the token
|
|
362
|
+
you just copied (starts with `npm_`).
|
|
363
|
+
|
|
364
|
+
### Cutting a release
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
# 1. Bump the version in package.json. Either edit by hand, or:
|
|
368
|
+
npm version patch # 0.3.0 → 0.3.1 (also creates a git commit + tag)
|
|
369
|
+
# npm version minor # 0.3.0 → 0.4.0
|
|
370
|
+
# npm version major # 0.3.0 → 1.0.0
|
|
371
|
+
|
|
372
|
+
# 2. If you edited package.json by hand instead of `npm version`, commit it:
|
|
373
|
+
# git add package.json && git commit -m "release: vX.Y.Z"
|
|
374
|
+
# git tag vX.Y.Z
|
|
375
|
+
|
|
376
|
+
# 3. Push the commit + tag.
|
|
377
|
+
git push && git push origin vX.Y.Z
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
That tag push triggers `publish.yml`, which:
|
|
381
|
+
|
|
382
|
+
1. Checks out the tagged commit.
|
|
383
|
+
2. Sets up Node 20 with the npm registry.
|
|
384
|
+
3. Verifies the tag (`vX.Y.Z`) matches `package.json`'s `version` — fails fast on a typo.
|
|
385
|
+
4. `npm ci` + `npm run build`.
|
|
386
|
+
5. `npm publish --access public --provenance` — provenance attaches a sigstore
|
|
387
|
+
attestation visible on npmjs.com showing exactly which GitHub Actions run produced
|
|
388
|
+
the tarball.
|
|
389
|
+
|
|
390
|
+
Watch progress in the repo's **Actions** tab. On success the new version appears on
|
|
391
|
+
[npmjs.com/package/job_ops-mcp](https://www.npmjs.com/package/job_ops-mcp).
|
|
392
|
+
|
|
393
|
+
## Contributing / feedback
|
|
394
|
+
|
|
395
|
+
Issues + PRs welcome. There's no contributor guide yet — open an issue first if you're
|
|
396
|
+
planning a large change.
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# job_ops-mcp profile configuration.
|
|
2
|
+
#
|
|
3
|
+
# Copy to `config/profile.yml` (or let `npx job_ops-mcp init` do it) and fill in your
|
|
4
|
+
# details. This is the source of truth for your identity + targeting + comp/location
|
|
5
|
+
# preferences. The chat reads it via the rubric + career_packet resources.
|
|
6
|
+
|
|
7
|
+
candidate:
|
|
8
|
+
full_name: "<Your Full Name>"
|
|
9
|
+
email: "<you@example.com>"
|
|
10
|
+
phone: "<+country area-number>"
|
|
11
|
+
location: "<City, State / Country>"
|
|
12
|
+
linkedin: "linkedin.com/in/<your-handle>"
|
|
13
|
+
portfolio_url: "https://<your-portfolio>"
|
|
14
|
+
github: "github.com/<your-handle>"
|
|
15
|
+
twitter: "" # optional
|
|
16
|
+
|
|
17
|
+
target_roles:
|
|
18
|
+
# Your North-Star roles — what you're optimizing for.
|
|
19
|
+
primary:
|
|
20
|
+
- "<role title 1>"
|
|
21
|
+
- "<role title 2>"
|
|
22
|
+
# Archetypes drive scoring (`role_category`) + tailoring per JD.
|
|
23
|
+
# fit values: primary | secondary | adjacent
|
|
24
|
+
archetypes:
|
|
25
|
+
- { name: "<archetype label, e.g. AI/ML Engineer>", level: "Senior", fit: "primary" }
|
|
26
|
+
- { name: "<archetype label, e.g. Technical PM>", level: "Senior/Staff",fit: "secondary" }
|
|
27
|
+
- { name: "<archetype label, e.g. Forward-Deployed>",level: "Mid-Senior", fit: "adjacent" }
|
|
28
|
+
|
|
29
|
+
narrative:
|
|
30
|
+
# One-line professional headline.
|
|
31
|
+
headline: "<your one-line headline>"
|
|
32
|
+
# Two-sentence story about what makes you uniquely hireable.
|
|
33
|
+
exit_story: "<your story>"
|
|
34
|
+
# Top 3–5 differentiators (used in score reasoning + outreach hooks).
|
|
35
|
+
superpowers:
|
|
36
|
+
- "<superpower 1>"
|
|
37
|
+
- "<superpower 2>"
|
|
38
|
+
- "<superpower 3>"
|
|
39
|
+
# The 2–4 things that excite you (used in taste_fit scoring).
|
|
40
|
+
likes:
|
|
41
|
+
- "<like 1, e.g. 'lean teams, fast iteration, AI/data tooling'>"
|
|
42
|
+
- "<like 2>"
|
|
43
|
+
# The dislikes that should drop taste_fit below 50.
|
|
44
|
+
dislikes:
|
|
45
|
+
- "<dislike 1, e.g. 'legacy Java enterprise modernization'>"
|
|
46
|
+
- "<dislike 2>"
|
|
47
|
+
# Proof points — projects/articles/case studies with measurable impact.
|
|
48
|
+
proof_points:
|
|
49
|
+
- { name: "<project name>", url: "<url>", hero_metric: "<short hero-metric phrase>" }
|
|
50
|
+
- { name: "<project name>", url: "<url>", hero_metric: "<...>" }
|
|
51
|
+
|
|
52
|
+
compensation:
|
|
53
|
+
target_range: "<currency-min – currency-max>" # e.g. "$130K-180K"
|
|
54
|
+
currency: "USD"
|
|
55
|
+
minimum: "<walk-away number>"
|
|
56
|
+
location_flexibility: "<e.g. 'Remote preferred; 1 week/month on-site possible'>"
|
|
57
|
+
|
|
58
|
+
location:
|
|
59
|
+
country: "<country>"
|
|
60
|
+
city: "<city>"
|
|
61
|
+
timezone: "<TZ abbr, e.g. PST>"
|
|
62
|
+
visa_status: "<e.g. 'No sponsorship needed' or 'On OPT, need H1B sponsorship'>"
|
|
63
|
+
# Optional. If your target locations differ from `city`, list them here.
|
|
64
|
+
onsite_availability: ""
|
|
65
|
+
|
|
66
|
+
cv:
|
|
67
|
+
output_format: "html" # "html" (default) or "latex"
|
package/cv.example.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# CV — <Your Full Name>
|
|
2
|
+
**Location:** <City, State / Country> (open to <relocation policy>)
|
|
3
|
+
**Email:** <you@example.com>
|
|
4
|
+
**Phone:** <+country area-number>
|
|
5
|
+
**LinkedIn:** linkedin.com/in/<your-handle>
|
|
6
|
+
**GitHub:** github.com/<your-handle>
|
|
7
|
+
**Portfolio:** <your-portfolio-url>
|
|
8
|
+
|
|
9
|
+
## Professional Summary
|
|
10
|
+
<2–3 sentences. State your specialism, the size/shape of the work you've owned, and the
|
|
11
|
+
hybrid skillset that makes you hire-able for the roles you actually want. Keep it
|
|
12
|
+
concrete — name systems, scopes, and one or two outcomes.>
|
|
13
|
+
|
|
14
|
+
## Work Experience
|
|
15
|
+
|
|
16
|
+
### <Company> — <Role Title>
|
|
17
|
+
<Location / Remote> · <Start Mon YYYY> – <End Mon YYYY or Present>
|
|
18
|
+
Products owned: <comma-separated list, optional>.
|
|
19
|
+
- <One-sentence bullet, action verb start, ~15–25 words, real metric inline.>
|
|
20
|
+
- <Second bullet — different verb, different shape of impact.>
|
|
21
|
+
- <Third bullet — emphasise scope (people / systems / dollars).>
|
|
22
|
+
- <Fourth bullet — emphasise a hard-to-mimic technical/product skill.>
|
|
23
|
+
- <Fifth bullet — emphasise a cross-functional or leadership thread.>
|
|
24
|
+
|
|
25
|
+
### <Earlier Company> — <Role>
|
|
26
|
+
<Location> · <Mon YYYY> – <Mon YYYY>
|
|
27
|
+
- <Bullet.>
|
|
28
|
+
- <Bullet.>
|
|
29
|
+
- <Bullet.>
|
|
30
|
+
|
|
31
|
+
### <Earliest Company> — <Role>
|
|
32
|
+
<Location> · <Mon YYYY> – <Mon YYYY>
|
|
33
|
+
- <Bullet.>
|
|
34
|
+
- <Bullet.>
|
|
35
|
+
|
|
36
|
+
## Projects & Open Source
|
|
37
|
+
|
|
38
|
+
- **<Project name>** (Open source / Personal / Academic) — <one-sentence description with
|
|
39
|
+
the credibility marker; stack named explicitly>. <github.com/you/repo or link>
|
|
40
|
+
- **<Project name>** — <description>. <link if public>
|
|
41
|
+
- **<Project name>** — <description>.
|
|
42
|
+
|
|
43
|
+
## Education
|
|
44
|
+
- **<Degree>**, <Institution> — <year range>. <optional 1-line coursework / honors>
|
|
45
|
+
- **<Earlier degree>**, <Institution> — <year range>.
|
|
46
|
+
|
|
47
|
+
## Skills
|
|
48
|
+
- **AI / LLM Systems:** <list>
|
|
49
|
+
- **Data & Analytics Engineering:** <list>
|
|
50
|
+
- **Infrastructure & DevOps:** <list>
|
|
51
|
+
- **Product:** <list>
|
|
52
|
+
- **Web & Tools:** <list>
|
|
53
|
+
- **Languages:** <primary first>
|