diff --git a/.test/baselines/databricks-app-python/baseline.yaml b/.test/baselines/databricks-apps-python/baseline.yaml similarity index 89% rename from .test/baselines/databricks-app-python/baseline.yaml rename to .test/baselines/databricks-apps-python/baseline.yaml index 300bbcf8..3a9bb677 100644 --- a/.test/baselines/databricks-app-python/baseline.yaml +++ b/.test/baselines/databricks-apps-python/baseline.yaml @@ -10,6 +10,6 @@ results_summary: status: RUNNING success: true run_id: 1fb85925959b453090dce7d3317559cf -skill_name: databricks-app-python +skill_name: databricks-apps-python test_count: 1 timestamp: '2026-02-12T20:17:59Z' diff --git a/.test/scripts/run_app_eval.py b/.test/scripts/run_app_eval.py index 17628bfb..66b93089 100644 --- a/.test/scripts/run_app_eval.py +++ b/.test/scripts/run_app_eval.py @@ -9,8 +9,8 @@ 5. Cleans up all test apps Usage: - DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-app-python [--test-ids id1 id2] - DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-app-python --keep # Don't delete apps after + DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-apps-python [--test-ids id1 id2] + DATABRICKS_CONFIG_PROFILE=ffe python run_app_eval.py databricks-apps-python --keep # Don't delete apps after """ import argparse @@ -226,7 +226,7 @@ def detect_framework_yaml(python_code: str) -> str: def main(): parser = argparse.ArgumentParser(description="Run app skill integration tests on Databricks") - parser.add_argument("skill_name", help="Name of skill to evaluate (e.g., databricks-app-python)") + parser.add_argument("skill_name", help="Name of skill to evaluate (e.g., databricks-apps-python)") parser.add_argument("--test-ids", nargs="+", help="Specific test IDs to run") parser.add_argument("--keep", action="store_true", help="Don't delete apps after testing") args = parser.parse_args() diff --git a/.test/skills/_routing/ground_truth.yaml b/.test/skills/_routing/ground_truth.yaml index d89e1fd9..1733c338 100644 --- a/.test/skills/_routing/ground_truth.yaml +++ b/.test/skills/_routing/ground_truth.yaml @@ -148,7 +148,7 @@ test_cases: inputs: prompt: "Create a Streamlit app that shows sales data" expectations: - expected_skills: ["databricks-app-python"] + expected_skills: ["databricks-apps-python"] is_multi_skill: false metadata: category: "single_skill" @@ -159,7 +159,7 @@ test_cases: inputs: prompt: "Build a Dash app with interactive charts" expectations: - expected_skills: ["databricks-app-python"] + expected_skills: ["databricks-apps-python"] is_multi_skill: false metadata: category: "single_skill" @@ -170,7 +170,7 @@ test_cases: inputs: prompt: "Create a Gradio app for testing my ML model" expectations: - expected_skills: ["databricks-app-python"] + expected_skills: ["databricks-apps-python"] is_multi_skill: false metadata: category: "single_skill" @@ -181,7 +181,7 @@ test_cases: inputs: prompt: "Build a FastAPI app that serves data from a warehouse" expectations: - expected_skills: ["databricks-app-python"] + expected_skills: ["databricks-apps-python"] is_multi_skill: false metadata: category: "single_skill" @@ -192,7 +192,7 @@ test_cases: inputs: prompt: "Create a Reflex app for managing inventory" expectations: - expected_skills: ["databricks-app-python"] + expected_skills: ["databricks-apps-python"] is_multi_skill: false metadata: category: "single_skill" @@ -205,7 +205,7 @@ test_cases: prompt: "Build a Dash app and deploy it using DABs" expectations: expected_skills: - - "databricks-app-python" + - "databricks-apps-python" - "databricks-bundles" is_multi_skill: true metadata: @@ -218,7 +218,7 @@ test_cases: prompt: "Create a Streamlit app that stores data in Lakebase" expectations: expected_skills: - - "databricks-app-python" + - "databricks-apps-python" - "databricks-lakebase-provisioned" is_multi_skill: true metadata: @@ -231,7 +231,7 @@ test_cases: prompt: "Build a Gradio app that queries a model serving endpoint" expectations: expected_skills: - - "databricks-app-python" + - "databricks-apps-python" - "model-serving" is_multi_skill: true metadata: @@ -246,7 +246,7 @@ test_cases: expectations: expected_skills: - "databricks-app-apx" - - "databricks-app-python" + - "databricks-apps-python" is_multi_skill: true metadata: category: "multi_skill" diff --git a/.test/skills/databricks-app-python/candidates.yaml b/.test/skills/databricks-apps-python/candidates.yaml similarity index 100% rename from .test/skills/databricks-app-python/candidates.yaml rename to .test/skills/databricks-apps-python/candidates.yaml diff --git a/.test/skills/databricks-app-python/ground_truth.yaml b/.test/skills/databricks-apps-python/ground_truth.yaml similarity index 100% rename from .test/skills/databricks-app-python/ground_truth.yaml rename to .test/skills/databricks-apps-python/ground_truth.yaml diff --git a/.test/skills/databricks-app-python/manifest.yaml b/.test/skills/databricks-apps-python/manifest.yaml similarity index 91% rename from .test/skills/databricks-app-python/manifest.yaml rename to .test/skills/databricks-apps-python/manifest.yaml index 9ed23b19..ff02aa39 100644 --- a/.test/skills/databricks-app-python/manifest.yaml +++ b/.test/skills/databricks-apps-python/manifest.yaml @@ -1,6 +1,6 @@ skill: - name: "databricks-app-python" - source_path: "databricks-skills/databricks-app-python" + name: "databricks-apps-python" + source_path: "databricks-skills/databricks-apps-python" description: "Python Databricks Apps: Dash, Streamlit, Gradio, Flask, FastAPI, Reflex" tool_modules: [apps, serving] diff --git a/.test/src/skill_test/scorers/routing.py b/.test/src/skill_test/scorers/routing.py index fa32c073..e16bb2ac 100644 --- a/.test/src/skill_test/scorers/routing.py +++ b/.test/src/skill_test/scorers/routing.py @@ -32,7 +32,7 @@ "fastapi react", "react frontend", ], - "databricks-app-python": [ + "databricks-apps-python": [ "python app", "streamlit", "dash", diff --git a/.test/tests/test_scorers.py b/.test/tests/test_scorers.py index 63de0125..6df1d6c4 100644 --- a/.test/tests/test_scorers.py +++ b/.test/tests/test_scorers.py @@ -70,34 +70,34 @@ def test_detect_genie(self): assert "databricks-agent-bricks" in skills def test_detect_app_python_streamlit(self): - """Test detection of databricks-app-python via Streamlit.""" + """Test detection of databricks-apps-python via Streamlit.""" prompt = "Create a Streamlit app that shows sales data" skills = detect_skills_from_prompt(prompt) - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills def test_detect_app_python_dash(self): - """Test detection of databricks-app-python via Dash.""" + """Test detection of databricks-apps-python via Dash.""" prompt = "Build a Dash app with interactive charts" skills = detect_skills_from_prompt(prompt) - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills def test_detect_app_python_gradio(self): - """Test detection of databricks-app-python via Gradio.""" + """Test detection of databricks-apps-python via Gradio.""" prompt = "Create a Gradio app for testing my ML model" skills = detect_skills_from_prompt(prompt) - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills def test_detect_app_python_fastapi(self): - """Test detection of databricks-app-python via FastAPI.""" + """Test detection of databricks-apps-python via FastAPI.""" prompt = "Build a FastAPI app that serves data from a warehouse" skills = detect_skills_from_prompt(prompt) - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills def test_detect_app_python_reflex(self): - """Test detection of databricks-app-python via Reflex.""" + """Test detection of databricks-apps-python via Reflex.""" prompt = "Create a Reflex app for managing inventory" skills = detect_skills_from_prompt(prompt) - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills def test_detect_app_apx(self): """Test detection of databricks-app-apx.""" @@ -109,13 +109,13 @@ def test_detect_fastapi_react_matches_both(self): """Test that 'FastAPI React' matches both APX and Python app skills. 'fastapi react' triggers APX, while bare 'fastapi' also triggers - databricks-app-python. This is intentional — the router sees both + databricks-apps-python. This is intentional — the router sees both and picks the best fit. """ prompt = "Create a FastAPI React app for my dashboard" skills = detect_skills_from_prompt(prompt) assert "databricks-app-apx" in skills - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills def test_detect_lakebase(self): """Test detection of databricks-lakebase-provisioned skill.""" @@ -140,14 +140,14 @@ def test_detect_multi_app_lakebase(self): """Test detection of app + lakebase.""" prompt = "Create a Streamlit app that stores data in Lakebase" skills = detect_skills_from_prompt(prompt) - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills assert "databricks-lakebase-provisioned" in skills def test_detect_multi_app_serving(self): """Test detection of app + model serving.""" prompt = "Build a Gradio app that queries a model serving endpoint" skills = detect_skills_from_prompt(prompt) - assert "databricks-app-python" in skills + assert "databricks-apps-python" in skills assert "databricks-model-serving" in skills def test_detect_no_match(self): @@ -171,7 +171,7 @@ def test_all_skills_have_triggers(self): expected_skills = [ "databricks-spark-declarative-pipelines", "databricks-app-apx", - "databricks-app-python", + "databricks-apps-python", "databricks-bundles", "databricks-python-sdk", "databricks-jobs", diff --git a/databricks-builder-app/README.md b/databricks-builder-app/README.md index 59780939..4d7ef413 100644 --- a/databricks-builder-app/README.md +++ b/databricks-builder-app/README.md @@ -179,7 +179,7 @@ Skills provide specialized guidance for Databricks development tasks. They are m Skills include: - **databricks-bundles**: DABs configuration - **databricks-app-apx**: Full-stack apps with APX framework (FastAPI + React) -- **databricks-app-python**: Python apps with Dash, Streamlit, Flask +- **databricks-apps-python**: Python apps with Dash, Streamlit, Flask - **databricks-python-sdk**: Python SDK patterns - **databricks-mlflow-evaluation**: MLflow evaluation and trace analysis - **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 - `databricks-spark-declarative-pipelines`: SDP/DLT pipeline development - `databricks-synthetic-data-gen`: Creating test datasets - `databricks-app-apx`: Full-stack apps with React (APX framework) -- `databricks-app-python`: Python apps with Dash, Streamlit, Flask +- `databricks-apps-python`: Python apps with Dash, Streamlit, Flask **Adding custom skills:** 1. Create a new directory in `../databricks-skills/` diff --git a/databricks-builder-app/app.yaml_backup b/databricks-builder-app/app.yaml_backup index 1349cb8c..e9c6f688 100644 --- a/databricks-builder-app/app.yaml_backup +++ b/databricks-builder-app/app.yaml_backup @@ -30,7 +30,7 @@ env: # ============================================================================= # Comma-separated list of skills to enable - name: ENABLED_SKILLS - 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" + 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" - name: SKILLS_ONLY_MODE value: "false" diff --git a/databricks-builder-app/client/src/pages/DocPage.tsx b/databricks-builder-app/client/src/pages/DocPage.tsx index 34f706b0..ca75328e 100644 --- a/databricks-builder-app/client/src/pages/DocPage.tsx +++ b/databricks-builder-app/client/src/pages/DocPage.tsx @@ -92,7 +92,7 @@ function OverviewSection() { Skills explain how to do things and reference the tools from databricks-tools-core.

- {['databricks-bundles/', 'databricks-app-apx/', 'databricks-app-python/', 'databricks-python-sdk/', 'databricks-mlflow-evaluation/', 'databricks-spark-declarative-pipelines/', 'databricks-synthetic-data-gen/'].map((skill) => ( + {['databricks-bundles/', 'databricks-app-apx/', 'databricks-apps-python/', 'databricks-python-sdk/', 'databricks-mlflow-evaluation/', 'databricks-spark-declarative-pipelines/', 'databricks-synthetic-data-gen/'].map((skill) => ( {skill} diff --git a/databricks-builder-app/server/services/skills_manager.py b/databricks-builder-app/server/services/skills_manager.py index 0732d5db..07a1f256 100644 --- a/databricks-builder-app/server/services/skills_manager.py +++ b/databricks-builder-app/server/services/skills_manager.py @@ -48,7 +48,7 @@ # APX (FastAPI+React) and Python (Dash/Streamlit/etc.) share the same # app lifecycle tools — the skill content differs, not the MCP operations. 'databricks-app-apx': ['manage_app'], - 'databricks-app-python': ['manage_app'], + 'databricks-apps-python': ['manage_app'], } diff --git a/databricks-builder-app/server/services/system_prompt.py b/databricks-builder-app/server/services/system_prompt.py index ea7c9dc5..4b34772a 100644 --- a/databricks-builder-app/server/services/system_prompt.py +++ b/databricks-builder-app/server/services/system_prompt.py @@ -12,7 +12,7 @@ ('SDK, API, Databricks client', 'databricks-python-sdk'), ('Unity Catalog, tables, volumes, schemas', 'databricks-unity-catalog'), ('Agent, chatbot, AI assistant', 'databricks-agent-bricks'), - ('App deployment, web app', 'databricks-app-python'), + ('App deployment, web app', 'databricks-apps-python'), ] diff --git a/databricks-mcp-server/databricks_mcp_server/tools/apps.py b/databricks-mcp-server/databricks_mcp_server/tools/apps.py index 34c7474d..7939b148 100644 --- a/databricks-mcp-server/databricks_mcp_server/tools/apps.py +++ b/databricks-mcp-server/databricks_mcp_server/tools/apps.py @@ -81,7 +81,7 @@ def manage_app( - delete: Delete an app. Requires name. Returns: {name, status}. - See databricks-app-python skill for app development guidance.""" + See databricks-apps-python skill for app development guidance.""" act = action.lower() if act == "create_or_update": diff --git a/databricks-skills/README.md b/databricks-skills/README.md index a5e50868..28151e74 100644 --- a/databricks-skills/README.md +++ b/databricks-skills/README.md @@ -102,7 +102,7 @@ cp -r ai-dev-kit/databricks-skills/databricks-agent-bricks .claude/skills/ ### 🚀 Development & Deployment - **databricks-bundles** - DABs for multi-environment deployments - **databricks-app-apx** - Full-stack apps (FastAPI + React) -- **databricks-app-python** - Python web apps (Dash, Streamlit, Flask) with foundation model integration +- **databricks-apps-python** - Python web apps (Dash, Streamlit, Flask) with foundation model integration - **databricks-python-sdk** - Python SDK, Connect, CLI, REST API - **databricks-config** - Profile authentication setup - **databricks-lakebase-autoscale** - Lakebase Autoscaling managed PostgreSQL with branching, scale-to-zero, reverse ETL diff --git a/databricks-skills/databricks-app-python/1-authorization.md b/databricks-skills/databricks-apps-python/1-authorization.md similarity index 100% rename from databricks-skills/databricks-app-python/1-authorization.md rename to databricks-skills/databricks-apps-python/1-authorization.md diff --git a/databricks-skills/databricks-app-python/2-app-resources.md b/databricks-skills/databricks-apps-python/2-app-resources.md similarity index 100% rename from databricks-skills/databricks-app-python/2-app-resources.md rename to databricks-skills/databricks-apps-python/2-app-resources.md diff --git a/databricks-skills/databricks-app-python/3-frameworks.md b/databricks-skills/databricks-apps-python/3-frameworks.md similarity index 100% rename from databricks-skills/databricks-app-python/3-frameworks.md rename to databricks-skills/databricks-apps-python/3-frameworks.md diff --git a/databricks-skills/databricks-app-python/4-deployment.md b/databricks-skills/databricks-apps-python/4-deployment.md similarity index 100% rename from databricks-skills/databricks-app-python/4-deployment.md rename to databricks-skills/databricks-apps-python/4-deployment.md diff --git a/databricks-skills/databricks-app-python/5-lakebase.md b/databricks-skills/databricks-apps-python/5-lakebase.md similarity index 100% rename from databricks-skills/databricks-app-python/5-lakebase.md rename to databricks-skills/databricks-apps-python/5-lakebase.md diff --git a/databricks-skills/databricks-app-python/6-cli-approach.md b/databricks-skills/databricks-apps-python/6-cli-approach.md similarity index 100% rename from databricks-skills/databricks-app-python/6-cli-approach.md rename to databricks-skills/databricks-apps-python/6-cli-approach.md diff --git a/databricks-skills/databricks-app-python/SKILL.md b/databricks-skills/databricks-apps-python/SKILL.md similarity index 76% rename from databricks-skills/databricks-app-python/SKILL.md rename to databricks-skills/databricks-apps-python/SKILL.md index c5a595a5..99850a01 100644 --- a/databricks-skills/databricks-app-python/SKILL.md +++ b/databricks-skills/databricks-apps-python/SKILL.md @@ -1,24 +1,71 @@ --- -name: databricks-app-python -description: "Builds Python-based Databricks applications using Dash, Streamlit, Gradio, Flask, FastAPI, or Reflex. Handles OAuth authorization (app and user auth), app resources, SQL warehouse and Lakebase connectivity, model serving integration, foundation model APIs, LLM integration, and deployment. Use when building Python web apps, dashboards, ML demos, or REST APIs for Databricks, or when the user mentions Streamlit, Dash, Gradio, Flask, FastAPI, Reflex, or Databricks app." +name: databricks-apps-python +description: "Builds Databricks applications. Prefers AppKit (TypeScript + React SDK) for new apps; falls back to Python frameworks (Dash, Streamlit, Gradio, Flask, FastAPI, Reflex) when Python is required. Handles OAuth authorization, app resources, SQL warehouse and Lakebase connectivity, model serving, foundation model APIs, and deployment. Use when building web apps, dashboards, ML demos, or REST APIs for Databricks, or when the user mentions AppKit, Streamlit, Dash, Gradio, Flask, FastAPI, Reflex, or Databricks app." --- -# Databricks Python Application +# Databricks Applications -Build Python-based Databricks applications. For full examples and recipes, see the **[Databricks Apps Cookbook](https://apps-cookbook.dev/)**. +Build Databricks applications. For full examples and recipes, see the **[Databricks Apps Cookbook](https://apps-cookbook.dev/)**. --- -## Critical Rules (always follow) +## AppKit (Preferred for New Apps) -- **MUST** confirm framework choice or use [Framework Selection](#framework-selection) below +**[AppKit](https://github.com/databricks/appkit)** is the recommended SDK for new Databricks apps. It is a TypeScript + React SDK with a plugin architecture, built-in caching, telemetry, and end-to-end type safety. + +### Requirements +- Node.js v22+ +- Databricks CLI v0.295.0+ + +### Scaffold a new app +```bash +databricks apps init +``` +This interactive command scaffolds the full project, installs dependencies, and optionally deploys. + +### Deploy +```bash +databricks apps deploy +``` + +### AppKit plugins +| Plugin | Purpose | +|--------|---------| +| **Analytics** | SQL queries against Databricks SQL Warehouses — file-based, typed, cached | +| **Genie** | Conversational AI/BI interface with natural language queries | +| **Files** | Browse/upload Unity Catalog Volumes | +| **Lakebase** | OLTP PostgreSQL via Lakebase with OAuth token management | + +### AI-assisted development +```bash +# Install agent skills for AI-powered scaffolding +databricks experimental aitools skills install + +# Query AppKit docs inline +npx @databricks/appkit docs "your question here" +``` + +### AppKit documentation +- **[AppKit Docs](https://databricks.github.io/appkit/docs/)** — getting started, plugins, API reference +- **[AI-assisted development](https://databricks.github.io/appkit/docs/development/ai-assisted-development)** — guidance for code assistants +- **[llms.txt](https://databricks.github.io/appkit/llms.txt)** — machine-readable docs for AI context + +--- + +## Python Apps (alternative) + +Use Python when: the team is Python-only, you need Streamlit/Dash/Gradio, or you are extending an existing Python app. + +## Critical Rules for Python apps (always follow) + +- **MUST** confirm framework choice or use [Python Framework Selection](#python-framework-selection) below - **MUST** use SDK `Config()` for authentication (never hardcode tokens) - **MUST** use `app.yaml` `valueFrom` for resources (never hardcode resource IDs) - **MUST** use `dash-bootstrap-components` for Dash app layout and styling - **MUST** use `@st.cache_resource` for Streamlit database connections - **MUST** deploy Flask with Gunicorn, FastAPI with uvicorn (not dev servers) -## Required Steps +## Required Steps for Python apps Copy this checklist and verify each item: ``` @@ -31,7 +78,7 @@ Copy this checklist and verify each item: --- -## Framework Selection +## Python Framework Selection | Framework | Best For | app.yaml Command | |-----------|----------|------------------| @@ -82,7 +129,7 @@ Copy this checklist and verify each item: 1. Determine the task type: - **New app from scratch?** → Use [Framework Selection](#framework-selection), then read [3-frameworks.md](3-frameworks.md) + **New app from scratch?** → Use [AppKit](#appkit-preferred-for-new-apps) (`databricks apps init`). Fall back to [Python Framework Selection](#python-framework-selection) only if Python is required. **Setting up authorization?** → Read [1-authorization.md](1-authorization.md) **Connecting to data/resources?** → Read [2-app-resources.md](2-app-resources.md) **Using Lakebase (PostgreSQL)?** → Read [5-lakebase.md](5-lakebase.md) @@ -195,6 +242,7 @@ class EntityIn(BaseModel): ## Official Documentation +- **[AppKit](https://databricks.github.io/appkit/docs/)** — preferred SDK for new apps (TypeScript + React) - **[Databricks Apps Overview](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/)** — main docs hub - **[Apps Cookbook](https://apps-cookbook.dev/)** — ready-to-use code snippets (Streamlit, Dash, Reflex, FastAPI) - **[Authorization](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/auth)** — app auth and user auth diff --git a/databricks-skills/databricks-app-python/examples/fm-minimal-chat.py b/databricks-skills/databricks-apps-python/examples/fm-minimal-chat.py similarity index 100% rename from databricks-skills/databricks-app-python/examples/fm-minimal-chat.py rename to databricks-skills/databricks-apps-python/examples/fm-minimal-chat.py diff --git a/databricks-skills/databricks-app-python/examples/fm-parallel-calls.py b/databricks-skills/databricks-apps-python/examples/fm-parallel-calls.py similarity index 100% rename from databricks-skills/databricks-app-python/examples/fm-parallel-calls.py rename to databricks-skills/databricks-apps-python/examples/fm-parallel-calls.py diff --git a/databricks-skills/databricks-app-python/examples/fm-structured-outputs.py b/databricks-skills/databricks-apps-python/examples/fm-structured-outputs.py similarity index 100% rename from databricks-skills/databricks-app-python/examples/fm-structured-outputs.py rename to databricks-skills/databricks-apps-python/examples/fm-structured-outputs.py diff --git a/databricks-skills/databricks-app-python/examples/llm_config.py b/databricks-skills/databricks-apps-python/examples/llm_config.py similarity index 100% rename from databricks-skills/databricks-app-python/examples/llm_config.py rename to databricks-skills/databricks-apps-python/examples/llm_config.py diff --git a/databricks-skills/databricks-bundles/SKILL.md b/databricks-skills/databricks-bundles/SKILL.md index 5b010512..3cff53a1 100644 --- a/databricks-skills/databricks-bundles/SKILL.md +++ b/databricks-skills/databricks-bundles/SKILL.md @@ -311,7 +311,7 @@ databricks bundle destroy -t prod --auto-approve - **[databricks-spark-declarative-pipelines](../databricks-spark-declarative-pipelines/SKILL.md)** - pipeline definitions referenced by DABs - **[databricks-app-apx](../databricks-app-apx/SKILL.md)** - app deployment via DABs -- **[databricks-app-python](../databricks-app-python/SKILL.md)** - Python app deployment via DABs +- **[databricks-apps-python](../databricks-apps-python/SKILL.md)** - Python app deployment via DABs - **[databricks-config](../databricks-config/SKILL.md)** - profile and authentication setup for CLI/SDK - **[databricks-jobs](../databricks-jobs/SKILL.md)** - job orchestration managed through bundles diff --git a/databricks-skills/databricks-lakebase-autoscale/SKILL.md b/databricks-skills/databricks-lakebase-autoscale/SKILL.md index 82fcbcdd..56bfd915 100644 --- a/databricks-skills/databricks-lakebase-autoscale/SKILL.md +++ b/databricks-skills/databricks-lakebase-autoscale/SKILL.md @@ -227,6 +227,6 @@ Custom billing tags / serverless budget policies. ## Related Skills -- [databricks-app-apx](../databricks-app-apx/SKILL.md), [databricks-app-python](../databricks-app-python/SKILL.md) — apps using Lakebase +- [databricks-app-apx](../databricks-app-apx/SKILL.md), [databricks-apps-python](../databricks-apps-python/SKILL.md) — apps using Lakebase - [databricks-bundles](../databricks-bundles/SKILL.md) — bundle deploys with Lakebase resources - [databricks-jobs](../databricks-jobs/SKILL.md) — scheduling reverse ETL pipelines diff --git a/databricks-skills/install_skills.sh b/databricks-skills/install_skills.sh index 67866942..09381eb1 100755 --- a/databricks-skills/install_skills.sh +++ b/databricks-skills/install_skills.sh @@ -47,7 +47,7 @@ MLFLOW_REPO_RAW_URL="https://raw.githubusercontent.com/mlflow/skills" MLFLOW_REPO_REF="main" # Databricks skills (hosted in this repo) -DATABRICKS_SKILLS="databricks-agent-bricks databricks-ai-functions databricks-aibi-dashboards databricks-bundles databricks-app-python databricks-config databricks-dbsql databricks-docs databricks-genie databricks-iceberg databricks-jobs databricks-lakebase-autoscale databricks-metric-views databricks-mlflow-evaluation databricks-model-serving databricks-python-sdk databricks-execution-compute databricks-spark-declarative-pipelines databricks-spark-structured-streaming databricks-synthetic-data-gen databricks-unity-catalog databricks-unstructured-pdf-generation databricks-vector-search databricks-zerobus-ingest spark-python-data-source" +DATABRICKS_SKILLS="databricks-agent-bricks databricks-ai-functions databricks-aibi-dashboards databricks-bundles databricks-apps-python databricks-config databricks-dbsql databricks-docs databricks-genie databricks-iceberg databricks-jobs databricks-lakebase-autoscale databricks-metric-views databricks-mlflow-evaluation databricks-model-serving databricks-python-sdk databricks-execution-compute databricks-spark-declarative-pipelines databricks-spark-structured-streaming databricks-synthetic-data-gen databricks-unity-catalog databricks-unstructured-pdf-generation databricks-vector-search databricks-zerobus-ingest spark-python-data-source" # MLflow skills (fetched from mlflow/skills repo) MLFLOW_SKILLS="agent-evaluation analyze-mlflow-chat-session analyze-mlflow-trace instrumenting-with-mlflow-tracing mlflow-onboarding querying-mlflow-metrics retrieving-mlflow-traces searching-mlflow-docs" @@ -72,7 +72,7 @@ get_skill_description() { "databricks-aibi-dashboards") echo "Databricks AI/BI Dashboards - create and manage dashboards" ;; "databricks-bundles") echo "Databricks Asset Bundles - deployment and configuration" ;; "databricks-app-apx") echo "Databricks Apps with React/Next.js (APX framework)" ;; - "databricks-app-python") echo "Databricks Apps with Python (Dash, Streamlit) and foundation model integration" ;; + "databricks-apps-python") echo "Databricks Apps with Python (Dash, Streamlit) and foundation model integration" ;; "databricks-config") echo "Profile authentication setup for Databricks" ;; "databricks-dbsql") echo "Databricks SQL - SQL scripting, MVs, geospatial, AI functions, federation" ;; "databricks-docs") echo "Documentation reference via llms.txt" ;; @@ -118,7 +118,7 @@ get_skill_extra_files() { "databricks-bundles") echo "alerts_guidance.md SDP_guidance.md" ;; "databricks-iceberg") echo "1-managed-iceberg-tables.md 2-uniform-and-compatibility.md 3-iceberg-rest-catalog.md 4-snowflake-interop.md 5-external-engine-interop.md" ;; "databricks-app-apx") echo "backend-patterns.md best-practices.md frontend-patterns.md" ;; - "databricks-app-python") echo "1-authorization.md 2-app-resources.md 3-frameworks.md 4-deployment.md 5-lakebase.md 6-cli-approach.md examples/llm_config.py examples/fm-minimal-chat.py examples/fm-parallel-calls.py examples/fm-structured-outputs.py" ;; + "databricks-apps-python") echo "1-authorization.md 2-app-resources.md 3-frameworks.md 4-deployment.md 5-lakebase.md 6-cli-approach.md examples/llm_config.py examples/fm-minimal-chat.py examples/fm-parallel-calls.py examples/fm-structured-outputs.py" ;; "databricks-jobs") echo "task-types.md triggers-schedules.md notifications-monitoring.md examples.md" ;; "databricks-python-sdk") echo "doc-index.md examples/1-authentication.py examples/2-clusters-and-jobs.py examples/3-sql-and-warehouses.py examples/4-unity-catalog.py examples/5-serving-and-vector-search.py" ;; "databricks-unity-catalog") echo "5-system-tables.md" ;; diff --git a/install.ps1 b/install.ps1 index 53e75af7..669083ca 100644 --- a/install.ps1 +++ b/install.ps1 @@ -83,7 +83,7 @@ $script:Channel = if ($env:AIDEVKIT_CHANNEL) { $env:AIDEVKIT_CHANNEL } else # Databricks skills (bundled in repo) $script:Skills = @( - "databricks-agent-bricks", "databricks-aibi-dashboards", "databricks-app-python", + "databricks-agent-bricks", "databricks-aibi-dashboards", "databricks-apps-python", "databricks-bundles", "databricks-config", "databricks-dbsql", "databricks-docs", "databricks-genie", "databricks-iceberg", "databricks-jobs", "databricks-lakebase-autoscale", "databricks-lakebase-provisioned", "databricks-metric-views", "databricks-mlflow-evaluation", "databricks-model-serving", "databricks-ai-functions", @@ -104,6 +104,11 @@ $MlflowRawUrl = "https://raw.githubusercontent.com/mlflow/skills/main" $script:ApxSkills = @("databricks-app-apx") $ApxRawUrl = "https://raw.githubusercontent.com/databricks-solutions/apx/main/skills/apx" +# Agent skills (fetched from databricks/databricks-agent-skills repo) +$script:AgentSkills = @("databricks-core:databricks", "databricks-apps", "databricks-lakebase") +$AgentSkillsRawUrl = "https://raw.githubusercontent.com/databricks/databricks-agent-skills/main/skills" +$AgentSkillsApiUrl = "https://api.github.com/repos/databricks/databricks-agent-skills/git/trees/main?recursive=1" + # ─── Skill profiles ────────────────────────────────────────── $script:CoreSkills = @("databricks-config", "databricks-docs", "databricks-python-sdk", "databricks-unity-catalog") @@ -127,15 +132,17 @@ $script:ProfileAiMlMlflow = @( "retrieving-mlflow-traces", "searching-mlflow-docs" ) $script:ProfileAppDeveloper = @( - "databricks-app-python", "databricks-app-apx", "databricks-lakebase-autoscale", + "databricks-apps-python", "databricks-app-apx", "databricks-lakebase-autoscale", "databricks-lakebase-provisioned", "databricks-model-serving", "databricks-dbsql", "databricks-jobs", "databricks-bundles" ) +$script:ProfileAppDeveloperAgent = @("databricks-core:databricks", "databricks-apps", "databricks-lakebase") # Selected skills (populated during profile selection) $script:SelectedSkills = @() $script:SelectedMlflowSkills = @() $script:SelectedApxSkills = @() +$script:SelectedAgentSkills = @() # ─── --list-skills handler ──────────────────────────────────── if ($script:ListSkills) { @@ -179,6 +186,10 @@ if ($script:ListSkills) { Write-Host "--------------------------------" foreach ($s in $script:ApxSkills) { Write-Host " $s" } Write-Host "" + Write-Host "Agent Skills (from databricks/databricks-agent-skills repo)" -ForegroundColor White + Write-Host "--------------------------------" + foreach ($s in $script:AgentSkills) { Write-Host " $($s -replace '^.*:', '')" } + Write-Host "" Write-Host "Usage: .\install.ps1 --skills-profile data-engineer,ai-ml-engineer" -ForegroundColor DarkGray Write-Host " .\install.ps1 --skills databricks-jobs,databricks-dbsql" -ForegroundColor DarkGray Write-Host "" @@ -915,12 +926,15 @@ function Resolve-Skills { $dbSkills = @() + $script:CoreSkills $mlflowSkills = @() $apxSkills = @() + $agentSkills = @() foreach ($skill in $userList) { $skill = $skill.Trim() if ($script:MlflowSkills -contains $skill) { $mlflowSkills += $skill } elseif ($script:ApxSkills -contains $skill) { $apxSkills += $skill + } elseif ($script:AgentSkills | ForEach-Object { $_ -replace '^.*:', '' } | Where-Object { $_ -eq $skill }) { + $agentSkills += ($script:AgentSkills | Where-Object { ($_ -replace '^.*:', '') -eq $skill }) } else { $dbSkills += $skill } @@ -928,6 +942,7 @@ function Resolve-Skills { $script:SelectedSkills = $dbSkills | Select-Object -Unique $script:SelectedMlflowSkills = $mlflowSkills | Select-Object -Unique $script:SelectedApxSkills = $apxSkills | Select-Object -Unique + $script:SelectedAgentSkills = $agentSkills | Select-Object -Unique return } @@ -936,6 +951,7 @@ function Resolve-Skills { $script:SelectedSkills = $script:Skills $script:SelectedMlflowSkills = $script:MlflowSkills $script:SelectedApxSkills = $script:ApxSkills + $script:SelectedAgentSkills = $script:AgentSkills return } @@ -943,6 +959,7 @@ function Resolve-Skills { $dbSkills = @() + $script:CoreSkills $mlflowSkills = @() $apxSkills = @() + $agentSkills = @() foreach ($profile in ($script:SkillsProfile -split ',')) { $profile = $profile.Trim() @@ -951,6 +968,7 @@ function Resolve-Skills { $script:SelectedSkills = $script:Skills $script:SelectedMlflowSkills = $script:MlflowSkills $script:SelectedApxSkills = $script:ApxSkills + $script:SelectedAgentSkills = $script:AgentSkills return } "data-engineer" { $dbSkills += $script:ProfileDataEngineer } @@ -962,6 +980,7 @@ function Resolve-Skills { "app-developer" { $dbSkills += $script:ProfileAppDeveloper $apxSkills += $script:ApxSkills + $agentSkills += $script:ProfileAppDeveloperAgent } default { Write-Warn "Unknown skill profile: $profile (ignored)" } } @@ -970,6 +989,7 @@ function Resolve-Skills { $script:SelectedSkills = $dbSkills | Select-Object -Unique $script:SelectedMlflowSkills = $mlflowSkills | Select-Object -Unique $script:SelectedApxSkills = $apxSkills | Select-Object -Unique + $script:SelectedAgentSkills = $agentSkills | Select-Object -Unique } function Invoke-PromptSkillsProfile { @@ -1160,9 +1180,12 @@ function Invoke-PromptCustomSkills { "data-engineer" { $preselected += $script:ProfileDataEngineer } "analyst" { $preselected += $script:ProfileAnalyst } "ai-ml-engineer" { $preselected += $script:ProfileAiMlEngineer + $script:ProfileAiMlMlflow } - "app-developer" { $preselected += $script:ProfileAppDeveloper + $script:ApxSkills } + "app-developer" { $preselected += $script:ProfileAppDeveloper + $script:ApxSkills + $script:ProfileAppDeveloperAgent } } } + # Normalize "source:install-name" entries (e.g. "databricks-core:databricks") to install-name only, + # so `-contains` exact-equality checks below match against the same names used in the menu. + $preselected = @($preselected | ForEach-Object { $_ -replace '^[^:]+:', '' }) Write-Host "" Write-Host " Select individual skills" -ForegroundColor White @@ -1189,8 +1212,11 @@ function Invoke-PromptCustomSkills { @{ Label = "Synthetic Data"; Value = "databricks-synthetic-data-gen"; State = ($preselected -contains "databricks-synthetic-data-gen"); Hint = "Generate test data" } @{ Label = "Lakebase Autoscale"; Value = "databricks-lakebase-autoscale"; State = ($preselected -contains "databricks-lakebase-autoscale"); Hint = "Managed PostgreSQL" } @{ Label = "Lakebase Provisioned"; Value = "databricks-lakebase-provisioned"; State = ($preselected -contains "databricks-lakebase-provisioned"); Hint = "Provisioned PostgreSQL" } - @{ Label = "App Python"; Value = "databricks-app-python"; State = ($preselected -contains "databricks-app-python"); Hint = "Dash, Streamlit, Flask" } + @{ Label = "App (AppKit + Python)"; Value = "databricks-apps-python"; State = ($preselected -contains "databricks-apps-python"); Hint = "AppKit, Dash, Streamlit, Flask" } @{ Label = "App APX"; Value = "databricks-app-apx"; State = ($preselected -contains "databricks-app-apx"); Hint = "FastAPI + React" } + @{ Label = "Agent: Databricks"; Value = "databricks"; State = ($preselected -contains "databricks"); Hint = "CLI auth, data exploration" } + @{ Label = "Agent: Apps"; Value = "databricks-apps"; State = ($preselected -contains "databricks-apps"); Hint = "AppKit + all frameworks" } + @{ Label = "Agent: Lakebase"; Value = "databricks-lakebase"; State = ($preselected -contains "databricks-lakebase"); Hint = "Lakebase OLTP" } @{ Label = "MLflow Onboarding"; Value = "mlflow-onboarding"; State = ($preselected -contains "mlflow-onboarding"); Hint = "Getting started" } @{ Label = "Agent Evaluation"; Value = "agent-evaluation"; State = ($preselected -contains "agent-evaluation"); Hint = "Evaluate AI agents" } @{ Label = "MLflow Tracing"; Value = "instrumenting-with-mlflow-tracing"; State = ($preselected -contains "instrumenting-with-mlflow-tracing"); Hint = "Instrument with tracing" } @@ -1259,7 +1285,8 @@ function Install-Skills { $dbCount = $script:SelectedSkills.Count $mlflowCount = $script:SelectedMlflowSkills.Count $apxCount = $script:SelectedApxSkills.Count - $totalCount = $dbCount + $mlflowCount + $apxCount + $agentCount = $script:SelectedAgentSkills.Count + $totalCount = $dbCount + $mlflowCount + $apxCount + $agentCount Write-Msg "Installing $totalCount skills" # Build set of all skills being installed now @@ -1267,6 +1294,7 @@ function Install-Skills { $allNewSkills += $script:SelectedSkills $allNewSkills += $script:SelectedMlflowSkills $allNewSkills += $script:SelectedApxSkills + $allNewSkills += $script:SelectedAgentSkills | ForEach-Object { $_ -replace '^.*:', '' } # Clean up previously installed skills that are no longer selected # Check scope-local manifest first, fall back to global for upgrades from older versions @@ -1361,6 +1389,74 @@ function Install-Skills { $ErrorActionPreference = $prevEAP2 Write-Ok "APX skills ($apxCount) -> $shortDir" } + + # Install Agent skills from databricks/databricks-agent-skills repo + if ($script:SelectedAgentSkills.Count -gt 0) { + # Fetch the full repo tree once (single API call) for all skills. + # Collapse pretty-printed JSON whitespace so the path/mode/type fields + # land adjacent for the per-entry regex below. + $agentTree = $null + $agentSuccess = 0 + try { + $rawTree = Invoke-WebRequest -Uri $AgentSkillsApiUrl -UseBasicParsing -ErrorAction Stop | Select-Object -ExpandProperty Content + $agentTree = ($rawTree -replace '\s+', ' ') + } catch { + Write-Warn "Could not fetch agent skills tree from GitHub API" + } + if ($agentTree) { + $prevEAP3 = $ErrorActionPreference; $ErrorActionPreference = "Continue" + foreach ($entry in $script:SelectedAgentSkills) { + $srcName = ($entry -split ':')[0] + $installName = ($entry -replace '^.*:', '') + $destDir = Join-Path $dir $installName + # Wipe any prior install so upstream-deleted files don't persist + if (Test-Path $destDir) { + Remove-Item -Recurse -Force $destDir -ErrorAction SilentlyContinue + } + New-Item -ItemType Directory -Path $destDir -Force | Out-Null + # Extract file paths under skills// — match only entries whose + # next JSON fields are `"mode": "...", "type": "blob"`, so directory + # entries (type=tree) are skipped. agentTree has been whitespace-collapsed + # above; the GitHub tree API returns fields in order path → mode → type. + $filePaths = [regex]::Matches($agentTree, '"path": *"(skills/' + [regex]::Escape($srcName) + '/[^"]+)", *"mode": *"[^"]+", *"type": *"blob"') | + ForEach-Object { $_.Groups[1].Value } + if (-not $filePaths) { + Remove-Item $destDir -ErrorAction SilentlyContinue + Write-Warn "Could not fetch agent skill '$srcName'" + continue + } + $okFlag = $true + foreach ($filePath in $filePaths) { + $rel = $filePath.Substring("skills/$srcName/".Length) + $dest = Join-Path $destDir ($rel -replace '/', '\') + $destParent = Split-Path $dest -Parent + if (-not (Test-Path $destParent)) { + New-Item -ItemType Directory -Path $destParent -Force | Out-Null + } + try { + Invoke-WebRequest -Uri "$AgentSkillsRawUrl/$srcName/$rel" -OutFile $dest -UseBasicParsing -ErrorAction Stop + } catch { + $okFlag = $false + } + } + if ($okFlag) { + $manifestEntries += "$dir|$installName" + $agentSuccess++ + } else { + Remove-Item -Recurse -Force $destDir -ErrorAction SilentlyContinue + Write-Warn "Could not install agent skill '$srcName'" + } + } + $ErrorActionPreference = $prevEAP3 + } + if ($agentSuccess -eq $agentCount) { + Write-Ok "Agent skills ($agentCount) -> $shortDir" + } elseif ($agentSuccess -gt 0) { + Write-Warn "Agent skills (only $agentSuccess of $agentCount installed) -> $shortDir" + } else { + Write-Warn "Agent skills (0 of $agentCount installed) -> $shortDir" + } + } } # Save manifest and profile to scope-local state directory @@ -2124,7 +2220,7 @@ function Invoke-Main { Write-Host " MCP server: " -NoNewline; Write-Host $script:InstallDir -ForegroundColor Green } if ($script:InstallSkills) { - $skTotal = $script:SelectedSkills.Count + $script:SelectedMlflowSkills.Count + $script:SelectedApxSkills.Count + $skTotal = $script:SelectedSkills.Count + $script:SelectedMlflowSkills.Count + $script:SelectedApxSkills.Count + $script:SelectedAgentSkills.Count if (-not [string]::IsNullOrWhiteSpace($script:UserSkills)) { Write-Host " Skills: " -NoNewline; Write-Host "custom selection ($skTotal skills)" -ForegroundColor Green } else { diff --git a/install.sh b/install.sh index 24b7a618..1ec2a3a2 100644 --- a/install.sh +++ b/install.sh @@ -102,7 +102,7 @@ MIN_SDK_VERSION="0.85.0" G='\033[0;32m' Y='\033[1;33m' R='\033[0;31m' BL='\033[0;34m' B='\033[1m' D='\033[2m' N='\033[0m' # Databricks skills (bundled in repo) -SKILLS="databricks-agent-bricks databricks-ai-functions databricks-aibi-dashboards databricks-app-python databricks-bundles databricks-config databricks-dbsql databricks-docs databricks-genie databricks-iceberg databricks-jobs databricks-lakebase-autoscale databricks-lakebase-provisioned databricks-metric-views databricks-mlflow-evaluation databricks-model-serving databricks-python-sdk databricks-spark-declarative-pipelines databricks-spark-structured-streaming databricks-synthetic-data-gen databricks-unity-catalog databricks-unstructured-pdf-generation databricks-vector-search databricks-zerobus-ingest spark-python-data-source" +SKILLS="databricks-agent-bricks databricks-ai-functions databricks-aibi-dashboards databricks-apps-python databricks-bundles databricks-config databricks-dbsql databricks-docs databricks-genie databricks-iceberg databricks-jobs databricks-lakebase-autoscale databricks-lakebase-provisioned databricks-metric-views databricks-mlflow-evaluation databricks-model-serving databricks-python-sdk databricks-spark-declarative-pipelines databricks-spark-structured-streaming databricks-synthetic-data-gen databricks-unity-catalog databricks-unstructured-pdf-generation databricks-vector-search databricks-zerobus-ingest spark-python-data-source" # MLflow skills (fetched from mlflow/skills repo) MLFLOW_SKILLS="agent-evaluation analyze-mlflow-chat-session analyze-mlflow-trace instrumenting-with-mlflow-tracing mlflow-onboarding querying-mlflow-metrics retrieving-mlflow-traces searching-mlflow-docs" @@ -112,6 +112,11 @@ MLFLOW_RAW_URL="https://raw.githubusercontent.com/mlflow/skills/main" APX_SKILLS="databricks-app-apx" APX_RAW_URL="https://raw.githubusercontent.com/databricks-solutions/apx/main/skills/apx" +# Agent skills (fetched from databricks/databricks-agent-skills repo) +AGENT_SKILLS="databricks-core:databricks databricks-apps databricks-lakebase" +AGENT_SKILLS_RAW_URL="https://raw.githubusercontent.com/databricks/databricks-agent-skills/main/skills" +AGENT_SKILLS_API_URL="https://api.github.com/repos/databricks/databricks-agent-skills/git/trees/main?recursive=1" + # ─── Skill profiles ────────────────────────────────────────── # Core skills always installed regardless of profile selection CORE_SKILLS="databricks-config databricks-docs databricks-python-sdk databricks-unity-catalog" @@ -121,12 +126,14 @@ PROFILE_DATA_ENGINEER="databricks-spark-declarative-pipelines databricks-spark-s PROFILE_ANALYST="databricks-aibi-dashboards databricks-dbsql databricks-genie databricks-metric-views" PROFILE_AIML_ENGINEER="databricks-agent-bricks databricks-ai-functions databricks-vector-search databricks-model-serving databricks-genie databricks-unstructured-pdf-generation databricks-mlflow-evaluation databricks-synthetic-data-gen databricks-jobs" PROFILE_AIML_MLFLOW="agent-evaluation analyze-mlflow-chat-session analyze-mlflow-trace instrumenting-with-mlflow-tracing mlflow-onboarding querying-mlflow-metrics retrieving-mlflow-traces searching-mlflow-docs" -PROFILE_APP_DEVELOPER="databricks-app-python databricks-app-apx databricks-lakebase-autoscale databricks-lakebase-provisioned databricks-model-serving databricks-dbsql databricks-jobs databricks-bundles" +PROFILE_APP_DEVELOPER="databricks-apps-python databricks-app-apx databricks-lakebase-autoscale databricks-lakebase-provisioned databricks-model-serving databricks-dbsql databricks-jobs databricks-bundles" +PROFILE_APP_DEVELOPER_AGENT="databricks-core:databricks databricks-apps databricks-lakebase" # Selected skills (populated during profile selection) SELECTED_SKILLS="" SELECTED_MLFLOW_SKILLS="" SELECTED_APX_SKILLS="" +SELECTED_AGENT_SKILLS="" # Output helpers msg() { [ "$SILENT" = true ] || echo -e " $*"; } @@ -205,7 +212,7 @@ if [ "${LIST_SKILLS:-false}" = true ]; then echo -e "${B}Available Skill Profiles${N}" echo "────────────────────────────────" echo "" - echo -e " ${B}all${N} All 34 skills (default)" + echo -e " ${B}all${N} All 37 skills (default)" echo -e " ${B}data-engineer${N} Pipelines, Spark, Jobs, Streaming (14 skills)" echo -e " ${B}analyst${N} Dashboards, SQL, Genie, Metrics (8 skills)" echo -e " ${B}ai-ml-engineer${N} Agents, RAG, Vector Search, MLflow (17 skills)" @@ -257,6 +264,12 @@ if [ "${LIST_SKILLS:-false}" = true ]; then echo -e " $skill" done echo "" + echo -e "${B}Agent Skills${N} (from databricks/databricks-agent-skills repo)" + echo "────────────────────────────────" + for entry in $AGENT_SKILLS; do + echo -e " ${entry#*:}" + done + echo "" echo -e "${D}Usage: bash install.sh --skills-profile data-engineer,ai-ml-engineer${N}" echo -e "${D} bash install.sh --skills databricks-jobs,databricks-dbsql${N}" echo "" @@ -893,19 +906,25 @@ prompt_mcp_path() { # ─── Skill profile selection ────────────────────────────────── # Resolve selected skills from profile names or explicit skill list resolve_skills() { - local db_skills="" mlflow_skills="" apx_skills="" + local db_skills="" mlflow_skills="" apx_skills="" agent_skills="" # Priority 1: Explicit --skills flag (comma-separated skill names) if [ -n "$USER_SKILLS" ]; then local user_list user_list=$(echo "$USER_SKILLS" | tr ',' ' ') - # Separate into DB, MLflow, and APX buckets, always include core + # Separate into DB, MLflow, APX, and Agent buckets db_skills="" for skill in $user_list; do - if echo "$MLFLOW_SKILLS" | grep -qw "$skill"; then + # Exact-match bucketing — `grep -w` treats `-` as a word boundary, so e.g. + # `grep -w databricks` would match `databricks-app-apx` and misclassify + # an agent install-name (`databricks`) as APX. + if echo "$MLFLOW_SKILLS" | tr ' ' '\n' | grep -Fxq "$skill"; then mlflow_skills="${mlflow_skills:+$mlflow_skills }$skill" - elif echo "$APX_SKILLS" | grep -qw "$skill"; then + elif echo "$APX_SKILLS" | tr ' ' '\n' | grep -Fxq "$skill"; then apx_skills="${apx_skills:+$apx_skills }$skill" + elif echo "$AGENT_SKILLS" | tr ' ' '\n' | sed 's/.*://' | grep -Fxq "$skill"; then + # Look up the full source:install-name entry (or bare entry if no colon) + agent_skills="${agent_skills:+$agent_skills }$(echo "$AGENT_SKILLS" | tr ' ' '\n' | grep -E "^.*:${skill}$|^${skill}$")" else db_skills="${db_skills:+$db_skills }$skill" fi @@ -914,6 +933,7 @@ resolve_skills() { SELECTED_SKILLS=$(echo "$db_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') SELECTED_MLFLOW_SKILLS=$(echo "$mlflow_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') SELECTED_APX_SKILLS=$(echo "$apx_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') + SELECTED_AGENT_SKILLS=$(echo "$agent_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') return fi @@ -922,6 +942,7 @@ resolve_skills() { SELECTED_SKILLS="$SKILLS" SELECTED_MLFLOW_SKILLS="$MLFLOW_SKILLS" SELECTED_APX_SKILLS="$APX_SKILLS" + SELECTED_AGENT_SKILLS="$AGENT_SKILLS" return fi @@ -929,6 +950,7 @@ resolve_skills() { db_skills="$CORE_SKILLS" mlflow_skills="" apx_skills="" + agent_skills="" local profiles profiles=$(echo "$SKILLS_PROFILE" | tr ',' ' ') @@ -938,6 +960,7 @@ resolve_skills() { SELECTED_SKILLS="$SKILLS" SELECTED_MLFLOW_SKILLS="$MLFLOW_SKILLS" SELECTED_APX_SKILLS="$APX_SKILLS" + SELECTED_AGENT_SKILLS="$AGENT_SKILLS" return ;; data-engineer) @@ -953,6 +976,7 @@ resolve_skills() { app-developer) db_skills="$db_skills $PROFILE_APP_DEVELOPER" apx_skills="$apx_skills $APX_SKILLS" + agent_skills="$agent_skills $PROFILE_APP_DEVELOPER_AGENT" ;; *) warn "Unknown skill profile: $profile (ignored)" @@ -964,6 +988,7 @@ resolve_skills() { SELECTED_SKILLS=$(echo "$db_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') SELECTED_MLFLOW_SKILLS=$(echo "$mlflow_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') SELECTED_APX_SKILLS=$(echo "$apx_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') + SELECTED_AGENT_SKILLS=$(echo "$agent_skills" | tr ' ' '\n' | sort -u | tr '\n' ' ') } # Interactive skill profile selection (multi-select) @@ -1118,12 +1143,15 @@ prompt_custom_skills() { data-engineer) preselected="$preselected $PROFILE_DATA_ENGINEER" ;; analyst) preselected="$preselected $PROFILE_ANALYST" ;; ai-ml-engineer) preselected="$preselected $PROFILE_AIML_ENGINEER $PROFILE_AIML_MLFLOW" ;; - app-developer) preselected="$preselected $PROFILE_APP_DEVELOPER $APX_SKILLS" ;; + app-developer) preselected="$preselected $PROFILE_APP_DEVELOPER $APX_SKILLS $PROFILE_APP_DEVELOPER_AGENT" ;; esac done _is_preselected() { - echo "$preselected" | grep -qw "$1" && echo "on" || echo "off" + # Strip "source:" prefix from each entry (e.g. "databricks-core:databricks" → "databricks"), + # then exact-match against $1. Plain `grep -w` is unsafe here because `-` is a non-word + # character — `grep -w databricks` would match `databricks-jobs`, `databricks-apps`, etc. + echo "$preselected" | tr ' ' '\n' | sed 's/.*://' | grep -Fxq "$1" && echo "on" || echo "off" } echo "" @@ -1152,8 +1180,11 @@ prompt_custom_skills() { "Synthetic Data|databricks-synthetic-data-gen|$(_is_preselected databricks-synthetic-data-gen)|Generate test data" \ "Lakebase Autoscale|databricks-lakebase-autoscale|$(_is_preselected databricks-lakebase-autoscale)|Managed PostgreSQL" \ "Lakebase Provisioned|databricks-lakebase-provisioned|$(_is_preselected databricks-lakebase-provisioned)|Provisioned PostgreSQL" \ - "App Python|databricks-app-python|$(_is_preselected databricks-app-python)|Dash, Streamlit, Flask" \ + "App (AppKit + Python)|databricks-apps-python|$(_is_preselected databricks-apps-python)|AppKit, Dash, Streamlit, Flask" \ "App APX|databricks-app-apx|$(_is_preselected databricks-app-apx)|FastAPI + React" \ + "Agent: Databricks|databricks|$(_is_preselected databricks)|CLI auth, data exploration" \ + "Agent: Apps|databricks-apps|$(_is_preselected databricks-apps)|AppKit + all frameworks" \ + "Agent: Lakebase|databricks-lakebase|$(_is_preselected databricks-lakebase)|Lakebase OLTP" \ "MLflow Onboarding|mlflow-onboarding|$(_is_preselected mlflow-onboarding)|Getting started" \ "Agent Evaluation|agent-evaluation|$(_is_preselected agent-evaluation)|Evaluate AI agents" \ "MLflow Tracing|instrumenting-with-mlflow-tracing|$(_is_preselected instrumenting-with-mlflow-tracing)|Instrument with tracing" \ @@ -1364,15 +1395,18 @@ install_skills() { dirs=("${unique[@]}") # Count selected skills for display - local db_count=0 mlflow_count=0 apx_count=0 + local db_count=0 mlflow_count=0 apx_count=0 agent_count=0 for _ in $SELECTED_SKILLS; do db_count=$((db_count + 1)); done for _ in $SELECTED_MLFLOW_SKILLS; do mlflow_count=$((mlflow_count + 1)); done for _ in $SELECTED_APX_SKILLS; do apx_count=$((apx_count + 1)); done - local total_count=$((db_count + mlflow_count + apx_count)) + for _ in $SELECTED_AGENT_SKILLS; do agent_count=$((agent_count + 1)); done + local total_count=$((db_count + mlflow_count + apx_count + agent_count)) msg "Installing ${B}${total_count}${N} skills" # Build set of all skills being installed now - local all_new_skills="$SELECTED_SKILLS $SELECTED_MLFLOW_SKILLS $SELECTED_APX_SKILLS" + local agent_install_names + agent_install_names=$(echo "$SELECTED_AGENT_SKILLS" | tr ' ' '\n' | sed 's/.*://' | tr '\n' ' ') + local all_new_skills="$SELECTED_SKILLS $SELECTED_MLFLOW_SKILLS $SELECTED_APX_SKILLS $agent_install_names" # Clean up previously installed skills that are no longer selected # Check scope-local manifest first, fall back to global for upgrades from older versions @@ -1381,8 +1415,8 @@ install_skills() { if [ -f "$manifest" ]; then while IFS='|' read -r prev_dir prev_skill; do [ -z "$prev_skill" ] && continue - # Skip if this skill is still selected - if echo " $all_new_skills " | grep -qw "$prev_skill"; then + # Skip if this skill is still selected (exact match — see _is_preselected for why) + if echo "$all_new_skills" | tr ' ' '\n' | grep -Fxq "$prev_skill"; then continue fi # Only remove if the directory exists @@ -1447,6 +1481,62 @@ install_skills() { done ok "APX skills ($apx_count) → ${dir#$HOME/}" fi + + # Install Agent skills from databricks/databricks-agent-skills repo + if [ -n "$SELECTED_AGENT_SKILLS" ]; then + # Fetch the full repo tree once (single API call) for all skills. + # Collapse pretty-printed JSON to a single line + squeeze whitespace so the + # path/mode/type fields land adjacent for the per-entry regex below. + local agent_tree agent_success=0 + agent_tree=$(curl -fsSL "$AGENT_SKILLS_API_URL" 2>/dev/null | tr -d '\n' | tr -s ' ') + for entry in $SELECTED_AGENT_SKILLS; do + local src_name="${entry%%:*}" + local install_name="${entry#*:}" + local dest_dir="$dir/$install_name" + # Wipe any prior install so upstream-deleted files don't persist + rm -rf "$dest_dir" + mkdir -p "$dest_dir" + # Extract file paths under skills// — match only entries whose + # next JSON fields are `"mode": "...", "type": "blob"`, so directory + # entries (type=tree) are skipped. Note the agent_tree has been + # whitespace-collapsed above; the GitHub tree API returns fields in + # the order path → mode → type → sha → size → url, so this pattern + # matches each blob exactly once. + local files + files=$(echo "$agent_tree" \ + | grep -oE '"path": *"skills/'"$src_name"'/[^"]+", *"mode": *"[^"]+", *"type": *"blob"' \ + | sed 's/.*"path": *"\([^"]*\)".*/\1/') + if [ -z "$files" ]; then + rmdir "$dest_dir" 2>/dev/null || true + warn "Could not fetch agent skill '$src_name'" + continue + fi + local ok_flag=1 + while IFS= read -r filepath; do + [ -z "$filepath" ] && continue + local rel="${filepath#skills/$src_name/}" + local dest="$dest_dir/$rel" + mkdir -p "$(dirname "$dest")" + if ! curl -fsSL "$AGENT_SKILLS_RAW_URL/$src_name/${rel}" -o "$dest" 2>/dev/null; then + ok_flag=0 + fi + done <<< "$files" + if [ "$ok_flag" -eq 1 ]; then + echo "$dir|$install_name" >> "$manifest.tmp" + agent_success=$((agent_success + 1)) + else + rm -rf "$dest_dir" + warn "Could not install agent skill '$src_name'" + fi + done + if [ "$agent_success" -eq "$agent_count" ]; then + ok "Agent skills ($agent_count) → ${dir#$HOME/}" + elif [ "$agent_success" -gt 0 ]; then + warn "Agent skills (only $agent_success of $agent_count installed) → ${dir#$HOME/}" + else + warn "Agent skills (0 of $agent_count installed) → ${dir#$HOME/}" + fi + fi done # Save manifest of installed skills (for cleanup on profile change) @@ -2179,7 +2269,7 @@ main() { echo -e " Skills: ${G}custom selection${N}" else local sk_total=0 - for _ in $SELECTED_SKILLS $SELECTED_MLFLOW_SKILLS $SELECTED_APX_SKILLS; do sk_total=$((sk_total + 1)); done + for _ in $SELECTED_SKILLS $SELECTED_MLFLOW_SKILLS $SELECTED_APX_SKILLS $SELECTED_AGENT_SKILLS; do sk_total=$((sk_total + 1)); done echo -e " Skills: ${G}${SKILLS_PROFILE:-all} ($sk_total skills)${N}" fi fi