用途
skill-creator 用于指导开发者或 Agent 为自己的 Unity 工程添加自定义技能,而不是修改 UnitySkills 插件源码。自定义技能是编译在工程 Editor 代码中的、带 [UnitySkill] 标记的 public static 方法,服务端会自动发现它,无需编辑插件。
触发场景包括:为自己的工程编写自定义技能、扩展 Agent 在本工程可调用的能力、了解 [UnitySkill] 元数据契约与发现规则。
代码放置位置
- C# 文件应放在 Assets/ 下的仅 Editor 位置,例如 Assets/Editor/UnitySkillsCustom/MySkills.cs,或任意 platform 为 Editor 的 asmdef。
- 插件的 editor asmdef 设置了 autoReferenced: true,因此 Assembly-CSharp-Editor 与普通用户 Editor asmdef 无需额外引用即可使用公开 API。
- 切勿把自定义技能代码放进包目录(Packages/com.besty.unity-skills/)或 Library/PackageCache/,包更新与自更新会替换整棵目录树并清除文件。
- 类不必是 MonoBehaviour,普通静态类即可。
编译与发现流程
写入 C# 后,Unity 会重新编译并执行 domain reload。路由器在下次请求时重新执行 TypeCache.GetMethodsWithAttribute<UnitySkillAttribute>(),新技能自动注册,无需重启或维护列表。
建议的 Agent 流程:
- 检查名称是否可用:GET /skills?q=<prefix> 或 GET /skills/schema?names=<cand>&wire=v2。
- 用 script_create { scriptName, folder: "Assets/...", content: <完整源码> } 创建脚本,返回 { path, jobId, waitUrl }。
- 等待编译:GET /jobs/<jobId>?wait=90(可跨 reload 重试),检查 resultData.compilation.errors;script_get_compile_feedback(scriptPath) 可获取按需诊断。
- 确认注册:GET /skills/schema?names=<your_skill>&wire=v2 应返回带描述与参数的技能。
- 首次真实调用使用 ?mode=dryRun。
注意:script_create 具有 MayTriggerReload 且属高风险,被标记为 NeverInSemi,需要 Bypass 模式或面板 Allowlist 条目;应请求用户授权而不是自行尝试授权。
命名规则
- 技能名为 snake_case 动词形式,如 gameobject_create。
- 自定义技能必须带前缀(如 my_、acme_),例如 my_apply_team_branding,而不是 apply_branding。
- 名称冲突时后注册者胜出,且注册顺序不保证;与内置技能同名会遮蔽或被遮蔽,注册表会记录警告并列出双方声明类型(Skill name conflict: '<name>' declared by both <A> and <B>; using the latter.)。务必先检查名称是否空闲。
- 当逐项循环有意义时,提供匹配的 xxx_batch 变体。
元数据契约(特性)
[UnitySkill] 的填写会影响路由、权限门控、schema 与 Agent 行为,必须如实填写:
- 第一个字符串参数是 Agent 读到的描述,应提及参数。
- Category = SkillCategory.Uncategorized(自定义技能不能新增枚举值)。
- Operation 可选 Query | Create | Modify | Delete | Execute | Analyze,可用 | 组合。
- Tags 用于改善 /skills/recommend 匹配。
- Outputs 必须是方法实际返回的键的子集。
- TracksWorkflow、MutatesScene 为诚实风险标志。
- RiskLevel 为 low | medium | high。
Category 是封闭枚举,自定义技能无法新增值,只能使用最接近的现有分类或 Uncategorized。GameObject/Component/Material/Scene/Sample 分类下的技能在 Guide 表面配置下会被隐藏,除非是纯读操作;任何 MutatesScene = true 的写操作在 NoSceneAuthoring 下隐藏。这是有意的诚实元数据,不是规避手段。
风险标志驱动权限:声明 Operation.Delete、MayEnterPlayMode、MayTriggerReload 或 RiskLevel = "high" 的技能会自动归为 NeverInSemi,在 Approval 与 Auto 模式下返回 MODE_FORBIDDEN,仅在 Bypass 或面板 Allowlist 下运行。Mode 默认为 FullAuto;仅对零副作用的纯读操作声明 Mode = SkillMode.SemiAuto。
Outputs 中每一项都必须是方法实际返回的键,schema 契约测试会检查这一点。
方法体编写(仅公开 API)
工程代码只能使用公开面,包括:
- Validate.Required(x, "x") 校验参数,返回错误对象时提前返回:if (Validate.Required(x, "x") is object err) return err;
- GameObjectFinder.FindOrError(name, instanceId, path) 用于查找对象,不要使用 GameObject.Find。
- SkillErrorResponse.Build(SkillErrorCode.X, message, ...) 构造业务错误;仅在真正未知的框架错误时抛异常。SkillErrorCodeExtensions 是 internal,不可调用。
- 修改场景状态的写操作应注册 Undo,并在 TracksWorkflow = true 时调用 WorkflowManager.SnapshotXxx(...);批量使用 BatchExecutor.Execute<TItem>(items, perItem, idFn)。
- 返回结构化对象(匿名对象或 DTO),以 SkillsCommon.JsonSettings 序列化。
最小完整示例:
using UnitySkills;
public static class MyCustomSkills { [UnitySkill("my_greet", "Return a greeting for a name.", Operation = SkillOperation.Query, Tags = new[] { "greeting" }, Outputs = new[] { "message" }, MutatesScene = false, RiskLevel = "low")] public static object MyGreet([SkillParam("Who to greet")] string name = "world") { if (Validate.Required(name, "name") is object err) return err; return new { message = $"Hello, {name}!" }; } }
Agent 如何发现技能(无需文档文件)
Agent 不通过读取 markdown 文件来调用技能,而是与内置技能一样走 schema 优先路径:
- GET /skills/recommend?intent=<words>&includeSchema=true&topN=3&wire=v2,按名称、Tags 与 Description 匹配。
- GET /skills/schema?names=my_greet&wire=v2,在已知名称时获取完整参数 schema(含每个 [SkillParam] 说明)。
因此 Description、Tags 与每个 [SkillParam] 的质量就是文档;描述首句应具体且提及参数。
可选长文档(不要放的位置)
若自定义技能需要超出 schema 的说明文字,可把 markdown 放在工程内文件(如 Assets/UnitySkillsCustom/README.md),并从技能 Description 指向它;或作为同级 agent-skill 文件夹放在受管安装树之外(如 <project>/.claude/skills/my-tool/SKILL.md)。
切勿把文档写入已安装的 unity-skills 技能文件夹(如 .claude/skills/unity-skills/skills/my-mod/SKILL.md):安装/更新/自动同步会覆盖该目录树,卸载会删除整个安装目录。
护栏与限制
- 不要新增 SkillCategory 枚举值、SkillRouter 条目或路由表行,发现是自动的。
- 不要引用插件内部成员(工程中只能编译公开 API)。
- 不要遮蔽内置名称,务必加前缀。
- 不要把 C# 或文档放进受管包或安装树(更新/卸载会删除)。
- 不要为绕过门控而篡改 MutatesScene / 风险标志;表面配置与权限模式依赖其真实性。
运行模式方面:本文档为纯文档性质,不包含需要门控的 REST 技能,可在任意操作模式(Approval / Auto / Bypass)下自由加载。