news 2026/9/25 8:30:43

GSD 技能表面管理实战:用 `/gsd:surface` 在不重装的情况下按需开关技能集群

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GSD 技能表面管理实战:用 `/gsd:surface` 在不重装的情况下按需开关技能集群

【免费下载链接】gsd-core

Git. Ship. Done - Core

项目地址:https://gitcode.com/gh_mirrors/ge/gsd-core
点击查看免费下载

/gsd:surface是 GSD(Get. Ship. Done — Core)提供的运行时技能表面(skill surface)开关命令,用于在已安装环境下动态启用/禁用技能集群、切换命名 Profile,而无需重新执行安装流程。本文以仓库变更记录 feat-3408-skill-surface.md 为核心骨架,结合 runbook、ADR-0011、研究备忘录与 src/surface.cts 源码,完整讲解该功能的背景、子命令、10 个集群、状态持久化模型与底层引擎原理,读完即可上手管理自己的技能表面。

一、为什么需要技能表面:技能清单预算与静默丢弃

Claude Code 等运行时会在每一轮对话把已安装 skill 的name + description枚举进系统提示中的<available_skills>块,该块受skillListingBudgetFraction限制——默认是模型上下文窗口的1%,在 200k 上下文中约2000 tokens。当多个插件叠加、描述总长超过预算时,运行时只会静默截断尾部,用户根本无法察觉部分技能已被丢弃。

研究备忘录 2026-05-12-skill-surface-budget.md 给出了 GSD 当时的审计数据:

指标数值
已安装技能66
已安装子代理33(不进入<available_skills>,经Task调用)
技能描述总字符数4,787
估算描述 tokens(÷4)~1,196
平均描述长度72.5 字符
描述长度上限(scripts/lint-descriptions.cjs 强制)100 字符
GSD 占 200k 上下文 1% 预算的份额~60%

也就是说,GSD 单靠自己就吃掉了默认技能清单预算的约六成,再叠加任何一个体量相近的插件就会超限、触发静默丢弃(issue #3408 的报告者装了 135 个技能)。更关键的是:描述已经压到 72.5 字符均值、100 字符硬上限,继续压缩文字不是出路,出路是少发射技能。根因是缺乏 profile/surface 接缝——安装器无条件写入全部技能,运行时又没有无需重装的开关。

二、整体方案:ADR-0011 的 Phase 1(安装 Profile)+ Phase 2(运行时 Surface)

方案沿用了研究备忘录的推荐路径,分两阶段落地,记录在 ADR-0011(并取代早期草案 ADR-0010):

  • Phase 1 — 安装期命名 Profile:安装时用--profile=<name>选择core/standard/full,计算requires:依赖闭包后写入运行时目录,并把所选 Profile 持久化到.gsd-profile标记文件;gsd update读取标记、尊重 Profile,不再在升级时悄悄膨胀回 full。详见同主题的变更记录 feat-3408-skill-profiles.md。
  • Phase 2 — 运行时 Surface 模块:即本文主角/gsd:surface。引擎在gsd-core/bin/lib/surface.cjs(TypeScript 真源为 src/surface.cts),复用 Phase 1 的stageSkillsForProfile/stageAgentsForProfile完成重新落地;集群定义独立放 src/clusters.cts,让引擎和未来的 SDK 调用方无需加载整个 profile 模块即可引用。

功能层面的权威说明可另见 skill-surface-budgeting.md,其中记录了三条需求约束:安装器必须解析--profile=<name>并持久化到.gsd-profile(REQ-SURFACE-01);--minimal与--core-only必须保持为--profile=core的别名(REQ-SURFACE-02);运行时表面状态必须独立于安装 Profile 标记持久化(REQ-SURFACE-03)。

三、三个命名 Profile 与requires:依赖闭包

Profile 定义在 src/install-profiles.cts 的PROFILES常量中(ADR-457 构建时发布:手写.cjs已坍缩为 TypeScript 真源,行为逐字节保留):

Profile用途基集(源码现状)
core最小主循环表面new-project、discuss-phase、plan-phase、execute-phase、phase、help、update、surface
standard核心 + 常用阶段/工作区命令core 基础上追加onboard、review、config、progress、resume-work、pause-work、workspace
full完整表面(默认)'*'哨兵,全部技能

值得注意两点演进:

  1. 研究备忘录曾指出旧 minimal allowlist 缺少phase——它被 38 个技能引用,是典型的"依赖热点"。当前源码的core已把phase纳入基集,规避了"最小安装 + 主循环调用断裂"的潜在缺陷。
  2. 每个 Profile 的有效技能集合是基集的传递闭包:effective = CLOSURE(base, requires: manifest)。standard自动包含core的全部成员,--profile=core,audit组合则解析为union(closure(core), closure(audit))。

闭包的"图"来自每个技能 frontmatter 新增的requires:字段(66 个技能全部声明)。解析函数resolveProfile对 mode 列表做flatMap(split(','))归一化,一旦命中full直接返回'*'哨兵;无效/损坏的 marker 会回退为 full,避免出现空安装。该依赖图由 CI 门禁 scripts/lint-skill-deps.cjs(接入pretest)强制校验:每个requires:必须能解析到真实技能 stem,防止 Profile 闭包静默过度安装或装坏依赖链。

四、/gsd:surface子命令全解

runbook 见 commands/gsd/surface.md(技能包装形态见 skills/gsd-surface/SKILL.md)。命令解析$ARGUMENTS的第一个 token:

Token动作
list显示启用 + 禁用的集群与技能
statuslist的别名,附加 token 成本汇总
profile <name>写入baseProfile并重新落地(re-stage)
profile <n1>,<n2>组合 Profile(逗号分隔,无空格)
disable <cluster>把集群加入disabledClusters并重新落地
enable <cluster>从disabledClusters移除集群并重新落地
reset删除.gsd-surface.json,回到安装期 Profile
(空)视作list

list输出示例(runbook 原始格式,…为省略的其余集群):

Enabled (N skills, ~T tokens): core_loop: new-project discuss-phase plan-phase execute-phase help update audit_review: … … Disabled: utility: health stats settings … Token cost: ~T (budget cap ~500 tokens for 200k context @ 1%)

status额外追加 Profile 摘要:

Base profile: standard (from .gsd-surface.json) Install profile: standard (from .gsd-profile)

五、10 个技能集群:定义与成员

集群是技能表面的唯一权威分类法,定义在 src/clusters.cts 的CLUSTERS常量(构建时发布,来源为研究备忘录 §3.2 的贪心聚类)。成员允许重叠(一个技能可属多个集群),且每个已安装技能 stem 必须至少出现在一个集群中(由surface-clusters.test.cjs强制)。源码当前十个集群:

集群成员(源码现状)语义
core_loopnext、new-project、onboard、discuss-phase、plan-phase、execute-phase、help、update主循环最小集
audit_reviewcode-review、review、audit-fix、audit-milestone、audit-uat、verify-work、validate-phase、plan-review-convergence、eval-review、add-tests、secure-phase审计与评审
milestonenew-milestone、complete-milestone、milestone-summary、health里程碑管理
research_ideatesketch、spike、forensics、explore、graphify、ns-ideate研究/构思
workspace_statepause-work、resume-work、workspace、workstreams、thread、capture、inbox工作区与状态
docsdocs-update、ingest-docs文档
uiui-phase、ui-reviewUI 工作流
ai_evalai-integration-phase、eval-reviewAI 集成与评估
ns_metans-context、ns-ideate、ns-manage、ns-project、ns-review、ns-workflow命名空间元工作流
utilityhealth、stats、settings、cleanup、pr-branch、ship、undo、fast、quick、quick-batch、autonomous、config、progress、phase、review、update、help、code-review、import、manager、map-codebase、profile-user、spec-phase、ultraplan-phase、mvp-phase、execute-phase、review-backlog、debug、extract-learnings、mempalace-recall、mempalace-capture、surface工具杂项(最重桶)

utility是描述 token 占比最重的集群(研究阶段约占总描述 tokens 的 36%),且最异构——大量技能是"每项目一次"而非"每会话一次",是开启按需裁剪时的首选目标。

六、状态持久化:.gsd-profile与.gsd-surface.json的分工

Phase 2 的核心设计决策是两套状态文件分离:

  • .gsd-profile(~/.claude/.gsd-profile):安装期身份,由安装器写入,gsd update尊重它。
  • .gsd-surface.json(~/.claude/.gsd-surface.json):会话期集群开关,由/gsd:surface读写。

注意:本 changeset 记录的状态文件路径为~/.claude/skills/.gsd-surface.json(skills 子目录),而最终实现(runbook 与 src/surface.cts 的SURFACE_FILE_NAME = '.gsd-surface.json'+path.join(runtimeConfigDir, ...))将其放在base Claude 配置目录~/.claude/.gsd-surface.json。runbook 的runtimeConfigDir resolution一节对此有专门说明:传给applySurface的是 base config 目录而非 skills 子目录,与installRuntimeArtifacts/uninstallRuntimeArtifacts收到~/.claude作为configDir保持一致;技能目录~/.claude/skills/gsd-*/是因为claude global布局的destSubpath = 'skills',由configDir派生而非根。本文以最终实现为准。

状态文件的结构(src/surface.cts 的SurfaceState类型,写入时经platformWriteSync原子写为缩进 2 的 JSON):

{ "baseProfile": "...", "disabledClusters": [...], "explicitAdds": [...], "explicitRemoves": [...] }

读取方readSurface会做结构校验:baseProfile必须是字符串、三个数组字段必须是数组,文件缺失或损坏一律返回null(failing closed)。

七、底层引擎原理:解析顺序与两阶段提交

引擎导出的核心函数(src/surface.cts)包括readSurface、writeSurface、resolveSurface、applySurface、listSurface、pruneSkillDirs。

有效技能集解析公式(resolveSurface,源码注释原话):

Effective skill set = base profile ∪ explicitAdds − disabledClusters − explicitRemoves

随后经 manifest 做传递闭包。解析顺序:

  1. 以surface.baseProfile(无则回退readActiveProfile,再回退'full')解析基础 Profile;
  2. 删除被禁用集群覆盖的技能;
  3. 加入explicitAdds及其传递闭包(BFS);
  4. 删除explicitRemoves(仅删该 stem,不级联)。

agents由技能派生:对每个保留技能,读取 manifest 中_calls_agents_<stem>条目,收集其引用的子代理 stem。返回的名称形如surface:<baseProfile>或profile:<name>。

两阶段提交协议(applySurface,runbook 的Mutation protocol一节):所有变更操作(profile/disable/enable/reset)都先在内存推导候选状态opts.surfaceState,再交给applySurface,绝不先调writeSurface。applySurface内部先遍历layout.kinds逐个kind.stage()把每种产物(skills / agents / commands / kimi-agents 等)暂存到临时目录,全部成功后:

  1. 执行retiredArtifactCleanup.pruneRetiredRuntimeArtifacts;
  2. 对每个 kind 执行_syncGsdDir同步到目标目录(skills 目录的裁剪统一委托给pruneSkillDirs,用户自建的gsd-*目录一律保留并告警);
  3. 最后才发布状态:candidateState === null时删除.gsd-surface.json(reset语义),否则writeSurface写入候选状态。

任何 kind 暂存失败都会让已安装产物和持久化状态双双保持原样——这就是"变更不落地则不写状态"的原子性保证。applySurface还有多重防护:runtimeConfigDir必须与layout.configDir相等(否则抛TypeError)、assertTestHomeSandboxed防测试逃逸到真实 home、assertDestWithinConfigHome约束目标路径。

token 成本估算(listSurface):对每个启用技能读取安装源的commands/gsd/<stem>.md,取 frontmatterdescription:值,按ceil(长度 ÷ 4)累加,与审计脚本口径一致。

八、运行时目录解析与环境变量

runbook 给出的 global 安装参考脚本:

# Claude Code — global install RUNTIME_CONFIG_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}" SCOPE="global" # Artifact destinations are derived from runtime layout # via resolveRuntimeArtifactLayout(runtime, RUNTIME_CONFIG_DIR, SCOPE) # then applySurface(RUNTIME_CONFIG_DIR, layout, manifest, CLUSTERS)
  • Surface 状态文件:${RUNTIME_CONFIG_DIR}/.gsd-surface.json(即默认~/.claude/.gsd-surface.json)。
  • 所有路径均可通过读取CLAUDE_CONFIG_DIR环境变量覆盖。
  • 多运行时场景下,安装期若 Profile 冲突,按最保守 Profile(最小有效技能集)解决。

九、错误处理与恢复路径

runbook 定义的错误行为:

  • 未知集群名 → 列出合法集群名,不写盘直接退出;
  • 未知 Profile 名 → 列出已知 Profile(core、standard、full),退出;
  • 缺少surface.cjs引擎模块 → 提示Run npm i -g @opengsd/gsd-core以重装 GSD。

enable的边界:若 surface 状态为null,说明没有任何增量,直接输出 "No surface delta active."。reset的边界:只有安装期 Profile 成功落地后,状态文件才被移除。

十、测试与 CI 保障

仓库对表面引擎有专门的回归测试(当前实际存在的测试文件,见 tests 目录):

  • surface-empty-manifest-agents.test.cjs — 空 manifest 下的代理派生边界;
  • runtime-artifact-layout-surface.test.cjs — 表面落地与安装引擎的产物路径/命名一致性(ADR 中提到的surface-state / surface-clusters / surface-resolve / surface-apply / surface-list系列测试已随源码折叠合并到上述文件与主测试套件);
  • surface-md-paths.regression.test.cjs — 技能文档路径回归;
  • 集群覆盖完整性由集群模块的allClusteredSkills()辅助函数与对应测试保证(每个已安装 stem 必须落入至少一个集群)。

配合 Phase 1 的scripts/lint-skill-deps.cjs(接入pretest),requires:依赖完整性在 CI 阶段即被拦截。

十一、实战速览:典型操作序列

# 1) 查看当前启/禁用状态与 token 成本 /gsd:surface list # 2) 查看 Profile 摘要(含安装期 vs 当前 base) /gsd:surface status # 3) 切换到 standard Profile(无需重装) /gsd:surface profile standard # 4) 组合 Profile /gsd:surface profile core,audit # 5) 按集群关闭最重的 utility 桶 /gsd:surface disable utility # 6) 需要时再加回 /gsd:surface enable utility # 7) 反悔:清空增量,回到安装期 Profile /gsd:surface reset

典型收益(ADR-0011 记录):受上下文预算约束的用户可先--profile=core安装,随后用/gsd:surface enable <cluster>增量扩容,全程无需重装;requires:闭包保证任何部分裁剪都不会悄悄破坏跨技能调用。需要注意:该命令是 GSD 侧的单方面解决方案,不依赖 Anthropic 平台的原生技能开关 API(平台侧的 per-skill toggle 与预算协商仍作为独立诉求跟进);utility桶技能体量大,按需启用是压预算最直接的手段。

【免费下载链接】gsd-core

Git. Ship. Done - Core

项目地址:https://gitcode.com/gh_mirrors/ge/gsd-core
点击查看免费下载

相关推荐

上一篇:微信支付分账比例配置:基于EasyWeChat的灵活分账策略实现
下一篇:HuLa版本控制策略:语义化版本与发布流程

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 8:29:50

AI编程工具插件窃取密钥的四大路径与防御实战

1. 一个插件如何成为密钥收割机先说说我上周遇到的一件真事。团队里一个刚入行半年的小伙子&#xff0c;在本地用某款主流AI编程工具写业务代码&#xff0c;图省事装了一个号称"智能补全增强"的第三方插件。三天后&#xff0c;他收到云服务商的账单告警——有人用他的…

作者头像 李华
网站建设 2026/9/25 8:29:38

磁力搜索与下载工具全解析:从原理到实战优化指南

1. 磁力搜索与下载工具的核心逻辑拆解1.1 磁力链接到底是什么&#xff0c;为什么它比传统下载更抗压很多人第一次接触磁力搜索&#xff0c;脑子里冒出来的问题是&#xff1a;这玩意儿跟普通下载到底差在哪。我用一个生活化的类比来解释——传统下载就像你去一家指定的书店买书&…

作者头像 李华
网站建设 2026/9/25 8:27:09

Kubernetes Agent编排实战:Orchestrator与Workspace设计

1. 从“ax”这个标题说起&#xff1a;一个被低估的Agent编排切口第一次看到“ax”这个标题&#xff0c;加上后面跟着的 agent、orchestrator、kubernetes、workspace 这几个词&#xff0c;我脑子里第一反应是&#xff1a;这大概率是一个把 AI Agent 跑在 Kubernetes 上的编排层…

作者头像 李华
网站建设 2026/9/25 8:26:11

Docker到gVisor:为CLI工具构建双层沙箱防御架构

1. 项目概述&#xff1a;为什么一个“Tool”需要两层沙箱&#xff1f;你有没有遇到过这样的场景&#xff1a;团队里有人随手从 GitHub 拉下一个叫pdf-converter-tool的开源 CLI 工具&#xff0c;一行命令docker run -v $(pwd):/data pdftool:latest input.pdf就把 PDF 转成了 M…

作者头像 李华