career-ops 多 CLI 求职技能路由详解:SKILL.md 的 Mode 路由、项目根解析与上下文加载机制
career-ops 是一个运行在 AI 编码 CLI(Claude Code、Codex、OpenCode、Antigravity、Grok、Cursor、Qwen、Kimi 等)中的开源求职指挥中心。它的统一入口是一个名为 SKILL.md 的技能路由文件:用户粘贴一段 JD(职位描述)文本或 URL,或者输入一个模式名(如 scan、pdf、tracker),路由就会把请求分发到对应的求职工作流模式。本文以 .grok/skills/career-ops/SKILL.md 为主体,完整讲解它的 frontmatter 元数据、Mode 路由表、auto-pipeline 自动检测、输出语言指令、Discovery 命令菜单和分层上下文加载规则,并结合 scaffolder/ 的引导代码与测试文件,说明这套路由如何做到跨 CLI、跨工作目录的确定性行为。
一、SKILL.md:一份被多 CLI 共享的技能定义
.grok/skills/career-ops/SKILL.md 并不是独立的一份副本,而是指向 canonical 定义 SKILL.md 的符号链接。这一设计来自仓库的开放标准约定:技能在 .agents/skills/career-ops/SKILL.md 中定义一次,然后为每个受支持的 CLI 各建一份 symlink(.claude/、.cursor/、.opencode/、.qwen/、.antigravitycli/、.grok/、.kimi/)。因此无论 Agent 从哪个 CLI 加载技能,读到的路由语义都完全一致——这也是 SKILL.md 开篇所说的 "The routing below is shared across supported agent CLIs even when the invocation surface differs"。
文件以 YAML frontmatter 开头,声明了 CLI 自动发现所需的元数据:
| 字段 | 取值 | 作用 |
|---|---|---|
name |
career-ops |
技能名,slash command 注册名 |
description |
AI job search command center — evaluate offers, generate CVs, scan portals, track applications… | 供 Agent 判断"何时触发本技能"的自然语言描述:粘贴 JD/URL、要求扫描门户、生成 CV/PDF、跟踪申请、面试准备、起草外联邮件时均应命中 |
arguments |
mode |
唯一参数名,路由的输入来源(即 $mode) |
user_invocable / user-invocable |
true |
允许用户主动调用(两种写法并存以兼容不同 CLI 的解析器) |
argument-hint |
[scan | discover | deep | pdf | text | … | update] |
交互界面中展示的候选模式提示,共 33 个模式名 |
license |
MIT |
许可证声明 |
关于 symlink 的健壮性,仓库有两层保障:
- 引导物化(materialize):skill-entrypoints.mjs 定义了
SKILL_ENTRYPOINTS注册表,canonical 路径为.agents/skills/career-ops/SKILL.md,其余 7 个 CLI 目录的入口都是指向它的指针。对不支持 symlink 的文件系统,ensureSkillEntrypoints()会写入指针文件;当检测到某个入口是"内容为指针字符串的普通文件"(而非真正的 symlink)时,materializeSkillEntrypoints()会把 canonical 的完整内容直接落盘,保证旧版本 clone 或特殊文件系统上技能依然可用。测试 test-all.mjs 中"SKILL SYMLINK INTEGRITY"一节会用realpathSync逐一验证 6 个 symlink 入口都解析到同一 canonical 文件,并断言引导测试中ensureSkillEntrypoints物化的.grok入口内容与 canonical 完全一致。 - CLI 支持面:各 CLI 的加载方式记录在 SUPPORTED_CLIS.md,例如 Grok Build CLI 通过
AGENTS.md加载、交互式命令为grok然后/career-ops,无头批处理为grok -p "prompt";Claude Code 为claude然后/career-ops,无头为claude -p "prompt";OpenCode 为opencode/opencode run "prompt"。
二、Project Root Resolution:用哨兵文件定位仓库根,而不是 cwd
SKILL.md 在读取任何仓库相对路径之前,要求先推导 PROJECT_ROOT,规则是:
从本 SKILL.md 所在目录开始向上逐层走,直到找到同时包含
AGENTS.md和modes/两个哨兵的最近目录。此后路由中出现的每一个路径(modes/、config/、data/、脚本、模板、输出路径)都必须相对PROJECT_ROOT解析,永远不要相对进程当前的工作目录(cwd)解析。
这条规则针对的是两类真实场景:checkout 本身嵌套在更深的路径下(例如 Development\career-ops),或用户从仓库某个子目录启动命令。只要哨兵缺失(既没有 AGENTS.md 也没有 modes/),技能应停下来先定位 career-ops 的 checkout,再继续读写文件。
仓库为这条规则配备了回归测试 skill-project-root.test.mjs(对应 issue #3332):
- 测试内实现的
findProjectRoot()与 SKILL.md 的语义一一对应:从技能文件目录向上找,直到某目录同时存在AGENTS.md与modes/; - 断言 8 个入口(
.agents、.antigravitycli、.claude、.cursor、.grok、.kimi、.opencode、.qwen下的skills/career-ops/SKILL.md)都能解析到同一个 checkout 根; - 用
hasRoutingRule()断言技能文本必须同时包含 "Resolve every path in this router" 和 "never against the process's current working directory" 两条关键语句,防止未来编辑删掉路由不变量; - 针对"Git index 中 mode 为
120000(symlink)但工作区物化成普通文件"的情况,测试构造了一个 fixture,验证通过 Git index mode 仍能把指针文件解析回 canonical 内容。
三、Invocation Notes:slash command 与自然语言是同一套路由的两种表面
SKILL.md 对不同 CLI 的调用面做了显式归一:
- 支持 slash command 注册的 CLI 把本技能暴露为
/career-ops; - Cursor 中技能位于
.cursor/skills/career-ops/并被自动发现——可以直接按名字要某个模式,或粘贴 JD/URL 触发 auto-pipeline; - Codex 的交互式会话在仓库根运行
codex启动。Codex 不保证提供 slash command,因此在/career-ops不可用时,用自然语言让 Codex 按名字运行同一模式;无头 Codex worker 使用codex exec "prompt"; - 无论入口是 slash command 还是自然语言提示,路由语义保持不变。
文档给出了与 slash command 等价的 Codex 提示词示例,这是把"命令面差异"落到"提示词层面"的关键映射:
Evaluate this JD with career-ops auto-pipeline: https://company.com/jobs/123
Run the career-ops scan mode and summarize new matches.
Run the career-ops pipeline mode for data/pipeline.md.
Run the career-ops pdf mode for the latest evaluated role.
Run the career-ops tracker mode and summarize the current statuses.
四、Mode Routing:从 $mode 到模式的完整路由表
路由的核心逻辑:从 $mode 判定模式。SKILL.md 给出的完整映射如下(左列输入,右列模式):
| 输入 | 模式 |
|---|---|
| (空 / 无参数) | discovery — 显示命令菜单 |
| JD 文本或 URL(无子命令) | auto-pipeline |
oferta / ofertas / contacto / deep |
同名模式 |
interview-prep / interview / interview/plan / interview/practice / interview/debrief / interview-redflag |
同名模式 |
eu-swe / eu-fintech |
regional/eu-swe / regional/eu-fintech |
pdf / text / latex / latex-tex / cover / email |
同名模式 |
add / expand / training / project |
同名模式 |
tracker / agent-inbox / inbox |
tracker;agent-inbox(inbox 是别名) |
pipeline / apply / scan / discover / batch |
同名模式 |
patterns / offer-prep / titles / upskill |
同名模式 |
followup / reply-watch / outcome / update |
同名模式 |
两个判定细节:
- auto-pipeline 检测:当
$mode不是已知子命令,且内容包含 JD 特征关键词("responsibilities"、"requirements"、"qualifications"、"about the role"、"we're looking for",或"公司名 + 职位"),或直接是 JD 的 URL 时,执行auto-pipeline。 - 兜底:当
$mode既不是子命令、也不像 JD 时,回落到 Discovery(显示菜单),而不是报错。
这意味着用户最常见的"把 JD 原文直接粘进来"这一动作,不需要任何模式前缀即可进入完整评估流水线——路由表把"意图识别"内建进了技能本身。
五、Output Language Directive:执行任何模式前的语言归一
在执行任何模式之前,路由要求先读取 config/profile.yml(若存在),解析两个键:
language.output→ 面向人类输出的 ISO 语言代码,默认en;language.modes_dir→ 可选的"市场模式目录",只控制市场词汇与本地评估规则(例如用 DACH 市场术语但仍用英文写作)。
随后在加载模式指令之后、产出任何用户可见内容之前,注入以下指令:
Write all human-facing output in
{language.output}regardless of the language of these instructions or of the job description. This includes reports, tracker notes, PDFs, cover letters, outreach, interview prep, form answers, and summaries. Iflanguage.modes_dirsupplies market-specific vocabulary, keep the market logic but explain terms in{language.output}when needed.
不变量是:language.output 对行文语言拥有最终决定权;modes_dir 只是市场上下文,不能强行改变行文语言。仓库中的 profile.example.yml 对这一设计有配套注释:language.output 用于报告、tracker 备注、PDF、求职信、外联与表单答案(zh-CN 还会启用中文 PDF 排版规则),而 language.modes_dir(如 modes/de)用于选择市场词汇/规则,两者相互独立。
六、Discovery Mode(无参数):完整的命令菜单
无参数调用时,CLI 展示命令菜单(Codex 等无 slash command 的场景则以纯文本列出同样选项,并按同样的方式映射模式)。SKILL.md 内置的菜单如下:
career-ops -- Command Center
Available commands:
/career-ops {JD} → AUTO-PIPELINE: evaluate + report + PDF + tracker (paste text or URL)
/career-ops pipeline → Process pending URLs from inbox (data/pipeline.md)
/career-ops oferta → Evaluation only A-F (no auto PDF)
/career-ops ofertas → Compare and rank multiple offers
/career-ops contacto → LinkedIn power move: find contacts + draft message
/career-ops deep → Deep research prompt about company
/career-ops interview-prep → Generate company-specific interview prep doc
/career-ops interview → Interactive profile/CV onboarding interview
/career-ops eu-swe → Calibrate a European SWE application before CV/apply/interview
/career-ops eu-fintech → Scan 21 EU fintech portals for Product Manager roles (zero-token)
/career-ops interview/plan → Time-blocked prep plan for an upcoming interview
/career-ops interview/practice → Practice interview, one question at a time with feedback
/career-ops interview/debrief → Post-interview debrief: close gaps, predict next round
/career-ops pdf → PDF only, ATS-optimized CV
/career-ops text → Tailored markdown CV (mirrors cv.md, no PDF)
/career-ops latex → Export CV as LaTeX/Overleaf .tex
/career-ops latex-tex → Tailor your own resume.tex in place (opt-in; cv.md stays default)
/career-ops cover → Cover letter: standalone JD paste or /career-ops cover {slug}
/career-ops email → Formal application email draft (draft-only; never sends, submits, or clicks)
/career-ops add → Add a project/paper/role to your CV (fetch + preview + confirm)
/career-ops expand → Auto-discover and add missing competencies from profile links
/career-ops training → Evaluate course/cert against North Star
/career-ops project → Evaluate portfolio project idea
/career-ops tracker → Application status overview
/career-ops agent-inbox → Queue/drain requests for the next session (data/agent-inbox.md)
/career-ops apply → Live application assistant (reads form + generates answers)
/career-ops scan → Scan portals and discover new offers
/career-ops discover → Resolve a company list to scannable ATS boards + append to portals.yml (zero-token)
/career-ops batch → Batch processing with parallel workers
/career-ops patterns → Analyze rejection patterns and improve targeting
/career-ops offer-prep → Read a received offer/contract with the candidate: clause walk + lawyer questions (not legal advice)
/career-ops titles → Suggest adjacent job titles from your CV to broaden the search
/career-ops upskill → Aggregate skill-gap analysis from your evaluated reports
/career-ops followup → Follow-up cadence tracker: flag overdue, generate drafts
/career-ops outcome → Record application outcome & archive artifacts
/career-ops update → Update career-ops system files with diff preview + compat check
Inbox: add URLs to data/pipeline.md → /career-ops pipeline
Or paste a JD directly to run the full pipeline.
菜单尾部给出了"收件箱"用法:把 URL 追加到 data/pipeline.md,再用 pipeline 模式批量处理;或者直接粘贴 JD 触发全流水线。
七、Context Loading by Mode:三层上下文 + 子代理委托
模式判定后、执行前,路由规定了精确的文件加载顺序。整个上下文体系分为三类模式加载策略:
1. 需要 _shared.md + 模式文件的模式
读取顺序:modes/_shared.md + modes/_profile.md(若存在)+ modes/_custom.md(若存在)+ modes/{mode}.md。适用于:auto-pipeline、oferta、ofertas、pdf、text、contacto、apply、pipeline、scan、batch。
2. 带 profile 与 custom 上下文的独立模式
读取顺序:modes/_profile.md(若存在)+ modes/_custom.md(若存在)+ modes/{mode}.md。适用于:tracker、agent-inbox、deep、interview-prep、interview、regional/eu-swe、interview/plan、interview/practice、interview/debrief、latex、latex-tex、training、project、patterns、titles、upskill、followup、reply-watch、outcome、cover、email、add、offer-prep、discover。
3. 委托给子代理(subagent)的模式
对 scan、apply(使用 Playwright 时)以及 pipeline(3 个及以上 URL):以 worker/subagent 形式启动,把 _shared.md + _profile.md + _custom.md + modes/{mode}.md 的内容注入 worker prompt。如果 CLI 提供 Agent(...) 原语,调用形如:
Agent(
subagent_type="general-purpose",
prompt="[output language directive]\n\n[content of modes/_shared.md]\n\n[content of modes/_profile.md if exists]\n\n[content of modes/_custom.md if exists]\n\n[content of modes/{mode}.md]\n\n[invocation-specific data]",
description="career-ops {mode}"
)
两个文件在加载顺序上有明确的语义边界:
modes/_custom.md在modes/_profile.md之后、模式文件之前读取。它承载用户自定义的流程规则与偏好,可以覆盖工作流/风格默认值,但永远不得引入关于候选人的事实性声明;- 加载完成后,执行从模式文件中读取到的指令。
这一分层与 AGENTS.md 中的数据契约(User Layer 与 System Layer,完整清单见 DATA_CONTRACT.md)一致:用户个性化事实写进 modes/_profile.md、config/profile.yml 等用户层文件,程序性规则写进 modes/_custom.md(可从 modes/_custom.template.md 复制),而 modes/_shared.md 属于系统层、不可写入用户特定内容——这样系统更新不会覆盖用户定制。_grok/.claude 等技能入口目录也在数据契约中被归为技能定义文件,如 DATA_CONTRACT.md 中记录的 .grok/skills/*(Grok Build CLI 的技能定义)。
八、测试视角下的路由完整性
除前面提到的 project-root 测试外,仓库的总测试入口 test-all.mjs 还对 SKILL.md 做了两类断言:
- 系统文件存在性:
.claude/skills/career-ops/SKILL.md、.cursor/…、.opencode/…、.qwen/…、.antigravitycli/…、.grok/…、.kimi/…全部列在systemFiles检查清单中,与CLAUDE.md、CODEX.md、modes/_shared.md、modes/oferta.md等系统文件一并验证存在; - symlink 完整性:逐一
realpathSync各 CLI 入口并断言解析结果等于 canonical 的.agents/skills/career-ops/SKILL.md;对"物化指针"(文件内容为单行../..指针)的情况,测试还会从指针字符串手动解析目标后再验证。
这套"canonical 单份 + symlink 多入口 + 引导物化 + 双重测试断言"的结构,让 SKILL.md 的路由表、语言指令和加载顺序只需维护一处,即可在所有受支持的 CLI 上保持行为一致。
九、小结:把 SKILL.md 当作路由契约来读
.grok/skills/career-ops/SKILL.md 本质上是一份可执行的路由契约,它约束了四件事:
- 路径基准:所有仓库路径相对哨兵文件推导出的
PROJECT_ROOT解析,与 cwd 无关; - 模式解析:33 个具名模式 + auto-pipeline 意图检测 + discovery 兜底,slash command 与自然语言提示映射到同一语义;
- 语言归一:
config/profile.yml的language.output对所有面向人类的输出拥有最终决定权,modes_dir仅承载市场上下文; - 上下文装配:
_shared.md/_profile.md/_custom.md/modes/{mode}.md的加载顺序按模式分三类,重负载模式(scan、Playwright 版apply、多 URLpipeline)委托给子代理执行。
对维护者而言,改动任何模式名、加载规则或语言指令时,需要同步检查 skill-project-root.test.mjs 的路由不变量断言与 test-all.mjs 的入口清单;对使用者而言,只需记住入口行为:粘贴 JD 走 auto-pipeline,输入模式名走具名路由,什么都不输就看 Discovery 菜单。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00