Skip to content

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

Merged
xsh310 merged 2 commits into
skills-picker-walkfrom
skills-picker-download-core
Sep 16, 2026
Merged

xsh310 merged 2 commits 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
Comment thread src/ucode/skills_download.py
@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
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 21a7d8d to aaa780b Compare September 15, 2026 04:42
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from aaa780b to 155e401 Compare September 15, 2026 14:43
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 155e401 to def026f Compare September 15, 2026 18:17
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from def026f to e1a77be Compare September 15, 2026 19:56
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from e1a77be to 0aa946e Compare September 15, 2026 21:19
xsh310 and others added 2 commits September 16, 2026 00:46
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>
bundle_name is server-provided and names the on-disk skill directory
(a write sink, and the future ug skill remove delete sink), so guard it
client-side against separators, .. traversal, and absolute paths rather
than relying only on FinalizeSkill's server-side naming rules.

Co-authored-by: Isaac <no-reply@databricks.com>
@xsh310
xsh310 force-pushed the skills-picker-download-core branch from 0aa946e to 30cb6b5 Compare September 16, 2026 00:51
@xsh310
xsh310 merged commit 9a67a2b into main Sep 16, 2026
18 checks passed
@xsh310
xsh310 deleted the skills-picker-download-core branch September 16, 2026 01:00
xsh310 added a commit that referenced this pull request Sep 16, 2026
## What

PR D (final) of the `ug skill add` interactive-picker stack: it wires
the feature. Running `ug skill add` with no `--mcp`, `--location`, or
`--skills` on an interactive terminal now opens a picker of the
workspace's skills to download, mirroring `ug mcp add`'s picker exactly.

Design doc: `ug_skill_add_download_interactive_picker_design.md` (PR
table, row D). Builds on PR A (picker primitives), PR B
(`walk_catalog_schemas`), and PR C (`download_selected_skills`).

## Changes

All in `skills_download.py` (discovery + picker glue) and `cli.py`
(routing):

- **`list_all_skills`** — workspace-wide skill walk via
`walk_catalog_schemas` (catalogs → schemas → skills in parallel under a
wall-clock deadline), flattening and streaming each schema's finalized
skills by FQN.
- **Picker glue** — `_skill_download_choice` (value = FQN, title flags
on-disk bundles, which stay selectable so a re-download can update
them), `_skills_download_background_loader` (runs `list_all_skills` on
the token the command already fetched and streams discovered skills into
the open picker as choices), and `prompt_for_skill_download_choices`
(`scrolling_checkbox` with `loading_noun="skills"`).
- **`configure_skills_download_picker_command`** — opens the picker
immediately, streams skills in behind it, then
`download_selected_skills` + `register_schemaless_skills_connection` on
save. Ctrl-C downloads nothing and leaves the connection untouched.
- **`skills_add`** — opens the picker when `--mcp`, `--location`, and
`--skills` are all omitted on an interactive terminal (via
`_stdin_is_interactive`). The typed `--location` / `--skills` paths are
unchanged, and a non-interactive run (piped/CI) still errors with
`--location is required`.
- **README** — documents the no-argument picker.

## Edge cases (handled by the reused primitives)

- **Empty / streaming:** the picker opens on an empty list and fills in
via the background loader.
- **Deadline / partial results:** `walk_catalog_schemas` returns what it
found once the budget is exceeded.
- **Permission / discovery failure:** discovery runs on the picker's
daemon thread, so a 403 or transient failure just stops the stream and
the picker stays open.
- **Ctrl-C:** exit 0, nothing downloaded, no registration.

## Testing

`uv run ruff check .`, `ruff format --check src tests`, `ty check src`,
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
`list_all_skills` (flatten, stream, dedupe by FQN, progress, deadline,
walk-failure reason), the picker glue (choice on-disk flag, background
loader streaming, prompt selection and cancel), the picker command
(download+register, Ctrl-C no-op), and CLI routing (interactive opens
the picker, `--skills` stays on the typed path, non-interactive errors).

Stacked on #578.



https://github.com/user-attachments/assets/e5140d3c-cdf0-4746-b7cf-ffe93826cfe3

This pull request and its description were written by Isaac.

---------

Co-authored-by: Isaac <no-reply@databricks.com>
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