Skip to content

[bug] githubSkills fails a whole repository on one binary file or one skill's frontmatter #2512

Open

Description

@daviesayo

Filed by Claude Opus 5.5 on behalf of Davies (@daviesayo).

Version. Reproduced against packages/apps on v2 at 2f4c398 (apps 0.0.1-beta.122). First seen on a deployment built from 2.0.0-beta.32.

What happens. githubSkills returns no skills at all when one file or one skill in the repository is unusable. Two real public repositories fail this way:

Repository (commit) Skills Result Cause
anthropics/skills (2c5958e) 20 SkillLoadFailed, reason encoding canvas-design/canvas-fonts/*.ttf (54 font files), plus a PDF and a .tar.gz in two other skills
mattpocock/skills (4ae2317) 39 SkillLoadFailed, reason document one skill, skills/engineering/pr, has nested metadata

Narrowing path to a folder without the bad skill loads fine (mattpocock/skills at skills/productivity: 7 skills; anthropics/skills at skills/pdf: 1 skill). The error does not name the file or skill, so an author cannot tell which one to exclude.

Repro (run from packages/apps with Bun):

import { githubSkills, fileSkill } from "./src/skills.ts";

for (const [repo, ref] of [
  ["mattpocock/skills", "4ae2317ddb22b046e26455e4f9c9b3aaaf62212d"],
  ["anthropics/skills", "2c5958ecac7cee2b583967a2c4981d0f4a75c579"],
]) {
  try {
    console.log(repo, (await githubSkills({ repo, ref, fetch })).length);
  } catch (e: any) {
    console.log(repo, e._tag, e.reason, e.message);
  }
}

const doc = (fm: string) => [
  { path: "SKILL.md", content: `---\nname: demo\ndescription: Demo.\n${fm}---\n\nBody\n` },
];
for (const fm of [
  "allowed-tools: Read Grep\n",
  "allowed-tools:\n  - Read\n  - Grep\n",
  "metadata:\n  author: someone\n",
  "metadata:\n  credits:\n    author: someone\n",
]) await fileSkill(doc(fm)).then(() => console.log("ok"), (e) => console.log(e._tag, e.reason));

Output:

mattpocock/skills SkillLoadFailed document A skill from GitHub is not a valid skill document.
anthropics/skills SkillLoadFailed encoding A skill file from GitHub is not valid UTF-8 text.
ok
SkillDefinitionInvalid metadata
ok
SkillDefinitionInvalid metadata

Cause.

  • Every file in a skill directory is read as fatal UTF-8 text (skills.ts L183-L191, L239-L243), and githubCatalog reads all skills in one Effect.forEach, so the first failure fails the catalog (L548-L583).
  • AppSkillMetadata accepts metadata only as string-to-string and allowed-tools only as a string (contracts/skills.ts L52-L53). Any other shape fails skillFromFiles (skill-files.ts L45-L47), which githubCatalog turns into a catalog-wide document failure.

What the spec says. The Agent Skills specification defines metadata as "a map from string keys to string values" and allowed-tools as "a space-separated string" (experimental). So Executor's metadata schema matches the spec, and the two frontmatter shapes above are non-conforming. The same spec lists images and data files under assets/ and says a skill directory "may contain any files", so binary files are conforming.

Suggestion. Isolate failures per skill and per file:

  • Skip a non-UTF-8 file, or every file outside SKILL.md that fails to decode, and list it as skipped. The skill stays usable from its text files.
  • Skip a skill whose frontmatter fails, and report its directory and reason beside the catalog, instead of failing the read. Alternatively, keep unknown metadata shapes as text in SKILL.md and drop only the field, as other unknown keys are already ignored.
  • Name the file or skill directory in SkillLoadFailed when one causes it.

Today an app has to reimplement the GitHub loader to serve these repositories.

Activity

  1. mikekeror-rgb commented on Nov 11, 2026

    @mikekeror-rgb

    I've put together a fix for the part of this that doesn't change behaviour: the failure now names the file or skill that caused it. Pull requests are limited to collaborators, so here's the branch and commit instead:

    mikekeror-rgb@e81e8bd2

    • A non-UTF-8 file: GitHub file "skills/canvas-design/canvas-fonts/X.ttf" is not valid UTF-8 text. Skill files must be text.
    • An invalid document: A skill from GitHub is not a valid skill document. followed by the SkillDefinitionInvalid message, which now names the skill's directory, e.g. The frontmatter of "skills/engineering/pr/SKILL.md" needs a valid name and description…

    What passes and fails is unchanged. I extended dynamic skills refresh remote publications without redeployment to assert the GitHub failure names skills/github-guide/SKILL.md. It passes on self-host and fails against the unfixed loader. Typecheck, oxfmt and oxlint pass.

    On skipping: dynamic-skills.spec.ts currently asserts that a non-UTF-8 reference file fails the bundle with 502, so I didn't change that. If you'd like non-UTF-8 files outside SKILL.md skipped, and invalid skills skipped while the load still fails when none succeed, I'm happy to do that next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions