Skip to content
Merged
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
25 changes: 15 additions & 10 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"version": "2",
"updated_at": "2026-05-11T13:22:07Z",
"updated_at": "2026-05-15T12:29:33Z",
"skills": {
"databricks-apps": {
"version": "0.1.1",
"description": "Databricks Apps development and deployment (evaluates analytics vs synced tables data access)",
"experimental": false,
"updated_at": "2026-05-11T13:22:01Z",
"updated_at": "2026-05-15T12:19:02Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
Expand All @@ -33,7 +33,7 @@
"version": "0.1.0",
"description": "Core Databricks skill for CLI, auth, and data exploration",
"experimental": false,
"updated_at": "2026-05-11T10:22:59Z",
"updated_at": "2026-05-12T22:07:25Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
Expand All @@ -48,7 +48,7 @@
"version": "0.0.0",
"description": "Declarative Automation Bundles (DABs) for deploying and managing Databricks resources",
"experimental": false,
"updated_at": "2026-05-05T15:31:42Z",
"updated_at": "2026-05-12T20:04:29Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
Expand All @@ -66,7 +66,7 @@
"version": "0.1.0",
"description": "Databricks Jobs orchestration and scheduling",
"experimental": false,
"updated_at": "2026-05-07T15:19:50Z",
"updated_at": "2026-05-12T20:04:29Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
Expand All @@ -78,34 +78,39 @@
"version": "0.1.0",
"description": "Databricks Lakebase Postgres: projects, scaling, connectivity, synced tables, and Data API",
"experimental": false,
"updated_at": "2026-05-11T10:23:05Z",
"updated_at": "2026-05-15T12:29:29Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
"assets/databricks.png",
"assets/databricks.svg",
"references/computes-and-scaling.md",
"references/connectivity.md",
"references/lakehouse-sync.md",
"references/medallion-from-cdc.md",
"references/off-platform.md",
"references/pgvector.md",
"references/synced-tables.md"
]
},
"databricks-model-serving": {
"version": "0.1.0",
"description": "Databricks Model Serving endpoint management",
"experimental": false,
"updated_at": "2026-05-07T15:19:45Z",
"updated_at": "2026-05-15T12:19:44Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
"assets/databricks.png",
"assets/databricks.svg"
"assets/databricks.svg",
"references/off-platform-streaming.md"
]
},
"databricks-pipelines": {
"version": "0.1.0",
"description": "Databricks Pipelines (DLT) for ETL and streaming",
"experimental": false,
"updated_at": "2026-05-07T15:19:55Z",
"updated_at": "2026-05-15T12:14:27Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
Expand Down Expand Up @@ -152,7 +157,7 @@
"version": "0.1.0",
"description": "Migrate Databricks workloads from classic compute to serverless compute, including compatibility checks and concrete fixes",
"experimental": false,
"updated_at": "2026-05-07T15:19:59Z",
"updated_at": "2026-05-12T20:04:29Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
Expand Down
25 changes: 22 additions & 3 deletions skills/databricks-apps/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: databricks-apps
description: "Build apps on Databricks Apps platform. Use when asked to create dashboards, data apps, analytics tools, or visualizations. Evaluates data access patterns (analytics vs Lakebase synced tables) before scaffolding. Invoke BEFORE starting implementation."
description: "Build apps on Databricks Apps platform. Use when asked to create dashboards, data apps, analytics tools, or visualizations. Auto-detects need for Lakebase when app stores state; evaluates data access patterns (analytics vs Lakebase synced tables) before scaffolding. Invoke BEFORE starting implementation."
compatibility: Requires databricks CLI (>= v0.294.0)
metadata:
version: "0.1.1"
Expand All @@ -17,7 +17,7 @@ Build apps that deploy to Databricks Apps platform.

| Phase | READ BEFORE proceeding |
|-------|------------------------|
| Scaffolding | **⚠️ STOP — complete the Data Access Decision Gate below before scaffolding.** Parent `databricks-core` skill (auth, warehouse discovery); then run `databricks apps manifest` + `databricks apps init` with `--features` and `--set` (see AppKit section below) |
| Scaffolding | **⚠️ STOP — evaluate the State Storage Rule and Data Access Decision Gate below before scaffolding.** Parent `databricks-core` skill (auth, warehouse discovery); then run `databricks apps manifest` + `databricks apps init` with `--features` and `--set` (see AppKit section below) |
| Writing SQL queries | [SQL Queries Guide](references/appkit/sql-queries.md) |
| Writing UI components | [Frontend Guide](references/appkit/frontend.md) |
| Using `useAnalyticsQuery` | [AppKit SDK](references/appkit/appkit-sdk.md) |
Expand Down Expand Up @@ -61,6 +61,16 @@ Build apps that deploy to Databricks Apps platform.

Before writing any SQL, use the parent `databricks-core` skill for data exploration — search `information_schema` by keyword, then batch `discover-schema` for the tables you need. Do NOT skip this step.

**State Storage Rule (evaluate BEFORE the Decision Gate):**

If the user's app description implies storing or persisting data — forms, CRUD operations, user input, preferences, bookmarks, orders, todos, comments, votes, or any user-generated content — the app needs a Lakebase database. Do not wait for the user to ask for one.

1. Use the **`databricks-lakebase`** skill to create a Lakebase project (if one doesn't already exist) and obtain the branch and database resource names.
2. Scaffold with `--features lakebase` and pass `--set lakebase.postgres.branch=<BRANCH_NAME> --set lakebase.postgres.database=<DATABASE_NAME>`.
3. If the app **also** reads from Unity Catalog tables, proceed to the Data Access Decision Gate below to determine whether to add `--features analytics` or use Lakebase synced tables.

This rule governs **state storage** only. For how the app reads existing lakehouse data, proceed to the Decision Gate below. This is not optional — any app that writes user-generated data needs Lakebase.

## Development Workflow (FOLLOW THIS ORDER)

**Data Access Decision Gate (REQUIRED before scaffolding):**
Expand All @@ -79,7 +89,7 @@ After the user chooses:
- (A) Lakebase synced tables → scaffold with `--features lakebase`. See [Lakebase Guide](references/appkit/lakebase.md) for full workflow.
- (B) Analytics → scaffold with `--features analytics`.
- Both → scaffold with `--features analytics,lakebase` if the app needs both patterns.
- If the app does NOT read UC data (pure CRUD, Genie, Model Serving), skip this gate and scaffold with the appropriate `--features` flag.
- If the app does NOT read UC data (pure CRUD, Genie, Model Serving), skip this gate. For pure CRUD/state apps, the State Storage Rule above already applies — scaffold with `--features lakebase`. For Genie or Model Serving, scaffold with the corresponding `--features` flag.

**Analytics apps** (`--features analytics`):

Expand Down Expand Up @@ -194,3 +204,12 @@ App names must be lowercase with hyphens only (≤26 chars).
Databricks Apps supports any framework that runs as an HTTP server. LLMs already know these frameworks — the challenge is Databricks platform integration.

**READ [Other Frameworks Guide](references/other-frameworks.md) BEFORE building any non-AppKit app.** It covers port/host configuration, `app.yaml` and `databricks.yml` setup, dependency management, networking, and framework-specific gotchas.

### Post-Deploy Verification

After deploying, verify the app is running:

```bash
databricks apps get <app-name> --profile <PROFILE> -o json # Check app_status.state: RUNNING
databricks apps logs <app-name> --follow --profile <PROFILE> # Stream live logs (Ctrl+C to stop)
```
4 changes: 4 additions & 0 deletions skills/databricks-apps/references/appkit/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,17 @@ Each volume key requires a resource with `WRITE_VOLUME` permission. Declare in `
resources:
apps:
my_app:
user_api_scopes:
- files.files # Needed when using .asUser(req) programmatic API
resources:
- name: uploads-volume
volume:
path: /Volumes/catalog/schema/uploads
permission: WRITE_VOLUME
```

> **Note:** The scaffolded HTTP routes (`/api/files/...`) execute as the service principal and do not require `user_api_scopes`. The scope is needed when using the programmatic `appkit.files("key").asUser(req)` API for per-user Volume access.

Wire the env var in `app.yaml`:

```yaml
Expand Down
104 changes: 104 additions & 0 deletions skills/databricks-apps/references/appkit/genie.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,107 @@ Update smoke tests if headings or routes changed, then `databricks apps validate

For advanced Genie plugin usage, see `npx @databricks/appkit docs ./docs/plugins/genie.md`.

## Multi-Space Deployment

For the `spaces` map API, `GenieChat alias` prop, and `useGenieChat` hook, see `npx @databricks/appkit docs ./docs/plugins/genie.md`.

This section covers the **deployment-specific patterns** for multi-space Genie apps (databricks.yml, app.yaml, stale conversation cleanup).

**databricks.yml** — add one variable + resource per space, plus target-level values:

```yaml
variables:
genie_space_id:
description: Default Genie space ID (required by AppKit)
genie_space_name:
description: Default Genie space name
genie_space_sales_id:
description: Sales Genie space ID
genie_space_support_id:
description: Support Genie space ID

resources:
apps:
app:
user_api_scopes:
- dashboards.genie
resources:
- name: genie-space
genie_space:
name: ${var.genie_space_name}
space_id: ${var.genie_space_id}
permission: CAN_RUN
- name: genie-space-sales
genie_space:
name: genie-space-sales
space_id: ${var.genie_space_sales_id}
permission: CAN_RUN
- name: genie-space-support
genie_space:
name: genie-space-support
space_id: ${var.genie_space_support_id}
permission: CAN_RUN

targets:
default:
variables:
genie_space_id: <any-space-id>
genie_space_name: <space-name>
genie_space_sales_id: <sales-space-id>
genie_space_support_id: <support-space-id>
```

**app.yaml** — keep `DATABRICKS_GENIE_SPACE_ID` (AppKit validates it on startup). Add one `valueFrom` per UI space:

```yaml
env:
- name: DATABRICKS_GENIE_SPACE_ID
valueFrom: genie-space
- name: DATABRICKS_GENIE_SPACE_SALES
valueFrom: genie-space-sales
- name: DATABRICKS_GENIE_SPACE_SUPPORT
valueFrom: genie-space-support
```

**Critical gotcha**: `DATABRICKS_GENIE_SPACE_ID` must always be set — AppKit validates it on startup even when using a custom `spaces` map.

**Build version stamp** — stamp every build so the page can detect a new deployment and clear stale conversation state:

```typescript
// client/vite.config.ts
export default defineConfig({
// ... existing config ...
define: {
"import.meta.env.VITE_APP_VERSION": JSON.stringify(Date.now().toString()),
},
});
```

**Stale conversation cleanup** — `GenieChat` stores conversation IDs in URLs and localStorage that become stale across space switches or redeployments:

```typescript
function clearConversationUrl() {
const url = new URL(window.location.href);
url.searchParams.delete("conversationId");
window.history.replaceState({}, "", url.toString());
}

function initAlias(): string {
const buildVersion = import.meta.env.VITE_APP_VERSION ?? "dev";
if (localStorage.getItem("appkit:genie:version") !== buildVersion) {
const savedAlias = localStorage.getItem("appkit:genie:alias");
Object.keys(localStorage)
.filter((k) => k.startsWith("appkit:genie:"))
.forEach((k) => localStorage.removeItem(k));
localStorage.setItem("appkit:genie:version", buildVersion);
if (savedAlias) localStorage.setItem("appkit:genie:alias", savedAlias);
clearConversationUrl();
}
// SPACES: array of {alias, spaceId} defined in your component
return localStorage.getItem("appkit:genie:alias") ?? SPACES[0]?.alias ?? "";
}
```

## Frontend

**For full component API**: run `npx @databricks/appkit docs "GenieChat"`.
Expand Down Expand Up @@ -197,3 +298,6 @@ The plugin mounts SSE endpoints under `/api/genie`:
| `plugin "genie" has no resource with key "..."` | Wrong `--set` flags during scaffold | Always derive resource keys from `databricks apps manifest` |
| Chat collapses or renders poorly | No explicit height on container | Give the parent a fixed height |
| Duplicate routes or import confusion | Old local Genie proxy file | Remove it — use `genie` from `@databricks/appkit` |
| `does not have required scopes: genie` | Missing API scope | Confirm `user_api_scopes` includes `dashboards.genie` in `databricks.yml` and redeploy |
| Genie space not found | Wrong space ID | Verify space ID matches the value on the Genie space **About** tab |
| `valueFrom` mismatch | `app.yaml` value doesn't match `databricks.yml` | `valueFrom` in `app.yaml` must exactly match the resource `name` in `databricks.yml` |
Loading
Loading