OpenHuman Skills 子系统完全指南:SKILL.md 发现、作用域解析、信任标记与安全执行
2026/9/10 1:18:07 网站建设 项目流程

OpenHuman Skills 子系统完全指南:SKILL.md 发现、作用域解析、信任标记与安全执行

【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman

导读

本文以 OpenHuman 仓库中 src/openhuman/skills/README.md 为核心,系统拆解 Skills 子系统的完整能力边界:如何发现并解析 agentskills.io 风格的技能包(一个含 YAML frontmatter 与 Markdown 指令的SKILL.md目录)、User / Project / Legacy 三种作用域如何解析与冲突裁决、信任标记(trust marker)如何门控项目级技能加载、资源读取的安全边界,以及技能如何通过run_skill在隔离 worker 中执行。读完本文,你将掌握技能包目录布局、frontmatter 字段语义、安装/卸载/资源读取的 RPC 面、事件总线触发机制,以及仓库源码中对应的实现与测试位置。

注:当前仓库已把技能领域内部术语从 "skill" 迁移为 "workflow"(如ops_types.rsWorkflow/WorkflowScope/WORKFLOW.md),但SKILL.md仍是向后兼容的主定义文件,RPC 面也保留skills.*命名,全文按既有公开 API 名称展开。

Skills 子系统的职责边界

根据 README 与 mod.rs 模块文档,Skills 子系统只负责技能的发现、解析、作用域管理、信任标记执行、资源读取与安装/卸载,明确不拥有运行时执行内部机制与通用工具执行(后者属于tools//javascript/)。

  • 发现与解析:扫描目录、读取SKILL.md的 YAML frontmatter 与 Markdown 指令体,见 ops_discover.rs 与 ops_parse.rs。
  • 作用域解析:User vs Project vs Legacy(以及后续新增的 Profile 作用域)的优先级裁决。
  • 信任标记执行:项目级技能仅在<workspace>/.openhuman/trust存在时加载。
  • 资源读取:读取技能捆绑的子资源(scripts/references/assets/等),并做路径穿越/符号链接/大小/UTF-8 四重防护。
  • 安装 / 卸载:基于 HTTPS 的 URL 安装与卸载,见 ops_install_part_01.rs。

技能最终以紧凑的## Installed Skills目录形式暴露给 Agent,并通过run_skill在隔离 worker 中执行——技能正文不再被拼接进聊天轮次。README 明确:"bodies are no longer spliced into chat turns",这是与早期"提示词拼接"式技能实现的关键区别。

从 mod.rs 还可以看到两个重要架构事实:

  1. 编译期特性门控pub mod skills;始终编译(作为 facade),而opsbusschemasregistry等行为性子模块由默认开启的skillsCargo feature 门控;关闭时由 stub.rs 提供同签名空实现。
  2. 类型不参与门控typesops_types在两种 feature 方向下都编译,因为ToolResult/ToolContenttools::traits再导出为整个 crate 的统一工具结果类型(约 236 个文件消费),Workflow/WorkflowFrontmatter/WorkflowScope也出现在常开的 agent-harness 与提示词签名中。

公开 API 面(Public surface)

README 列出的公开 API 全部可在源码中逐项确认:

公开项位置说明
pub enum SkillScope(现为WorkflowScopeops_types.rs发现作用域User/Project/Legacy(另有Profile),决定同名冲突时的优先级
MAX_SKILL_RESOURCE_BYTES(现为MAX_WORKFLOW_RESOURCE_BYTES = 128 * 1024ops_types.rs单资源 RPC 载荷上限(128 KB)
pub use ops::*mod.rs再导出发现、解析、安装、卸载、资源读取与 frontmatter 类型
pub struct ToolResult/pub enum ToolContenttypes.rs技能/工具执行返回的内容块
pub mod busbus.rs在全局事件总线上发出技能事件
RPCskills.{skills_list, skills_read_resource, skills_create, skills_install_from_url, skills_uninstall}schemas/mod.rs 与 controller_schemas.rs通过all_skills_controller_schemas/all_skills_registered_controllers注册

RPC 控制器全部通过持久化配置层(config::load_config_with_timeout)解析活动工作区,因此 CLI 与 UI 看到的是同一份技能目录,调用方无需手动传入工作区路径。

技能包格式:SKILL.md + frontmatter + 捆绑资源

目录布局与定义文件

一个技能就是一个目录,核心定义文件是SKILL.md:YAML frontmatter(含namedescription等必填字段)+ Markdown 指令体。可选捆绑资源位于兄弟子目录中。从 ops_types.rs 的RESOURCE_DIRS可以看到当前支持的资源目录:

  • scripts/references/assets/(传统三个)
  • templates/examples/prompts/(Hermes 风格技能常见目录,按可浏览资源处理,不作为可执行运行时入口)

此外 ops_types.rs 定义了向后兼容的文件名常量:

常量文件名状态
WORKFLOW_MDWORKFLOW.md当前主定义文件(create/update 写入)
WORKFLOW_TOMLworkflow.toml当前 sidecar 清单(inputs / when_to_use / [github])
SKILL_MDSKILL.md旧定义文件,skills→workflows 重命名前编写的技能仍会读取
SKILL_TOMLskill.toml旧 sidecar 清单,向后兼容读取
SKILL_JSONskill.json更早的清单格式,向后兼容读取

Frontmatter 字段语义

WorkflowFrontmatter(ops_types.rs)严格对齐 agentskills.io SKILL.md 规范:

字段必填说明
name技能名,也是同名冲突的裁决键
description短描述,用于目录摘要
license许可证
compatibility兼容性说明
platforms平台兼容提示(Hermes 风格),缺省表示全平台
metadata规范兼容的元数据 map,versionauthortags等非必填字段应放这里
allowed-tools技能作者声明的依赖工具(非强制提示,宿主决定暴露什么)
triggers激活该技能的事件触发模式(见下文事件总线章节)
extra规范扩展的落点(#[serde(flatten)]);旧式顶层version/author/tags会触发迁移警告

解析时对顶层遗留字段的兼容处理可参看 ops_types.rs 的extract_version/extract_author/extract_tags:优先读metadata.*,否则回退到顶层并在warnings中记录弃用提示。

frontmatter 解析实现

ops_parse.rs 的parse_workflow_md/parse_workflow_md_str展示了解析细节:

  • 以首行---开启 frontmatter 块,以第二个---终止;未终止的 frontmatter 块返回None(解析失败)。
  • 无 frontmatter 时整文件视为指令体(返回默认WorkflowFrontmatter)。
  • YAML 反序列化失败不致命:记录frontmatter parse error警告并回退到默认 frontmatter,保证技能仍可被发现。

load_from_workflow_md(同文件后半部分)将SKILL.md组装为完整的Workflow结构,inventory_resources(ops_parse.rs)浅扫技能目录枚举资源——注意它用symlink_metadata拒绝符号链接资源根,且walk_files递归时同样跳过符号链接,防止无限递归与目录外泄漏。

作用域(Scope)解析与冲突裁决

三种作用域 + Profile

README 描述的是三作用域模型,当前源码已扩展为四作用域(ops_types.rs):

作用域磁盘位置优先级
User(默认)~/.openhuman/skills/<name>/~/.agents/skills/<name>/1
Project<workspace>/.openhuman/skills/<name>/<workspace>/.agents/skills/<name>/需信任标记2
Legacy<workspace>/skills/<name>/(扁平旧布局)0
Profile<workspace>/personalities/<id>/skills/,仅活动 profile 的轮次可见3

从源码结构看,Profile 作用域是后来为"按 Agent profile 私有技能"新增的:discover_workflows_with_profile扫描 profile 私有根目录,无需信任标记(目录由 core 管理),且对所属 profile 在同名冲突中拥有最高优先级,会遮蔽同名的全局技能。默认会话与其他 profile 完全不受影响(Nonediscover_workflows逐字节等价)。

信任标记(Trust Marker)

项目级技能只有在<workspace>/.openhuman/trust存在时才加载。is_workspace_trusted(ops_discover.rs)实现极简:文件内容被忽略,存在即信任。这是关键安全边界——克隆一个陌生仓库后,skills/目录中的项目级技能默认不会进入 Agent 上下文,用户必须显式放置信任标记才会加载。

发现顺序与冲突裁决

discover_filtered(ops_discover.rs)的实现要点:

  • 扫描顺序:User 根 → Project 根(仅 trusted 时)→ Legacy<ws>/skills/→ Profile 根。HashMap以 name 为键,后注册者覆盖先注册者。
  • 优先级函数precedenceLegacy=0 < User=1 < Project=2 < Profile=3。同名冲突时高优先级保留,低优先级技能被丢弃并在保留者的warnings中记录遮蔽原因(如"shadowed Project-scope skill ... at <path>"),这些警告会浮现在目录摘要中供用户调试。
  • 稳定性保证read_dir顺序未定义,为避免同名兄弟目录跨运行产生非确定性胜者,scan_root_inner先按磁盘目录名排序再处理。
  • 排除规则EXCLUDED_SKILL_DIRS跳过.git.githubnode_modules__pycache__.venv等常见无关目录;点开头的目录名也跳过。
  • 符号链接防护:用file_type()而非path.is_dir()判断——is_dir()会解引用符号链接,可能重新打开目录外加载漏洞;manifest 文件也要求是真实(非符号链接)常规文件。

发现结果按name排序输出。README 提到的 "project-scope wins" 在代码中得到印证,并且冲突警告中同时给出dir_namename、作用域与磁盘位置,方便定位。

资源读取的安全边界

read_workflow_resource/read_workflow_resource_with_profile(ops_discover.rs)是 README 所述"resource reading"的实现核心,防护层层递进:

  1. 参数校验skill_idrelative_path非空;拒绝绝对路径;拒绝任何...、空组件与 Windows 前缀(Component::ParentDir | CurDir | RootDir | Prefix)。
  2. 技能解析:复用标准发现管线(含信任标记与 profile 根),将读取范围限定在已安装技能集合内。
  3. 根目录校验:先canonicalize技能根(要求真实目录,非符号链接)。
  4. 叶子检查:用symlink_metadata预先拒绝符号链接与非常规文件(socket/fifo/目录)。
  5. 大小门禁leaf_meta.len() > MAX_WORKFLOW_RESOURCE_BYTES (128 KB)直接拒绝——先看元数据再读文件,避免为超大文件分配缓冲区。
  6. 穿越校验canonicalize完整路径并断言其仍在技能根之内。
  7. 严格 UTF-8:非 UTF-8 内容直接拒绝(不做 lossy 替换,宁可拒绝二进制文件也不静默损坏)。

resolve_workflow_for_resource(同文件 ops_discover.rs)支持用dir_name(磁盘目录 id)或name(frontmatter 显示名)定位技能,二者歧义时报错,明确要求使用目录 id。

安装 / 卸载:HTTPS URL 安装器

install_workflow_from_url(ops_install_part_01.rs 起)实现了 README 所述的 URL 安装:

核心常量

常量含义
DEFAULT_INSTALL_TIMEOUT_SECS60s默认拉取超时
MAX_INSTALL_TIMEOUT_SECS600s调用方可请求的超时上限
MAX_INSTALL_URL_LEN2048URL 长度上限
MAX_WORKFLOW_MD_BYTES1 MiBSKILL.md 正文大小上限(防御恶意/错误配置主机流式返回无限响应)

网络 I/O 前的验证

  • URL 必须为https://;拒绝回环、私网、link-local、组播、共享地址段、localhost.local/.localhostmDNS 主机名。
  • github.com/<o>/<r>/blob/<b>/<p>自动改写为raw.githubusercontent.com/<o>/<r>/<b>/<p>,方便用户直接粘贴浏览器地址。
  • 路径必须以.md结尾(大小写不敏感);repo/tree URL 与 tarball 被拒绝(unsupported url form:)。
  • timeout_secs被钳制到MAX_INSTALL_TIMEOUT_SECS

运行时行为

  • 先查Content-Length头,下载后再校验缓冲长度(双保险,防谎报头)。
  • frontmatter 校验:按 agentskills.io 规范要求namedescription必填。
  • slug 派生:优先metadata.id,否则用清洗后的name。若目标目录已有SKILL.md,视为幂等成功(报告"已安装");其他目录冲突保持致命,已有文件绝不静默覆盖
  • 写入原子化:目标目录写SKILL.md.tmp,成功后rename
  • 安装完成后重新发现完整目录,返回自调用开始新出现的 skill slug 列表(new_skills)。

安装目的地为<workspace>/.openhuman/skills/<slug>/SKILL.md。README 所在模块的注释解释了设计动因:vercel-labsskillsCLI 写入的 per-agent 目录(./claude-code/skills/./cursor/skills/等)与 OpenHuman 的技能布局不兼容,因此直接拉取 SKILL.md 并写入发现管线可见的布局。

一个值得注意的运维细节:HTTP localhost 安装默认被拒,需显式设置OPENHUMAN_SKILL_INSTALL_ALLOW_LOCAL_HTTP=1(仅用于本地 fixture)。

事件总线与触发器(bus.rs)

bus.rs 实现了 README 中 "emits skill events on the global event bus" 的承诺,并进一步支撑了WorkflowFrontmatter::triggers字段:

  • TriggerPattern::parse:将"composio""composio/trigger_received""cron""channel/inbound_message"等原始字符串解析为domain+ 可选event_slug。裸 domain(无/)匹配该域内任何事件;slug 为*也视为匹配整个域。
  • TriggerPattern::matches:先比对event.domain(),slug 限定模式在DomainEvent暴露稳定slug()之前暂不能精确匹配(源码留有TODO(#skills-triggers),实现上保守地避免静默匹配整个域)。
  • TriggeredWorkflowIndex+TriggeredSkillSubscriber:启动时为声明triggers:的技能建立索引并注册订阅者;匹配事件到达时记录应激活的技能。实际 agent-session 启动有意不在此处——它需要完整 harness 上下文(provider、memory、config),由 channel runtime 在总线初始化后接线,本模块只提供类型管道与观察者。

运行时执行:catalog 与 runtime 两个子模块

虽然 README 声明"Does NOT own runtime execution internals",当前仓库已将技能领域进一步组织为两个子模块,理解它们有助于定位源码:

catalog(技能注册表)

catalog/README.md 说明skill_registry负责远程技能目录与已装技能生命周期:

  • 拉取并缓存远程目录(默认https://hermes-agent.nousresearch.com/docs/api/skills.json)。
  • 核心启动时异步强制刷新远程目录(OPENHUMAN_SKILL_REGISTRY_REFRESH_ON_BOOT=0可关闭),不阻塞核心就绪。
  • 提供浏览/搜索、派生 Hermes 内置与可选技能的安装 URL、安装到用户技能目录、卸载用户作用域技能,并托管内置skill_setupagent。

可用环境变量覆盖(用于生产脚本与确定性测试):

OPENHUMAN_SKILL_REGISTRY_CATALOG_URL=https://example.com/skills.json OPENHUMAN_SKILL_REGISTRY_DOWNLOAD_BASE_URL=https://example.com/skills OPENHUMAN_SKILL_REGISTRY_REFRESH_ON_BOOT=0

生产冒烟示例:

openhuman skill_registry schemas openhuman skill_registry browse --force_refresh true openhuman skill_registry search --query git openhuman skill_registry sources openhuman skill_registry install --entry_id git-helper openhuman skill_registry uninstall --name git-helper

runtime(技能执行)

runtime/README.md 说明skill_runtime拥有已装SKILL.md工作流的执行:

  • 启动与取消技能运行、读取近期运行元数据与运行日志。
  • 脚本型技能运行前解析可复用的语言运行时:复用runtime_node(Node.js、npm、npx 与 PATH 注入)与runtime_python(Python 解释器解析与进程启动),复用workflows的发现、元数据、资源与运行日志。
  • 托管内置skill_executoragent。

生产冒烟示例:

openhuman skill_runtime schemas openhuman skill_runtime resolve_runtimes --runtime all openhuman skill_runtime run --skill_id git-helper --inputs '{}' openhuman skill_runtime recent_runs --limit 10

兼容性承诺:既有openhuman workflows runworkflows cancel与运行日志 RPC 保持可用;新脚本应优先使用skill_runtime命名空间。

技能即带输入的 Agent

registry.rs 揭示了技能与 Agent 的关系:一个技能就是一个AgentDefinition加上声明的[[inputs]]。agent 字段(idsystem_prompttoolsmax_iterationssandbox_mode等)从同一skill.toml扁平化注入,因此技能本质是"同时广告自己所需输入的、可运行的 Agent"。WorkflowInputname/description/required/type)在skill_run时取值并渲染进提示词(render_inputs_block)。[github]块(含IdentityMatch枚举:Strict/Any/None)是可选预检门——存在且required = true时,orchestrator 启动前会运行 GitHub 身份一致性预检。

与 Agent 层的交互点

README 的 "Calls into / Called by" 章节说明了技能目录如何进入 Agent 上下文:

  • ## Installed Skills目录渲染:prompt.rs 渲染该章节,数据源是PromptContext上的技能列表(context.rs)。
  • 每轮注入:turn.rs 是 per-turn 注入点;fork_context.rs 在 fork 上下文时传播注入的技能。
  • 提示词章节:mod.rs 与 types.rs 渲染## Available Skills目录章节。
  • 工具结果类型共享:traits.rs 消费ToolResult/ToolContent
  • 工作区引导:ops.rs 在工作区启动时触碰技能目录布局。
  • 集成 agent:integrations_agent/prompt.rs 读取技能目录。
  • 控制器注册:all.rs 完成all_skills_registered_controllers的接线。

测试布局

README 指出本领域没有独立*_tests.rs文件,单测与实现同文件共存(#[cfg(test)] mod tests)。当前仓库结构有所演进,实测测试文件分布为:

  • 顶层:ops_tests.rs、ops_types.rs(types_tests.rs等)、bus_tests.rs、registry_tests.rs、preflight_tests.rs、run_log_tests.rs、tools_tests.rs、schemas_tests.rs。
  • 作用域与解析专项:ops_discover_include_skills_tests_tests.rs、ops_discover_profile_scope_tests_tests.rs、ops_create_render_skill_toml_tests_tests.rs、ops_install_install_fetch_tests_tests.rs。
  • 端到端:e2e_plumbing_tests.rs 与 e2e_run_tests.rs。
  • 跨切面行为:README 指出由 turn_tests.rs 与 runtime_tests.rs 间接覆盖(agent + skill 的组合行为)。

小结:一张图看懂技能生命周期

一个技能从落地到执行,完整经过以下阶段:

  1. 落地skills.install_from_url经 HTTPS 拉取SKILL.md(校验 URL 安全、大小与超时、frontmatter 必填项、slug 冲突),原子写入<workspace>/.openhuman/skills/<slug>/;或由skills.create脚手架新技能,或用户手动放置到~/.openhuman/skills/
  2. 发现:启动/轮次时扫描 User / Project(需信任标记)/ Legacy / Profile 根,按优先级吸收同名冲突,产出按 name 排序的目录。
  3. 暴露:技能以## Installed Skills紧凑目录进入 Agent 提示词;skills.list/skills.describe(含[[inputs]])供 UI 渲染动态表单。
  4. 资源skills.read_resource以 128 KB 上限 + 路径穿越/符号链接/UTF-8 防护读取捆绑资源。
  5. 触发:声明triggers:的技能由事件总线订阅者匹配DomainEvent记录激活。
  6. 执行skill_runtime run/run_skill在隔离 worker 中运行(复用 Node/Python 语言运行时),skills.cancel取消,运行日志经run_log查询。

至此,你已掌握 OpenHuman Skills 子系统的目录规范、frontmatter 语义、四作用域裁决、信任标记门控、资源读取安全边界、URL 安装器的验证链、事件触发机制与运行时架构——这些都可以直接对照 src/openhuman/skills/ 目录下的源码与测试继续深挖。

【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询