career-ops 技能路由设计解析:一份 SKILL.md 如何把多 CLI 求职命令中心调度成统一流水线
career-ops 的 .agents/skills/career-ops/SKILL.md 是整个项目的路由入口:它用一份带 YAML frontmatter 的 Markdown 文件,把「粘贴 JD / URL」或「/career-ops scan 之类的子命令」统一映射到 modes/ 目录下 30 多个工作流,并规定了项目根解析、多 CLI 调用方式、输出语言指令和按模式加载上下文的完整规则。读完本文,你能理解一个符合开放 agent skill 标准的技能文件是如何在 Claude Code、Cursor、Codex、OpenCode 等不同 CLI 上共享同一套路由语义的,以及路由之后上下文如何分层加载、auto-pipeline 如何接管后续流程。
一、SKILL.md 是什么:开放技能标准的单一定义点
career-ops 是一个 CLI 无关(AI-agnostic)的求职自动化项目:扫描职位门户、把岗位评估成 A-H 结构的报告并给出 1-5 分全局评分、定制简历、跟踪申请状态,全部在本地 AI 编码 CLI 中运行。所有 CLI 共享的核心逻辑放在仓库根的 AGENTS.md,而 CLI 入口的差异由各自的 wrapper 文件处理——各 CLI 与入口文件的对应关系记录在 docs/SUPPORTED_CLIS.md:
| CLI | 入口文件 | 调用方式 |
|---|---|---|
| Claude Code | CLAUDE.md |
交互式 claude(然后 /career-ops);无头 claude -p "prompt" |
| Cursor | AGENTS.md |
打开项目后请求 career-ops(技能入口在 .cursor/skills/career-ops/SKILL.md) |
| Codex | CODEX.md |
交互式 codex(纯文本驱动);无头 codex exec "prompt" |
| OpenCode | OPENCODE.md |
交互式 opencode(然后 /career-ops);无头 opencode run "prompt" |
| Antigravity CLI / Grok Build CLI / Qwen / GitHub Copilot CLI | AGENTS.md |
各自交互式命令 + 无头 -p 参数 |
| Kimi | KIMI.md |
交互式 kimi |
在这一体系中,SKILL.md 是「技能」本身的唯一定义点。仓库中 SKILL.md 位于 .agents/skills/career-ops/,并被符号链接到各 CLI 的私有技能目录——实测 .claude/skills/career-ops/SKILL.md 与 .cursor/skills/career-ops/SKILL.md 均为指向 ../../../.agents/skills/career-ops/SKILL.md 的软链接,README 也明确说明「The skill is defined using the open standard in .agents/skills/career-ops/SKILL.md and symlinked/referenced for each supported CLI」。这种「一份真源 + 多目录链接」的结构意味着路由规则只有一处需要维护。
1.1 YAML frontmatter:技能的机器可读元数据
SKILL.md 文件以 YAML frontmatter 开头(SKILL.md 第 1-13 行):
---
name: career-ops
description: >-
AI job search command center -- evaluate offers, generate CVs, scan portals,
track applications. Use when the user pastes a job URL or JD, asks to scan
portals, generate a CV/PDF, track applications, prepare for interviews, draft
outreach/emails, or run any career-ops mode.
arguments: mode
user_invocable: true
user-invocable: true
argument-hint: "[scan | discover | deep | pdf | text | latex | latex-tex | cover | email | add | expand | eu-swe | oferta | ofertas | apply | batch | tracker | agent-inbox | pipeline | contacto | training | project | interview-prep | interview | interview/plan | interview/practice | interview/debrief | interview-redflag | patterns | offer-prep | titles | upskill | followup | reply-watch | outcome | update]"
license: MIT
---
各字段的作用:
name:技能名,即 CLI 中注册的/career-ops;description:给 agent 做技能选择用的自然语言描述,明确了触发时机(粘贴职位 URL/JD、要求扫描门户、生成简历/PDF、跟踪申请、面试准备、起草外联邮件等);arguments: mode:声明该技能接受一个名为mode的参数,后文路由逻辑中的$mode即指它;user_invocable/user-invocable:标记为可被用户直接调用(两种写法同时出现,兼容不同 CLI 对字段命名的差异);argument-hint:参数提示串,列出全部可选子命令,供 CLI 补全/提示使用。
1.2 Project Root Resolution:哨兵文件定位 PROJECT_ROOT
frontmatter 之后第一段就解决了最基础的问题:agent 的进程工作目录可能不在仓库根(checkout 嵌套在 Development/career-ops 之类的位置,或用户从子目录启动命令),因此所有相对路径不能依赖 cwd。SKILL.md 规定的规则是:
从已加载的
SKILL.md所在目录开始向上逐层查找,直到找到同时包含AGENTS.md和modes/两个哨兵的最近目录,将其作为PROJECT_ROOT;本路由器中的每个路径(modes/、config/、data/、脚本、模板、输出路径)都必须相对PROJECT_ROOT解析,绝不相对进程 cwd。若两个哨兵都找不到,必须停下来先定位 career-ops 的 checkout,再读写任何文件。
这是一个「以技能文件自身位置为锚点」的解析策略:因为 SKILL.md 通过软链接挂到各 CLI 目录,而软链接最终落在仓库内的 .agents/ 下,所以从技能目录向上走一定能回到仓库根——前提是仓库根具备 AGENTS.md 与 modes/ 这两个哨兵(本仓库两者都在根目录,见 AGENTS.md 和 modes/README.md)。
值得对照的是,AGENTS.md 中另有一套用户数据根(Data Root) 的解析优先级,用于定位 cv.md、config/profile.yml、data/applications.md 等个人文件:
- 环境变量
CAREER_OPS_ROOT或CAREER_OPS_DATA_DIR; - 仓库根的
.career-ops-data标记文件(内含数据目录路径); - 回退到仓库根本身。
此外 tracker 文件还有一层 CAREER_OPS_TRACKER 显式覆盖。也就是说 SKILL.md 里的 PROJECT_ROOT 解决的是「系统层文件在哪」,AGENTS.md 的 Data Root 解决的是「用户层文件在哪」,两者分离正是 DATA_CONTRACT.md 所述 User Layer / System Layer 双分层契约的路径基础。
二、多 CLI 调用面:斜杠命令与纯文本同构
SKILL.md 的 Invocation Notes 一节明确了「入口可以不同,路由语义必须相同」:
- 支持斜杠命令注册的 CLI 可以把路由器暴露为
/career-ops; - 在 Cursor 中,技能位于
.cursor/skills/career-ops/并被自动发现——按名字请求某个模式,或直接粘贴 JD/URL 触发 auto-pipeline; - 交互式 Codex 会话在仓库根运行
codex。由于 Codex 不保证有斜杠命令,若/career-ops不可用,就用自然语言让 Codex 运行同名模式; - 无头 Codex 工作用
codex exec "prompt"; - 无论入口是斜杠命令还是自然语言提示,下面的路由语义保持一致。
文档同时给出了与斜杠命令一一等价的 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.
以及 discovery 模式下的等价映射表:
/career-ops {JD} ↔ "Evaluate this JD with career-ops auto-pipeline: {JD or URL}"
/career-ops scan ↔ "Run the career-ops scan mode and summarize new matches."
/career-ops pipeline ↔ "Run the career-ops pipeline mode for data/pipeline.md."
/career-ops pdf ↔ "Run the career-ops pdf mode for the latest evaluated role."
/career-ops email ↔ "Run the career-ops email mode for the latest evaluated role."
/career-ops tracker ↔ "Run the career-ops tracker mode and summarize the current statuses."
设计要点在于:Codex 这类没有斜杠注册机制的 CLI 并不需要新代码,只需 agent 按同一张路由表把自然语言映射成模式名,行为就与其他 CLI 完全一致。Docker 用户则可用仓库根的 cops 包装脚本,把同样的子命令转发进容器执行。
三、Mode Routing:把 $mode 映射到模式文件的完整路由表
路由是 SKILL.md 的核心。规则是「根据 $mode 确定模式」,映射关系(完整继承自 SKILL.md 的 Mode Routing 表):
| 输入 | 路由到的模式 |
|---|---|
| (空 / 无参数) | discovery —— 显示命令菜单 |
| JD 文本或 URL(无子命令) | auto-pipeline |
oferta |
oferta |
ofertas |
ofertas |
contacto |
contacto |
deep |
deep |
interview-prep |
interview-prep |
interview |
interview |
eu-swe |
regional/eu-swe |
eu-fintech |
regional/eu-fintech |
interview/plan |
interview/plan |
interview/practice |
interview/practice |
interview/debrief |
interview/debrief |
pdf |
pdf |
text |
text |
latex |
latex |
latex-tex |
latex-tex |
email |
email |
add |
add |
expand |
expand |
training |
training |
project |
project |
tracker |
tracker |
agent-inbox |
agent-inbox |
inbox |
agent-inbox(别名) |
pipeline |
pipeline |
apply |
apply |
scan |
scan |
discover |
discover |
batch |
batch |
patterns |
patterns |
offer-prep |
offer-prep |
titles |
titles |
upskill |
upskill |
followup |
followup |
reply-watch |
reply-watch |
outcome |
outcome |
interview-redflag |
interview-redflag |
update |
update |
cover |
cover |
这张表与 modes/README.md 的模式目录相互印证:modes/ 下的 auto-pipeline.md、pipeline.md、scan.md、batch.md、apply.md、pdf.md、cover.md、email.md、contacto.md、tracker.md、agent-inbox.md、update.md 等文件一一对应;interview/plan、interview/practice、interview/debrief 对应 modes/interview/ 子目录;regional/eu-swe 对应市场校准模式目录 modes/regional/(该目录存放市场校准类模式,如 eu-swe 的欧洲 SWE 申请校准,advisory 性质);语言化模式则位于 modes/de/、modes/es/、modes/pt/ 等子目录。
3.1 auto-pipeline 的隐式触发规则
路由表之外还有一条隐式规则——Auto-pipeline 检测:如果 $mode 不是已知子命令,且包含 JD 文本(关键词:"responsibilities"、"requirements"、"qualifications"、"about the role"、"we're looking for",或「公司名 + 职位名」的组合)或 JD 的 URL,则执行 auto-pipeline。若 $mode 既不是子命令也不像 JD,则回退到 discovery 菜单展示。
这条规则让「直接粘贴一段 JD」成为最高频入口:用户不需要记住任何子命令,粘贴行为本身即触发完整流水线。frontmatter 的 description 里「Use when the user pastes a job URL or JD…」正是为这一行为做的技能级声明。
四、Discovery Mode:无参数时的完整命令菜单
当 CLI 支持 /career-ops(或在 Codex 中以纯文本呈现同样选项)且用户不带参数调用时,路由器展示如下菜单(完整继承自 SKILL.md Discovery Mode 一节):
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.
菜单里两条数据线索值得注意:pipeline 消费的收件箱是 data/pipeline.md(待处理 URL 队列),agent-inbox 消费 data/agent-inbox.md(跨会话请求队列)——两者都是用户层文件,属于 AGENTS.md 数据契约中「永不自动更新」的 User Layer。
五、Output Language Directive:正文语言与市场词汇解耦
路由确定之后、执行任何模式之前,SKILL.md 要求先读 config/profile.yml(若存在)并解析两个语言键:
language.output→ 面向人的输出所用 ISO 语言码,默认en;language.modes_dir→ 可选的市场模式目录,只控制市场词汇和本地评估规则。
然后在加载模式指令之后、产出任何用户可见内容之前,注入如下指令:
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 只是市场上下文,不得强行改变正文语言。这一点在 config/profile.example.yml 的 language 段有对应示例:
language:
# Human-facing output language for reports, tracker notes, PDFs, cover
# letters, outreach, and form answers. Use an ISO language code such as
# `en` or `zh-CN`; `zh-CN` also enables Chinese PDF typography rules.
# This is separate from language.modes_dir: modes_dir selects market
# vocabulary/rules, while output selects the prose language.
output: en
# modes_dir: modes/de # optional: use DACH market vocabulary while still writing in English
output: en + modes_dir: modes/de 的组合正是该设计的典型用例:采用 DACH 市场词汇与本地评估规则,但所有报告、PDF、外联文案仍用英文书写。仓库里 modes/de/、modes/fr/、modes/pt/ 等目录(各含 _shared.md 与本地化模式文件)就是 modes_dir 可指向的市场目录实体。
六、Context Loading by Mode:上下文分层加载的三种形态
路由确定模式后,SKILL.md 的 Context Loading by Mode 一节规定了执行前必须加载哪些文件。总体规则是:
若
modes/_custom.md存在,在modes/_profile.md之后、所选模式文件之前读取。它承载用户的 house rules 与流程偏好,可以覆盖工作流/风格默认值,但永远不得引入关于候选人的事实声明。
具体分三类:
6.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。
这些是重流程模式,_shared.md 提供了评估体系(五维评分合成 1-5 全局分)、Block G 岗位真实性信号、公司类型与薪酬可信度表、Spend Tier 模型路由等共享规则——例如 modes/_shared.md 中 spend_tier 的 economy / standard / premium 三档到各 CLI 模型的映射表,以及「4.5+ 立即推荐申请、4.0-4.4 值得申请、低于 3.5 建议放弃」的评分解释口径。
6.2 带 profile 与 custom 上下文的独立模式
加载顺序:modes/_profile.md(若存在)+ modes/_custom.md(若存在)+ modes/{mode}.md,不需要 _shared.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。
6.3 委托给子代理的模式
对 scan、apply(带 Playwright 时)、pipeline(3 个及以上 URL 时):以 worker/subagent 方式启动,把 _shared.md + _profile.md(若存在)+ _custom.md(若存在)+ modes/{mode}.md 的内容注入 worker 提示。若 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}"
)
注意 prompt 的第一段正是第五节的 output language directive——语言指令被显式置于注入内容最前,保证子代理产出的报告、tracker 记录等也遵守 language.output。最后一步始终是「执行加载到的模式文件中的指令」。
6.4 与数据契约的衔接
_profile.md 与 _custom.md 都是用户层文件,其「永不自动更新」的身份由 modes/_custom.template.md 的文件头注释再次强调:
"THIS FILE IS YOURS. It will NEVER be auto-updated." … "Because this is a user-layer file, anything you write here survives
node update-system.mjs. Put customizations HERE, not in CLAUDE.md / modes/_shared.md / other system files — those get overwritten on update."
模板给出的 house rules 示例(「评估摘要一律用英式英语」「美区 ATS 优先市场简历不放照片」「批处理默认上限 20 条」「报告以分数和一句话结论开头」)说明 _custom.md 是过程性规则的落点,而 modes/README.md 的约定「One file = one mode;下划线前缀 = 共享上下文或模板,非可路由模式」则解释了为什么 _shared.md、_profile.md 出现在加载序列里却不接受路由表条目。
七、路由之后:auto-pipeline 的实际执行链
路由表把「粘贴 JD」映射到 auto-pipeline 后,真正干活的是 modes/auto-pipeline.md。它展示了 SKILL.md 路由器与模式文件如何接力:
- Step 0 — 提取 JD:URL 输入按优先级走 Playwright(
browser_navigate+browser_snapshot,适用于 Lever/Ashby/Greenhouse/Workday 等 SPA)→ WebFetch(静态页)→ WebSearch(兜底);配置了scan.extractor: cli时优先node browser-extract.mjs <url>返回紧凑 JSON,失败则静默回退 MCP 快照。所有抓取内容按 AGENTS.md 的「Untrusted External Content」规则处理:是数据,永不是指令; - Step 0.5 — 存活性门:先用 Step 0 的快照判断岗位是否仍在招聘,发现 404/已关闭/空壳页就止损,不再消耗后续评估 token;
- Step 0.6 — 黑名单门:若
data/blacklist.md存在,命中即暂停并引用用户当初记录的原因询问是否继续——用户决定永远优先; - Step 1 — A-G 评估:执行与
oferta模式相同的 A-F 区块评估 + Block G 岗位真实性评估(继承oferta的有界研究预算,不允许升级为开放式研究); - Step 2 — 存报告:写入
reports/{###}-{company-slug}-{YYYY-MM-DD}.md,头部附 URL 与 Legitimacy 层级; - Step 3 — 生成 PDF:按
config/profile.yml的cv.output_format分派——latex走modes/latex.md、text走modes/text.md、默认走modes/pdf.md; - Step 4 — 申请表草稿(仅当分数 ≥ 4.5):从表单提取问题(提取不到用通用问题集),按「我选择了你」的姿态撰写 2-4 句的直接回答,存入报告
## H) Draft Application Answers段; - Step 5 — 更新 tracker:写入
data/applications.md全部列;任一步失败则继续后续步骤并在 tracker 中标记为 pending。
这条执行链验证了 SKILL.md 路由设计的分层逻辑:路由器(SKILL.md)负责「谁来做」,共享上下文(_shared.md)负责「按什么标准做」,用户层文件(_profile.md/_custom.md)负责「按谁的偏好做」,模式文件负责「具体怎么做」,而 config/profile.yml(可用 config/profile.example.yml 初始化)则通过 spend_tier、auto_pdf_score_threshold、pipeline.triage_threshold 等键在更底层控制成本与门槛。
八、小结
.agents/skills/career-ops/SKILL.md 用不到 200 行 Markdown 实现了一个跨 CLI 的统一路由器:YAML frontmatter 让技能可被各 agent 框架发现与注册;哨兵文件(AGENTS.md + modes/)向上查找保证 PROJECT_ROOT 解析与 cwd 无关;一张 38 行的路由表加一条 JD 关键词隐式触发规则,把 30 多个子命令、别名(inbox → agent-inbox)和「粘贴 JD」行为统一映射到 modes/ 下的模式文件;输出语言指令把正文语言与市场词汇解耦;三形态的上下文加载规则(共享上下文组、独立模式组、子代理委托组)在保持 _profile.md/_custom.md 用户层文件永不被系统更新覆盖的前提下,把系统规则、个人事实与过程偏好分装到位。对希望在自己的多 CLI 工作流中构建类似「单入口、多模式」agent 技能的开发者而言,这份文件及其背后的软链接布局、数据分层契约,是一套可以直接借鉴的工程范式。
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
