Internal preview

WeHub Research Blog

这是研究博客的内部预览入口。输入口令后继续阅读。

2026-06-05 preview 14 min read

Agent runtime / Skill portability

打破 Runtime 壁垒:Agent Skills 的 Portable Core 与 Runtime Adapter

从 Claude Code、Codex、OpenCode、Cursor、OpenClaw、Hermes 的 skill 支持看 Agent Skills 的共同外壳、portable core 与 runtime adapter 边界。

如果只看表面,2026 年的 agent skill 生态正在明显收敛:越来越多 runtime 都开始接受一个朴素形态:

my-skill/
  SKILL.md
  scripts/
  references/
  assets/

SKILL.md 里有 YAML frontmatter,至少声明 namedescription;正文写明 agent 在某类任务里该如何判断、行动和验收;脚本、参考资料、模板和静态资源按需放在附属目录里。Anthropic 的 Agent Skills 标准把这个模式正式化,并把核心机制命名为 progressive disclosure:启动时只暴露名称和描述;任务匹配时再加载完整 SKILL.md;必要时继续读取 references/scripts/assets/

这就是“可移植”的来源。

但真正有意思的地方不是大家都叫 SKILL.md,而是不同 runtime 在这个共同外壳下做了完全不同的工程取舍。Claude Code、Codex、OpenClaw、Hermes、OpenCode、Cursor 都可以读 skill,但它们分别在回答不同问题:命令如何触发,workflow 如何分发,gateway 如何做安全门,长期 agent 如何复用程序化记忆,terminal agent 如何按需加载,IDE agent 如何结合文件上下文。

所以,Runtime 壁垒不是 SKILL.md 能不能复制的问题。真正的壁垒藏在加载时机、权限模型、分发机制、工具命名、消息通道、上下文预算、IDE/terminal/gateway 语义和安全边界里。

本文的结论很简单:不要写一份“万能 skill”。应该写一份足够纯的 portable core,再为每个 runtime 写很薄的 runtime adapter

生长卡片:这篇博客不是终稿,而是 MSP Blog

这篇文章本身也是一个正在生长的 MSP artifact。它现在已经从“调研文章”长出三层进展:

  • 认知层:确认 skill 的可迁移部分不是某个 runtime 的 Markdown 文件,而是任务判断、流程、输入输出和验收标准。
  • 对照层:形成 Claude Code、Codex、OpenCode、Cursor、OpenClaw、Hermes 六个 runtime 的 adapter matrix。
  • 实验层:开始用 nano-seed-card 做 cross-runtime sample,把一个 portable core 拆成 Hermes / OpenClaw / Codex / Claude Code adapters,并用 manifest 记录 smoke test 与 forbidden-in-core 规则。

下一步不是继续把正文写长,而是让每篇博客都保持一个可继续 grow 的 seed:当新的 runtime、真实迁移失败或团队内部 skill 投放需求出现时,文章、matrix、sample adapter 和 seed file 一起迭代。

1. SKILL.md 共同标准解决了什么

Agent Skills 标准的最小合同很克制:

---
name: pdf-processing
description: Extract PDF text, fill forms, merge files. Use when handling PDFs.
---

正文可以写步骤、例子、边界和验收。附属目录可以放脚本、参考资料和模板。它解决的不是“让 agent 拥有新工具”,而是让 agent 在遇到某类任务时拥有一份可复用的操作手册。

这点很关键:工具是函数,skill 是程序化知识。工具告诉 agent “你可以调用什么”;skill 告诉 agent “在这个任务里,怎样判断、怎样组织上下文、怎样避免常见错误、怎样验收结果”。

共同标准真正可迁移的部分包括:

  • 触发条件:什么用户意图应该使用这个 skill。
  • 工作姿态:agent 在这类任务里应该如何判断。
  • 抽象流程:先收集什么,再执行什么,再验证什么。
  • 输入输出:接收哪些材料,产出什么证据。
  • 验收标准:怎样算完成,怎样算失败。
  • 参考材料组织:哪些内容放正文,哪些放 references/
  • 确定性脚本:只要脚本不依赖特定 runtime 的隐式路径和工具名。

这些内容构成 portable core。它应该尽量描述任务本身,而不是描述某个 runtime 的私有能力。

2. 六个 runtime,其实是六种合同

同一个 SKILL.md 外壳,在不同系统里承担的合同并不一样。

Claude Code 更像“命令 + 自动触发上下文”。它把 custom commands 和 skills 合流:.claude/skills/deploy/SKILL.md 既可以成为 /deploy,也可以被模型按 description 自动选中。它关心 user-invocable、allowed/disallowed tools、argument hint、是否走子 agent、是否动态注入命令输出等问题。因此 Claude Code 的 adapter 重点是 invocation、permission 和 developer workflow。

Codex 更像“workflow 作者格式 + plugin 分发单元”。它支持 .agents/skills、用户级与系统级 skills,也区分 local skill 和 plugin。skill 负责描述 workflow;plugin 负责可安装、可分发、可带 MCP/app metadata 的包。Codex 还会管理初始 skill list 的上下文预算,说明它把 skills 当成可规模化安装生态,而不只是三五个本地脚本。

OpenClaw 更像“agent gateway 里的能力包、安装单元和安全门”。它不只是把 SKILL.md 给模型看,还要判断这个 skill 在当前 agent、机器、sandbox、channel 中是否安全可用。metadata.openclaw、依赖探测、env/secrets 注入、ClawHub verify、command dispatch、eligible skill snapshot 等,都属于 gateway adapter 语义。OpenClaw 的问题域是:怎样把一个不完全可信的能力包挂进长期运行的本地 agent gateway。

Hermes 更像“长期运行 agent 的程序化记忆”。Hermes skill 常常沉淀某类任务的入口、工具集、profile 约束、平台通道习惯和验证清单。真实能力通常由 session、profile、toolsets、gateway 和 channel 共同决定,而不是由 SKILL.md 单独声明。Hermes 的 adapter 重点不是 package spec,而是长期 agent 在具体运行现场怎样稳定复用经验。

OpenCode 进一步证明了 terminal coding agent 也在收敛到 Agent Skills。它支持 skill folder + SKILL.md,通过 native skill tool 按需加载完整内容;搜索路径覆盖 .opencode/skills~/.config/opencode/skills,也兼容 .claude/skills.agents/skills 等目录。它的特殊之处在于 permission.skill:skill 可以被 allow、deny、ask,并且可按 agent override。OpenCode 还同时有 .opencode/commands.opencode/agents,这些属于 adapter 层,不应混进 portable core。

Cursor 则说明 IDE agent 场景也在向 Agent Skills 靠拢。它支持 .cursor/skills.agents/skills、用户级 skills,并兼容 Claude / Codex 目录;还支持 scripts/references/assets/。但 Cursor 的 IDE 语义很强:paths 可以按文件 glob scope skill,disable-model-invocation 可以把 skill 变成只手动触发;同时原有 .cursor/rules/*.mdc 仍然存在,并有 Rules → Skills migration。Cursor 的 adapter 边界是 IDE context、file scoping、rules/team dashboard,而不是任务本身。

把这六个放在一起看,结论反而更清楚:生态确实在收敛到 SKILL.md 外壳,但每个 runtime 都把自己的权限、分发、上下文和交互语义留在了外壳之外。每个 runtime 的完整设计原因,详情见 Claude CodeCodexOpenCodeCursorOpenClawHermes;横向对照见 六大 runtime skill adapter matrix

3. 为什么不能直接复制 skill

直接复制失败,通常不是因为 Markdown 读不了,而是因为 skill 里混入了 runtime 私有语义。

最常见的污染有六类。

第一类是路径污染。例如把 ~/.claude~/.codex~/.openclaw~/.hermes.cursor.opencode 这类路径写成任务本身的一部分。路径属于安装和发现策略,不属于 portable core。

第二类是工具名污染。一个 runtime 叫 message,另一个可能叫 send_message;一个有 browser tool,另一个只有 shell;一个有 Feishu/Discord first-class tool,另一个只是 MCP。portable core 最多说“把结果发送到用户所在 channel,并验证送达”;具体调用哪个工具属于 adapter。

第三类是权限污染allowed-toolspermission.skill、sandbox、secrets、ask/allow/deny 都不能只靠 Markdown 授权。Markdown 可以表达意图,但真实权限必须由 runtime 控制。

第四类是上下文污染。Claude Code / Codex / OpenCode / Cursor 都有 progressive disclosure,但触发和预算策略不同;OpenClaw 会把 eligible skills 编译进紧凑提示块;Hermes 更依赖 session/profile/toolset。skill 正文不该假设自己总会完整进入上下文。

第五类是消息语义污染。OpenClaw / Hermes 这类长期 agent gateway 需要区分“最终回答”和“显式发消息到 Discord/Feishu”;Cursor / Codex / OpenCode 更多是在 IDE 或 terminal 里和用户交互。把某个平台的回复协议写进 core,会让迁移时产生错发、漏发或双发。

第六类是分发污染。Codex plugin、Claude plugin、ClawHub、Cursor GitHub remote rule、OpenCode config directory 都是不同的分发层。SKILL.md 是作者格式,不等于完整 package manager。

所以,越成熟的 skill,越需要把“任务怎么做”和“在某个 runtime 里怎么跑”拆开。

4. Portable core 应该长什么样

一个健康的跨 runtime skill,可以这样组织:

skill-name/
  SKILL.md                 # portable core
  references/
  scripts/
  adapters/
    claude-code.md          # invocation / permissions / plugin notes
    codex.md                # .agents paths / plugin / openai.yaml notes
    opencode.md             # skill tool / permission.skill / command boundary
    cursor.md               # paths / rules / IDE scoping notes
    openclaw.md             # metadata.openclaw / gating / message rules
    hermes.md               # profile / toolsets / gateway/channel semantics

这里的 SKILL.md 只回答:

  • 什么时候使用这个 skill。
  • agent 应该怎样理解任务。
  • 有哪些关键步骤和判断点。
  • 需要读取哪些输入。
  • 产出什么结果和证据。
  • 什么情况下要停下来问人。
  • 怎样验收完成。

adapter 才回答:

  • 放在哪个目录会被发现。
  • 是否允许自动触发。
  • 是否暴露为 slash command。
  • 哪些工具/权限/secret/sandbox 是必须的。
  • 输出如何送回 IDE、terminal、Discord、Feishu 或其他 channel。
  • 是否需要 runtime-specific metadata。

这不是形式主义。它是在保护 core 的可迁移性。portable core 越纯,越容易在 Claude Code、Codex、OpenCode、Cursor、OpenClaw、Hermes 之间迁移;adapter 越薄,越容易看出具体 runtime 的真实边界。

5. 一个实用判断框架

写 skill 时,可以用五个问题决定内容该放哪里。

  1. 这句话是否只描述任务本身?
  • 是,放 portable SKILL.md
  1. 这句话是否提到了某个 runtime 的路径、命令、工具名、配置或 UI?
  • 是,放 adapter。
  1. 这句话是否决定权限、secret、sandbox 或安装依赖?
  • 是,放 runtime metadata / config;不要只写在正文里。
  1. 这段内容是否很长,且只有部分任务会用到?
  • 是,放 references/
  1. 这一步是否需要确定性执行?
  • 是,考虑放 scripts/,但脚本参数、依赖和路径要显式化。

用这个框架看各 runtime,差异就不再混乱:Claude Code 在回答“workflow 怎样变成命令”;Codex 在回答“workflow 怎样跨 CLI / IDE / App / plugin 分发”;OpenCode 在回答“terminal agent 怎样按需加载 skill 并做 per-agent permission”;Cursor 在回答“IDE agent 怎样结合文件上下文和 rules”;OpenClaw 在回答“能力是否能安全挂进 agent gateway”;Hermes 在回答“长期 agent 怎样稳定复用操作经验”。

6. 对 WeHub 的意义:从 seed.md 长出 runtime adapter

这件事对 WeHub 不只是技术写法问题,而是 agent 协作基础设施问题。

如果每个 runtime 都维护一套不可迁移 skill,我们会很快陷入重复劳动:OpenClaw 写一份,Hermes 写一份,Codex 写一份,Cursor/OpenCode 再各写一份。更糟的是,团队会把 runtime 私有约定误认为通用标准,导致迁移时不断踩权限、路径、工具和消息语义的坑。

按照 MSP 的理念,更合理的起点不是先写一份完整规范,而是让每个 skill 先有一个 seed.md。这个 seed 不绑定任何 runtime,只承载这个 skill 的最小真实问题:

  • 这个 skill 解决什么问题。
  • 什么用户意图应该触发它。
  • agent 的工作姿态是什么。
  • 最小流程和验收标准是什么。
  • 哪些材料是参考,哪些步骤需要脚本。
  • 哪些地方还不确定,暂时作为 seed 折叠。
  • 哪些内容显然属于 runtime adapter,而不是 core。

然后,用 seed.md + target runtime 作为输入,生成或 grow 出对应 runtime 的 skill:

seed.md + claude-code  -> .claude/skills/<name>/SKILL.md + permission notes
seed.md + codex        -> .agents/skills/<name>/SKILL.md + plugin/openai.yaml notes
seed.md + opencode     -> .opencode/skills/<name>/SKILL.md + permission.skill notes
seed.md + cursor       -> .cursor/skills/<name>/SKILL.md + paths/rules notes
seed.md + openclaw     -> OpenClaw skill + metadata.openclaw + install/security gate
seed.md + hermes       -> Hermes skill + profile/toolset/channel notes

这比“写一个万能 SKILL.md”更稳。seed.md 保持问题本身的纯度;runtime adapter 承接路径、权限、secret、channel、IDE/terminal/gateway 语义。未来如果某个 runtime 规则变了,只需要更新对应 adapter,不需要污染 core。

一个健康的项目结构可以是:

skill-name/
  seed.md             # MSP seed: problem, trigger, posture, flow, acceptance
  SKILL.md                  # portable core grown from the seed
  references/
  scripts/
  adapters/
    claude-code.md
    codex.md
    opencode.md
    cursor.md
    openclaw.md
    hermes.md

这套规范也不需要一开始做成大标准。先从一个真实 skill 做种子:比如 nano-seed-cardmsp-seed-iteration 或代码 review 类 skill。让它同时跑过 OpenClaw / Hermes / Codex / Cursor / OpenCode 中的两三个 runtime,再把实际迁移痛点长进 seed 和 adapter。

SKILL.md 让 agent 技能第一次有了足够简单的共同外壳:一个文件夹,一份说明书,一些可选脚本和参考资料。它让工作流可以被复制、审查、版本化和迁移。

但 runtime 壁垒不会因为文件名相同就消失。Claude Code、Codex、OpenCode、Cursor、OpenClaw、Hermes 的真正差异,都在 SKILL.md 之外:谁发现它,谁决定触发它,谁给它工具权限,谁安装它,谁验证它可信,谁管理上下文成本,谁负责把输出送到用户所在界面或 channel。

因此最成熟的做法不是写一份“万能 skill”,而是保留一份足够纯的 skill seed / portable core,再为每个 runtime 长出薄 adapter。真正打破 Runtime 壁垒的方式,不是抹平差异,而是让差异只出现在该出现的 adapter 里。

Sources

Source: research/blog/2026-06-05-portable-skill-core.md