aitools: parse experimental_skills manifest section#5243
Conversation
- experimental/README.md: install examples now use the -experimental suffix on the skill name + the --experimental flag (matching the install-path behaviour landed in databricks/cli#5243). Adds a short note explaining why the in-repo dir name and the install dir name differ. - experimental/README.md: drop databricks-model-serving from the collision example (it was removed from this PR earlier). - experimental/README.md: update the (also available as stable skill) note for databricks-jobs to point at the open TODO #1a. - Root README: clarify the suffixed install name in the by-name install example. Co-authored-by: Isaac
- experimental/README.md: install examples now use the -experimental suffix on the skill name + the --experimental flag (matching the install-path behaviour landed in databricks/cli#5243). Adds a short note explaining why the in-repo dir name and the install dir name differ. - experimental/README.md: drop databricks-model-serving from the collision example (it was removed from this PR earlier). - experimental/README.md: update the (also available as stable skill) note for databricks-jobs to point at the open TODO #1a. - Root README: clarify the suffixed install name in the by-name install example. Co-authored-by: Isaac
0ab792b to
2994859
Compare
|
👋 @simonfaltum — Claude here on James's behalf. Rebased onto current Diff is the actual content delta: 22 files, +601/-50 (8 modified, 14 new — 4 acceptance test dirs + Ready for review whenever you've got time. Note on testability: this PR's end-to-end behavior still depends on d-a-s #73 merging and a d-a-s release being cut that contains (comment posted by Claude) |
Teaches the aitools installer to parse the new manifest shape from databricks/databricks-agent-skills (paired with d-a-s #73): - Single `skills` map; each entry's `repo_dir` ("skills" or "experimental") is the source of truth for stable-vs-experimental. - `SkillMeta.IsExperimental()` derives state from `RepoDir`. - Experimental skills get a `-experimental` suffix on their install-side key in `normalizeManifest`; new `SourceName` field preserves the unsuffixed name for fetch URLs. - The existing `--experimental` flag (already wired in `cmd/skills.go`) now has skills to install; `resolveSkills` filters them otherwise. - New acceptance tests at `acceptance/experimental/aitools/skills/install*/` cover stable-only, --experimental, specific-skill, and empty-manifest cases. `DATABRICKS_SKILLS_BASE_URL` env-var lets the tests mock the manifest server. Rebased onto current main; layout drift reconciled from `experimental/aitools/lib/installer/` → `libs/aitools/installer/` and `experimental/aitools/cmd/list.go` → `cmd/aitools/list.go` (per #4917's final shape). Acceptance test golden files regenerated to capture the legacy-alias deprecation warning that #4917 added on `databricks experimental aitools install`. Co-authored-by: Isaac
5d21edf to
a8c1689
Compare
Re-applied after the latest squash-and-rebase reset HEAD:
- libs/aitools/installer/installer.go: alternateVariantKey uses
strings.CutSuffix (modernize lint hint that now hard-fails CI).
- libs/aitools/installer/uninstall.go: drop the redundant `name := raw`
copy of the loop variable (copyloopvar lint hint; Go 1.22+ semantics).
- acceptance/experimental/aitools/skills/*/script: stub the Claude Code
install dir under "${USERPROFILE:-$HOME}/.claude". On Windows the
acceptance harness sets USERPROFILE (Go's os.UserHomeDir backing var
on that platform), not HOME, so the previous `$HOME/.claude` wrote to
the wrong path and the cli reported "No supported coding agents
detected." The fallback keeps Linux/macOS behavior unchanged.
Co-authored-by: Isaac
Ensure update cleans up stale stable/experimental skill variants and keep the manifest comments focused on the invariants that matter.
Use repo_dir as the experimental signal without suffixing install keys, and track repo dirs in state so source-folder moves still refresh installed files.
- Drop the -experimental suffix model entirely. Skills install under their plain names; the install dir is `~/.claude/skills/<name>/`. Stable+experimental collisions are resolved upstream by renaming (not by suffixing), and the manifest generator raises if a collision shows up. - Update README install instructions to the new top-level `databricks aitools install [name] --experimental` surface (was the legacy `databricks experimental aitools skills install ...` path). - Trim the experimental/README "Provenance & sync model" section per Dustin's L113/L126 asks — the long-term deprecation plan lives in ai-dev-kit when it's ready, not here. - Apply Dustin's L78 wording suggestion for the "previously experimental" callout. - Add @cankoklu-db and @yogesh-dbx as Code Owners on /experimental/. - Fix the databricks-pipelines manifest description: "Databricks Spark Declarative Pipelines (SDP) for ETL and streaming". - Drop the broken n8n-to-databricks cross-reference in databricks-ai-functions/4-document-processing-pipeline.md (the referenced skill does not exist). Paired with the cli-side suffix removal in databricks/cli#5243. Co-authored-by: Isaac
#5234 added a deprecation message when --global is passed; regenerate the affected aitools install goldens so the acceptance tests pass after the merge from main. Co-authored-by: Isaac
## Summary The skills manifest in `databricks/databricks-agent-skills` is gaining experimental skills sourced from a new `experimental/` directory in the repo (see paired [d-a-s PR databricks#73](databricks/databricks-agent-skills#73), which imports the ai-dev-kit skill catalog into `experimental/`). This wires the parsing through the aitools installer: - `Manifest.Skills` is a **single map** holding both stable and experimental entries; the per-skill `repo_dir` field ("skills" or "experimental") is the source of truth for whether a skill is experimental. `SkillMeta.IsExperimental()` derives state from `RepoDir`. - Experimental skills get a `-experimental` suffix on their install-side key during `normalizeManifest`; `SourceName` preserves the unsuffixed name for fetch URLs. - The existing `--experimental` flag (already wired in `cmd/skills.go`) now has experimental skills to install; without it, `resolveSkills` filters them out as before. ## UX ``` # default — only stable skills databricks experimental aitools skills install # all experimental skills, plus stable databricks experimental aitools skills install --experimental # one experimental skill by name (--experimental still required by resolveSkills) databricks experimental aitools skills install databricks-iceberg-experimental --experimental ``` ## TODOs / caveats for iteration 1. ~~**`DATABRICKS_SKILLS_REF` pin.**~~ **Partially resolved.** The default ref is still the latest stable release tag (sourced from `experimental/aitools/lib/installer/SKILLS_VERSION`); experimental entries won't exist there until d-a-s cuts a release with [PR databricks#73](databricks/databricks-agent-skills#73) merged. The default ref bump is a follow-up automated by the SKILLS_VERSION file. **UX fix shipped in this PR**: if `--experimental` is passed but the manifest at the resolved ref exposes no experimental skills, a warning is logged pointing users at `DATABRICKS_SKILLS_REF=main`. 2. ~~**Collision handling is naive.**~~ **Resolved.** Every experimental skill gets a `-experimental` suffix on its install-side key during `normalizeManifest`. The manifest key + install dir both carry the suffix; the `SourceName` field on `SkillMeta` preserves the upstream repo dir name for fetch URLs. Users see at a glance which installed skills are experimental. Also handled: **experimental↔stable transitions**. If a skill flips its experimental status upstream (the same logical skill changes manifest key), `install` removes the stale variant on disk + state before installing the new one, and `uninstall` accepts either variant name (and removes both if both are present). Helper: `alternateVariantKey()`. Covered by tests `TestInstallReplacesAlternateVariant`, `TestUninstallByEitherVariantRemovesBoth`, `TestUninstallByAlternateNameWhenOnlyOneVariantInstalled`. 3. ~~**`list` UX.**~~ **Resolved.** `aitools skills list` shows experimental skills with an `[experimental]` tag in the NAME column (driven by `meta.IsExperimental()`). Combined with the TODO databricks#2 resolution (`-experimental` suffix in the manifest key), every experimental row reads e.g. `databricks-iceberg-experimental [experimental]` — slightly redundant but a clear visual anchor. Hide-by-default was considered but rejected: users running `list` are usually looking for what's available, and silently omitting experimental skills makes them un-discoverable. 4. ~~**State tracking.**~~ **Resolved — kept additive semantics.** `InstallState.IncludeExperimental` records what was last requested but is not used to drive retroactive removal. Running `install` without `--experimental` leaves previously-installed experimental skills in place. Rationale: (a) users running `install` are typically adding/updating, not declaring set membership; (b) silently uninstalling things the user previously asked for is surprising; (c) the transition cleanup shipped under TODO databricks#2 handles the actual drift case (skill's experimental status flipping upstream). Removal is what `uninstall` is for. 5. ~~**No acceptance test yet.**~~ **Resolved.** Added acceptance tests under `acceptance/experimental/aitools/skills/install*/` covering the install flow against a mocked manifest server: - Stable-only install (no flag) → 1 skill installed - `--experimental` install adds the experimental skill (with `-experimental` suffix per the install-path model) → 2 skills total - Re-running `--experimental` is idempotent - Specific-skill install (`install --skills <name>`) for both stable and experimental - `--experimental` against a manifest with no experimental entries logs a nudge To make these reachable, exposed a new env-var override `DATABRICKS_SKILLS_BASE_URL` that overrides the hard-coded `raw.githubusercontent.com` base URL used by `GitHubManifestSource.FetchManifest` and `fetchSkillFile`. Defaults to the canonical URL when unset, so no production behavior change. Updated `Taskfile.yml`'s `test-exp-aitools` task to include `acceptance/experimental/aitools/**`. Variants left as follow-up acceptance tests (the structure is now in place): - Variant transition cleanup (stable → experimental, experimental → stable) - Uninstall flow (with both variants installed) 6. ~~**`--experimental` flag scope.**~~ **Resolved — kept current scope.** Each command has internally consistent behavior: - `install --experimental` → explicit opt-in (required to install experimental skills). - `update` → state-driven (honors `InstallState.IncludeExperimental` from the last `install`). If you opted in once, future updates refresh experimentals; otherwise they're skipped. - `list` → shows all skills with an `[experimental]` tag (no filtering — discovery first, opt-in to install). Adding `--experimental` / `--no-experimental` to `update` for one-off overrides was considered but rejected: the natural workflow is to re-run `install --experimental` (or just `install`), which already sets the desired state. Follow-up if real users hit a use case for the override. 7. ~~**Manifest shape.**~~ **Resolved.** Replaced the original two-map design (`skills` + `experimental_skills` + a per-skill `experimental` bool) with a single `skills` map where each entry's `repo_dir` (`"skills"` or `"experimental"`) is the source of truth. The cli derives experimental state from `RepoDir` via `SkillMeta.IsExperimental()`. Collisions between stable and experimental skills with the same repo dir name must be resolved upstream in d-a-s (which they already are — d-a-s PR databricks#73's TODO #1a merged the only known collision into stable). The d-a-s manifest generator should be updated to emit `repo_dir` per skill; until then `normalizeManifest` defaults a missing `RepoDir` to `"skills"` so older manifests still parse. ## Test plan - [x] `go build ./...` passes. - [x] `go test ./experimental/aitools/...` passes (`source_test.go` covers the normalize/IsExperimental cases). - [x] `go test ./acceptance -run TestAccept/experimental/aitools` passes (a pre-existing flake intermittently surfaces an `lstat` warning during copyDir, ~10% of multi-test runs; unrelated to this refactor). - [ ] Run `./task lint` and `./task fmt` before merge. - [ ] Manual: against a d-a-s ref containing experimental entries with `repo_dir`, verify the four UX cases above behave correctly. This pull request and its description were written by Claude. --------- Co-authored-by: simon <4305831+simonfaltum@users.noreply.github.com> Co-authored-by: simon <simon.faltum@databricks.com>
) ## Summary Adds an `experimental/` directory containing 19 agent skills from [databricks-solutions/ai-dev-kit](https://github.com/databricks-solutions/ai-dev-kit) `databricks-skills/`, imported as a snapshot on a **best-effort basis**. Excluded: `databricks-model-serving` (TODO #1b — different surface than stable, heavy MCP coupling) and `databricks-spark-declarative-pipelines` (TODO #5 — different surface than stable `databricks-pipelines`). `databricks-lakebase-provisioned` is not in the upstream `experimental` branch either, so absent here. The manifest now exposes both stable and experimental skills in a **single `skills` map**. Each entry carries a `repo_dir` field (`"skills"` or `"experimental"`) that points to the directory the skill lives in. Consumers derive experimental state from `repo_dir` — there is no parallel `experimental_skills` map and no per-skill `experimental` bool. Paired with [databricks/cli#5243](databricks/cli#5243) which teaches `databricks experimental aitools skills install` to: - read `repo_dir` and skip experimental entries by default, - install all of them with `--experimental`, - install one by name (with `--experimental` required and `-experimental` suffix on the install dir). ## Source Synced from [`f9b404b`](databricks-solutions/ai-dev-kit@f9b404b) on `databricks-solutions/ai-dev-kit:experimental`. Initial import was [`9c7a5b3`](databricks-solutions/ai-dev-kit@9c7a5b3) (head of [a-d-k PR #533](databricks-solutions/ai-dev-kit#533) on the `appkit-on-experimental` branch). PR #533 has since merged into `experimental` (`7b07f18`), and the branch has two further commits worth pulling: - [`0ebc38b`](databricks-solutions/ai-dev-kit@0ebc38b) "Surface silent failures in installer + dashboard skill" — updates `databricks-aibi-dashboards/SKILL.md` (CLI flag JSON-vs-flag form). - [`f9b404b`](databricks-solutions/ai-dev-kit@f9b404b) "Replace mas_manager.py with native supervisor-agents CLI" — updates `databricks-agent-bricks/SKILL.md` + `2-supervisor-agents.md` to the new supervisor-agents CLI group (Beta, CLI 0.299.2+); removes the 667-line `scripts/mas_manager.py` shim. Both pulled in commit `10baa35`. The fork branch's installer-side fixes (`5d2e6ac` / `39c349c` / `dd2257c`) are a-d-k tooling and don't touch `databricks-skills/`, so nothing to pull from there. ~~**Landing dependency**: a-d-k PR #533 should merge before this PR so the first periodic sync from a-d-k doesn't conflict.~~ **Resolved** — PR #533 merged upstream. The rename (`databricks-app-python` → `databricks-apps-python`) is preserved in the merged version, which is what prevents a 3rd skill-name collision with d-a-s's stable `databricks-apps`. ## Direction caveat — please read In the Apr 28 thread ([Slack link](https://databricks.slack.com/archives/C0AKALZU65P/p1778088227285599?thread_ts=1774540245.454779&cid=C0AKALZU65P)), Dustin's stated plan was to move `databricks-agent-skills` skills **into** `ai-dev-kit`'s `experimental` branch as defaults. **This PR goes the other direction** (a-d-k content → d-a-s/experimental). I don't see any d-a-s commits from Dustin yet, and the timing has slipped. Opening this so we have something concrete to iterate on — happy to drop it if the original direction is still preferred. ## TODOs / caveats for iteration 1. **Name collisions.** Resolved in this PR: - **1a. `databricks-jobs` — merged into stable.** Imported the comprehensive reference content from a-d-k's `databricks-jobs` skill into `skills/databricks-jobs/`, bumping version to `0.2.0`. The merged skill keeps stable's scaffolding workflow + `parent: databricks-core` hierarchy + Codex `agents/openai.yaml` + compatibility note, and adds the experimental's full task-types reference (9 types), trigger types (6), notifications/health/retries/queues, and 7 worked end-to-end examples. Layered structure: SKILL.md as overview + four reference files (`task-types.md`, `triggers-schedules.md`, `notifications-monitoring.md`, `examples.md`). Cleanups during merge: dropped trigger-spam description, normalized `/Workspace/Users/user@example.com/...` paths to `/Workspace/Shared/...`. The experimental copy is removed. With the single-map manifest shape, collisions are no longer possible — `_add_skill` raises if the same skill name shows up under both `skills/` and `experimental/`, so any future drift fails generation loudly. - **1b. `databricks-model-serving` — dropped from this PR.** After a deep compare, the two skills cover almost entirely different surfaces: stable is **ops-focused** (manage existing endpoints via CLI: `serving-endpoints create/get/query/update-config/build-logs/put-ai-gateway/get-permissions/...`, AI Gateway, traffic config, app integration via `databricks-apps` skill); experimental is **dev-focused** (build & ship MLflow models / GenAI agents: autolog → `mlflow.pyfunc.log_model` → `databricks.agents.deploy()` → query, with full Classical ML / Custom PyFunc / `ResponsesAgent` + LangGraph / UCFunctionToolkit / VectorSearchRetrieverTool coverage). Near-zero content overlap. Experimental version also has heavy MCP-tool dependency (60+ refs to ai-dev-kit's `manage_serving_endpoint`, `manage_workspace_files`, `manage_jobs`, `manage_job_runs`, `execute_code` that don't exist in the d-a-s/`databricks experimental aitools` flow). Removed `experimental/databricks-model-serving/` from this PR; manifest regenerated. **Follow-up**: port the high-value dev-side content into the stable skill — classical-ml autolog patterns (`mlflow.{sklearn,xgboost,lightgbm,pytorch,tensorflow,spark}.autolog()`), Custom PyFunc signatures, `ResponsesAgent` pattern with the `create_text_output_item` helper-method gotcha, `UCFunctionToolkit` + `VectorSearchRetrieverTool` with resource passthrough for auth, the Foundation Model API endpoint table. Strip MCP refs; replace with CLI/SDK equivalents. Owners: @databricks/eng-apps-devex (per CODEOWNERS). 2. ~~**CODEOWNERS for `experimental/`**~~ **Resolved.** Per @simonfaltum review: the top 10 a-d-k contributors (>=10 commits at import time) are now Code Owners of `/experimental/` alongside the d-a-s maintainers (@lennartkats-db, @simonfaltum, @databricks/eng-apps-devex), so their review satisfies the Required-Code-Owner-Review branch protection. Maintainer review still works as an alternate path. 3. ~~**No sync mechanism with upstream a-d-k.**~~ **Resolved with a paired RFC.** Two-part plan: - **Pre-lock (this PR)**: periodic manual re-syncs from upstream `ai-dev-kit` into `experimental/`. Documented in `experimental/README.md`. - **Post-lock (follow-up)**: invert the direction. a-d-k becomes the consumer; `databricks-skills/imported/` in a-d-k is a `git subtree` of this repo's `experimental/`. RFC PR opened against a-d-k: databricks-solutions/ai-dev-kit#530 (draft). To make subtree work, d-a-s needs to publish an `experimental-only` branch via `git subtree split --prefix=experimental` after every push to main — that's a small workflow to add here in a follow-up PR. A one-shot preview branch `experimental-only-preview` was pushed to this repo to enable the RFC demo and should be deleted once the auto-publish workflow lands. 4. ~~**No agent metadata.**~~ **Resolved.** Imported skills install fine on Codex CLI — the missing `agents/openai.yaml` was a cosmetic gap, not a functional blocker (skill files still get copied; only the marketplace UI metadata is absent). `scripts/skills.py` now auto-generates `agents/openai.yaml` + copies shared assets for each experimental skill on `generate`, using SKILL.md frontmatter as the source. Stubs are only written when missing, so upstream a-d-k can override by shipping its own files in the skill. The auto-generated names are titlecased from the skill key — most look good (`Databricks Iceberg`, `Databricks Genie`); a few degrade gracefully (`Databricks Aibi Dashboards`). Refining those is a follow-up. 5. ~~**`databricks-pipelines` was deliberately excluded.**~~ **Resolved.** a-d-k doesn't ship a `databricks-pipelines` skill under that name, but it *does* ship `databricks-spark-declarative-pipelines` covering the same product. After a deep compare, that experimental version covers a different surface than stable: scaffolding (`databricks pipelines init` + bundle/MCP workflow A/B/C), DLT migration guide, language-selection rules, per-language performance reference. The stable skill covers feature reference (decision tree, common traps, format options, fine-grained per-feature × per-language refs). Partial overlap; experimental's DAB-coupled workflow is the exact concern Dustin flagged in the Apr 28 Slack thread for demo-generator flows. **Removed `experimental/databricks-spark-declarative-pipelines/` from this PR**. **Follow-up TODO** (post-merge): port the high-value pieces into stable `skills/databricks-pipelines/` — DLT migration guide, workflow A/B/C decision matrix, per-language performance reference, language-selection rules. Strip MCP-tool refs. Owners: @lennartkats-db / @camielstee-db (per CODEOWNERS). 6. ~~**`spark-python-data-source` naming exception.**~~ **Kept as-is.** The skill is about the OSS Apache Spark 4+ PySpark DataSource API (building custom connector libraries), not a Databricks product — only lightly flavored with Databricks idioms. The convention break is acceptable given the content. 7. ~~**Versioning.**~~ **Resolved.** Bumped the `extract_version_from_skill` fallback in `scripts/skills.py` from `0.0.0` → `0.0.1` so the manifest never reports `0.0.0` (which some tools treat as \"unset\"). Applies to skills that currently have no explicit `version:` in their SKILL.md frontmatter. Skills with an explicit version are unchanged. The change is sync-safe: when upstream a-d-k eventually adds version fields, those win; until then, the manifest reports the floor. 8. ~~**`installed_dir` for experimental skills.**~~ **All experimental skills install under a `-experimental` suffix.** Every experimental skill installs to `~/.claude/skills/<name>-experimental/` regardless of whether there's a stable skill with the colliding base name. Implemented in [databricks/cli#5243](databricks/cli#5243) via a new `SourceName` field on `SkillMeta`: the install-side manifest key (and install dir) carry the `-experimental` suffix; `SourceName` preserves the unsuffixed name for fetching from `experimental/<name>/` in this repo. Users see at a glance which installed skills are experimental. 9. ~~**Excluded a-d-k content.**~~ **Confirmed scope.** Excluded: `TEMPLATE/` (template, not a skill), `install_skills.sh` + `install_genie_code_skills.py` (a-d-k's installers — we use the cli installer instead), `databricks-builder-app/` (a Python app for a-d-k's builder UI), `databricks-mcp-server/` (the a-d-k MCP server — separate concern from skills), `databricks-tools-core/` (Python lib used by a-d-k tooling — no experimental skill references it), `hooks/hooks.json` (a-d-k plugin lifecycle hooks tied to `\${CLAUDE_PLUGIN_ROOT}/.claude-plugin/setup.sh`/`check_update.sh` — plugin-specific, not skill content), plus top-level repo metadata (`.github/`, `LICENSE.md`, `README.md`, `VERSION`, `install.{sh,ps1}`, etc.). Verified no experimental skill cross-references any excluded path. 10. ~~**README placement.**~~ **Verified.** `experimental/README.md` retains the adapted a-d-k skill list with a top warning block; the root `README.md` has an \"Experimental Skills\" section with an install-by-name example. Three concrete fixes applied during the verification pass: (a) dropped the stale `databricks-model-serving` collision example since that skill was removed from the PR, (b) install commands updated to include the `-experimental` suffix + flag per TODO #8's resolution, (c) added a short note in `experimental/README.md` explaining why the in-repo dir names don't carry the suffix (it's added at install time). 11. ~~**Manifest shape.**~~ **Resolved.** Replaced the original two-map design (top-level `skills` + `experimental_skills` plus per-skill `experimental` bool) with a single `skills` map where each entry's `repo_dir` field is the source of truth. Rationale: the directory location in the repo already determines status, so it's the natural single source. Consumers derive experimental state from `repo_dir` (see cli's `SkillMeta.IsExperimental`). The manifest generator (`scripts/skills.py`) raises a clear error if the same skill name appears under both `skills/` and `experimental/`, so future drift fails generation rather than silently overwriting. ## Test plan - [x] `python3 scripts/skills.py generate` regenerates the manifest cleanly. - [x] `python3 scripts/skills.py validate` passes. - [ ] CI green on this branch. - [ ] Manual: `databricks experimental aitools skills install` (no flag) installs only stable skills. - [ ] Manual: `databricks experimental aitools skills install --experimental` installs both. - [ ] Manual: `databricks experimental aitools skills install databricks-iceberg-experimental` errors because it's experimental. - [ ] Manual: `databricks experimental aitools skills install databricks-iceberg-experimental --experimental` installs that one skill. This pull request and its description were written by Claude.
Summary
The skills manifest in
databricks/databricks-agent-skillsis gaining experimental skills sourced from a newexperimental/directory in the repo (see paired d-a-s PR #73, which imports the ai-dev-kit skill catalog intoexperimental/).This wires the parsing through the aitools installer:
Manifest.Skillsis a single map holding both stable and experimental entries; the per-skillrepo_dirfield ("skills" or "experimental") is the source of truth for whether a skill is experimental.SkillMeta.IsExperimental()derives state fromRepoDir.-experimentalsuffix on their install-side key duringnormalizeManifest;SourceNamepreserves the unsuffixed name for fetch URLs.--experimentalflag (already wired incmd/skills.go) now has experimental skills to install; without it,resolveSkillsfilters them out as before.UX
TODOs / caveats for iteration
Partially resolved. The default ref is still the latest stable release tag (sourced fromDATABRICKS_SKILLS_REFpin.experimental/aitools/lib/installer/SKILLS_VERSION); experimental entries won't exist there until d-a-s cuts a release with PR #73 merged. The default ref bump is a follow-up automated by the SKILLS_VERSION file. UX fix shipped in this PR: if--experimentalis passed but the manifest at the resolved ref exposes no experimental skills, a warning is logged pointing users atDATABRICKS_SKILLS_REF=main.Collision handling is naive.Resolved. Every experimental skill gets a-experimentalsuffix on its install-side key duringnormalizeManifest. The manifest key + install dir both carry the suffix; theSourceNamefield onSkillMetapreserves the upstream repo dir name for fetch URLs. Users see at a glance which installed skills are experimental.Also handled: experimental↔stable transitions. If a skill flips its experimental status upstream (the same logical skill changes manifest key),
installremoves the stale variant on disk + state before installing the new one, anduninstallaccepts either variant name (and removes both if both are present). Helper:alternateVariantKey(). Covered by testsTestInstallReplacesAlternateVariant,TestUninstallByEitherVariantRemovesBoth,TestUninstallByAlternateNameWhenOnlyOneVariantInstalled.Resolved.listUX.aitools skills listshows experimental skills with an[experimental]tag in the NAME column (driven bymeta.IsExperimental()). Combined with the TODO Bump gopkg.in/ini.v1 from 1.66.4 to 1.66.5 #2 resolution (-experimentalsuffix in the manifest key), every experimental row reads e.g.databricks-iceberg-experimental [experimental]— slightly redundant but a clear visual anchor. Hide-by-default was considered but rejected: users runninglistare usually looking for what's available, and silently omitting experimental skills makes them un-discoverable.State tracking.Resolved — kept additive semantics.InstallState.IncludeExperimentalrecords what was last requested but is not used to drive retroactive removal. Runninginstallwithout--experimentalleaves previously-installed experimental skills in place. Rationale: (a) users runninginstallare typically adding/updating, not declaring set membership; (b) silently uninstalling things the user previously asked for is surprising; (c) the transition cleanup shipped under TODO Bump gopkg.in/ini.v1 from 1.66.4 to 1.66.5 #2 handles the actual drift case (skill's experimental status flipping upstream). Removal is whatuninstallis for.No acceptance test yet.Resolved. Added acceptance tests underacceptance/experimental/aitools/skills/install*/covering the install flow against a mocked manifest server:--experimentalinstall adds the experimental skill (with-experimentalsuffix per the install-path model) → 2 skills total--experimentalis idempotentinstall --skills <name>) for both stable and experimental--experimentalagainst a manifest with no experimental entries logs a nudgeTo make these reachable, exposed a new env-var override
DATABRICKS_SKILLS_BASE_URLthat overrides the hard-codedraw.githubusercontent.combase URL used byGitHubManifestSource.FetchManifestandfetchSkillFile. Defaults to the canonical URL when unset, so no production behavior change. UpdatedTaskfile.yml'stest-exp-aitoolstask to includeacceptance/experimental/aitools/**.Variants left as follow-up acceptance tests (the structure is now in place):
Resolved — kept current scope. Each command has internally consistent behavior:--experimentalflag scope.install --experimental→ explicit opt-in (required to install experimental skills).update→ state-driven (honorsInstallState.IncludeExperimentalfrom the lastinstall). If you opted in once, future updates refresh experimentals; otherwise they're skipped.list→ shows all skills with an[experimental]tag (no filtering — discovery first, opt-in to install).Adding
--experimental/--no-experimentaltoupdatefor one-off overrides was considered but rejected: the natural workflow is to re-runinstall --experimental(or justinstall), which already sets the desired state. Follow-up if real users hit a use case for the override.Manifest shape.Resolved. Replaced the original two-map design (skills+experimental_skills+ a per-skillexperimentalbool) with a singleskillsmap where each entry'srepo_dir("skills"or"experimental") is the source of truth. The cli derives experimental state fromRepoDirviaSkillMeta.IsExperimental(). Collisions between stable and experimental skills with the same repo dir name must be resolved upstream in d-a-s (which they already are — d-a-s PR Add bricks command string to user agent #73's TODO #1a merged the only known collision into stable). The d-a-s manifest generator should be updated to emitrepo_dirper skill; until thennormalizeManifestdefaults a missingRepoDirto"skills"so older manifests still parse.Test plan
go build ./...passes.go test ./experimental/aitools/...passes (source_test.gocovers the normalize/IsExperimental cases).go test ./acceptance -run TestAccept/experimental/aitoolspasses (a pre-existing flake intermittently surfaces anlstatwarning during copyDir, ~10% of multi-test runs; unrelated to this refactor)../task lintand./task fmtbefore merge.repo_dir, verify the four UX cases above behave correctly.This pull request and its description were written by Claude.