首页
/ career-ops SKILL.md 路由器详解:一个路由文件如何驱动多 CLI 下的 30+ 求职模式

career-ops SKILL.md 路由器详解:一个路由文件如何驱动多 CLI 下的 30+ 求职模式

2026-09-03 15:34:59作者:仰钰奇

本文以 career-ops 仓库中 .cursor/skills/career-ops/SKILL.md 为核心对象,拆解这个"路由器"文件的工作机制:它如何解析项目根目录、如何把用户输入映射到 30 余种执行模式、如何注入输出语言指令、以及如何按模式分级加载上下文文件并委派子代理。读完后,你能理解一个 Agent 技能路由器的完整设计范式,并知道如何在自己的多模式 CLI 项目中复刻类似的路由与上下文加载策略。

路由器的定位与文件结构

career-ops 是一个开源的 AI 求职命令行工作系统:扫描招聘门户、把职位评估为带 A-H 报告块和 1-5 全局分数的结构化结果、定制简历、跟踪申请状态,并本地运行在各种 AI 编码 CLI(Claude Code、Codex、OpenCode、Antigravity 等)中。在这个体系里,SKILL.md 承担"总路由"的角色——文件开头自述为 # career-ops -- Router,并强调"以下路由在各受支持的 Agent CLI 之间共享,即使各 CLI 的调用界面不同"。

文件由两部分构成:一段 YAML frontmatter(技能元数据)+ 一段自然语言路由规则(Agent 遵循的行为指令)。frontmatter 定义了技能的身份与触发方式:

---
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 | ... | update]"
license: MIT
---

几个字段各有分工:name 是技能注册名;description 同时服务于人读(说明用途)和 Agent 匹配(列出了触发条件:粘贴职位 URL/JD、要求扫描门户、生成 CV/PDF、跟踪申请、准备面试等);arguments: mode 声明该技能接受一个位置参数 $modeuser_invocable: true 允许用户直接调用;argument-hint 列出全部可选模式名,作为调用时的补全提示。值得注意的是 description 里那句 "Use when..." 的写法——这是让 LLM 在自然语言场景下也能正确命中该技能的关键设计。

PROJECT_ROOT 解析:嵌套检出的路径安全

路由规则的第一节就解决了一个容易被忽视的工程问题:技能文件里的所有仓库相对路径(modes/config/data/、脚本与输出路径)应该相对于什么解析?SKILL.md 给出的答案是从技能文件自身向上推导,而不是依赖进程当前工作目录

从加载的 SKILL.md 所在目录开始,向上逐层查找,直到找到同时包含 AGENTS.mdmodes/ 这两个哨兵(sentinel)的最近目录,该目录即为 PROJECT_ROOT。本路由中解析的所有路径(modes/config/data/、脚本、模板、输出路径)必须相对于 PROJECT_ROOT,绝不相对于进程当前工作目录。即使用户检出目录本身是嵌套的(例如 Development\career-ops),或者命令从某个子目录发起,这条规则也成立。如果找不到这两个哨兵,停止操作,先定位 career-ops 检出目录,再读写文件。

这条规则有三个要点值得学习:

  1. 双哨兵判定:单个文件(如 AGENTS.md)可能在其他项目里也存在,用"同时存在 AGENTS.mdmodes/"两个标志共同判定项目根,降低了误判概率。仓库根目录确实同时含有这两个标志,modes/ 目录下有 50 余个模式文件(oferta.mdscan.mdauto-pipeline.md 等),与规则描述一致。
  2. 显式拒绝 CWD 依赖:很多 CLI 会话的工作目录不可控(用户在子目录启动、检出目录嵌套),以 CWD 解析相对路径是典型的失败来源,这里被明确禁止。
  3. 失败即停:找不到哨兵时不猜测、不继续,而是要求先定位检出目录——这是一种防数据写错位置的保守策略,对"会写文件"的技能尤为重要,因为 career-ops 的模式会写入 data/applications.mdreports/ 等用户层文件。

多 CLI 调用面:同一套路由语义

SKILL.md 的 "Invocation Notes" 一节规定了路由在不同调用面上的映射关系:

  • 支持斜杠命令注册的 CLI 可以把该路由器暴露为 /career-ops
  • 在 Cursor 中,技能位于 .cursor/skills/career-ops/,被自动发现;用户可以用模式名请求,或直接粘贴 JD/URL 触发 auto-pipeline;
  • 交互式 Codex 会话在仓库根运行 codex。由于 Codex 不保证支持斜杠命令,如果 /career-ops 不可用,就请 Codex 按名称运行同一模式;
  • 无头 Codex worker 使用 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.

这与仓库中 docs/SUPPORTED_CLIS.md 的 CLI 清单互相印证:Claude Code 走 CLAUDE.md 入口、交互式 claude 后用 /career-ops、无头 claude -p "prompt";OpenCode 走 OPENCODE.md;Antigravity CLI、Grok Build CLI、Qwen 都走 AGENTS.md 入口;Codex 走 CODEX.md 入口、无头 codex exec "prompt";Kimi 走 KIMI.md;GitHub Copilot CLI 仅无头 copilot -p "prompt";Gemini 的 GEMINI.md 是重定向到 AGENTS.md 的遗留包装。从源码结构看,"核心逻辑共享于 AGENTS.md,CLI 特有细节由各入口包装文件处理"这一分层,正是 SKILL.md 敢于宣称"路由语义不变"的前提——路由器只依赖共享的 modes/ 文件,不依赖任何特定 CLI 的界面。

模式路由表:$mode 到模式文件的映射

路由器核心是一张映射表,Agent 根据 $mode 参数确定要执行的模式:

输入 模式
(空 / 无参数) 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/ 目录下的文件一一对应:如 interview/plan 对应 modes/interview/plan.mdeu-swe 对应 modes/regional/eu-swe.mdinboxagent-inbox 的别名。部分菜单项(如 eu-fintech)在当前检出的 modes/regional/ 下没有独立文件,从路由表结构看它们属于区域变体,可推断由 regional/eu-swe 一类的区域模式承载或按需扩展,文章不对其做超出仓库证据的断言。

表之后是两条兜底规则:

Auto-pipeline 检测:如果 $mode 不是已知的子命令,并且内容包含 JD 特征(关键词:"responsibilities"、"requirements"、"qualifications"、"about the role"、"we're looking for"、公司名+职位名),或者是 JD 的 URL,则执行 auto-pipeline

Discovery 兜底:如果 $mode 既不是子命令也不像 JD,则显示 discovery 菜单。

这条"关键词启发式 + URL 判定"的兜底规则,使得用户最自然的动作——直接粘贴一段 JD 文本——被路由到完整流水线 modes/auto-pipeline.md,而不是落到菜单。auto-pipeline 本身是五步流程:Step 0 用 Playwright/WebFetch/WebSearch 优先级提取 JD(全部视为不可信外部内容),Step 0.5 存活性门禁(已关闭/404 的职位在此终止,避免对幽灵内容做完整评估),Step 0.6 黑名单门禁,Step 1 执行与 oferta 模式相同的 A-G 评估(含 Block G 职位真实性三级判定),Step 2 存报告到 reports/{###}-{company-slug}-{YYYY-MM-DD}.md,Step 3 按 cv.output_format 生成 PDF/LaTeX/文本,Step 4 仅在分数 ≥ 4.5 时起草申请表答案,Step 5 更新 tracker;任一步失败则继续后续步骤并在 tracker 中标记 pending。

输出语言指令:prose 语言与市场词汇分离

路由执行前有一个横切规则——Output Language Directive。Agent 在执行任何模式前,如果 config/profile.yml 存在则读取并解析两个键:

  • language.output → 面向人类输出的 ISO 语言代码,默认 en
  • language.modes_dir → 可选的市场模式目录,只控制市场词汇与本地评估规则。

然后在加载模式指令之后、产出任何用户可见内容之前,注入如下指令:

无论本指令或职位描述的语言是什么,所有面向人类的输出都用 {language.output} 撰写。这包括报告、tracker 笔记、PDF、求职信、外联消息、面试准备、表单答案和摘要。如果 language.modes_dir 提供了市场特定词汇,保留市场逻辑,但必要时用 {language.output} 解释术语。

关键约束是"language.output 对 prose 具有权威性,modes_dir 只是市场上下文,绝不能强制 prose 语言"。仓库中的 config/profile.example.yml 给出了配套示例:

language:
  output: en
  # modes_dir: modes/de  # 可选:使用 DACH 市场词汇但仍用英文写作

从配置注释看,zh-CN 还会额外启用中文 PDF 排版规则。这个设计的实用价值在于:一个在德国市场求职、但希望所有报告和简历都用英文写作的用户,可以同时获得 DACH 市场的词汇与评估规则(modes/de/ 目录确实存在)而不改变输出语言。

Discovery 菜单:36 个入口的完整清单

无参数调用时,路由器展示如下命令菜单(原文完整保留,作为该系统的"功能总目录"):

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.

菜单末尾的 Inbox 提示揭示了另一条常用工作流:把 URL 追加到 data/pipeline.md,再用 /career-ops pipeline 批量处理。对 Codex 这类无斜杠命令的会话,SKILL.md 还给出了一组"斜杠命令 ↔ 自然语言提示词"的等价映射,例如 /career-ops scan ↔ "Run the career-ops scan mode and summarize new matches.",保证同一套语义在两种调用面上都能落地。

上下文加载:三个级别的文件组合

确定模式后,路由器的最后一节规定"执行前先加载必要文件",按模式分成三个加载级别:

级别一:_shared.md + 模式文件(重评估类模式)。读取顺序为 modes/_shared.md + modes/_profile.md(若存在)+ modes/_custom.md(若存在)+ modes/{mode}.md。适用模式:auto-pipelineofertaofertaspdftextcontactoapplypipelinescanbatch。这些正是需要评分、事实门控、报告格式的评估型模式。

级别二:独立模式 + profile/custom 上下文。读取 modes/_profile.md(若存在)+ modes/_custom.md(若存在)+ modes/{mode}.md,不需要 _shared.md。适用模式:trackeragent-inboxdeepinterview-prepinterviewregional/eu-sweinterview/planinterview/practiceinterview/debrieflatexlatex-textrainingprojectpatternstitlesupskillfollowupreply-watchoutcomecoveremailaddoffer-prepdiscover

级别三:委派子代理的模式scanapply(带 Playwright)、pipeline(3 个以上 URL)以 worker/subagent 方式启动,把 _shared.md + _profile.md + _custom.md + modes/{mode}.md 的内容注入 worker 提示。SKILL.md 给出了标准调用形状:

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/_shared.md 中有明确定义,这是理解级别一/二差异的钥匙:

  • modes/_shared.md(系统层,可自动更新):文件头注释声明"THIS FILE IS AUTO-UPDATABLE",存放系统规则、评分逻辑与工具配置,"随每个 career-ops 发布改进"。它定义了唯一事实来源表(cv.mdarticle-digest.mdconfig/profile.yml_profile.md 等)、Data Root 解析顺序(环境变量 CAREER_OPS_ROOT/CAREER_OPS_DATA_DIR.career-ops-data 标记文件 → 仓库根)、spend_tier 到具体模型的映射表、五维评分体系与全局 1-5 分解释(4.5+ 立即申请、4.0-4.4 值得申请、3.5-3.9 视情况、低于 3.5 不建议申请)、Block G 职位真实性三档判定、公司类型与薪酬可信度分级、六大角色原型检测(AI Platform/LLMOps、Agentic/Automation、Technical AI PM、AI Solutions Architect、AI Forward Deployed、AI Transformation)、NEVER/ALWAYS 全局规则与工具表。
  • modes/_profile.md(用户层,永不自动更新):用户画像、叙事、谈判立场,用户自定义覆盖 _shared.md 的默认值。仓库提供 modes/_profile.template.md 作为起步模板。
  • modes/_custom.md(用户家规):SKILL.md 特别说明——如果存在,在 _profile.md 之后、所选模式文件之前读取;它可以覆盖工作流/风格默认值,但"绝不添加关于候选人的事实声明"。仓库同样提供 modes/_custom.template.md

这套分层的成本工程意图在 _shared.md 的"Subagent delegation (cost guardrail)"一节得到佐证:career-ops 派生的任何子代理都是"单程 worker"——不得再派生子代理、不得调用其他技能(尤其是开放式研究技能),因为"嵌套 Agent 会在一次运行中烧掉数千万 token";公司与薪酬研究必须 inline 完成,限定在模式点名的少量 WebSearch/WebFetch 查询内。这与 AGENTS.md 的 Headless/Batch 一节呼应:并行 fan-out 前先用 node reserve-report-num.mjs --count N 预占报告号段,避免并行 worker 各自计算 max+1 造成编号竞争(原文标注为 #749 race)。

从路由到执行:一次调用的完整链路

把以上各节串起来,一次 /career-ops https://company.com/jobs/123 调用的执行链路是:

  1. 入口:CLI 把该技能注册为 /career-ops(或 Cursor 自动发现该技能),$mode 收到 URL;
  2. 根解析:Agent 从 .cursor/skills/career-ops/ 向上找到同时含 AGENTS.mdmodes/ 的目录,确立 PROJECT_ROOT
  3. 路由判定:URL 不是已知子命令但符合 JD URL 特征 → 命中 auto-pipeline 兜底规则;
  4. 语言指令:读取 config/profile.ymllanguage.output(缺省 en),拼装输出语言指令;
  5. 上下文加载:级别一组合——_shared.md_profile.md_custom.mdauto-pipeline 所需模式文件(含 modes/oferta.md 的 A-G 块定义,auto-pipeline 的 Step 1 明确"执行与 oferta 模式相同的 A-G 评估");
  6. 执行:五步流水线(提取 JD → 存活/黑名单门禁 → A-G 评估 → 存报告 + 按分数阈值生成 PDF → 更新 tracker),其中评分口径(五维、全局 1-5、4.0 申请线)由 _shared.md 统一约束,保证任何 CLI、任何层级模型产出结构一致的报告——_shared.md 的 Output parity 规则明确"模型选择不改变 A-H 报告结构、标题或分节"。

复刻要点:多模式 Agent 路由器的设计清单

从 SKILL.md 这个 200 行不到的文件里,可以提炼出可直接迁移的设计要点:

  1. 路由器与执行体分离:SKILL.md 不含任何业务逻辑,只做"参数解析 + 文件加载顺序 + 委派决策";业务逻辑全部在 modes/*.md。这让新增一个模式(在路由表加一行 + 新增一个模式文件)成为低耦合操作。
  2. 双哨兵根解析替代 CWD 假设:对一切会读写文件的多目录 Agent 系统,"从技能/入口文件自身向上找哨兵目录"是比"信任当前工作目录"更稳的路径策略,且必须配"找不到就停"的失败行为。
  3. 启发式兜底优于报错:未知参数不是错误,而是进入两级判定(JD 特征 → auto-pipeline;都不像 → 菜单),把用户最随意的输入映射到最有价值的路径。
  4. 语言与市场双轨分离output 决定 prose 语言、modes_dir 决定市场词汇,两个正交配置键解决"目标市场语言 ≠ 用户偏好输出语言"的真实场景。
  5. 上下文加载分级 + 加载顺序即主从关系:系统规则(可自动更新)→ 用户画像(覆盖默认)→ 用户家规(覆盖流程但不添加事实)→ 模式文件,顺序本身就是权限模型;子代理委派时把同样的顺序序列化进 prompt,保证主/子会话行为一致。
  6. 成本控制写进路由层:哪些模式走子代理、子代理禁止嵌套、并行前预占编号资源——这些运行时纪律在路由文档中前置声明,而不是散落在各模式里。

对于正在用 Claude Code / Codex / OpenCode 等 CLI 构建"一个入口、多个子模式"的 Agent 技能,SKILL.md 提供了一个可完整参照的范本:frontmatter 声明触发面,正文声明根解析、路由表、兜底规则、横切指令(语言)与上下文加载协议,业务则全部外置到可独立演进的模式文件中。

登录后查看全文
热门项目推荐
相关项目推荐