Skip to content

Commit 6479f76

Browse files
Add AppKit support and databricks-agent-skills integration (#356)
* Apps: Add AppKit, and prefer it over other app frameworks * rename local databricks-apps skill to databricks-apps-python * install: enable renaming skills from remote repos * Drop agent skills for jobs and pipelines Remove databricks-jobs:databricks-jobs-bundles and databricks-pipelines from agent skills in both install.sh and install.ps1. Co-authored-by: Isaac * Rename databricks-app-python → databricks-apps-python everywhere Completes the pre-existing-bug fix called out in the PR description. The skill directory `databricks-apps-python` (plural) is the canonical name; this updates all remaining stale singular references (.test eval skill, routing ground truth, scorer, baselines, run_app_eval docs, builder-app system prompt + UI, MCP tool docstring, install_skills.sh, related-skill links in lakebase-provisioned/bundles SKILL.md). Verified .test/tests/test_scorers.py: 36/36 pass. Co-authored-by: Isaac * fix: ACE multi-model review findings on agent-skill installer Two issues caught in parallel review by GPT 5.4 and Gemini 3.1 Pro: 1. **Upstream skill name mismatch** (HIGH, GPT 5.4): The agent skill at `databricks/databricks-agent-skills` is named `databricks-core`, not `databricks`. Previously `--skills-profile app-developer` would silently fail to install one of three advertised skills. Fix: use the source:install-name syntax this PR already introduces — `databricks-core:databricks` keeps the local install name while pointing at the correct upstream directory. 2. **Partial-download false success** (CRITICAL, Gemini 3.1 Pro): `ok_flag` was initialized to 0 and flipped to 1 on the first successful file download, never reset on subsequent failures. Any single successful file (even an examples/*.py) marked the skill as installed, leaving a broken skill on disk. Same pattern in install.ps1 with $okFlag. Fix: initialize the flag to 1 (true) and only flip to 0 (false) on any single download failure — a skill installs cleanly iff every file lands. Not addressed (acceptable today, worth a follow-up): - Unauthenticated GitHub API rate limit (60/hr) — fine for single- user installs, can bite CI. - `grep '\.'` heuristic to filter trees vs blobs — brittle but works for current skills (all files have extensions). - Sequential vs parallel curl — perf nit, not a bug. Co-authored-by: Isaac * fix: address ACE multi-model review findings GPT 5.4 xhigh and Gemini 3.1 Pro both flagged the new short agent-skill names triggering latent bugs in the install scripts. Three fixes: 1. install.sh `_is_preselected`: `grep -qw` treats `-` as a word boundary, so checking for `databricks` would falsely match `databricks-jobs`, `databricks-apps`, etc. Strip `source:` prefix from each preselected entry and use `grep -Fxq` for exact whole-line equality. Same fix applied to the deselection cleanup at the cleanup loop. 2. install.ps1: `$preselected -contains "databricks"` is exact equality on array elements, so it never matched the `"databricks-core:databricks"` entry seeded by the app-developer profile — the Agent: Databricks checkbox was never auto-preselected. Normalize `$preselected` by stripping `source:` prefixes once before the menu is built. 3. install.sh/ps1: the "Agent skills (N) -> ..." success line ran unconditionally, even when the GitHub tree fetch failed or every per-skill download warned and was rolled back. Track an `agent_success`/`$agentSuccess` counter and only print the success line when all selected agent skills installed; print a warning when only some succeeded. Co-authored-by: Isaac * fix: agent-skills installer regex matches live GitHub API + clears stale dirs Two more ACE review findings, both real: 1. The path-extraction regex `"path":"skills/..."` (no space) does NOT match the GitHub tree API's actual response, which is pretty-printed as `"path": "skills/..."` (space after colon). Result: the installer would warn "Could not fetch agent skill" for every entry and install nothing. Fix: collapse the JSON whitespace before regex extraction, and switch from the `grep '\.'` heuristic to matching the adjacent `"type": "blob"` field so directory entries are correctly skipped. 2. Reinstalls reused the existing $dest_dir / $destDir without clearing it, so files removed upstream would persist locally across upgrades. Fix: `rm -rf` / `Remove-Item -Recurse` the destination before each skill is downloaded. Co-authored-by: Isaac * fix: resolve_skills bucketing + 0-of-N agent install summary ACE iteration 2 findings: - Gemini caught that the `grep -qw` word-boundary bug I fixed in `_is_preselected` still bit the resolve_skills() bucketing chain (lines 918/920/922). Passing `--skills databricks` (a valid agent install-name) would match `databricks-app-apx` via the hyphen word-boundary on the APX branch and get misclassified. Switched all three buckets to exact match via `tr ' ' '\n' | grep -Fxq`, and rewrote the source:install-name lookup on line 923 with `-E` and a clean anchored alternation. - GPT caught that when the GitHub tree fetch fails entirely (`agent_tree` empty / `$agentTree` null), the summary branch emits nothing — neither OK nor "only N of M installed" — even though zero of N agent skills were actually installed. Added an `else` branch that emits a `0 of $agent_count installed` warning. Out of scope (flagged but not addressed): - GPT raised legacy-name compatibility for `databricks-app-python` → `databricks-apps-python`. The rename is intentional per the product decision; back-compat aliasing is a separate concern. Co-authored-by: Isaac
1 parent 4e55b48 commit 6479f76

31 files changed

Lines changed: 308 additions & 74 deletions

File tree

.test/baselines/databricks-app-python/baseline.yaml renamed to .test/baselines/databricks-apps-python/baseline.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ results_summary:
1010
status: RUNNING
1111
success: true
1212
run_id: 1fb85925959b453090dce7d3317559cf
13-
skill_name: databricks-app-python
13+
skill_name: databricks-apps-python
1414
test_count: 1
1515
timestamp: '2026-02-12T20:17:59Z'

.test/scripts/run_app_eval.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
5. Cleans up all test apps
1010
1111
Usage:
12-
DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-app-python [--test-ids id1 id2]
13-
DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-app-python --keep # Don't delete apps after
12+
DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-apps-python [--test-ids id1 id2]
13+
DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-apps-python --keep # Don't delete apps after
1414
"""
1515

1616
import argparse
@@ -226,7 +226,7 @@ def detect_framework_yaml(python_code: str) -> str:
226226

227227
def main():
228228
parser = argparse.ArgumentParser(description="Run app skill integration tests on Databricks")
229-
parser.add_argument("skill_name", help="Name of skill to evaluate (e.g., databricks-app-python)")
229+
parser.add_argument("skill_name", help="Name of skill to evaluate (e.g., databricks-apps-python)")
230230
parser.add_argument("--test-ids", nargs="+", help="Specific test IDs to run")
231231
parser.add_argument("--keep", action="store_true", help="Don't delete apps after testing")
232232
args = parser.parse_args()

.test/skills/_routing/ground_truth.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ test_cases:
148148
inputs:
149149
prompt: "Create a Streamlit app that shows sales data"
150150
expectations:
151-
expected_skills: ["databricks-app-python"]
151+
expected_skills: ["databricks-apps-python"]
152152
is_multi_skill: false
153153
metadata:
154154
category: "single_skill"
@@ -159,7 +159,7 @@ test_cases:
159159
inputs:
160160
prompt: "Build a Dash app with interactive charts"
161161
expectations:
162-
expected_skills: ["databricks-app-python"]
162+
expected_skills: ["databricks-apps-python"]
163163
is_multi_skill: false
164164
metadata:
165165
category: "single_skill"
@@ -170,7 +170,7 @@ test_cases:
170170
inputs:
171171
prompt: "Create a Gradio app for testing my ML model"
172172
expectations:
173-
expected_skills: ["databricks-app-python"]
173+
expected_skills: ["databricks-apps-python"]
174174
is_multi_skill: false
175175
metadata:
176176
category: "single_skill"
@@ -181,7 +181,7 @@ test_cases:
181181
inputs:
182182
prompt: "Build a FastAPI app that serves data from a warehouse"
183183
expectations:
184-
expected_skills: ["databricks-app-python"]
184+
expected_skills: ["databricks-apps-python"]
185185
is_multi_skill: false
186186
metadata:
187187
category: "single_skill"
@@ -192,7 +192,7 @@ test_cases:
192192
inputs:
193193
prompt: "Create a Reflex app for managing inventory"
194194
expectations:
195-
expected_skills: ["databricks-app-python"]
195+
expected_skills: ["databricks-apps-python"]
196196
is_multi_skill: false
197197
metadata:
198198
category: "single_skill"
@@ -205,7 +205,7 @@ test_cases:
205205
prompt: "Build a Dash app and deploy it using DABs"
206206
expectations:
207207
expected_skills:
208-
- "databricks-app-python"
208+
- "databricks-apps-python"
209209
- "databricks-bundles"
210210
is_multi_skill: true
211211
metadata:
@@ -218,7 +218,7 @@ test_cases:
218218
prompt: "Create a Streamlit app that stores data in Lakebase"
219219
expectations:
220220
expected_skills:
221-
- "databricks-app-python"
221+
- "databricks-apps-python"
222222
- "databricks-lakebase-provisioned"
223223
is_multi_skill: true
224224
metadata:
@@ -231,7 +231,7 @@ test_cases:
231231
prompt: "Build a Gradio app that queries a model serving endpoint"
232232
expectations:
233233
expected_skills:
234-
- "databricks-app-python"
234+
- "databricks-apps-python"
235235
- "model-serving"
236236
is_multi_skill: true
237237
metadata:
@@ -246,7 +246,7 @@ test_cases:
246246
expectations:
247247
expected_skills:
248248
- "databricks-app-apx"
249-
- "databricks-app-python"
249+
- "databricks-apps-python"
250250
is_multi_skill: true
251251
metadata:
252252
category: "multi_skill"
File renamed without changes.
File renamed without changes.

.test/skills/databricks-app-python/manifest.yaml renamed to .test/skills/databricks-apps-python/manifest.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
skill:
2-
name: "databricks-app-python"
3-
source_path: "databricks-skills/databricks-app-python"
2+
name: "databricks-apps-python"
3+
source_path: "databricks-skills/databricks-apps-python"
44
description: "Python Databricks Apps: Dash, Streamlit, Gradio, Flask, FastAPI, Reflex"
55

66
tool_modules: [apps, serving]

.test/src/skill_test/scorers/routing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"fastapi react",
3333
"react frontend",
3434
],
35-
"databricks-app-python": [
35+
"databricks-apps-python": [
3636
"python app",
3737
"streamlit",
3838
"dash",

.test/tests/test_scorers.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,34 +70,34 @@ def test_detect_genie(self):
7070
assert "databricks-agent-bricks" in skills
7171

7272
def test_detect_app_python_streamlit(self):
73-
"""Test detection of databricks-app-python via Streamlit."""
73+
"""Test detection of databricks-apps-python via Streamlit."""
7474
prompt = "Create a Streamlit app that shows sales data"
7575
skills = detect_skills_from_prompt(prompt)
76-
assert "databricks-app-python" in skills
76+
assert "databricks-apps-python" in skills
7777

7878
def test_detect_app_python_dash(self):
79-
"""Test detection of databricks-app-python via Dash."""
79+
"""Test detection of databricks-apps-python via Dash."""
8080
prompt = "Build a Dash app with interactive charts"
8181
skills = detect_skills_from_prompt(prompt)
82-
assert "databricks-app-python" in skills
82+
assert "databricks-apps-python" in skills
8383

8484
def test_detect_app_python_gradio(self):
85-
"""Test detection of databricks-app-python via Gradio."""
85+
"""Test detection of databricks-apps-python via Gradio."""
8686
prompt = "Create a Gradio app for testing my ML model"
8787
skills = detect_skills_from_prompt(prompt)
88-
assert "databricks-app-python" in skills
88+
assert "databricks-apps-python" in skills
8989

9090
def test_detect_app_python_fastapi(self):
91-
"""Test detection of databricks-app-python via FastAPI."""
91+
"""Test detection of databricks-apps-python via FastAPI."""
9292
prompt = "Build a FastAPI app that serves data from a warehouse"
9393
skills = detect_skills_from_prompt(prompt)
94-
assert "databricks-app-python" in skills
94+
assert "databricks-apps-python" in skills
9595

9696
def test_detect_app_python_reflex(self):
97-
"""Test detection of databricks-app-python via Reflex."""
97+
"""Test detection of databricks-apps-python via Reflex."""
9898
prompt = "Create a Reflex app for managing inventory"
9999
skills = detect_skills_from_prompt(prompt)
100-
assert "databricks-app-python" in skills
100+
assert "databricks-apps-python" in skills
101101

102102
def test_detect_app_apx(self):
103103
"""Test detection of databricks-app-apx."""
@@ -109,13 +109,13 @@ def test_detect_fastapi_react_matches_both(self):
109109
"""Test that 'FastAPI React' matches both APX and Python app skills.
110110
111111
'fastapi react' triggers APX, while bare 'fastapi' also triggers
112-
databricks-app-python. This is intentional — the router sees both
112+
databricks-apps-python. This is intentional — the router sees both
113113
and picks the best fit.
114114
"""
115115
prompt = "Create a FastAPI React app for my dashboard"
116116
skills = detect_skills_from_prompt(prompt)
117117
assert "databricks-app-apx" in skills
118-
assert "databricks-app-python" in skills
118+
assert "databricks-apps-python" in skills
119119

120120
def test_detect_lakebase(self):
121121
"""Test detection of databricks-lakebase-provisioned skill."""
@@ -140,14 +140,14 @@ def test_detect_multi_app_lakebase(self):
140140
"""Test detection of app + lakebase."""
141141
prompt = "Create a Streamlit app that stores data in Lakebase"
142142
skills = detect_skills_from_prompt(prompt)
143-
assert "databricks-app-python" in skills
143+
assert "databricks-apps-python" in skills
144144
assert "databricks-lakebase-provisioned" in skills
145145

146146
def test_detect_multi_app_serving(self):
147147
"""Test detection of app + model serving."""
148148
prompt = "Build a Gradio app that queries a model serving endpoint"
149149
skills = detect_skills_from_prompt(prompt)
150-
assert "databricks-app-python" in skills
150+
assert "databricks-apps-python" in skills
151151
assert "databricks-model-serving" in skills
152152

153153
def test_detect_no_match(self):
@@ -171,7 +171,7 @@ def test_all_skills_have_triggers(self):
171171
expected_skills = [
172172
"databricks-spark-declarative-pipelines",
173173
"databricks-app-apx",
174-
"databricks-app-python",
174+
"databricks-apps-python",
175175
"databricks-bundles",
176176
"databricks-python-sdk",
177177
"databricks-jobs",

databricks-builder-app/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ Skills provide specialized guidance for Databricks development tasks. They are m
179179
Skills include:
180180
- **databricks-bundles**: DABs configuration
181181
- **databricks-app-apx**: Full-stack apps with APX framework (FastAPI + React)
182-
- **databricks-app-python**: Python apps with Dash, Streamlit, Flask
182+
- **databricks-apps-python**: Python apps with Dash, Streamlit, Flask
183183
- **databricks-python-sdk**: Python SDK patterns
184184
- **databricks-mlflow-evaluation**: MLflow evaluation and trace analysis
185185
- **databricks-spark-declarative-pipelines**: Spark Declarative Pipelines (SDP) development
@@ -313,7 +313,7 @@ Skills are loaded from `../databricks-skills/` and filtered by the `ENABLED_SKIL
313313
- `databricks-spark-declarative-pipelines`: SDP/DLT pipeline development
314314
- `databricks-synthetic-data-gen`: Creating test datasets
315315
- `databricks-app-apx`: Full-stack apps with React (APX framework)
316-
- `databricks-app-python`: Python apps with Dash, Streamlit, Flask
316+
- `databricks-apps-python`: Python apps with Dash, Streamlit, Flask
317317

318318
**Adding custom skills:**
319319
1. Create a new directory in `../databricks-skills/`

databricks-builder-app/app.yaml_backup

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ env:
3030
# =============================================================================
3131
# Comma-separated list of skills to enable
3232
- name: ENABLED_SKILLS
33-
value: "databricks-asset-bundles,databricks-agent-bricks,databricks-aibi-dashboards,databricks-app-apx,databricks-app-python,databricks-config,databricks-docs,databricks-jobs,databricks-python-sdk,databricks-unity-catalog,mlflow-evaluation,spark-declarative-pipelines,synthetic-data-generation,unstructured-pdf-generation"
33+
value: "databricks-asset-bundles,databricks-agent-bricks,databricks-aibi-dashboards,databricks-app-apx,databricks-apps-python,databricks-config,databricks-docs,databricks-jobs,databricks-python-sdk,databricks-unity-catalog,mlflow-evaluation,spark-declarative-pipelines,synthetic-data-generation,unstructured-pdf-generation"
3434
- name: SKILLS_ONLY_MODE
3535
value: "false"
3636

0 commit comments

Comments
 (0)