#6309·openhuman

Skill catalog: a GitHub sourceUrl pointing at any .md file installs that file, and blob links with ?plain=1 build an unfetchable URL

Author: M3gA-MindCreated Sep 15, 2026Updated Sep 15, 2026
Labelspriority: p1

Summary

Two defects in the GitHub sourceUrl → raw download URL rewrite for catalog skills. Both predate #6307 (which only moved this code from skills/catalog/ops.rs into skills/catalog/download.rs); tinysweeper surfaced them while reviewing that move.

Class of task broken: installing any registry skill whose catalog entry carries a GitHub sourceUrl — the GitHub, Anthropic, OpenAI, HuggingFace, NVIDIA, gstack and browse.sh sources, roughly 1,500 entries.

1. Any .md blob is accepted as the skill file

download_url_from_source_url appends /SKILL.md only when the rewritten URL does not already end in .md:

rust
"blob" => {
    if raw.ends_with("/SKILL.md") || raw.ends_with(".md") {
        Some(raw)
    } else {
        Some(format!("{raw}/SKILL.md"))
    }
}

crates/openhuman-core/src/skills/catalog/download.rs:103 after #6307, skills/catalog/ops.rs:706 on main @ 700281685 — identical line.

So an entry whose sourceUrl is https://github.com/o/r/blob/main/README.md yields a download URL for README.md, and install fetches that file and tries to parse it as a skill. The installer requires frontmatter with name and description, so the usual outcome is a confusing parse error rather than a wrong skill, but a Markdown file that happens to carry frontmatter would install as one.

Expected: only a blob that is a SKILL.md is taken directly; any other blob path should resolve to the SKILL.md beside it, or be rejected.

2. A blob link with a query or fragment produces a broken URL

The same function splits the source URL as plain text, so ?plain=1 or #L10 stays inside path:

https://github.com/o/r/blob/main/SKILL.md?plain=1
  -> https://raw.githubusercontent.com/o/r/main/SKILL.md?plain=1/SKILL.md

because SKILL.md?plain=1 does not end in .md, so /SKILL.md is appended after the query. ?plain=1 is what GitHub's own "copy permalink to plain view" produces, and such a URL cannot be fetched.

Expected: strip the query and fragment before rewriting, then decide whether to append /SKILL.md.

Notes

  • Both are pure sourceUrl handling; the ClawHub file API, the skills.sh repo resolution and docsPath are unaffected.
  • Not introduced by #6307: that PR moved the function verbatim to bring ops.rs under the 750-line layout limit. Worth fixing separately with a unit test per case in download_tests.rs, next to download_url_from_source_url_rejects_non_github_and_malformed.