screenpipe/screenpipe · error

skill name must be lowercase letters, digits, and single hyp

Error message

skill name must be lowercase letters, digits, and single hyphens (max 64)

What it means

`parse_frontmatter` validates the skill `name` from SKILL.md frontmatter. The name must be non-empty, at most 64 bytes, not start or end with '-', contain no consecutive '--', and consist only of ASCII lowercase letters, digits, and single hyphens. Any violation raises this error. This normalization keeps skill names URL/ID-safe and consistent across the team skill registry.

Source

Thrown at crates/screenpipe-engine/src/cli/team_skills.rs:375

        .ok_or_else(|| anyhow::anyhow!("SKILL.md needs a name"))?
        .to_string();
    let description = metadata
        .get("description")
        .and_then(serde_yaml::Value::as_str)
        .map(str::trim)
        .filter(|value| !value.is_empty())
        .ok_or_else(|| anyhow::anyhow!("SKILL.md needs a description"))?
        .to_string();
    let valid_name = !name.is_empty()
        && name.len() <= 64
        && !name.starts_with('-')
        && !name.ends_with('-')
        && !name.contains("--")
        && name
            .chars()
            .all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '-');
    if !valid_name {
        anyhow::bail!("skill name must be lowercase letters, digits, and single hyphens (max 64)");
    }
    if description.is_empty() || description.len() > 1024 {
        anyhow::bail!("skill description must contain 1-1024 characters");
    }
    Ok((name, description))
}

fn print_preview(bundle: &PreparedBundle, title: Option<&str>) {
    println!("team skill proposal preview");
    println!("title: {}", title.unwrap_or(&bundle.name));
    println!("name: {}", bundle.name);
    println!("description: {}", bundle.description);
    println!("source: {}", bundle.root.display());
    println!(
        "files: {} · bytes: {} · discovery: {} chars · activated: {} chars · scripts: {}",
        bundle.files.len(),
        bundle.total_bytes,
        bundle.discovery_chars,

View on GitHub (pinned to 4ebf712990)

Solutions

  1. Rewrite the name using only lowercase a-z, 0-9, and single hyphens (no leading/trailing '-', no '--'), max 64 chars
  2. Replace spaces or underscores with single hyphens (e.g. 'my_skill' -> 'my-skill')
  3. Convert uppercase letters to lowercase (e.g. 'MySkill' -> 'myskill')
  4. Shorten names over 64 characters; keep the long title in the description or preview title instead

Example fix

// before (SKILL.md frontmatter)
name: My Great_Skill--v2
// after
name: my-great-skill-v2
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_skill_name(name: &str) -> bool {
    !name.is_empty()
        && name.len() <= 64
        && !name.starts_with('-')
        && !name.ends_with('-')
        && !name.contains("--")
        && name.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')
}
assert!(is_valid_skill_name(&name), "invalid skill name");

Type guard

fn valid_skill_name(name: &str) -> Option<&str> {
    if !name.is_empty()
        && name.len() <= 64
        && !name.starts_with('-')
        && !name.ends_with('-')
        && !name.contains("--")
        && name.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')
    { Some(name) } else { None }
}

Try / catch

match prepare_bundle(&skill_dir) {
    Err(e) if e.to_string().contains("skill name must be") => {
        eprintln!("use lowercase a-z, 0-9, single hyphens; max 64 chars: {e}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running the team skill bundle flow with a SKILL.md whose `name:` field uses uppercase letters, spaces, underscores, non-ASCII characters, leading/trailing hyphens, double hyphens, or exceeds 64 characters.

Common situations: Naming a skill with CamelCase or spaces (e.g. 'My Skill', 'my_skill'); copying a display title into the name field; migrating older skills that allowed other formats; auto-generated names from paths that contain uppercase or underscores; very long names from concatenated titles.

Related errors


AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01). Data as JSON: /api/errors/9eaafd6a2874c53e. Report an issue: GitHub.