Skills
SKILL.md 已成跨厂商标准:CC 与 Codex 都读 ~/.agents/skills 或同构目录,分歧在触发方式(CC 编译成 /命令 + 模型自触发,Codex 用 $mention + 隐式调用探测)与 frontmatter 丰富度
Skills
结论
Skills 是继 hooks 之后第二个跨厂商收敛点,而且收敛到了文件格式层面:两家都用 skill-name/SKILL.md 目录格式,Codex 甚至直接扫描 ~/.agents/skills 和项目内 .agents/skills(agentskills.io 开放标准的共享目录)。分歧在运行模型:CC 把 skill 编译成 Command 对象(与 slash command 同一类型),用户可 /skill-name 调用、模型可自动触发,frontmatter 字段多达 17 个(model/effort/agent/context:fork/paths/hooks…);Codex 把 skill 当上下文注入,用 $skill-name mention 显式引用,注入为 <skill> 用户消息片段,并独有"隐式调用探测"——模型 bash 跑了某 skill 的 scripts/ 下脚本也算调用了该 skill。harness 校验器以 agentskills.io 的 name+description 必填为底线,再按 runtime 叠加各自字段规则。
研究问题
- skill 文件格式与 frontmatter 各家差异(必填项、扩展字段)?
- 扫描目录与 scope 优先级?
- 触发机制:用户调用、模型自动触发、隐式调用各如何实现?
- harness 内置校验器应覆盖哪些规则?
各 Agent 设计与实现
Claude Code
格式与标准。 [一手文档] claude-code-docs/docs/skills.md:19:CC skills 遵循 Agent Skills 开放标准(agentskills.io),CC 在标准之上扩展了 invocation control、subagent 执行、动态上下文注入。/skills/ 目录只接受 skill-name/SKILL.md 目录格式,单文件 .md 不支持([一手源码] src_2026-03-31/skills/loadSkillsDir.ts:426);legacy /commands/ 目录两种格式都收(loadSkillsDir.ts:632-634)。
扫描目录与 scope。 [一手源码] loadSkillsDir.ts:638-714:managed(<managed>/.claude/skills,可用 CLAUDE_CODE_DISABLE_POLICY_SKILLS 关)、user(~/.claude/skills)、project(.claude/skills,从 cwd 向上走到 home)、--add-dir 附加目录、legacy commands 目录,五路并行加载后按文件 identity(realpath)去重,先到先得(loadSkillsDir.ts:728-763)。同名时 enterprise > personal > project,plugin skill 用 plugin-name:skill-name 命名空间永不冲突([一手文档] skills.md:110)。
Frontmatter:17 个字段。 [一手源码] loadSkillsDir.ts:185-264 parseSkillFrontmatterFields:name(displayName) / description / allowed-tools / argument-hint / arguments / when_to_use / version / model / effort / disable-model-invocation / user-invocable(默认 true) / hooks(skill 可携带会话级 hooks!)/ context: fork / agent(指定在哪个 subagent 里跑)/ paths(glob 命中才激活的条件 skill)/ shell。description 缺省时从正文抽取。
权限面。 [一手文档] docs/skills.md:531-534:skill 可被 permissions 规则逐个允许/拒绝:
{ "permissions": { "allow": ["Skill(commit)"], "deny": ["Skill(deploy-*)"] } }这是 CC 侧"禁用单个 skill"的实际等价物——不是加载期开关(Codex 的 [skills.config] 才是),而是调用期权限门。两种范式对 harness 的含义不同:CC 的 skill 仍占 frontmatter 索引 token,Codex 被禁用的 skill 完全不进上下文。
编译为 Command。 [一手源码] loadSkillsDir.ts:316-343 createSkillCommand 返回 type:'prompt' 的 Command——skill 和 slash command 在 CC 内部是同一个类型。运行时替换 ${CLAUDE_SKILL_DIR}、${CLAUDE_SESSION_ID}、$ARGUMENTS,并执行正文里的 !`cmd` bash 注入;MCP 来源的 skill 被禁止执行 bash 注入(远程不可信,loadSkillsDir.ts:371-374)。
触发:用户 /skill-name;模型经 SkillTool 自动触发(disable-model-invocation: true 可关);paths 命中文件时自动激活——带 paths 的"条件 skill"与无条件 skill 分池管理,激活后进入 activatedConditionalSkillNames 集合(loadSkillsDir.ts:771-779)。
渐进披露的成本模型。 [一手源码] loadSkillsDir.ts:97-104:skill 的常驻 token 成本只按 frontmatter(name+description+whenToUse)估算,注释原文 "full content is only loaded on invocation"。这是 skills 能大规模铺开而不爆上下文的关键设计,也是 harness 做"skill token 预算面板"时应采用的口径。
Codex CLI
格式。 [一手源码] codex-rs/core-skills/src/loader.rs:107:SKILLS_FILENAME = "SKILL.md",同样目录格式。元数据模型(core-skills/src/model.rs:14):name / description / short_description / interface / dependencies / policy / scope / plugin_id。其中 CC 没有的:
interface:display_name、大小图标、brand_color、default_prompt——为 GUI 门面准备(model.rs:60-67);dependencies.tools:声明 skill 依赖的工具(type/value/transport/command/url,可声明依赖某 MCP server,model.rs:69-82);policy:allow_implicit_invocation与products产品门控(model.rs:51-57)。
扫描目录与 scope。 [一手源码] loader.rs:290-360 + protocol.rs:3394 SkillScope { User, Repo, System, Admin }:
- Repo:各
.codex/配置层下的skills/,以及 cwd 到项目根之间每一级的.agents/skills(loader.rs:363-384); - User:
$CODEX_HOME/skills(已标记 deprecated,向后兼容)+~/.agents/skills(注释原文 "user-installed skills"); - System:
$CODEX_HOME/skills/.system(内嵌系统 skill 缓存); - Admin:
/etc/codex/skills。 排序 Repo(0) < User(1) < System(2) < Admin(3)(loader.rs:214-220)。
开关。 [一手源码] config/src/skills_config.rs:[skills] 支持 include_instructions(是否注入自动 skills 说明块)、bundled.enabled,以及按 path 或 name 选择器的逐条 enabled 开关——Codex 可以禁用单个 skill,CC 侧未见等价配置。
自动说明块与渲染。 [一手源码] core-skills/src/ 的 system.rs/render.rs 负责把可用 skill 清单渲染进自动 instructions 块([skills] include_instructions 可关),mention_counts.rs 统计 mention 频次喂遥测;远程 skill 有独立加载路径(remote.rs),skill 正文经 ExecutorFileSystem 抽象读取——支持从远端执行环境的文件系统读 skill(model.rs:150-157),与 MCP 章的 environment_id 远端能力同构。
触发:mention + 隐式探测。 [一手源码] mention 符号是 $(utils/plugins/src/mention_syntax.rs:4 TOOL_MENTION_SIGIL = '$')。被提及的 skill 正文以 <skill><name>…</name><path>…</path>…</skill> 用户消息片段注入(core-skills/src/skill_instructions.rs:31-40)。独有机制:detect_implicit_skill_invocation_for_command(invocation_utils.rs:29)——拦截 bash 命令,若模型在跑某 skill 的 scripts/ 目录下脚本或在读 SKILL.md 本体,就记账为该 skill 的隐式调用(识别 python/bash/node 等 10 种 runner + 7 种脚本后缀)。
差异矩阵
| 维度 | Claude Code | Codex CLI |
|---|---|---|
| 文件格式 | skill-name/SKILL.md(agentskills.io 标准) | 同(SKILLS_FILENAME = "SKILL.md") |
共享目录 .agents/skills | 不读 [推断](源码扫描列表中无) | 读:~/.agents/skills + 项目内逐级 .agents/skills |
| Scope | managed/user/project/--add-dir/plugin/bundled/mcp | Admin/System/User/Repo + plugin |
| Frontmatter 扩展 | 17 字段:model/effort/agent/context:fork/paths/hooks… | interface(图标/品牌色)/dependencies(工具依赖)/policy |
| 用户调用 | /skill-name(skill 即 Command) | $skill-name mention |
| 模型自动触发 | SkillTool;disable-model-invocation 可关 | 自动 instructions 块 + allow_implicit_invocation |
| 隐式调用探测 | 无 | 有:跑 scripts/ 脚本或读 SKILL.md 即记账 |
| 禁用单个 skill | 仅 permissions 规则(Skill(name))[一手文档] | [[skills.config]] name/path + enabled=false |
| 正文 bash 注入 | 有 !`cmd`(MCP skill 禁用) | 无(skill 是纯上下文注入) |
| 携带 hooks | 可(frontmatter hooks) | 不可(元数据无此字段) |
| 常驻 token 成本 | 仅 frontmatter 索引,正文按需载入 | 自动 instructions 块(可整体关闭) |
| 远端文件系统读取 | 不支持 [推断] | 支持(ExecutorFileSystem 抽象) |
最小复现
# 双 runtime 共享一个 skill(验证 .agents/skills 收敛)
mkdir -p ~/.agents/skills/demo && cat > ~/.agents/skills/demo/SKILL.md <<'EOF'
---
name: demo
description: say hello politely
---
Always greet in French.
EOF
codex # 输入 "$demo bonjour?" → skill 正文应注入(loader.rs:323 证明该目录被扫)
claude # /demo 不存在——CC 不扫 ~/.agents/skills,需复制到 ~/.claude/skills/(未实测,基于 loadSkillsDir.ts 目录清单)Harness 接入建议(Yoda 实践)
Yoda 的 harness-spec.ts 已声明 claude: ['.claude/skills']、codex: ['.agents/skills', '.codex/skills'],方向正确。建议:
- 检测补全:Codex 侧补
~/.agents/skills(用户级)与$CODEX_HOME/skills(deprecated 但仍生效);CC 侧补 managed 目录与 legacy.claude/commands(它们也是 skill)。注意 Codex 的.agents/skills是 cwd→项目根逐级扫描,单层检测会漏。 - 校验器分层:L1 通用(agentskills.io 底线):目录名/SKILL.md 存在、frontmatter 可解析、name+description 非空;L2 per-runtime:CC 校验 17 字段类型(重点
pathsglob、agent引用存在性、allowed-tools工具名);Codex 校验dependencies.tools引用的 MCP server 是否在 config 中、interface图标路径存在。 - 触发方式要在 UI 上区分:同一个 skill 在 CC 是
/demo、在 Codex 是$demo,harness 的"运行 skill"按钮要按目标 runtime 生成正确的调用语法。 - 调试:CC 看 skill 是否被 dedup 掉(同 realpath 先到先得);Codex 看
[skills.config]是否禁用、以及SkillLoadOutcome.errors(loader 失败不是静默的,有结构化错误可展示)。
失效条件
- CC 开始扫描
.agents/skills(与 Codex 完全收敛,"共享目录"差异行失效) - agentskills.io 规范字段变更(本章 L1 校验底线基于 name+description 必填)
- Codex
$mention 语法或<skill>注入格式变更(mention_syntax.rs/skill_instructions.rs) - CC skill frontmatter 字段增删(
parseSkillFrontmatterFields返回类型变化)
参考资料
- CC 源码:
src_2026-03-31/skills/loadSkillsDir.ts、skills/bundledSkills.ts、tools/SkillTool/SkillTool.ts - Codex 源码:
codex/codex-rs/core-skills/src/{loader.rs,model.rs,injection.rs,skill_instructions.rs,invocation_utils.rs}、config/src/skills_config.rs、utils/plugins/src/mention_syntax.rs - 文档:
claude-code-docs/docs/skills.md;codex/docs/skills.md(指向 https://developers.openai.com/codex/skills );https://agentskills.io - 未确认(UNCONFIRMED):agentskills.io 规范移交 Linux Foundation AAIF 一事在本地源码与文档中无佐证,引用前需另行核实
- Yoda:
yoda/src/renderer/features/projects/components/harness-view/harness-spec.ts
Plugins 与扩展分发
两家都有 plugin + marketplace 体系,且 Codex 直接兼容读取 CC 的 .claude-plugin/plugin.json——插件格式正在事实统一;CC 插件组件面更宽(7 类),Codex 把插件当 App Store 商品做(interface 元数据 + 模型可调用的安装工具)
Slash / 自定义命令
CC 已把自定义命令并入 skills(.claude/commands 与 SKILL.md 等价,同一 Command 类型);Codex 的 slash 命令是纯内建枚举,用户自定义入口完全让位给 skills 的 $mention——"自定义命令"作为独立概念正在消亡