Discover examples for remotely-loaded skills - #253
Conversation
A skill loaded from a URL exposed no examples at all. `_discover_examples` scanned the `examples/` directory, which only works for a local skill -- the remote branch was a comment saying examples "must be declared in the frontmatter (not yet implemented)". So a remote skill gave the agent instructions and reference files, and silently dropped every worked example the author shipped. That is the tier the agent most wants before writing code, and the loss is invisible: the prompt reports `has_code_examples: false` and nothing indicates that the examples exist but could not be seen. Take them from the body instead of the filesystem. Skill authors already publish an example listing as markdown links -- a bulleted `[examples/x.py] (examples/x.py) - what it shows` is the convention -- and `_build_skill_ integration` already has the parsed body in hand. Titles come from the link text, descriptions from the text following the link, and content is still fetched on demand, so discovery costs no additional requests. Local skills keep scanning the directory, which stays authoritative. Verified against two published skills served from raw.githubusercontent.com: all eight examples are now discovered with their descriptions intact, and loading one fetches correctly from the skill's base URL. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01555XSwMPRxBZFAEsvubUMz
mattprintz
left a comment
There was a problem hiding this comment.
Good catch on a legitimate oversight. Suggested a potential different path below that I think is workable but would be cleaner and more maintainable overall.
| _EXAMPLE_LINK_PATTERN = re.compile(r'\[([^\]]*)\]\((examples/[^)\s]+)\)([^\n]*)') | ||
|
|
||
|
|
||
| def extract_example_references(body: str) -> list[tuple[str, str, str]]: | ||
| """Extract examples declared as markdown links in the body. | ||
|
|
||
| Used for remote skills, where the ``examples/`` directory cannot be listed. | ||
| Local skills scan the directory instead, which stays authoritative. | ||
|
|
||
| Returns ``(relative_path, title, description)`` per example, deduplicated on | ||
| path and in document order. ``relative_path`` is relative to the skill root | ||
| (i.e. it retains the ``examples/`` prefix). | ||
| """ | ||
| examples: dict[str, tuple[str, str, str]] = {} | ||
| for match in _EXAMPLE_LINK_PATTERN.finditer(body): | ||
| link_text, path, trailing = match.group(1).strip(), match.group(2).strip(), match.group(3) | ||
| if path in examples: | ||
| continue | ||
| # Authors usually write the path as the link text; a filename reads | ||
| # better as a title than a repeated path does. | ||
| title = link_text if link_text and link_text != path else Path(path).name | ||
| description = trailing.strip().lstrip("-–—:*").strip() | ||
| examples[path] = (path, title, description) | ||
| return list(examples.values()) |
There was a problem hiding this comment.
Instead of manually extracting the examples separately, I think a better solution might be to remove the guard clause in the extract_file_references function above at lines 158-159.
This would keep the extraction consistent and that function is already being called and should handle this situation, I believe.
Doing so will likely mean that we have to dedupe examples detected via local path traversal (_discover_examples class method below, starting at line 507), but I think that should not be difficult.
Per review: drop the examples/ guard in extract_file_references rather than adding a second regex pass over the same body, and dedupe the two example sources where they meet. Extraction is now one uniform pass; the caller decides what a path becomes. _build_skill_integration routes examples/ paths to SkillExampleResources and everything else to SkillFileResources, so examples still do not double as reference files. A bare examples/ directory link names no file and is dropped rather than becoming an unloadable resource. The backtick pattern gained examples/ for the same consistency. _discover_examples now takes the referenced paths and merges them with the directory scan, keyed on filename, scan winning -- it carries a real parsed title and description where a referenced path yields only a filename. Losing the link glosses costs little: the agent must call load_skill_instructions, which returns the whole body including the author's own example listing, before it can ask for an example by name. Those descriptions were duplicated context. This also fixes local skills, which the first version did not. The scan globs *.md, so a skill shipping examples/*.py was invisible whether loaded locally or remotely. Both paths now see them. 487 passed. Verified against the two published skills: 4 examples each, none leaking into file resources, content still fetched on demand. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01555XSwMPRxBZFAEsvubUMz
|
Good call — done in c8fe864. Guard dropped from Two things your version catches that mine didn't:
One loss worth flagging: I was scraping each link's trailing text into Tests: dropped |
An example discovered from a reference in the body carries no title beyond its own filename, so the listing rendered "- **basic_fetch.py**: basic_fetch.py" -- which reads as a bug and spends tokens saying nothing. Omit the title when it adds nothing to the filename. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01555XSwMPRxBZFAEsvubUMz
mattprintz
left a comment
There was a problem hiding this comment.
Fix looks good. Tested with the dump command and no issues.
Problem
A skill loaded from a URL exposes no examples at all.
_discover_examplesscans theexamples/directory, which only works for a local skill:So a remote skill gives the agent instructions and reference files, and silently drops every worked example the author shipped. That's the tier the agent most wants before writing code — and the loss is invisible. The prompt reports
has_code_examples: false, which reads as "this skill has no examples" rather than "this skill's examples could not be seen".Reproduced against two published skills served from
raw.githubusercontent.com:Both ship four runnable examples.
Approach
Take examples from the body rather than from the filesystem.
Skill authors already publish an example listing as markdown links — the convention across skills I looked at is
and
_build_skill_integrationalready has the parsed body in hand. A newextract_example_references()pulls(path, title, description)out of those links: titles from the link text (falling back to the filename when the author wrote the path as the text), descriptions from the text following the link.Notably this costs no extra network requests — discovery stays free and content is still fetched on demand at tier 3. Declaring examples in frontmatter, the originally-sketched approach, would either need one request per example up front or duplicate every title and description into the frontmatter.
Local skills keep scanning the directory, which stays authoritative. This is additive: a remote skill with no example links behaves exactly as before.
Result
Same two skills, after:
Tests
15 new tests covering the extractor (listing form, descriptive link text, separator stripping, dedup, nested paths, non-example links ignored) and end-to-end remote discovery (descriptions preserved, content not fetched during discovery, exactly one request made, examples not double-counted as file resources, skills without example links unaffected).
Full suite: 489 passed.
🤖 Generated with Claude Code
https://claude.ai/code/session_01555XSwMPRxBZFAEsvubUMz