Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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/)**.

---

## 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/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:
```
Expand All @@ -31,7 +78,7 @@ Copy this checklist and verify each item:

---

## Framework Selection
## Python Framework Selection

| Framework | Best For | app.yaml Command |
|-----------|----------|------------------|
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
90 changes: 84 additions & 6 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ $script:ListSkills = $false

# 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",
Expand All @@ -100,6 +100,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", "databricks-apps", "databricks-jobs:databricks-jobs-bundles", "databricks-lakebase", "databricks-pipelines")
$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")

Expand All @@ -123,15 +128,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", "databricks-apps", "databricks-lakebase", "databricks-pipelines")

# Selected skills (populated during profile selection)
$script:SelectedSkills = @()
$script:SelectedMlflowSkills = @()
$script:SelectedApxSkills = @()
$script:SelectedAgentSkills = @()

# ─── --list-skills handler ────────────────────────────────────
if ($script:ListSkills) {
Expand Down Expand Up @@ -175,6 +182,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 ""
Expand Down Expand Up @@ -845,19 +856,23 @@ 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
}
}
$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
}

Expand All @@ -866,13 +881,15 @@ function Resolve-Skills {
$script:SelectedSkills = $script:Skills
$script:SelectedMlflowSkills = $script:MlflowSkills
$script:SelectedApxSkills = $script:ApxSkills
$script:SelectedAgentSkills = $script:AgentSkills
return
}

# Build union of selected profiles
$dbSkills = @() + $script:CoreSkills
$mlflowSkills = @()
$apxSkills = @()
$agentSkills = @()

foreach ($profile in ($script:SkillsProfile -split ',')) {
$profile = $profile.Trim()
Expand All @@ -881,6 +898,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 }
Expand All @@ -892,6 +910,7 @@ function Resolve-Skills {
"app-developer" {
$dbSkills += $script:ProfileAppDeveloper
$apxSkills += $script:ApxSkills
$agentSkills += $script:ProfileAppDeveloperAgent
}
default { Write-Warn "Unknown skill profile: $profile (ignored)" }
}
Expand All @@ -900,6 +919,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 {
Expand Down Expand Up @@ -1090,7 +1110,7 @@ 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 }
}
}

Expand Down Expand Up @@ -1119,8 +1139,13 @@ 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: Jobs"; Value = "databricks-jobs-bundles"; State = ($preselected -contains "databricks-jobs-bundles"); Hint = "Lakeflow Jobs (bundle scaffold)" }
@{ Label = "Agent: Lakebase"; Value = "databricks-lakebase"; State = ($preselected -contains "databricks-lakebase"); Hint = "Lakebase OLTP" }
@{ Label = "Agent: Pipelines"; Value = "databricks-pipelines"; State = ($preselected -contains "databricks-pipelines"); Hint = "Declarative Pipelines" }
@{ 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" }
Expand Down Expand Up @@ -1161,14 +1186,16 @@ 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
$allNewSkills = @()
$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
Expand Down Expand Up @@ -1263,6 +1290,57 @@ 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
$agentTree = $null
try {
$agentTree = Invoke-WebRequest -Uri $AgentSkillsApiUrl -UseBasicParsing -ErrorAction Stop | Select-Object -ExpandProperty Content
} 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
if (-not (Test-Path $destDir)) {
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
}
# Extract all file paths under skills/<srcName>/ that contain a dot (i.e. are files not dirs)
$filePaths = [regex]::Matches($agentTree, '"path":"(skills/' + [regex]::Escape($srcName) + '/[^"]*\.[^"]*)"') |
ForEach-Object { $_.Groups[1].Value }
if (-not $filePaths) {
Remove-Item $destDir -ErrorAction SilentlyContinue
Write-Warn "Could not fetch agent skill '$srcName'"
continue
}
$okFlag = $false
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
$okFlag = $true
} catch {}
}
if ($okFlag) {
$manifestEntries += "$dir|$installName"
} else {
Remove-Item -Recurse -Force $destDir -ErrorAction SilentlyContinue
Write-Warn "Could not install agent skill '$srcName'"
}
}
$ErrorActionPreference = $prevEAP3
}
Write-Ok "Agent skills ($agentCount) -> $shortDir"
}
}

# Save manifest and profile to scope-local state directory
Expand Down Expand Up @@ -1822,7 +1900,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 {
Expand Down
Loading