{"record":{"id":"7c196aded97b13bf","repo":"sipeed/picoclaw","slug":"description-is-required","errorCode":null,"errorMessage":"description is required","messagePattern":"description is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skills/loader.go","lineNumber":51,"sourceCode":"type SkillInfo struct {\n\tName        string `json:\"name\"`\n\tPath        string `json:\"path\"`\n\tSource      string `json:\"source\"`\n\tDescription string `json:\"description\"`\n}\n\nfunc (info SkillInfo) validate() error {\n\tvar errs error\n\tif info.Name == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name is required\"))\n\t} else {\n\t\tif err := ValidateSkillName(info.Name); err != nil {\n\t\t\terrs = errors.Join(errs, err)\n\t\t}\n\t}\n\n\tif info.Description == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"description is required\"))\n\t} else if len(info.Description) > MaxDescriptionLength {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"description exceeds %d character\", MaxDescriptionLength))\n\t}\n\treturn errs\n}\n\ntype SkillsLoader struct {\n\tworkspace       string\n\tworkspaceSkills string // workspace skills (project-level)\n\tglobalSkills    string // global skills (~/.picoclaw/skills)\n\tbuiltinSkills   string // builtin skills\n}\n\n// SkillRoots returns all unique skill root directories used by this loader.\n// The order follows resolution priority: workspace > global > builtin.\nfunc (sl *SkillsLoader) SkillRoots() []string {\n\troots := []string{sl.workspaceSkills, sl.globalSkills, sl.builtinSkills}\n\tseen := make(map[string]struct{}, len(roots))","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/skills/loader.go#L33-L69","documentation":"SkillInfo.validate rejects a skill whose Description is empty. Descriptions are mandatory (they drive skill selection/recall) and must not exceed MaxDescriptionLength (1024 chars) — exceeding it produces a separate joined error ('description exceeds 1024 character').","triggerScenarios":"A SKILL.md frontmatter or SkillInfo payload with no description key or an empty description string, passed through validate() during load/registration.","commonSituations":"SKILL.md written with only a name; description key misspelled (desc:, summary:); a generated skill whose LLM output omitted the field.","solutions":["Add a concise description (<= 1024 characters) to the SKILL.md frontmatter: 'description: ...'","If you also see the length error, trim the description below 1024 chars","Re-run the skills loader after fixing the file to confirm the skill is picked up"],"exampleFix":"# before\n---\nname: my-skill\n---\n\n# after\n---\nname: my-skill\ndescription: Searches the web and summarizes results for the user.\n---","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(info.Description) == \"\" {\n    return fmt.Errorf(\"skill %s: description is required\", info.Path)\n}\nif len(info.Description) > skills.MaxDescriptionLength {\n    return fmt.Errorf(\"skill %s: description exceeds %d chars\", info.Path, skills.MaxDescriptionLength)\n}","typeGuard":null,"tryCatchPattern":"if err := info.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"description is required\") {\n        // add a description to SKILL.md frontmatter\n    }\n}","preventionTips":["Write descriptions as part of the skill template","Keep descriptions under 1024 characters (MaxDescriptionLength)","Lint SKILL.md files in CI using the skills package constants"],"tags":["skills","validation","configuration"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}