内容
# jobops
一个自托管的 **Model Context Protocol** 服务器,用于整个求职循环——门户扫描、职位评估、量身定制的简历和求职信PDF、拓展草稿、故事库、谈判简报——所有这些都由您的MCP感知聊天客户端驱动(Claude Desktop、Cursor、任何支持流式HTTP MCP的客户端)。
聊天是核心。这个服务器执行机械工作,并将每个工件作为 `http://localhost:7891/...` 链接返回。
> **状态:** 早期。有效。API可能仍在1.0版本之前发生变化。
---
## 快速入门
```bash
# 1. 为工作目录搭建(cv.md、profile.yml、portals.yml、modes/*.md + SQLite DB)
npx @mohith_das/jobops init
# 2. 打开 cv.md、config/profile.yml、portals.yml 并替换每个 <TODO> 占位符。
# (可选:调整 modes/*.md — 评分标准、定制规则、拓展语气 — 您的编辑生效。)
# 3. 从您实际的 cv.md 重建 career_packet
# (或者只需重新运行 `init` — 它在检测到 cv.md 更改时自动重新初始化)
npx @mohith_das/jobops reseed
# 4. 确认所有内容都已连接
npx @mohith_das/jobops doctor
# 5. 启动服务器(Chromium 在首次运行时自动安装)
npx @mohith_das/jobops start
# ▷ jobops 监听 http://127.0.0.1:7891
# 6. 获取 MCP 客户端的复制粘贴配置块
npx @mohith_das/jobops connect
# 7. 在聊天中粘贴工作网址或职位描述 — 聊天调用 evaluate_job,根据
# 您的评分标准 + career_packet + 定制规则,并完成其余的工作流程。
```
这就是循环。其他所有功能(暖介绍查找器、故事库、谈判简报、批量评分器、调度器等)都已连接但可选。
### 编辑 career packet — 两个安全方向
您的 `career_packet` 是聊天用于评估职位和草拟材料的事实来源。您可以从 **两个方向** 进行编辑,并且 **两个方向都不会无声地破坏对方** — 两个方向都是显式的:
**1. 聊天驱动(packet 是您的编辑界面)。** 请聊天更改标语、删除项目、收紧子弹 — 它调用 `update_career_packet`,它写入新版本并 **标记 packet 为用户编辑**。从那时起,普通的 `reseed` 将 **拒绝** 覆盖它(它会警告并告诉您传递 `force` 或同步首先)。章节编辑符合人体工程学 — “更改我的标语” 只会重新发送第 2 节,而不是整个 packet:
```text
update_career_packet section="2" section_content='- **Builder PM** — "ships product with engineering teeth"'
```
对于外科手术级别的 **项目级别** 更改,有 `edit_packet_item` / `remove_packet_item` — 地址一个章节(`projects`、`skills`、`taglines` 或编号)和一个项目(按索引或匹配子字符串)以更改或删除单个子弹/项目/技能/标语而不触及其余部分。每次更改仍然版本化 packet,并且 `edit_packet_item` 运行新的文本的签证泄漏扫描。`remove_packet_item` 回应它删除的内容。 由于每次更改都是一个版本,**没有任何内容真正丢失** — `restore_packet_version` 列出历史并恢复任何以前的版本(恢复本身是可逆的)。
**2. 文件驱动(cv.md / profile.yml 是源)。** 编辑 `cv.md` / `config/profile.yml`,然后 **reseed** 以从它们重建 packet:
```bash
npx @mohith_das/jobops reseed # 安全:拒绝如果 packet 有聊天编辑不在 cv.md 中
npx @mohith_das/jobops reseed --force # 从 cv.md 重建 packet(丢弃聊天编辑)
```
**将两者恢复同步。** 当您在聊天中编辑并希望 `cv.md` 赶上时,运行 `sync_packet_to_cv` — 它将 packet 写回 `cv.md` + `profile.yml`,以便源文件反映您的聊天编辑(稍后 `reseed` 将复制它们而不是覆盖它们)。因此,两个方向是对称的:**reseed**(cv.md → packet)和 **sync-back**(packet → cv.md),两者都是显式的,都不是自动的。
`reseed` 写入一个新的活动版本(以前的降级,历史记录保留)。`doctor` 在 packet 被聊天编辑(预期 — 不是通知)与 `cv.md` 更改下的文件驱动 packet 时报告。
---
## 它做什么
两个系统合并为一个MCP服务器:
- **评估 + 材料方面** — [santifer/career-ops](https://github.com/santifer/career-ops) 的端口:6块A-F(+ G合法性)报告,原型检测,ATS友好HTML→PDF简历+求职信生成,故事库,谈判剧本。
- **管道方面** — 个人Postgres + n8n管道(“JSA”)的端口:Greenhouse / Ashby / Lever / Workday轮询器+封闭板Playwright爬虫,内容哈希去重,批量LLM评分器,暖介绍/创始人DM草稿,签证信号来自DOL OFLC H1B数据。
所有内容都存在于单个Node进程中,带有单个SQLite文件。无需外部Postgres,无需n8n,无需云服务。如果您想使用API/批量路径,请自带LLM密钥(默认情况下为Gemini免费层,可选DeepSeek)。聊天模式工具无需密钥即可工作。
> **与santifer的career-ops无关联或背书。** 该项目是独立的,它移植并适配了公开发布的MIT许可模板和评分标准形状到MCP传输表面。参见 [Attribution](#attribution) 部分。
---
## 工具(58 — 一个MCP `tools/list` 调用)
| 分组 | 工具 |
|---|---|
| **评估** | `evaluate_job`、`batch_evaluate`、`get_top_jobs`、`evaluate_training`、`evaluate_project` |
| **材料** | `generate_materials`、`render_pdf`(PDF / `.tex` / `.docx`)、`get_report` |
| **跟踪器** | `get_tracker`、`update_status`、`mark_ready_to_apply`、`delete_jobs`(软删除 → 垃圾箱)、`restore_jobs`、`list_trashed`、`purge_jobs`(永久,备份优先) |
| **来源** | `scan_portals`(Greenhouse + Ashby + Lever + Workday + Amazon + Google + generic Playwright) |
| **外联** | `find_warm_intros`、`find_founders`、`draft_outreach`、`draft_followup`、`draft_reply`、`get_outreach_queue`、`update_outreach`、`get_followups_due` |
| **联系人** | `add_contacts`(从聊天中插入)、`export_contacts`(CSV+JSON备份)、`import_contacts`(合并,非破坏性)、`delete_contacts`(软删除,可恢复) |
| **面试 / Offer** | `extract_stories`、`get_story_bank`、`negotiation_brief` |
| **研究** | `deep_research`、`enrich_company`、`daily_digest` |
| **个人资料 + 操作** | `get_career_packet`、`update_career_packet`(整个文档)、`edit_packet_item` / `remove_packet_item`(单个子弹/项目/技能/标语)、`restore_packet_version`(历史记录 + 恢复)、`reseed_career_packet`(默认安全)、`sync_packet_to_cv`、`update_profile`(询问)、`cost_estimate`、`doctor`(只读健康检查) |
| **联合** | `compile_career_packet`、`get_career_packet_json`(公共安全)、`sync_to_livingcv`、`generate_embeddings`、`get_embeddings`、`broadcast_signal`、`get_federation_status`、`update_jobops` |
| **申请(仅预览 - 永远不会提交)** | `apply_prefill` |
| **签证(可选,可以隐藏)** | `visa_signal`、`import_h1b`、`import_linkedin` |
| **调度器(可选cron,默认关闭)** | `scheduler_status`、`scheduler_enable`、`scheduler_disable` |
六个MCP **资源** 携带可编辑的行为 — 评分标准、报告格式、定制规则、外联语气、谈判剧本、职业包 — 所有这些都从 `modes/*.md` 加载并在编辑时重新加载。无需触摸代码即可调整评分或语气。
> **提示:** 随时询问聊天运行 **`doctor`** — 它是一个只读的健康报告(与 `npx @mohith_das/jobops doctor` CLI命令相同),涵盖packet ↔ cv.md同步状态、LLM提供者/密钥、采样+身份验证姿势、活动模板、模式、签证评分和公共基URL。 在不离开聊天的情况下,检查服务器是否正确连接。
---
## 垃圾和恢复(工作)
工作遵循与联系人和职业包相同的非破坏性、可恢复、删除前回声的哲学。 **软删除是默认值;硬删除始终是显式、确认和备份优先的。**
- **`delete_jobs`** 将1..N个工作移到 **垃圾箱**(按 `job_ids` 和/或按 `statuses` — 例如,将所有处于 `skip`/`discard`/`sourced`状态的工作放入垃圾箱)。被放入垃圾箱的工作将从跟踪器、`get_top_jobs`和批量评分中删除,但 **保留并可恢复**。它会准确回声哪些工作(标题+公司)被放入垃圾箱。这是可恢复的 — *不是* 硬删除。
- **`list_trashed`** 显示当前垃圾箱中的内容(标题、公司、评分、之前的状态、放入垃圾箱的时间),以便您在永久删除或恢复之前查看。
- **`restore_jobs`** 将被放入垃圾箱的工作恢复到其之前的状态。
- **`purge_jobs`** 是唯一的硬删除:它永久删除 **被放入垃圾箱** 的工作(永远不会是活跃的工作)。传递 `job_ids`,或 `purge_all: true`(需要 `confirm: true`)。在删除前,会在项目根目录中写入受影响行的 **时间戳备份**;它会准确回声哪些内容被永久删除。
**在跟踪器UI**( `/` )中,**状态**单元格是一个内联下拉菜单(原位编辑),每行都有一个紧凑的 **垃圾箱** 按钮(软删除;该行离开,摘要卡更新)。一个专用的 **[/trash](/trash)** 页面列出了被放入垃圾箱的工作,您可以在此处 **恢复** 项目、**永久删除** 项目(带有确认对话框),或 **清空垃圾箱**(一个明确警告的不可逆硬删除 — 无论如何都会写入备份)。
---
## 过滤、搜索和分页(跟踪器)
在1000+个工作时,跟踪器不会将所有行发送到浏览器 — 它会 **服务器端分页**(SQL `WHERE`/`LIMIT`/`OFFSET` + `COUNT`,从不内存)。 `/` 仪表板有:
- **过滤器(可组合):** 多选 **状态**、**最小/最大评分**、**公司**(包含,带有当前公司的datalist)、**角色** 和 **级别**,以及一个 **显示已放入垃圾箱** 的切换按钮。
- **搜索:** **标题或公司** 的延迟、不区分大小写的子字符串搜索。
- **分页:** 每页大小选择器(25/50/100,默认为50),第一/上一/下一/最后一页跳转,以及“N匹配 · 显示X-Y”的指示器。
- **排序:** 点击 **评分 / 公司 / 发现** 表头(默认为评分↓)。
- **可分享的URL:** 每个过滤器/排序/页面都在查询字符串中(`/?status=applied&min_score=70&q=engineer&sort=score&page=2`)— 可收藏且刷新后仍然有效。
- **摘要卡保持真实总数** — 整个活动管道,独立于当前过滤器/页面。内联状态编辑和放入垃圾箱在过滤/分页视图中仍然有效(行更新/离开,计数刷新不会丢失位置)。
**相同的查询为 `get_tracker` MCP工具提供支持**,因此聊天可以询问切片 — 例如。 *"显示我评分超过70且标题中包含'engineer'的已申请工作。"* `get_tracker` 接受 `statuses[]`、`min_score`/`max_score`、`company`、`role_category`、`seniority`、`q`、`sort`、`dir`、`limit`、`offset` 和 `show_trashed`,并返回 `items` + `total_matching` + 全管道 `counts_by_status`。
---
## 无LLM密钥的评分 — 如果您的客户端支持MCP采样
如果您的 **连接的客户端** 支持 **MCP采样**,则可以仅使用客户端的模型运行 `batch_evaluate`、`evaluate_job` 模式=“api”)的评分工具 — 相同的评分标准,相同的严格JSON合同,**无需单独的Gemini/DeepSeek密钥** — **但前提是连接的客户端在其初始化握手期间声明`sampling`功能**。
> ⚠️ **大多数客户端不支持(直到现在)— 包括Claude Desktop。** Claude Desktop仅声明其UI扩展,从不声明`sampling`。传输(stdio vs HTTP)**本身不足以** — 这是每个客户端的**功能**。因此,在Claude Desktop和类似客户端上,批量/ API评分 **会回落到您自带的密钥**(`JOBOPS_LLM_PROVIDER` + 密钥),这是预期且正确的。检查 [modelcontextprotocol.io/clients](https://modelcontextprotocol.io/clients)上的当前支持。
- **如果(并且仅当)采样功能支持的客户端连接时,它会自动启用** — 无需配置。网关检查客户端声明的`sampling`功能 **和** 传输可以承载服务器→客户端请求(stdio;无状态HTTP传输不能,所以它甚至不尝试)。当采样不可用时,评分使用您自带的密钥;如果您未设置密钥,`evaluate_job mode="chat"`(默认)仍然有效 — 您的聊天直接评分它。回落是干净的(不会卡住)。
- **Claude Desktop用户的结论:** 为 `batch_evaluate` / `evaluate_job mode="api"` 设置 `JOBOPS_LLM_PROVIDER` + 匹配的密钥。(普通 `mode="chat"` 不需要密钥。)
- **成本。** 当使用采样时,它在客户端的模型上运行,因此成本由 **客户端承担**;`cost_estimate` 记录那些标记为客户端承担的调用($0 服务器成本)。
- 运行 `doctor` 工具查看 **实时** 状态 — 它报告您的当前客户端是否声明了采样,或者您正在使用自带密钥路径。
- 设置 `JOBOPS_SAMPLING=false` 以强制使用自带密钥路径,即使采样可用。
## 无缝个人资料设置(MCP询问)
`update_profile` 使用 **MCP询问** (表单模式),因此您的客户端可以收集身份字段 + 按原型标语 — 通过结构化表单 — 无需手动编辑YAML。接受后,它写入 `config/profile.yml` 并在一步中为职业包重新初始化。
敏感输入(您的LinkedIn导出路径、凭证)使用 **URL模式询问**(2025-11-25):服务器为您提供一次性本地URL,您可以直接在那里输入值,因此它 **永远不会通过MCP客户端 / 聊天记录传递**。`import_linkedin` 在您省略 `path` 且您的客户端支持时使用此功能。
两个功能都是功能和传输门控(就像采样一样,询问是服务器→客户端请求,需要stdio连接)。不支持询问的客户端 — 以及所有HTTP客户端 — 回落到基于文件 + 参数路径(`update_profile fields=…`,编辑 `config/profile.yml`,传递 `import_linkedin path=…`),它们与以前一样工作。
---
## 设计为您的定制版本
默认值假设您的位置、国籍、角色或行业。每个 **行为塑造部分都是一个markdown文件,您可以重写**。 **`init` 将它们复制到 `<project-root>/modes/`,所以它们是您的编辑副本** — 加载程序读取您的项目根目录副本,然后回落到捆绑的默认值,因此您永远不会触摸包安装。重新 `init` 不会覆盖已编辑的副本(它会警告并保留您的编辑); `doctor` 报告哪些文件是用户重写 vs 捆绑。
| 您可以更改… | 通过编辑… |
|---|---|
| 评分维度 + 权重 | `modes/rubric.md` |
| 6块报告形状 | `modes/report_format.md` |
| 简历/求职信定制规则 | `modes/tailoring_rules.md` |
| 外联语气 + 字符上限 | `modes/outreach_tone.md` |
| 谈判脚本 + 框架 | `modes/negotiation_playbook.md` |
| 您的项目库 | `modes/career_packet.md` (或通过 `update_career_packet` )
| 每种原型标语 | `config/profile.yml` → `taglines:` (自动填充职业包第2节) |
| 跟踪的公司 + 过滤器 | `portals.yml` |
| 身份 + 角色目标 | `config/profile.yml` |
### 非美国用户 / 非赞助案例
签证评分是 **完全可选的**。设置:
```bash
export JOBOPS_VISA_SCORING=false
```
当关闭时:
- `score_total = round(0.6 · resume_fit + 0.4 · taste_fit)` (服务器端权威)
- `visa_signal`、`import_h1b`、`import_linkedin` 工具从 `tools/list` 中隐藏
- `score_visa_fit` 从 `get_top_jobs` 项中删除以及评估报告HTML徽章
- 评分资源获得“签证评分已禁用”覆盖前缀,聊天会读取
其他功能不受影响。如果您是美国公民、非美国用户或任何人都在评估没有赞助的角色 — 关闭它;其余部分正常工作。
### 非美国市场
`portals.yml` 配备了Greenhouse / Ashby / Lever / Workday / Amazon / Google / generic Playwright示例。添加您所在市场的相关板块。`modes/rubric.md` + `modes/negotiation_playbook.md` + `config/profile.yml` 都是您可以本地化的(语言,薪酬范围,地理优先事项)。
---
## 环境变量
| 变量名 | 默认值 | 用途 |
|---|---|---|
| `JOBOPS_PORT` | `7891` | HTTP端口(MCP + 文件服务器 + 跟踪器仪表盘) |
| `JOBOPS_HOST` | `127.0.0.1` | 绑定主机 |
| `JOBOPS_PROJECT_ROOT` | 当前工作目录 | `cv.md` / `config/profile.yml` / `portals.yml` 存放位置 |
| `JOBOPS_DATA_DIR` | `<安装目录>/data` | SQLite + WAL 位置 |
| `JOBOPS_OUTPUT_DIR` | `<安装目录>/output` | 渲染后的制品(PDF、报告HTML) |
| `JOBOPS_VISA_SCORING` | `true` | 设置为 `false` 以完全删除签证表面(参见上文) |
| `JOBOPS_TEMPLATE_DIR` | 空 | 用户拥有的额外简历/求职信主题目录 - 覆盖同名捆绑主题。参见 [自定义主题](#自定义主题) + [`TEMPLATES.md`](./TEMPLATES.md)。 |
| `JOBOPS_DEFAULT_TEMPLATE` | `default` | `render_pdf` 没有显式 `template` 参数时使用的主题。 |
| `JOBOPS_PUBLIC_BASE_URL` | 空 | 工件链接中发出的公共URL。默认:`http://127.0.0.1:<端口>`。在远程主机上运行时设置(Tailscale、LAN等)- 参见 [在远程主机上运行](#在远程主机上运行--tailscale)。 |
| `JOBOPS_AUTH_TOKEN` | 空 | `/mcp`、`/files/*` 和仪表盘的 bearer token。**必填** 以绑定到localhost以外的任何地址 - 没有它,非localhost绑定拒绝启动(默认拒绝)。参见 [安全模型](#安全模型)。 |
| `JOBOPS_SAMPLING` | `true` | 为 `api`/批量评分使用MCP采样 **当连接的客户端宣传时** (大多数客户端不宣传 - 然后使用自带密钥)。设置为 `false` 以始终使用自带密钥。 |
| `JOBOPS_LLM_PROVIDER` | `gemini` | `api`/批量评分的自带密钥路径 - 客户端不支持采样时使用(常见情况):`gemini`、`deepseek`、`none` |
| `JOBOPS_LLM_MODEL` | 空 | 提供者特定的模型ID |
| `GEMINI_API_KEY` / `DEEPSEEK_API_KEY` | 空 | 提供者凭证 - 除非客户端支持MCP采样(大多数不支持;`mode="chat"` 从不需要密钥) |
| `JOBOPS_SCHEDULER_ENABLED` | `false` | 是否启用选择加入的cron运行 |
| `JOBOPS_LIVINGCV_URL` | 空 | LivingCV基准URL(无默认值 - 设置为已部署的LivingCV,例如 `https://jobs.example.com`) |
| `JOBOPS_LIVINGCV_TOKEN` | 空 | LivingCV **主中继** bearer密钥(管理员 → 设置 → MCP → `mcp.master_key`) |
| `JOBOPS_HIREBRIDGE_URL` | `https://api.hirebridge.io` | HireBridge中央路由器基准URL,用于信号广播 |
| `JOBOPS_HIREBRIDGE_TOKEN` | 空 | HireBridge的bearer token(由 `connect_to_hirebridge` 设置) |
| `JOBOPS_HIREBRIDGE_EMAIL` | 空 | 与HireBridge连接关联的电子邮件 |
| `JOBOPS_EMBEDDING_PROVIDER` | `local` | 嵌入提供者:`local`(全MiniLM-L6-v2 via `@xenova/transformers`)、`openai`、`voyage`、`none` |
| `JOBOPS_EMBEDDING_MODEL` | `all-MiniLM-L6-v2` | 嵌入提供者的模型名称 |
| `OPENAI_API_KEY` / `VOYAGE_API_KEY` | 空 | OpenAI / Voyage嵌入提供者的凭证 |
`.env.example` 中有一个可用的启动器。
---
## 运行一个服务器,使用所有客户端
推荐的多客户端拓扑结构:**一个长期运行的HTTP服务器 = 一个真实数据源。** 启动它一次,将所有接口指向它:
```bash
npx @mohith_das/jobops start # HTTP模式 - 支持多个并发MCP客户端
npx @mohith_das/jobops connect # 打印每个客户端的配置信息
```
所有客户端都连接到同一个 `http://127.0.0.1:7891/mcp`(或Tailscale主机:端口 - 参见 [在远程主机上运行](#在远程主机上运行--tailscale))。在**任何**客户端中进行物料、跟踪器移动、联系人、数据包编辑后,所有其他客户端都能立即看到这些变化,因为只有一个进程和一个SQLite数据库在它们后面。
| 客户端 | 配置(均由 `connect` 打印) |
|---|---|
| **Claude 代码** | `claude mcp add --transport http jobops <url>` 或 `.mcp.json`(`"type": "http"`) |
| **Claude 桌面版** | `mcp-remote` 桥接在 `claude_desktop_config.json`(stdio→HTTP),或付费计划的自定义连接器 |
| **opencode** | `opencode.json` → `"mcp": { … "type": "remote", "url": … }` |
| **codex** | `~/.codex/config.toml` → `[mcp_servers.jobops]` 包含 `url` + `bearer_token_env_var` |
| **gemini-cli** | `~/.gemini/settings.json` → `"httpUrl"` + `"headers"` |
| **LibreChat** | `librechat.yaml` → `type: streamable-http`(参见下面的Docker) |
| **Web UI / 浏览器** | 仪表盘在 `/` 与同一个服务器、同一个数据库 |
> **已知问题(mcp-remote × Node ≥ 26):** `mcp-remote`(≤ 0.1.38)在Node 26+上失败,出现 `StreamableHTTPError: Unexpected content type: null` - 其捆绑的undici `EnvHttpProxyAgent`全局调度器剥夺了Node内置`fetch`的响应头。服务器的响应是规范正确的;桥接器在客户端修改了它们。直到修复,在Node ≤ 24上运行桥接器:用绝对路径替换`"command": "npx"`,并将参数指向Node 24安装的`mcp-remote`(`npm i -g mcp-remote` 在该Node下)。
并发安全性设计上是安全的:每个HTTP请求都获得一个隔离的MCP协议实例,读取操作并发运行(SQLite WAL),**所有写入操作通过一个写入锁** 在单个服务器进程中序列化 - 多客户端负载下无损坏,无需每个客户端启动,无端口冲突。
通过以下命令验证所有内容是否都连接到同一个实例:
```bash
npx @mohith_das/jobops status # 运行时、数据源DB路径 + 指纹、启动后看到的客户端(根据需要添加 --url / --token)
```
`doctor` 工具从任何聊天客户端报告相同的服务器身份块。
**身份验证:** 服务器一旦可从localhost以外访问(Tailscale / LAN / 始终在线的盒子),您**必须**设置 `JOBOPS_AUTH_TOKEN` - 它为每个连接的端点提供PII(简历、联系人、H1B数据),并且如果没有它,远程绑定拒绝启动(参见 [安全模型](#安全模型))。然后,令牌进入每个客户端的配置中;`connect`在设置环境变量时自动嵌入它。
---
## 将其连接到Claude Desktop(stdio传输)
**单客户端替代方案。** 这在Claude Desktop内部启动了一个**私有**服务器,而不是连接到共享服务器 - 当Claude Desktop是您的唯一客户端时可以正常使用。对于上面的共享拓扑结构,请使用 `connect`打印的 `mcp-remote` 桥接器。(下一个stdio实例需要自己的 `JOBOPS_PORT`,否则HTTP文件服务器内部会失败,出现 `EADDRINUSE`。)
Claude Desktop的本地MCP仅支持 **stdio**,不支持HTTP。使用 `--stdio` 标志:
```jsonc
{
"mcpServers": {
"jobops": {
"command": "npx",
"args": ["-y", "jobops", "start", "--stdio"],
"env": {
"JOBOPS_PORT": "7891",
"JOBOPS_PROJECT_ROOT": "/绝对路径/到/您的/求职/目录"
}
}
}
}
```
(放入 `~/Library/Application Support/Claude/claude_desktop_config.json` 在macOS上,`%APPDATA%/Claude/claude_desktop_config.json` 在Windows上。重启Claude Desktop。)
在 `--stdio` 模式下,MCP传输通过stdin/stdout(Claude Desktop通过 `npx` 启动);HTTP文件服务器仍然绑定到后台的 `JOBOPS_PORT`,因此服务器返回的 `http://127.0.0.1:7891/files/*` 链接在您的浏览器中继续解析。
对于接受流式HTTP URL的通用MCP客户端:跳过 `--stdio` 标志,运行 `npx @mohith_das/jobops start` 在终端中,并将您的客户端指向 `http://127.0.0.1:7891/mcp`。
`npx @mohith_das/jobops connect` 打印两个块以粘贴。
### LibreChat
`npx @mohith_das/jobops connect` 还会打印一个 `librechat.yaml` 块。有两种形状:
- **LibreChat 作为主机进程:** `type: streamable-http`, `url: http://127.0.0.1:7891/mcp`.
- **LibreChat 在Docker中:** 换成 `http://host.docker.internal:7891/mcp` 并在 `mcpSettings.allowedAddresses` 下允许该地址(LibreChat 默认阻止私有/内部地址作为SSRF保护)。在Linux上,还要在 `docker-compose.yml` 中的LibreChat服务中添加 `extra_hosts: ["host.docker.internal:host-gateway"]`。
(参考:
[librechat.ai/docs/.../mcp_servers](https://www.librechat.ai/docs/configuration/librechat_yaml/object_structure/mcp_servers),
[features/mcp](https://www.librechat.ai/docs/features/mcp).)
---
## 有效的 `evaluate_job` 有效载荷
### 步骤 1 — 粘贴工作描述或URL
```jsonc
{
"method": "tools/call",
"params": {
"name": "evaluate_job",
"arguments": {
"input": "https://jobs.ashbyhq.com/example/123",
"mode": "chat",
"title": "Builder PM",
"company": "Frontier AI Tools Co"
}
}
```
返回评分标准、报告格式、活动职业包和一个 `job_id`。聊天客户端使用这些来评分 + 起草 6 个块。
### 步骤 2 — 完成
```jsonc
{
"method": "tools/call",
"params": {
"name": "evaluate_job",
"arguments": {
"job_id": "<从步骤 1>",
"mode": "chat",
"report": {
"archetype_detected": "Agentic / LLMOps hybrid",
"block_role_summary": "…",
"block_cv_match": "…",
"block_level": "…",
"block_comp": "…",
"block_personalize": "…",
"block_interview": "…",
"block_legitimacy": "…",
"keywords": ["builder pm", "agentic workflows", "…"]
},
"scores": {
"resume_fit": 86, "taste_fit": 92, "visa_fit": 88, "score_total": 88,
"reasoning": "Strong match on agentic workflows + PRDs + SQL/Python.",
"concerns": "Evals experience is adjacent rather than LLM-eval-specific.",
"role_category": "pm",
"seniority": "senior"
}
}
}
```
服务器持久化,渲染HTML到 `/files/reports/<id>.html`,返回URL。
---
## 在远程主机 / Tailscale上运行
默认情况下,服务器返回的每个工件链接都以 `http://127.0.0.1:<端口>` 开头。这在服务器和聊天在同一台机器上运行时效果很好。如果您在云实例、homelab盒子或您通过Tailscale / LAN /隧道到达的任何其他位置运行服务器,则 `127.0.0.1` 链接解析为您的 **聊天机器** - 而不是服务器 - 链接不起作用。
设置 `JOBOPS_PUBLIC_BASE_URL` 为聊天机实际用于访问服务器的URL:
```bash
# Tailscale 魔术DNS
export JOBOPS_PUBLIC_BASE_URL="https://jobs.example.ts.net"
# Tailscale 100.x IP
export JOBOPS_PUBLIC_BASE_URL="http://100.64.0.5:7891"
# LAN IP
export JOBOPS_PUBLIC_BASE_URL="http://192.168.1.20:7891"
# 反向代理
export JOBOPS_PUBLIC_BASE_URL="https://jobs.example.com"
```
每个工件链接(简历PDF,.tex,.docx,评估报告,apply_prefill截图,跟踪器URL)现在都使用该基准。服务器仍然绑定到 `JOBOPS_HOST`(默认为 `127.0.0.1`);要接受来自其他设备的连接,还要设置 `JOBOPS_HOST=0.0.0.0` - **这现在需要 `JOBOPS_AUTH_TOKEN`**(参见 [安全模型](#安全模型))。`npx @mohith_das/jobops doctor` 打印有效的公共基准URL和身份验证姿势。
格式不正确的数值(例如 `not-a-url`)会在启动时被拒绝,并带有stderr上的警告;服务器继续使用默认的127.0.0.1基准。尾部斜杠被剥离。
---
## 安全模型
该服务器处理 **PII**:您的简历PDF、求职信、评估报告、LinkedIn连接和H1B派生雇主数据。身份验证姿势完全由 **绑定位置** 和 **是否设置令牌** 决定:
| 绑定(`JOBOPS_HOST`) | `JOBOPS_AUTH_TOKEN` | 结果 |
|---|---|---|
| `127.0.0.1`(默认) | 未设置 | **开放** - 无缝本地使用。PII停留在环回。 |
| `127.0.0.1` | 已设置 | **需要令牌** - 甚至本地强制身份验证(选择加入)。 |
| `0.0.0.0` / LAN / Tailscale | **未设置** | **拒绝启动**(默认拒绝)。 |
| `0.0.0.0` / LAN / Tailscale | 已设置 | **需要令牌** - 每个PII路由都需要身份验证令牌。 |
当需要令牌时,每个PII承载路由 - MCP端点(`/mcp`)、文件服务器(`/files/*`)和跟踪器仪表盘( `/`)- 要求 `Authorization: Bearer <token>` 头部。没有它的请求会收到带有 `WWW-Authenticate` 头的 `401`。这与MCP 2025-06-18模型一致,将服务器视为 **OAuth资源服务器**,在可行的情况下适用于自托管的单用户工具:一个操作员配置的静态令牌,没有完整的授权服务器没有发送器流程:一个静态令牌由操作员提供,没有完整的授权服务器流程。
```bash
# 通过Tailscale/LAN公开 - 先生成一个强令牌
export JOBOPS_HOST=0.0.0.0
export JOBOPS_AUTH_TOKEN="$(openssl rand -hex 32)"
export JOBOPS_PUBLIC_BASE_URL="https://jobs.example.ts.net"
npx @mohith_das/jobops start
```
**保护内容:** `/mcp`、`/files/*`、**不保护内容:** `/healthz`(存活检查,无PII)和发现元数据。**硬性规定:** PII绝不能在网络上未经身份验证提供 - 默认拒绝启动保护措施正是为了防止缺少令牌而导致的数据暴露。仍然首选私有网络(Tailscale / VPN /身份验证反向代理)而不是公共互联网。
---
## 可下载、可编辑的源格式
`render_pdf` 生成三个格式中的任意子集:
| 格式 | 存放位置 | 用途 |
|--------|-----------------|---------------------------------------------------------------|
| `pdf` | `/files/pdfs/` | 可交付成果。浅色/白色背景,ATS清理。 |
| `tex` | `/files/tex/` | 可编辑的LaTeX源代码。编译时使用普通的`pdflatex`。 |
| `docx` | `/files/docx/` | Word / Google Docs 编辑。真正的标题 + 项目符号,ATS安全。 |
默认为 `formats: ["pdf"]` 以兼容旧版。请求任意子集:
```jsonc
{
"method": "tools/call",
"params": {
"name": "render_pdf",
"arguments": {
"job_id": "<from evaluate_job>",
"kind": "both",
"formats": ["pdf", "tex", "docx"],
"cover_body": "我正在联系您关于 ..."
}
}
}
```
所有 URL 都持久化到 `rendered_files` JSON 列的应用程序行中,以便 `get_tracker`、`apply_prefill` 和 `daily_digest` 可以稍后找到它们。重新渲染一个格式会合并到现有的映射中 - 永远不会覆盖其他格式。
所有格式在一个调用中共享一个单一的内容快照,该快照在调用开始时获取:`cv.md` + `profile.yml`,活动职业包(聊天编辑计算 - 无需同步回馈),以及作业的持久化定制材料(`generate_materials` 输出,当前 `materials_v)。` 编辑和编译 `.tex` 会重现相同的文档,重写后一个包或新的材料版本会产生更新的文档。签证泄漏轨道在写入文件之前会对所有输出格式运行。
### 自定义主题
`render_pdf` 接受一个 `template` 参数 - 选择一个命名主题来渲染。 主题是 `templates/themes/<name>/` 下的目录,包含任意:
```
resume.tex cover.tex resume.html cover.html
```
开箱即用,您将获得 `default`。 要创作自己的:
```bash
mkdir -p ~/job-themes/compact
# 在那里编写 resume.tex / cover.tex / resume.html / cover.html。
# 每个主题文件都是一个带有 {{PLACEHOLDER}} 插槽的普通模板 - 参见
# TEMPLATES.md 获取完整的占位符合同。
export JOBOPS_TEMPLATE_DIR=~/job-themes
npx @mohith_das/jobops templates # 列出捆绑和用户主题
# 然后在您的MCP聊天中:
# render_pdf job_id=... kind=both formats=["pdf","tex"] template="compact" cover_body="..."
```
加载程序首先检查 `$JOBOPS_TEMPLATE_DIR` **,然后检查捆绑主题。**
| 环境变量 | 默认值 | 用途 |
|---------|---------|--------------|
| `JOBOPS_TEMPLATE_DIR` | 空 | 额外目录,包含您的自定义主题(每个主题一个子目录)。 |
| `JOBOPS_DEFAULT_TEMPLATE` | `default` | 当 `render_pdf` 没有显式 `template` 参数时使用的主题。 |
自定义主题如果省略占位符,则会优雅地降级(该部分被删除,渲染器不会崩溃)。在 `.tex` 主题中,注释掉占位符(`% {{SUMMARY_SECTION}}`)会删除该部分,就像 LaTeX 注释一样。格式错误的主题(缺少 `\documentclass`,缺少 `\begin{document}` 等)会返回一个明确的错误,指出主题 + 文件 - pdflatex 的整个回溯信息都不会到达用户。 签证泄漏扫描和 ATS 硬性规则适用于您选择的主题。
参见 [`TEMPLATES.md`](./TEMPLATES.md) 获取完整的占位符引用 + 示例自定义主题。
> `.docx` 是以编程方式生成的,不使用主题。 Word 文件遵循 ATS 友好的固定 Calibri / 标题样式布局;如果您需要视觉变化,请在 Word 中编辑输出。
---
## 高级/外联功能(可选)
### 导入您的LinkedIn网络 → 暖启动查找器
下载您的LinkedIn数据导出(设置 → 数据隐私 → 获取您的数据副本 → 连接),然后:
```bash
TODO
```
# 通过您的MCP聊天:
import_linkedin path="/绝对路径/到/Connections.csv"
现在,`find_warm_intros(company="…")` 返回您实际认识的人,他们在那里工作(过滤掉非招聘人员,按工程/领导权重排序)。
**从聊天中添加联系人(无需CSV)** 发现有人在搜索过程中很有用,或者想捕获几个人而不进行批量导出?使用 **`add_contacts`** - 它接受一个数组,包含1到N个联系人,一次调用并将它们插入同一个存储中,以便它们立即出现在 `find_warm_intros` / `find_founders` 中:
```text
add_contacts contacts=[
{ "full_name": "Dana Lee", "company": "Anthropic, Inc.", "title": "Staff Engineer",
"linkedin_url": "https://linkedin.com/in/dana-lee" },
{ "full_name": "Sam Park", "company": "Vercel", "title": "Head of Talent" }
]
```
仅 `full_name` 是必需的。它与现有人员匹配(通过 `linkedin_url`,否则 `full_name` + 公司),因此 **没有重复记录**;更新时合并(省略的字段保留);解析公司名称时使用与CSV路径 **相同的模糊归一化** ;除非您传递它们,否则从职称推断 `is_recruiter` / `is_engineering` / `is_leadership`。 部分联系人存储后,每个联系人结果报告缺少的内容(`no linkedin_url`,公司不匹配等),以便聊天可以要求您填写空白。 (Claude在调用之前将您的自由文本/粘贴的联系信息解析为这些字段。)
**备份,可移植性和安全删除** - 所有非破坏性的,共用一个哲学(有时间戳的备份,在进行任何风险操作之前;删除是可逆转的):
- **`export_contacts`** 将 **每个** 联系人和字段(标志,笔记,电子邮件,解析的公司,ID,存档状态)写入时间戳的 `contacts_export_*.csv` **和** `.json` 到项目根目录。您的备份/移植路径。
- **`import_contacts path="…"`** 读取一个 `.json`/`.csv` (例如,先前的导出)并 **插入/合并** - 绝不删除并替换:空白/缺失的字段绝不会覆盖更丰富的现有数据,现有行匹配(无重复记录),新行插入。重新导入导出是 **幂等** 的 - 相同的数据库,零损失。在导入之前写入备份。
- **`delete_contacts`** 软删除1到N个人(按 `linkedin_url`,`full_name`+公司或 `id`)。存档的联系人从 `find_warm_intros` / `find_founders` 中消失,但 **仍然可恢复** 在行中;写入备份;并且结果 **精确回显哪些行匹配** (名称+公司+网址),以便捕获错误的模糊匹配。
> **保证:** 导出 → (编辑发生)→ 重新导入永远不会破坏导出文件中不存在的数据。导入文件是附加/更新的,而不是覆盖整个文件的。
公司名称 **模糊** 匹配,以便合法名称变体相互对应:`import_linkedin`,`import_h1b`,JD摄入,`visa_signal`和`find_warm_intros`都通过剥离通用合法后缀(Inc,LLC,PBC,Ltd,Corp,Co,GmbH等),小写和修剪标点符号来规范名称。因此,LinkedIn连接中的“Anthropic”,H1B文件中的“ANTHROPIC PBC”和JD爬取的“Anthropic,Inc.”都解析为 **相同的公司行** - 这使得暖导入和签证信号连接实际上起作用。已解析的变体记录在`company_aliases`表中。
### 导入DOL OFLC H1B数据→签证友好度信号
从 <https://www.dol.gov/agencies/eta/foreign-labor/performance> 下载季度LCA披露CSV,然后:
```bash
# 通过您的MCP聊天:
import_h1b path="/绝对路径/到/LCA_Disclosure_Data_FY2025_Q1.csv"
```
然后,`visa_signal(company="…")` 返回一个友好的频段(`strong | mixed | weak | none`),根据申报数量+最近度计算。 **仅限内部** - 永远不会在任何简历,封面信或外联中显示(参见签证硬规则)。
如果您禁用了签证评分(`JOBOPS_VISA_SCORING=false`),这些工具不会出现在`tools/list`中。
### 调度器(可选cron)
默认情况下关闭。 要在计划上运行扫描+批量费率:
```bash
# 在您的MCP聊天中:
scheduler_enable jobs=["scan_portals_4h", "batch_evaluate_30m", "daily_digest_morning"]
```
作业节奏是固定的(4h / 30m /每小时,8AM消化窗口)。使用`scheduler_disable`关闭它。仅在服务器进程运行时有效。
---
## 联邦 - 私有边缘智能节点
JobOps作为联邦人才发现网络中的**私有边缘智能节点**运行。您的本地数据(cv.md,profile.yml,故事库)编译成规范的`career-packet.json`,同步到LivingCV(您的个人中继),嵌入本地,并作为签名的快照信号广播到HireBridge(中央路由器)进行机会匹配。 **在您明确操作之前,** 没有数据会离开您的机器 - 默认情况下,嵌入在本地生成。
### 数据流
```
cv.md + profile.yml + story_bank
↓ compile_career_packet
career-packet.json(JSON Resume superset + Lightcast IDs +证据)
↓ sync_to_livingcv(MCP SSE → sync_career_packet {packet})
LivingCV(规范存储 - 自己的/career-packet.json路由)
↓ generate_embeddings
本地向量(按数据包哈希缓存; __packet__优先)
↓ broadcast_signal(POST /ingest/snapshot,ed25519签名)
HireBridge路由器(签名快照 - `embedding[0]`是唯一索引的)
```
### 联邦合同v1(与hirebridge + LivingCV共享)
jobops实现了 **Canonical Federation Contract v1** - 相同的信封,身份验证流程和签名方案,其他两个存储库使用。 关键不变性:
- `candidate_id` = `sha256(lowercase(trim(email)))`的前32个十六进制字符。
- 每个快照都使用 **ed25519** 签名,而不是HMAC。 jobops在首次连接时生成密钥对,并在`federation_state`中持久化; `public_key`在HireBridge的`/auth/device`处注册。
- 整个数据包嵌入 **必须** 是`embedding[0]` - HireBridge仅索引元素0(`hirebridge/internal/store/repo/snapshots.go:45-57`)。
- LivingCV同步是 **MCP-over-SSE** ,而不是裸JSON-RPC。 bearer token是LivingCV的`mcp.master_key`(Admin → Settings → MCP)。 工具名称是`sync_career_packet`,参数为`{packet: <LcvPacket>}`。
### CLI命令
```bash
# 编译规范的career-packet.json
jobops compile-packet # 将技能映射到Lightcast IDs(通过LLM)
jobops compile-packet --skip-lightcast # 跳过Lightcast映射(更快)
# 将career-packet.json同步到您的LivingCV实例
jobops sync # 推送到LivingCV
jobops sync --force # 即使内容未更改也推送
# 通过神奇链接与HireBridge进行身份验证
jobops connect_to_hirebridge # 提示输入电子邮件
jobops connect_to_hirebridge --email you@example.com
# 向HireBridge广播信号快照
jobops broadcast
# 检查jobops更新
jobops update
```
### MCP工具
| 工具 | 描述 |
|------|-------------|
| `compile_career_packet` | 编译cv.md + profile.yml + story_bank成`career-packet.json`(JSON Resume superset with Lightcast Open Skills IDs)。 持久化到DB + 编写`output/career-packet.json`。 |
| `get_career_packet_json` | 获取主动编译的职业数据包(只读,**public-safe**)。 |
| `sync_to_livingcv` | 通过 **MCP SSE** 将编译的职业数据包推送到LivingCV(工具`sync_career_packet {packet}`)。 需要`JOBOPS_LIVINGCV_URL` + `JOBOPS_LIVINGCV_TOKEN`。 |
| `generate_embeddings` | 使用配置的提供程序(本地,OpenAI或Voyage)生成职业数据包部分的向量嵌入。 按数据包哈希缓存。 `__packet__`部分是规范的整个数据包向量,在`embedding[0]`处广播。 |
| `get_embeddings` | 获取缓存的嵌入元数据(部分,模型,维度)而无需向量数据。 只读。 |
| `broadcast_signal` | 编译并广播签名的快照到`POST /ingest/snapshot`。 信封为`{candidate_id, payload, embedding, signature}`;签名是 **ed25519** 的有效载荷字节(不是HMAC)。 |
| `get_federation_status` | 获取联邦状态:LivingCV同步时间,HireBridge连接状态,缓存的嵌入计数,广播历史。 只读。 |
| `update_jobops` | 检查npm注册表是否有更新。 如果有新版本可用,则报告更新命令。 |
### HireBridge设备身份验证+神奇链接流程
```
1. jobops connect_to_hirebridge
2. 输入您的电子邮件
3. jobops → POST /auth/device JSON {node_type:"jobops", endpoint_url, public_key}
← {device_code, user_code, verification_uri, …}
4. jobops → POST /auth/request form-encoded email=<you>&uc=<user_code>
→ HireBridge将神奇链接发送到您的邮箱
5. 点击电子邮件中的神奇链接(或打开verification_uri_complete)
6. jobops → POST /auth/token form-encoded grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=…
← 200 {access_token, node_id, email}
7. 在.env和federation_state中保存令牌+ node_id
```
按照 [RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628),待处理状态返回 **HTTP 400**,带有JSON `{error: …}`正文。 jobops中的轮询循环 **每次** 读取正文(包括400错误)并切换到`authorization_pending`,`slow_down`,`expired_token`和`access_denied`。 在第一个投票请求时抛出非2xx会导致非常严重的v0.16.x错误; v1客户端是正确的。
bearer令牌是一个长期令牌,存储在`.env`(`JOBOPS_HIREBRIDGE_TOKEN`)中。 jobops **永远不会** 在职业数据包中存储令牌,也不会在快照中发送它 - 快照使用ed25519针对本地存储的私钥签名(服务器使用注册的`public_key`进行验证)。
### 嵌入提供商
| 提供商 | 环境变量 | 模型 | 维度 | 备注 |
|----------|---------|-------|-----|-------|
| **本地** (默认) | `JOBOPS_EMBEDDING_PROVIDER=local` | `all-MiniLM-L6-v2` | 384 | 完全在设备上运行,通过`@xenova/transformers`。 模型在首次使用时自动下载(~90MB)。 没有数据离开您的机器。 |
| **openai** | `JOBOPS_EMBEDDING_PROVIDER=openai` | `text-embedding-3-small` | 1536 | 需要`OPENAI_API_KEY`。 |
| **voyage** | `JOBOPS_EMBEDDING_PROVIDER=voyage` | `voyage-3-lite` | 384 | 需要`VOYAGE_API_KEY`。 |
| **none** | `JOBOPS_EMBEDDING_PROVIDER=none` | - | - | 禁用嵌入生成。 没有嵌入,广播将无法工作。 |
### 完整的工作流程示例
```text
# 在聊天中(或CLI中):
compile_career_packet # 步骤1:构建career-packet.json
generate_embeddings # 步骤2:本地嵌入
sync_to_livingcv # 步骤3:推送到LivingCV
connect_to_hirebridge # 步骤4:与HireBridge身份验证(一次性)
broadcast_signal # 步骤5:广播签名信号
get_federation_status # 检查同步/广播状态
```
### 信号快照形状(合约v1)
```json
{
"candidate_id": "8a3f... (32-hex,sha256(lowercase(email))[:16]字节)",
"payload": {
"candidate": { "email": "...", "livingcv_url": "..." },
"career_packet": { /* 公共安全编译的数据包 - 与get_career_packet_json返回的相同 */ },
"capabilities": [{ "competency": "leadership", "evidence_count": 3, "story_ids": ["..."] }],
"packet_hash": "sha256...",
"packet_version": 3,
"broadcast_at": "2026-07-10T..."
},
"embedding": [ [/* __packet__ 向量 - 维度与HB_EMBED_DIM匹配,默认为384 */], [...每个部分的向量] ],
"signature": "ed25519 英尺超过JSON.stringify(payload) 字节"
}
```
签名是 **ed25519** ,由本地密钥对签名,在 `/auth/device` 时注册。 HireBridge从确切的负载字节重新计算它,并与存储的 `public_key` 进行验证。 抛出HMAC会像无密钥一样被静默接受 - 这是v0.16.x故障模式,v1合约修复了它。
`embedding[0]` 是规范的整个数据包向量(本地缓存中的`__packet__`部分)。 HireBridge的存储库仅索引元素0(参见`hirebridge/internal/store/repo/snapshots.go:45-57`);后续向量可能跟随,但在存储时被忽略。
### LivingCV同步前提条件
LivingCV堆栈必须具有这些Admin → Settings → MCP标志启用,否则`sync_to_livingcv`返回401/403:
- `mcp.enabled = 1`
- `mcp.jobops_sync_enabled = 1`
`JOBOPS_LIVINGCV_TOKEN`是 **master-relay key** (LivingCV Admin → Settings → MCP中的`mcp.master_key`)- 它带有jobops-sync范围。
> **公共安全表面:`get_career_packet_json`被标记为`publicSafe`,这意味着它在`/mcp/public`端点中可用,供外部招聘方AI代理使用。 它返回结构化的数据包(JSON Resume superset)- 与同步到LivingCV和嵌入广播的相同数据包。除了您的`profile.yml`标识字段中的PII外,不会暴露任何PII。
---
## 硬规则
1. **永远不会在任何简历,封面信或外联中显示签证/工作权限**。 签证数据仅用于内部评分。
2. **永远不会发明`career_packet`中没有的声明**。 材料生成器在持久化之前根据数据包验证LLM输出。
3. **在所有地方都需要人为干预**。 任何工具都不会自动提交申请或自动发送DM。 `apply_prefill`仅预览 - 它打开表单,填写值,截图,然后停止。 您手动提交。
4. **API路径上的严格JSON解析**,并记录`PARSE_ERROR`回落 - 从不静默归零。
5. **跟踪器/申请/外联写入是串行的**,在单个写入锁之后。
---
## 布局
```
jobops/
├── modes/ # MCP资源(编辑我以调整大脑)
├── templates/ # CV HTML/LaTeX模板 + 封面信模板
├── fonts/ # Space Grotesk, DM Sans(woff2子集)
├── cv.example.md → cv.md 之后初始化
├── config/profile.example.yml → config/profile.yml 1.0.0后初始化
├── .env.example → .env 之后初始化(LivingCV,HireBridge,嵌入配置)
├── src/ # TypeScript源代码(不发布)
│ ├── cli.ts # init / start / doctor / connect / compile-packet / sync / connect_to_hirebridge / broadcast / update
│ ├── server.ts # HTTP + MCP启动
│ ├── core/ # llm,providers,jobs,reports,render,scan_engine,…
│ │ ├── career_packet_json.ts # federation: 编译career-packet.json
│ │ ├── lightcast.ts # federation: LLM辅助Lightcast技能映射
│ │ ├── embeddings.ts # federation: 本地/API嵌入提供程序
│ │ ├── livingcv_client.ts # federation: JSON-RPC同步到LivingCV
│ │ ├── hirebridge_client.ts # federation: 设备身份验证+信号广播
│ │ ├── signal_broadcast.ts # federation: 快照编译器+广播
│ │ ├── updater.ts # federation: npm注册表版本检查器
│ │ └── env_loader.ts # .env文件加载器(优先级:shell > .env > legacy)
│ ├── http/ # express应用+仪表板
│ ├── mcp/ # 定义+注册+工具/
│ │ └── tools/
│ │ ├── career_packet_json.ts # federation 工具
│ │ ├── embeddings.ts # federation 工具
│ │ ├── sync_to_livingcv.ts # federation 工具
│ │ ├── signal_broadcast.ts # federation 工具
│ │ └── update_jobops.ts # federation 工具
│ └── migrations/*.sql # SQLite迁移(007添加了federation表)
└── data/, output/ # gitignored运行时状态
```
提交并推送git push && git push origin vX.Y.Z
```
此次标签推送触发 `publish,其执行步骤如下:
1. 检出已标记的提交。
2. 使用 npm 注册表设置 Node 20。
3. 验证标签(`v.Z`)与 `package.json` 中的 `version` 匹配 — 快速失败以防拼写错误。
4. 执行 `npm ci` 和 `npm run build`。
5. 执行 `npm publish --access public --provenance` — provenance 附加一个 sigstore 声明,在 npmjs.com 上可见,显示了 tarball 的生成过程。
在仓库的 **Actions** 选项卡中查看进度。成功后,新版本将出现在
[npmjs.com/package/jobops](https://www.npmjs.com/package/jobops)。
## 贡献 / 反馈
欢迎提出问题和拉取请求。目前尚无贡献者指南 — 如果您计划进行重大更改,请先提出问题。
---
MIT — 见 [LICENSE](./LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器