{"record":{"id":"28da84a677194076","repo":"siyuan-note/siyuan","slug":"rename-or-delete-the-skill-directory-instead-of-skill-md","errorCode":null,"errorMessage":"rename or delete the skill directory instead of SKILL.md","messagePattern":"rename or delete the skill directory instead of SKILL\\.md","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/skill_manage.go","lineNumber":390,"sourceCode":"\t\t\tif ret.ReadOnlyReason == \"\" {\n\t\t\t\treturn ret, readErr\n\t\t\t}\n\t\t}\n\t\tret.Revision, err = managedSkillRevision(root, request.Path)\n\t\treturn ret, err\n\t}\n\tif info == nil || !info.IsDir() {\n\t\tif !strings.Contains(request.Path, \"/\") {\n\t\t\treturn ret, errors.New(\"only text files inside a skill can be edited\")\n\t\t}\n\t\tif info != nil {\n\t\t\tif _, err = readManagedSkillSource(root, request.Path); err != nil {\n\t\t\t\treturn ret, err\n\t\t\t}\n\t\t}\n\t}\n\tif (request.Action == \"move\" || request.Action == \"remove\") && isManagedSkillManifest(request.Path) {\n\t\treturn ret, errors.New(\"rename or delete the skill directory instead of SKILL.md\")\n\t}\n\tif info != nil {\n\t\trevision, revisionErr := managedSkillRevision(root, request.Path)\n\t\tif revisionErr != nil {\n\t\t\treturn ret, revisionErr\n\t\t}\n\t\tif request.Revision == \"\" || request.Revision != revision {\n\t\t\treturn ret, errors.New(\"skill changed; reload it before saving, renaming or deleting\")\n\t\t}\n\t}\n\tswitch request.Action {\n\tcase \"write\":\n\t\tif info != nil && info.IsDir() {\n\t\t\treturn ret, errors.New(\"cannot write a skill directory\")\n\t\t}\n\t\tif err = writeManagedSkillSource(root, request.Path, request.Content, info == nil, request.Revision); err != nil {\n\t\t\treturn ret, err\n\t\t}","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/skill_manage.go#L372-L408","documentation":"SKILL.md at the top level of a skill directory is the manifest that defines the skill. It cannot be moved or deleted on its own; the whole skill directory must be renamed (move with the directory path) or removed. This keeps the manifest and directory lifecycle atomic.","triggerScenarios":"ManageSkillFiles action \"move\" or \"remove\" where isManagedSkillManifest(request.Path) is true — i.e. the path has exactly one slash and its base is \"SKILL.md\" (case-insensitive), e.g. \"my-skill/SKILL.md\".","commonSituations":"Client UI let users select SKILL.md and issue delete/rename; scripts deleting manifest files to 'reset' a skill; refactoring code that renames manifest files to change a skill's display name.","solutions":["To rename a skill, move the directory path: Action \"move\", Path \"my-skill\", Target \"new-name\"","To delete a skill, remove the directory: Action \"remove\", Path \"my-skill\"","Edit the manifest's frontmatter (name/description) with action \"write\" instead of moving the file"],"exampleFix":"// before\nManageSkillFiles(SkillFileRequest{Action: \"remove\", Path: \"my-skill/SKILL.md\", Revision: rev})\n// after\nManageSkillFiles(SkillFileRequest{Action: \"remove\", Path: \"my-skill\", Revision: dirRev})","handlingStrategy":"validation","validationCode":"func isManifest(p string) bool {\n  return strings.Count(p, \"/\") == 1 && strings.EqualFold(path.Base(p), \"SKILL.md\")\n}\nif (req.Action == \"move\" || req.Action == \"remove\") && isManifest(req.Path) {\n  // redirect to the directory path instead\n}","typeGuard":"func isSkillDirPath(p string) bool { return strings.Count(p, \"/\") == 0 }","tryCatchPattern":"if err := ManageSkillFiles(req); err != nil && strings.Contains(err.Error(), \"instead of SKILL.md\") {\n  // retry against the parent directory path\n}","preventionTips":["Never expose SKILL.md as a deletable/renamable item in UIs","Operate on the skill directory for lifecycle changes","Treat SKILL.md as write-only content (frontmatter edits via write)"],"tags":["api","manifest","skills"],"backgroundTag":"invalid-state-transition","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}