Skip to content

Fixed skills failing to load: quote SKILL.md frontmatter in every channel, warn on over-long description/name (0.7.1) - #11

Merged
dzykovic merged 3 commits into
mainfrom
fix/skill-frontmatter-load-failures
Jul 12, 2026
Merged

Fixed skills failing to load: quote SKILL.md frontmatter in every channel, warn on over-long description/name (0.7.1)#11
dzykovic merged 3 commits into
mainfrom
fix/skill-frontmatter-load-failures

Conversation

@dzykovic

Copy link
Copy Markdown
Contributor

Summary

Skills were failing to load in Claude Code, Cursor and Copilot, with two different errors and one shared cause: the engine only quoted SKILL.md frontmatter on its way into the Agent Skills open-standard directory (.agents/skills/). Every other channel got the source frontmatter verbatim — so argument-hint: [route-name], which YAML reads as a flow sequence, arrived as a list and Claude Code rejected the whole skill ("argument-hint must be a string"). It does not degrade; the skill simply vanishes from the picker. The second error ("Skill description must be at most 1024 characters") is an authoring problem the engine had no opinion about at all — it synced the file happily and the tool rejected it later, with nothing in the sync output pointing at the cause.

Non-breaking: no migration, no schema change. Patch release 0.7.1.

Type of change

  • Bug fix
  • New adapter
  • New helper / skill
  • Documentation
  • Refactor (no behavior change)

What changed

Symptom Cause Fix
argument-hint must be a string in .claude/skills/, .cursor/skills/, .github/skills/ Quoting ran only in sync_open_skill_dirs (the .agents/skills/ path); copy_skill_bundle — the copy path every other adapter uses — did not quote Quoting moved into copy_skill_bundle, so it is applied once, on the single path all adapters share. The now-redundant second pass in sync_open_skill_dirs is removed. Idempotent: already-quoted values pass through untouched.
Skill description must be at most 1024 characters Nothing in the engine ever looked at field length lint_frontmatter now warns at sync time with file, line and actual length — for description (>1024) and name (>64). Stays a warning: the engine reports, the author shortens the text.

Verification

  • bash intelligence/sync/scripts/sync.sh runs cleanly (IS_STATUS=ok) against five examples/* (on Linux via WSL)
  • lint_frontmatter produces no new warnings on valid input; the new length warning fires exactly on the over-long fixture
  • shellcheck --severity=warning clean
  • repo-purity: vendored docs identical, VERSION / INIT.md / all six examples in lockstep at 0.7.1
  • Documentation updated (docs/CONVENTIONS.md — a table of the limits that reject a skill outright; docs/ADAPTERS.md — adapters must copy skills through copy_skill_bundle; CHANGELOG.md)
  • Adapter changes tested with an actual IDE — not done; verified on generated output

Reproduced both reported errors as fixtures first (an unquoted list-shaped argument-hint, and a 1480-char description), then confirmed:

  • argument-hint: "[suite-name]" — a string — in all four channels (.claude, .cursor, .github, .agents); parsed back with a YAML reader to confirm the type, not just the text
  • the over-long description now surfaces as WARN: …/SKILL.md:3 description is 1480 chars — over the 1024-char limit; the skill/agent will be REJECTED at load time
  • bundled skill resources (references/) still ship — the quoting pass sits inside the bundle copy and does not disturb it

Notes for reviewers

  • New CI gate: the smoke fixture's skill now carries an unquoted argument-hint: [route-name], and CI asserts every channel emits it quoted. Without that, this regresses silently — the failure only ever appears inside someone's IDE, never in sync output.
  • Quoting on the shared path means .claude / .cursor / .github skills now carry quoted description / argument-hint where they previously carried the raw value. That is the fix, and it is what .agents/skills/ has always emitted.
  • The length limits are enforced by the consuming tools, not by us, so sync warns rather than fails — failing closed would block a sync over content the engine cannot fix for you.

… channel and warning on over-long description or name, released as 0.7.1
Copilot AI review requested due to automatic review settings July 12, 2026 20:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes cross-adapter skill loading failures by ensuring SKILL.md frontmatter is consistently normalized/quoted on the single shared copy path, and adds sync-time warnings for frontmatter fields that will be rejected by downstream skill loaders.

Changes:

  • Move SKILL.md frontmatter quoting into copy_skill_bundle and remove the redundant quoting pass in sync_open_skill_dirs.
  • Extend lint_frontmatter to warn when description (>1024 chars) or name (>64 chars) exceed known loader limits.
  • Bump sync version to 0.7.1, update docs/changelog, and add CI coverage to prevent regressions.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
intelligence/sync/scripts/VERSION Bumps engine version to 0.7.1.
intelligence/sync/scripts/lib/common.sh Centralizes SKILL frontmatter quoting in copy_skill_bundle; adds length warnings in lint_frontmatter; removes redundant pass in open-skill sync.
intelligence/sync/INIT.md Updates embedded sync_version to 0.7.1.
intelligence/sync/docs/CONVENTIONS.md Documents hard limits that cause skills to be rejected/disappear.
intelligence/sync/docs/ADAPTERS.md Documents that adapters must route skill copies through copy_skill_bundle and why.
examples/with-remote-skills/config.yaml Updates example sync_version to 0.7.1.
examples/platform-with-submodules/config.yaml Updates example sync_version to 0.7.1.
examples/go-api/config.yaml Updates example sync_version to 0.7.1.
examples/go-api-with-pi-and-codex/config.yaml Updates example sync_version to 0.7.1.
examples/go-api-with-opencode/config.yaml Updates example sync_version to 0.7.1.
examples/dotnet-api-with-react-frontend/config.yaml Updates example sync_version to 0.7.1.
docs/CONVENTIONS.md Mirrors conventions update in top-level docs.
docs/ADAPTERS.md Mirrors adapters update in top-level docs.
CHANGELOG.md Adds 0.7.1 release notes describing the fix and new warnings.
.github/workflows/ci.yml Adds fixture + assertion ensuring argument-hint is quoted in all emitted channels.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread intelligence/sync/scripts/lib/common.sh Outdated
Comment on lines +364 to +367
if [ -f "$dest_dir/SKILL.md" ]; then
copy_md_with_quoted_frontmatter "$dest_dir/SKILL.md" "$dest_dir/SKILL.md.tmp-q"
mv "$dest_dir/SKILL.md.tmp-q" "$dest_dir/SKILL.md"
fi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, and thank you — that was a real regression I introduced. [ -f ] follows the link, so the quoting pass would have read the symlink's target and written that content into a real file, turning skills/x/SKILL.md -> /etc/… into a copy of a host file inside .claude/skills/. Exactly the leak cp -R is used to prevent.

Fixed: a symlinked SKILL.md is now left precisely as copied (-L checked before -f), with a WARN saying it is emitted unprocessed — no quoting, no token expansion. The find … -type f loop already skipped symlinks, so that path was safe; this was the one that followed them.

Verified on Linux with a hostile fixture (SKILL.md -> /tmp/secret/passwd containing a marker string): the marker appears in no generated output, .claude/skills/evil-skill/SKILL.md is still a symlink rather than a materialized file, and a normal sibling skill still gets its argument-hint quoted. Added as a CI guardrail step so the guarantee has a test rather than a comment.

@dzykovic
dzykovic merged commit f45264d into main Jul 12, 2026
11 checks passed
@dzykovic
dzykovic deleted the fix/skill-frontmatter-load-failures branch July 12, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants