尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

cc-haha 项目 Skills 使用指南:从六种来源到条件激活的完整实战手册

cc-haha 项目 Skills 使用指南:从六种来源到条件激活的完整实战手册 人工智能AI 应用桌面应用代码智能体MCP Clients【免费下载链接】cc-hahaLocal-first cross-platform desktop workspace for Claude Code / agents: multi-agent, Git worktrees, code diffs, skill marketplace, multi-model, Computer Use, task-aware desktop pets, with WeChat, Feishu, DingTalk, Telegram, WhatsApp and H5 access.项目地址https://gitcode.com/gh_mirrors/cl/cc-haha点击查看免费下载导读Skills 是 Claude Code 体系内的扩展能力引擎它让开发者可以用纯 Markdown 文件含 YAML frontmatter为 Agent 定义可复用的专业化工作流——代码审查、TDD、调试、批量处理等标准流程都能固化成一条斜杠命令。本文以 cc-haha 仓库 docs/internals/skills.md 为主线完整覆盖 Skill 的六种来源、Frontmatter 字段全解、三种调用方式、inline/fork 两种执行上下文、条件激活机制与权限控制并结合 src/skills/ 与 src/tools/SkillTool/ 的源码实现讲清一个 Skill 从磁盘文件到进入模型对话的完整链路。读完你可以直接上手创建、配置、共享和管控自己的 Skill。什么是 SkillsSkills 是 Claude Code 的可扩展能力插件系统。每个 Skill 是一个目录下的 Markdown 文件含 YAML frontmatter它定义了一段专门的提示词和行为配置让 Agent 在特定场景下执行专业化的工作流。与硬编码在二进制里的内建命令不同Skill 以纯文本形式存在谁都可以写、可以改、可以分享。核心能力一览能力说明专业化工作流定义代码审查、TDD、调试等标准流程工具权限控制限制 Skill 只能使用指定的工具模型切换为不同 Skill 指定不同的模型执行隔离Fork 模式在子 Agent 中独立运行条件激活只在操作特定文件时才激活Hook 注入Skill 调用时自动注册生命周期钩子在 cc-haha 的整体架构见 docs/internals/index.md中Skills 属于 CLI 内核的横切能力之一入口层初始化后Skills 与插件、MCP、OAuth、记忆等服务一起被主链路调用。桌面端、IM 端最终都复用同一套 CLI 内核因此 Skills 在任意入口下行为一致。六种 Skill 来源Agent 从 6 个不同来源加载 Skills按优先级从高到低依次为Bundled内置、Managed策略管理、User用户、Project项目、Plugin插件、MCPMCP 服务器。优先级决定同名冲突时的解析结果理解这一点对排查为什么我写的 Skill 没生效至关重要。1. Bundled内置 Skills编译到 CLI 二进制中所有用户可用。以 TypeScript 定义通过registerBundledSkill()注册见 src/skills/bundledSkills.ts。从 src/skills/bundled/index.ts 的initBundledSkills()可以看到内置 Skills 在 CLI 启动时同步注册部分还受特性门控feature flag约束。当前内置 SkillsSkill说明特殊条件/verify验证代码变更—/debug调试助手—/simplify代码简化审查—/remember记忆管理需启用 auto-memory/batch批量处理—/stuck卡住时求助—/skillify创建新 Skill—/keybindings自定义快捷键—/loop定时循环任务AGENT_TRIGGERS 特性门控/schedule远程代理调度AGENT_TRIGGERS_REMOTE 特性门控/claude-apiClaude API 集成BUILDING_CLAUDE_APPS 特性门控/dream自动记忆整理KAIROS 特性门控仓库中 src/skills/bundled/ 目录给出了这些内置 Skill 的实体实现例如verify.ts、debug.ts、simplify.ts、remember.ts、skillify.ts、dream.ts、loop.ts、claudeApi.ts等其中claude-api、verify、imagegen还携带了配套的 SKILL.md 与文档目录。2. Managed策略管理 Skills由组织策略控制存放在managed-path/.claude/skills/适用于企业部署。加载路径来自getManagedFilePath()见 src/skills/loadSkillsDir.ts 中getSkillsPath()对policySettings的处理这类 Skill 的权限由组织统一下发用户不能随意修改。3. User用户 Skills用户个人定义存放在~/.claude/skills/同时也会读取跨工具开放标准目录~/.agents/skills/。~/.claude/skills/ ├── my-review/ │ └── SKILL.md ← 主 Skill 文件 ├── deploy-check/ │ └── SKILL.md └── ... ~/.agents/skills/ ← 开放标准目录与 Codex / Cursor / Gemini CLI 共享 └── pdf-processing/ └── SKILL.md从 src/skills/skillRoots.ts 的实现看用户级根目录按.claude在前、.agents在后的顺序注册且共享同一scopeKey: user——这意味着同一层级的同名 Skill 会被视为冲突而非合法的覆盖关系.claude中的版本优先。4. Project项目 Skills项目级别定义存放在.claude/skills/或.agents/skills/可提交到版本控制随代码库分发给所有协作者。your-project/ ├── .claude/ │ └── skills/ │ ├── lint-fix/ │ │ └── SKILL.md │ └── test-runner/ │ └── SKILL.md └── .agents/ └── skills/ ← 团队共享其它 Agent 工具同样能发现 └── deploy-app/ └── SKILL.md项目级根目录的扫描范围由getProjectSkillRoots()定义从 cwd 向上遍历到 git 根目录最终不超过 HOME每个目录层级是独立的 scope因此pkg/.claude/skills/foo与pkg/.agents/skills/foo冲突而pkg/...与repo-root/...不冲突。关于.agents/skills/Agent Skills 开放标准.agents/skills/是跨客户端共享目录规范agentskills.io约定的目录名OpenAI Codex、Cursor、Gemini CLI、opencode 等工具都会扫描它。放在这里的技能不必再往每个工具的私有目录里复制一份。cc-haha 的实现在 src/skills/skillRoots.ts 中由AGENT_SKILLS_DIR .agents常量驱动并配套完整的开关逻辑两种目录同时生效SKILL.md格式完全一致无需改写。同一层级下若出现同名技能.claude/优先.agents/中的同名项被忽略会记录一条 warn 日志。不同层级如用户级与项目级同名仍按原有规则各自保留。通过软链接共享同一份技能时会自动识别为同一个不会重复加载——去重逻辑基于realpath()解析后的文件标识getFileIdentity()见 src/skills/loadSkillsDir.ts。如需关闭在settings.json中设置disableAgentSkillsDirectory: true或设置环境变量CLAUDE_CODE_DISABLE_AGENT_SKILLS_DIR1。关闭后.claude/skills/不受影响。源码中isAgentSkillsDirectoryEnabled()会先检查环境变量、再读 settings两者任一命中即关闭。技能市场安装、/skillify创建等写入操作仍然写到~/.claude/skills/。5. Plugin插件 Skills由已安装的插件提供。插件通过 manifest 的skillsPath/skillsPaths声明 Skills 目录。命名格式{pluginName}:{skillName}。例如superpowers:code-reviewer superpowers:brainstorming插件 Skill 的加载流程见 docs/internals/skills-internals.md会读取manifest.skillsPath与manifest.skillsPaths[]支持${CLAUDE_PLUGIN_ROOT}、${CLAUDE_PLUGIN_DATA}、${CLAUDE_SKILL_DIR}、${user_config.X}等变量替换命名空间展开为{pluginName}:{namespace}:{skillName}。6. MCPMCP 服务器 Skills由连接的 MCP 服务器提供命名格式mcp__server-name__prompt-name。MCP 的 prompts 通过fetchCommandsForClient()转换为 Command 对象见 src/services/mcp/client.ts由feature(MCP_SKILLS)特性门控控制可用性。安全限制MCP Skills 为远程不受信来源禁止执行!... 内联 shell 命令——在getPromptForCommand中会跳过executeShellCommandsInPrompt()这一步。Skill 定义格式目录结构每个 Skill 是一个目录包含一个SKILL.md文件文件名必须是SKILL.md大小写不敏感skill-name/ └── SKILL.md ← 文件名必须是 SKILL.md大小写不敏感Frontmatter 完整字段--- name: 我的技能 # 显示名称可选默认用目录名 description: 这个技能做什么 # 描述必填缺少时自动从内容提取 when_to_use: 什么时候该用这个技能 # 使用场景说明可选 version: 1.0.0 # 版本号可选 # ── 调用控制 ── user-invocable: true # 用户能否通过 /skill-name 调用默认 true disable-model-invocation: false # 禁止模型通过 Skill tool 调用可选 argument-hint: 文件路径 # 参数提示可选 # ── 执行配置 ── context: inline # 执行上下文inline默认或 fork子代理 agent: general-purpose # fork 时使用的代理类型可选 model: sonnet # 模型覆盖haiku / sonnet / opus / inherit可选 effort: high # 思考力度low / medium / high / max可选 allowed-tools: Bash, Read # 允许使用的工具逗号分隔或 YAML 列表 shell: bash # Shell 类型bash默认或 powershell # ── 条件激活 ── paths: src/**/*.ts, test/**/*.ts # Glob 模式只在匹配文件被操作时激活 # ── 生命周期 Hook ── hooks: PreToolUse: - matcher: Bash hooks: - command: echo Before bash once: true # 仅执行一次 --- # Skill 正文内容 这里是 Markdown 格式的提示词Claude 调用此 Skill 时会看到这些内容。 支持的特殊语法 - ${CLAUDE_SKILL_DIR} — 展开为 Skill 所在目录 - ${CLAUDE_SESSION_ID} — 展开为当前会话 ID - $ARGUMENTS / ${ARG1} — 参数替换 - !shell command — 内联 Shell 命令执行关于上述字段的源码佐证parseSkillFrontmatterFields()见 src/skills/loadSkillsDir.ts负责把 frontmatter 解析为结构化的 Command 对象其中description的提取优先级为frontmatter 中的description字段 → Markdown 第一个#标题 → 技能名称兜底model走parseUserSpecifiedModel()别名解析effort走parseEffortValue()Hook 配置经parseHooksFromFrontmatter()校验后按HooksSchema落库。FrontmatterData类型的完整定义可参考 src/utils/frontmatterParser.ts。Frontmatter 字段速查表字段类型默认值说明namestring目录名显示名称覆盖descriptionstring自动提取Skill 简述when_to_usestring—使用场景描述user-invocablebooleantrue用户能否输入 /name 调用disable-model-invocationbooleanfalse禁止模型调用contextinline|forkinline执行上下文agentstringgeneral-purposefork 时代理类型modelstring继承模型覆盖haiku/sonnet/opuseffortstring | int—思考力度allowed-toolsstring | list全部允许工具白名单pathsstring | list—条件激活 Glob 模式shellbash|powershellbashShell 命令类型hooksobject—生命周期 Hook 配置argument-hintstring—参数提示文本versionstring—版本号调用方式方式一用户斜杠命令直接在终端输入/skill-name /commit /review-pr 123 /verify前提Skill 的user-invocable必须为true。方式二模型自动调用Agent 在对话中识别到合适的 Skill 时通过 SkillTool 自动调用用户帮我审查一下这段代码 Claude[通过 SkillTool 调用 superpowers:code-reviewer]前提Skill 的disable-model-invocation不能为true。模型看到的 SkillTool 提示词src/tools/SkillTool/prompt.ts明确要求当某个 Skill 匹配时先生成任何其他回复之前调用该工具可用的 Skill 列表通过 system-reminder 消息注入绝不提及一个 Skill 却不调用工具不重复调用正在运行的 Skill。方式三嵌套调用一个 Skill 执行过程中可以触发另一个 Skill/verify → 内部调用 → /simplify遥测中通过invocation_trigger: nested-skill追踪。调用优先级当同名 Skill 存在于多个来源时按以下顺序解析先匹配先用1. Bundled内置 ← 最高优先级 2. Built-in Plugin内置插件 3. Skill Dirs用户/项目目录 4. Workflow Commands 5. Plugin Commands插件命令 6. Plugin Skills插件技能 7. Built-in Commands内建命令 ← 最低优先级该顺序在源码loadAllCommands()见 src/commands.ts中得到精确印证函数把bundledSkills → builtinPluginSkills → skillDirCommands → workflowCommands → pluginCommands → pluginSkills → COMMANDS()依次拼接成最终的命令表并使用memoize按 cwd 缓存加载结果避免重复磁盘 I/O。值得注意的是skillDirCommands内部又按 managed → user → project各自最具体优先→--add-dir的顺序排列因此策略级 Skill 在同目录层级内拥有更高话语权。执行上下文Inline 模式默认Skill 内容展开到当前对话中Agent 直接看到提示词并在同一上下文中执行。context: inline # 默认值可省略特点共享父对话的 token 预算可以访问对话历史上下文allowedTools限制当前轮次可用工具model覆盖当前轮次使用的模型从源码看inline 路径由processPromptSlashCommand()承载先经command.getPromptForCommand(args, context)展开内容完成${CLAUDE_SKILL_DIR}、${CLAUDE_SESSION_ID}、$ARGUMENTS替换与内联 shell 执行再注册 Skill 级 Hook、记录addInvokedSkill()最后通过返回的contextModifier()闭包更新 allowedTools、model 与 effort——其中模型覆盖通过resolveSkillModelOverride()保留[1m]之类的后缀标记。Fork 模式子 AgentSkill 在隔离的子 Agent中运行拥有独立的 token 预算和上下文。context: fork agent: general-purpose # 可选指定代理类型特点独立的 token 预算不消耗父对话额度隔离的对话上下文可指定不同的 agent 类型如Bash、general-purpose执行完成后提取结果返回父对话支持进度汇报onProgress回调Fork 路径由executeForkedSkill()驱动见 src/utils/forkedAgent.ts 的prepareForkedCommandContext()先获取 Skill 内容与工具白名单parseToolListFromCLI再通过createGetAppStateWithAllowedTools()修改 AppState 以收紧工具集选择command.agent ?? general-purpose作为子代理类型把 Skill 内容包装成一条用户消息喂给runAgent()最后从子代理消息中提取最后一条 assistant 文本作为结果嵌入 tool_result。fork 执行后不产生newMessages这是它和 inline 在返回结构上的本质区别。两种模式对比特性InlineForkToken 预算共享父对话独立预算上下文访问完整对话历史仅 Skill 提示词结果返回直接在对话中提取文本嵌入 tool_result适用场景简短指导、扩展上下文长任务、独立运算工具限制contextModifier 修改modifiedGetAppState条件激活Skill 可以通过pathsfrontmatter 实现按需激活只在操作匹配文件时才对模型可见。这能显著节省上下文一个带paths的 Skill 在启动时被放入conditionalSkillsMap 而不暴露给模型只有用户真正操作了匹配文件后才会被激活。配置方式--- name: TypeScript 修复 description: 修复 TypeScript 类型错误 paths: src/**/*.ts, test/**/*.ts ---工作原理1. 启动时加载所有 Skill 2. 带 paths 的 Skill 存入 conditionalSkills Map不暴露给模型 3. 当用户操作文件时Read/Write/Edit 4. activateConditionalSkillsForPaths() 用 ignore 库匹配 5. 匹配成功 → 移入 dynamicSkills Map → 模型可见 6. 一旦激活在会话内持续有效源码确认见 src/skills/loadSkillsDir.ts加载时无 paths → unconditionalSkills立即可用有 paths → conditionalSkills Map等待激活运行时activateConditionalSkillsForPaths()用ignore库把文件路径转为 cwd 相对路径后匹配 Glob 模式命中即移入dynamicSkillsMap同时记录遥测事件tengu_dynamic_skills_changed并触发skillsLoaded.emit()使命令缓存失效下一轮对话即加载新列表。动态发现除了条件激活Skills 还支持运行时发现——操作深层目录文件时自动向上寻找技能目录1. 用户操作某个深层目录中的文件 2. discoverSkillDirsForPaths() 从文件路径向上遍历 3. 寻找 .claude/skills/ 与 .agents/skills/ 目录不超过 cwd 4. 跳过 .gitignore 忽略的目录 5. 发现新目录 → addSkillDirectories() → 加载并注册discoverSkillDirsForPaths()见 src/skills/loadSkillsDir.ts从文件所在目录一路向上遍历到 cwd不含 cwd 本身逐层检查.claude/skills是否存在且未被.gitignore忽略最终按深度从深到浅排序返回——这意味着就近的 Skill 优先级更高。缓存失效链为skillsLoaded.emit()→clearCommandMemoizationCaches()清空loadAllCommands、getSkillToolCommands、getSlashCommandToolSkills等缓存→ 下一轮对话加载新列表。权限控制自动允许如果 Skill 只包含安全属性无allowedTools、无hooks、无fork将自动获准执行无需用户确认。源码中skillHasOnlySafeProperties()检查SAFE_SKILL_PROPERTIES白名单type、name、description、source、loadedFrom 等基础字段核心逻辑是新增的 frontmatter 字段默认需要权限除非显式加入白名单。手动确认包含工具限制、Hook 或 fork 执行的 Skill首次调用时会提示用户Execute skill: my-custom-skill Allow? (y)es / (n)o / (a)lways allow / (d)eny权限规则规则类型格式说明精确允许Skill:commit允许执行 commit Skill前缀允许Skill:review:*允许所有 review: 前缀的 Skill精确拒绝Skill:dangerous设为 deny拒绝执行前缀拒绝Skill:untrusted:*设为 deny拒绝所有 untrusted: 前缀处理顺序deny 规则 → allow 规则 → 安全属性检查 → 询问用户。对应源码checkPermissions()的五步Deny 规则检查含精确匹配commit commandName与前缀匹配review:*→ 远程 Skill 自动允许_canonical_slug前缀Ant 专属实验性→ Allow 规则检查 → 安全属性自动允许 → 默认询问用户并给出精确允许 前缀允许的建议。快速参考创建一个 Skill# 1. 创建目录 mkdir -p ~/.claude/skills/my-skill # 2. 创建 SKILL.md cat ~/.claude/skills/my-skill/SKILL.md EOF --- name: 我的技能 description: 一个示例 Skill user-invocable: true --- # 技能内容 你好这是我的自定义 Skill。 EOF想偷懒的话直接在终端输入/skillify可以让 Agent 帮你生成 Skill。仓库内置的skillify.tssrc/skills/bundled/skillify.ts就是干这个的。常用操作操作方法创建 Skill~/.claude/skills/name/SKILL.md项目级 Skill.claude/skills/name/SKILL.md跨工具共享 Skill~/.agents/skills/name/SKILL.mdCodex / Cursor / Gemini CLI 同样可见调用 Skill终端输入/skill-name查看可用 Skills终端输入/skills用 AI 创建 Skill/skillify限制工具frontmatter 添加allowed-toolsFork 执行frontmatter 添加context: fork条件激活frontmatter 添加paths: src/**Skill 可用性矩阵来源用户可调用模型可调用支持 Fork支持 HookBundled依定义依定义是是Managed是是是是User是默认是是是Project是默认是是是Plugin依配置依配置是是MCP依配置依配置是否安全限制深入一个 Skill 从磁盘到对话的完整生命周期结合 docs/internals/skills-internals.md 与源码可以把上述内容串成一条清晰的链路共四个阶段发现与注册CLI 启动时initBundledSkills()注册内置 SkillsgetSkillDirCommands(cwd)并行加载 managed/user/project/--add-dir四个层级的目录 Skills再经getFileIdentity()realpath去重、按paths分离条件 Skills最终loadAllCommands()按优先级聚合全部来源并 memoize。注入到对话每轮对话由getSkillListingAttachments()src/utils/attachments.ts生成 skill 列表经formatCommandsWithinBudget()按上下文预算截断后包装为system-reminder用户消息注入。预算常量为SKILL_BUDGET_CONTEXT_PERCENT 0.01上下文窗口的 1%、DEFAULT_CHAR_BUDGET 8000、MAX_LISTING_DESC_CHARS 250见 src/tools/SkillTool/prompt.ts——技能列表只用于发现正文在调用时才加载因此编写描述时应先写清触发条件和用途把操作步骤、示例和参考文件放进正文。调用与执行SkillTool.validateInput()校验错误码1 格式无效、2 未知技能、4 模型调用被禁用、5 非 prompt 类型、6 远程技能未发现→checkPermissions()权限检查 →SkillTool.call()按context分流到 inline 的processPromptSlashCommand()或 fork 的executeForkedSkill()。inline 内容通过addInvokedSkill()记录到会话状态确保上下文压缩后仍可恢复。运行时发现文件操作触发discoverSkillDirsForPaths()动态发现新目录与activateConditionalSkillsForPaths()条件激活随后clearCommandMemoizationCaches()让下一轮对话加载最新列表。Skill 级的 Hook 由registerSkillHooks()src/utils/hooks/registerSkillHooks.ts注册为会话级 Hook遍历HOOK_EVENTSPreToolUse、PostToolUse、Stop 等为每个 matcher 调用addSessionHook()once: true的 Hook 在首次执行后自动removeSessionHook()。源码索引与延伸阅读核心文件文件职责src/tools/SkillTool/SkillTool.tsSkillTool 定义、验证、权限、执行src/tools/SkillTool/prompt.ts工具提示词、Skill 列表格式化、预算控制src/skills/loadSkillsDir.ts目录 Skill 发现、加载、去重、条件激活、动态发现src/skills/skillRoots.tsSkill 根目录.claude/.agents 双目录唯一来源src/skills/bundledSkills.ts内置 Skill 注册系统src/skills/bundled/index.ts内置 Skills 初始化入口含特性门控src/commands.ts命令聚合、排序、过滤、缓存管理src/utils/frontmatterParser.tsFrontmatterData、ParsedMarkdown类型与解析src/utils/forkedAgent.tsFork 上下文准备、结果提取src/utils/hooks/registerSkillHooks.tsSkill Hook 注册延伸阅读Skills 的底层实现细节发现、注入、fork 执行可继续阅读 docs/internals/skills-internals.mdSkills 在整体架构中的位置参见 docs/internals/index.md多 Agent 体系fork 依赖的子代理机制参见 docs/internals/agent.md 与 docs/internals/agent-internals.md。赞分享人工智能AI 应用桌面应用代码智能体MCP Clients【免费下载链接】cc-hahaLocal-first cross-platform desktop workspace for Claude Code / agents: multi-agent, Git worktrees, code diffs, skill marketplace, multi-model, Computer Use, task-aware desktop pets, with WeChat, Feishu, DingTalk, Telegram, WhatsApp and H5 access.项目地址https://gitcode.com/gh_mirrors/cl/cc-haha点击查看免费下载相关推荐解决LLM幻觉难题Azure GenAI Design Patterns数据 grounding技术详解解决LLM幻觉难题Azure GenAI Design Patterns数据 grounding技术详解 Azure GenAI Design Patterncc-haha Skills 系统实现原理Skill 从发现、注入到执行的完整链路剖析cc haha Skills 系统实现原理Skill 从发现、注入到执行的完整链路剖析 Skills 是 cc hahaClaude Code 本地优先工作人工智能AI 应用桌面应用代码智能体MCP ClientsObsidian网页剪藏工具完整上手指南让收藏的网页自动变成知识库笔记Obsidian网页剪藏工具完整上手指南让收藏的网页自动变成知识库笔记 开头先说结论 Obsidian网页剪藏工具是 Obsidian 官方发布的浏览器扩展前端上一篇三星固件一站式管理Bifrost跨平台解决方案的三大突破下一篇从零开始Pig系统集成ActiveMQ消息队列实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表