Skip to content

Extract shared skill-download core and add selective download - #578

Open
xsh310 wants to merge 1 commit into
skills-picker-walkfrom
skills-picker-download-core
Open

xsh310 wants to merge 1 commit into
skills-picker-walkfrom
skills-picker-download-core

Conversation

@xsh310

@xsh310 xsh310 commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

What

PR C of the ug skill add interactive-picker stack. It reshapes skills_download.py so the download mechanics become one reusable core, and adds the (still unwired) functions the picker will call in PR D. No behavior changes on any existing path.

Design doc: ug_skill_add_download_interactive_picker_design.md (PR table, row C).

Changes

  • SkillRef carries its full location. New catalog/schema fields plus an fqn property, parsed once from the API name in _skill_ref, so a ref is self-contained and can be downloaded on its own.
  • Extract _download_refs(refs, roots) -> (written, total), the shared core: collision dedup, overwrite prompt, parallel fetch, write. should_download_skill and _reject_bundle_name_collisions now read the source off the ref (ref.fqn) instead of an explicit location arg, which produces byte-identical messages and lets the core serve a flat, cross-schema set.
  • _fetch_bundles keys results by FQN (a securable name is unique only within its schema) and takes its progress-bar label from the caller.
  • Rename download_skills to download_skills_from_schema_locations, now calling _download_refs per location and keeping the exact per-location Downloaded k/n from <location> summary.
  • Add get_skill(fqn) (GetSkill at /2.1/unity-catalog/skills/<fqn>, reusing _skill_ref; NOT_FOUND to None) and download_selected_skills(fqns, path) (one _download_refs pass over the flat selection). Both are dead code until PR D wires the picker.

Deviations from the design doc

  • download_managed_skills_on_launch is a second caller of _fetch_bundles the doc did not mention; it is updated to the new keying (behavior-preserving).
  • The doc lists should_download_skill / _reject_bundle_name_collisions as reused unchanged, but making the core location-agnostic means they read the source off the ref. The emitted messages are identical (<catalog>.<schema>.<securable> equals ref.fqn).

Testing

uv run ruff check ., ruff format --check src tests, and uv run pytest all pass (the 2 pre-existing e2e failures in test_e2e_user_agent and test_claude_smart_routing_v2 are unrelated and also fail on the base branch). New unit tests cover _download_refs (including cross-schema dedup), get_skill (NOT_FOUND to None, unfinalized to None), and download_selected_skills.

Stacked on #574 (skills-picker-walk).

This pull request and its description were written by Isaac.

@xsh310
xsh310 added this pull request to stack #576 September 11, 2026 23:15
Comment thread src/ucode/skills_download.py
@xsh310
xsh310 marked this pull request as ready for review September 12, 2026 07:13
@xsh310
xsh310 force-pushed the skills-picker-download-core branch 2 times, most recently from 274f6b0 to 5a90185 Compare September 14, 2026 03:08
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 5a90185 to a6fbd13 Compare September 14, 2026 20:09
overwriting a skill already on disk (naming the source by ``ref.fqn``), so a
declined skill is never fetched. Dedup keys on the bundle name, since that is
the directory an agent would load. Name validity is the server's job --
FinalizeSkill enforces the Agent Skills naming rules on ``bundle_name`` before

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

P1 (defense-in-depth): bundle_name flows straight into filesystem paths — write_skill does root / ref.bundle_name, and _skill_installs records those same dirs, which ug skill remove later shutil.rmtrees. Today that's safe because, as this docstring says, FinalizeSkill enforces Agent Skills naming rules server-side (no .//), so a legit bundle_name can't traverse. But it's a remote-provided value feeding a write and delete sink with zero client-side check — if the server guarantee ever regresses or is bypassed, we write/delete outside the skill dir. A one-line guard where the ref is built (reject .., /, or absolute paths, skip+warn) is cheap insurance for a delete sink. Not exploitable as-is — flagging for hardening.

@xsh310
xsh310 force-pushed the skills-picker-download-core branch from a6fbd13 to eda0255 Compare September 14, 2026 22:32
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from eda0255 to 0571612 Compare September 14, 2026 23:20
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 0571612 to 1d7543c Compare September 15, 2026 00:53
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 1d7543c to 69292f2 Compare September 15, 2026 01:17
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 69292f2 to 202fd05 Compare September 15, 2026 01:41
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 202fd05 to 3f6aa4e Compare September 15, 2026 03:30
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 3f6aa4e to 21a7d8d Compare September 15, 2026 03:40
Refactor skills_download.py so the download mechanics (collision dedup,
overwrite prompt, parallel fetch, write) become one reusable core, ahead of
the interactive picker (PR D) which selects individual skills across schemas.

- SkillRef now carries catalog/schema and exposes fqn, so a ref is fully
  self-contained; _skill_ref parses all three from the API name.
- Extract _download_refs(refs, roots) -> (written, total), the shared core.
  should_download_skill and _reject_bundle_name_collisions read the source
  off the ref (ref.fqn), yielding identical messages, so the core is
  location-agnostic and handles a cross-schema set.
- _fetch_bundles keys results by fqn (a securable is unique only within its
  schema) and takes its progress-bar label from the caller.
- Rename download_skills to download_skills_from_schema_locations; it calls
  _download_refs per location and keeps the per-location summary.
- download_managed_skills_on_launch (the other _fetch_bundles caller) moves
  to the new keying; behavior unchanged.
- Add get_skill(fqn) (GetSkill, NOT_FOUND to None) and
  download_selected_skills(fqns, path); both unwired this PR.

No behavior change on any existing path. New unit tests cover _download_refs
(including cross-schema dedup), get_skill, and download_selected_skills.

Co-authored-by: Isaac <no-reply@databricks.com>
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 21a7d8d to aaa780b Compare September 15, 2026 04:42
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