sipeed/picoclaw · error

skill frontmatter description is required

Error message

skill frontmatter description is required

What it means

Final check of validateAppliedSkillBody (pkg/evolution/apply.go:167): the rendered skill body's frontmatter must contain a non-empty `description`. renderDeployableSkillBody already substitutes a default string when a `description:` line exists with an empty value, so in practice this fires when the description key is missing entirely — either from a create/replace draft body, or from the preserved frontmatter of an existing skill being appended/merged onto.

Source

Thrown at pkg/evolution/apply.go:167

		return fmt.Errorf("skill frontmatter is required")
	}
	if !strings.Contains(body, "\n# ") {
		return fmt.Errorf("skill heading is required")
	}
	frontmatter, _ := splitSkillFrontmatter(body)
	fields, err := parseSkillFrontmatterFields(frontmatter, allowExtraFrontmatterFields)
	if err != nil {
		return err
	}
	name := strings.TrimSpace(fields["name"])
	if name == "" {
		return fmt.Errorf("skill frontmatter name is required")
	}
	if name != targetSkillName {
		return fmt.Errorf("skill frontmatter name %q does not match target skill %q", name, targetSkillName)
	}
	if strings.TrimSpace(fields["description"]) == "" {
		return fmt.Errorf("skill frontmatter description is required")
	}
	return nil
}

func allowsExistingFrontmatterFields(kind ChangeKind, hadOriginal bool) bool {
	return hadOriginal && (kind == ChangeKindAppend || kind == ChangeKindMerge)
}

func renderAppliedBody(draft SkillDraft, existingBody string, hadOriginal bool) (string, error) {
	switch draft.ChangeKind {
	case ChangeKindCreate:
		if hadOriginal {
			return "", fmt.Errorf("cannot create skill %q: skill already exists", draft.TargetSkillName)
		}
		return renderDeployableSkillBody(draft.BodyOrPatch), nil
	case ChangeKindReplace:
		if !hadOriginal {
			return "", fmt.Errorf("cannot replace skill %q: skill does not exist", draft.TargetSkillName)

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Add a non-empty `description:` line to the draft body's frontmatter
  2. For append/merge, add a description to the existing target SKILL.md frontmatter first
  3. Regenerate the draft with the description requirement enforced

Example fix

// before
---
name: deploy-checks
---
# Deploy checks

// after
---
name: deploy-checks
description: Run pre-deploy checks and report failures
---
# Deploy checks
Defensive patterns

Strategy: validation

Validate before calling

func frontmatterHasDescription(body string) error {
	lines := strings.Split(strings.TrimSpace(body), "\n")
	if len(lines) < 2 || strings.TrimSpace(lines[0]) != "---" {
		return nil
	}
	for i := 1; i < len(lines); i++ {
		if strings.TrimSpace(lines[i]) == "---" {
			break
		}
		if strings.HasPrefix(strings.TrimSpace(lines[i]), "description:") {
			if strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(lines[i]), "description:")) != "" {
				return nil
			}
		}
	}
	return fmt.Errorf("frontmatter description key missing or empty")
}

Try / catch

if err := applier.ApplyDraft(ctx, ws, draft); err != nil {
	if strings.Contains(err.Error(), "description is required") {
		// add description to draft body (or to the existing target SKILL.md for append/merge)
	}
}

Prevention

When it happens

Trigger: Create/replace draft whose BodyOrPatch frontmatter contains only `name:`; append/merge onto an existing SKILL.md whose frontmatter never had a `description:` key; hand-edited draft JSON that dropped the field.

Common situations: LLM omitting description despite the generator prompt requiring it (skillDraftPromptInstructions); legacy skills written before description became mandatory; hand-trimmed SKILL.md files.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/9c3c132fea052903. Report an issue: GitHub.