fix(skills): add normalize_skill_files() helper and document path naming convention#1590
Open
ppradyoth wants to merge 2 commits into
Open
fix(skills): add normalize_skill_files() helper and document path naming convention#1590ppradyoth wants to merge 2 commits into
ppradyoth wants to merge 2 commits into
Conversation
…ing convention Adds a `normalize_skill_files()` utility to `anthropic.lib.tools` that rewrites every file-tuple path in a `beta.skills.create(files=...)` call so it is correctly prefixed with the skill name read from the SKILL.md frontmatter. The `files=` parameter requires all paths to start with `<name>/`; without the helper callers must do this manually, and the error they get when they forget is an opaque API 400. Also updates the `files=` param docstring in the generated skills resource to describe the naming convention and cross-reference the new helper. Fixes anthropics#1575
…dempotency - Wire normalize_skill_files() into Skills.create / AsyncSkills.create so callers never need to know about the <name>/ prefix requirement — bare paths and wrong-prefix paths are fixed transparently before the request is sent (symmetric with _archive_top_dir on the download side). - Add display_title fallback: when SKILL.md frontmatter has no name: field, the method's display_title param is normalized to lowercase-with-hyphens and used as the prefix instead of surfacing a confusing 400. - Idempotent: already-correct paths are left unchanged; wrong top-level prefix is stripped-and-replaced rather than double-prefixed (bug in anthropics#1604). - _parse_skill_name_from_frontmatter now returns str | None instead of raising, keeping error-path control in normalize_skill_files(). - Updated docstrings in Skills.create / AsyncSkills.create to show that normalization is automatic; users no longer need to think about layout. - 27 tests passing (added 10 new: idempotency, display_title fallback, special-char normalization, 2-tuple entries, PathLike content, frontmatter parse returning None, wrong-prefix replacement). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1575.
beta.skills.create(files=...)silently requires every path to be prefixedwith a top-level directory whose name exactly matches the
name:field inSKILL.mdfrontmatter (e.g.my-skill/SKILL.md,my-skill/scripts/tool.py).When callers pass bare names like
"SKILL.md"they receive a cryptic 400 withno guidance on what went wrong.
What this PR does
Normalization is now automatic —
Skills.create/AsyncSkills.createcall
normalize_skill_files()internally before building the multipart request,so callers never need to know about the prefix requirement:
This makes upload symmetric with
_archive_top_diron the download side, whichalready strips the wrapper directory when extracting — the constraint was always
there in both directions, but only enforced on upload.
Name resolution order
name:field inSKILL.mdYAML frontmatter (primary)display_titlenormalised tolowercase-with-hyphens(fallback when frontmatter omitsname:)Key advantages over the other PRs addressing #1575
create()display_titlefallbacknormalize_skill_files()exported for explicit useChanges
src/anthropic/lib/tools/_skills.py—normalize_skill_files(files, *, display_title=None)with wrong-prefix replacement,display_titlefallback, and idempotency;_parse_skill_name_from_frontmatterreturnsstr | Noneinstead of raisingsrc/anthropic/lib/tools/__init__.py— re-exportsnormalize_skill_filesfor callers who want to inspect normalized paths before uploadingsrc/anthropic/resources/beta/skills/skills.py— auto-wires normalization into bothSkills.createandAsyncSkills.create; updatedfiles=docstring to say normalization is automatictests/lib/tools/test_skills.py— 27 tests total (10 new: idempotency, display_title fallback, special-char normalization, 2-tuple entries, PathLike content, frontmatter returning None, wrong-prefix replacement)Test plan