diff --git a/manifest.json b/manifest.json
index 54ec72f..77a41fe 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,17 +1,18 @@
{
"version": "2",
- "updated_at": "2026-04-30T11:02:41Z",
+ "updated_at": "2026-04-30T12:02:18Z",
"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-04-30T11:00:26Z",
+ "updated_at": "2026-04-30T12:02:15Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
"assets/databricks.png",
"assets/databricks.svg",
+ "references/appkit/agent-browser.md",
"references/appkit/appkit-sdk.md",
"references/appkit/files.md",
"references/appkit/frontend.md",
@@ -33,7 +34,7 @@
"version": "0.1.0",
"description": "Core Databricks skill for CLI, auth, and data exploration",
"experimental": false,
- "updated_at": "2026-04-23T13:47:44Z",
+ "updated_at": "2026-04-30T11:30:47Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
@@ -48,7 +49,7 @@
"version": "0.0.0",
"description": "Declarative Automation Bundles (DABs) for deploying and managing Databricks resources",
"experimental": false,
- "updated_at": "2026-04-23T13:47:44Z",
+ "updated_at": "2026-04-30T11:30:47Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
@@ -66,7 +67,7 @@
"version": "0.1.0",
"description": "Databricks Jobs orchestration and scheduling",
"experimental": false,
- "updated_at": "2026-04-23T13:47:44Z",
+ "updated_at": "2026-04-30T11:30:47Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
@@ -78,7 +79,7 @@
"version": "0.1.0",
"description": "Databricks Lakebase Postgres: projects, scaling, connectivity, synced tables, and Data API",
"experimental": false,
- "updated_at": "2026-04-30T11:02:37Z",
+ "updated_at": "2026-04-30T11:30:47Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
@@ -93,7 +94,7 @@
"version": "0.1.0",
"description": "Databricks Model Serving endpoint management",
"experimental": false,
- "updated_at": "2026-04-23T13:47:44Z",
+ "updated_at": "2026-04-30T11:30:47Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
@@ -105,7 +106,7 @@
"version": "0.1.0",
"description": "Databricks Pipelines (DLT) for ETL and streaming",
"experimental": false,
- "updated_at": "2026-04-23T13:47:44Z",
+ "updated_at": "2026-04-30T11:30:47Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
@@ -152,7 +153,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-04-24T15:10:23Z",
+ "updated_at": "2026-04-30T11:30:47Z",
"files": [
"SKILL.md",
"agents/openai.yaml",
diff --git a/skills/databricks-apps/SKILL.md b/skills/databricks-apps/SKILL.md
index 515fa9c..8bc8729 100644
--- a/skills/databricks-apps/SKILL.md
+++ b/skills/databricks-apps/SKILL.md
@@ -28,6 +28,7 @@ Build apps that deploy to Databricks Apps platform.
| Typed data contracts (proto-first design) | [Proto-First Guide](references/appkit/proto-first.md) and [Plugin Contracts](references/appkit/proto-contracts.md) |
| Managing files in UC Volumes | [Files Guide](references/appkit/files.md) |
| Triggering / monitoring Lakeflow Jobs from the app | [Jobs Guide](references/appkit/jobs.md) |
+| Driving the running app in a browser (visual checks, screenshots, agent-driven UI smoke) | [agent-browser Guide](references/appkit/agent-browser.md) |
| Platform rules (permissions, deployment, limits) | [Platform Guide](references/platform-guide.md) — READ for ALL apps including AppKit |
| Non-AppKit app (Streamlit, FastAPI, Flask, Gradio, Next.js, etc.) | [Other Frameworks](references/other-frameworks.md) |
diff --git a/skills/databricks-apps/references/appkit/agent-browser.md b/skills/databricks-apps/references/appkit/agent-browser.md
new file mode 100644
index 0000000..5b2ef3d
--- /dev/null
+++ b/skills/databricks-apps/references/appkit/agent-browser.md
@@ -0,0 +1,183 @@
+# agent-browser: Render a Running App for Visual Inspection
+
+Use this when you (or an agent) need to **load a Databricks app in a browser and interact with it programmatically** — verify a UI change, capture a screenshot, drive a smoke flow.
+
+The primary target is a **deployed app URL** (real OAuth/SSO). For local UI iteration, the right path is the app's own Vite dev server (`npm run dev`) — no platform proxy, no auth, instant HMR. The `databricks apps run-local` proxy is an edge case for testing platform header-injection behavior locally without deploying; covered at the bottom.
+
+| | **Deployed app** (primary) | **Local Vite dev server** | **Local platform proxy** (edge case) |
+|---|---|---|---|
+| When | Verify what's actually in staging/prod | Iterate on UI code with HMR | Test how the app behaves under the platform's auth-header proxy without deploying |
+| Auth | Real OAuth/SSO | None | None — proxy injects fake `X-Forwarded-*` |
+| Run command | (already deployed) | `npm run dev` | `databricks apps run-local --entry-point app.yaml` |
+| agent-browser command | `agent-browser --headed --profile
open ` (first run); plain `agent-browser open ` after | `agent-browser open http://localhost:` | `agent-browser open http://localhost:8001` |
+
+The browser daemon persists across commands; only the auth path differs.
+
+## When NOT to use this
+
+- **Non-visual smoke tests** — for AppKit, the scaffold ships `tests/smoke.spec.ts` (Playwright); see [testing.md](../testing.md).
+- **Verifying real per-user OBO behavior** — only the deployed app gives you a real OBO token. Neither Vite nor `run-local` will.
+
+## Pre-flight checks
+
+Run these before anything else. If any fail, surface the failing check and stop — don't try to fix forward.
+
+1. **`agent-browser` on PATH** — `command -v agent-browser`. If missing, install it (it's a public npm package):
+ ```bash
+ npm install -g agent-browser
+ # or: pnpm add -g agent-browser
+ # or: yarn global add agent-browser
+ ```
+ Then re-check with `command -v agent-browser` and `agent-browser --version`. Surface the failing check to the user before continuing — don't try to script around a missing binary.
+2. **(Deployed mode)** the user can navigate to the deployed app URL in a regular browser and log in via SSO — that is the login `--headed --profile` will reproduce once.
+3. **(Deployed mode, if discovering the URL)** `databricks` on PATH and authenticated for the workspace — `databricks apps list --profile `.
+
+## Driving a deployed app (primary)
+
+For URLs like `https://..databricksapps.com`, the platform demands real OAuth/SSO. Pick one of the following.
+
+### Preferred: `--headed --profile ` (one-time SSO)
+
+```bash
+# First run — interactive: user logs in via SSO once; cookies persist in :
+agent-browser --headed --profile ./.agent-browser-profile open
+
+# Subsequent runs — same profile, no login prompt:
+agent-browser --profile ./.agent-browser-profile open
+```
+
+Use this by default. Least disruptive — it doesn't touch the user's regular Chrome.
+
+### Alternative: `--auto-connect` to an existing Chrome
+
+Only viable if Chrome is **already** running with `--remote-debugging-port=9222`. A normal Chrome window does **not** have this flag, and you cannot add it to a running Chrome — relaunching the binary with the flag prints `Opening in existing browser session` and silently no-ops.
+
+To use this path:
+
+```bash
+# Fully quit Chrome first (closing the window is not enough):
+osascript -e 'quit app "Google Chrome"'
+
+# Relaunch with the debug port:
+open -a "Google Chrome" --args --remote-debugging-port=9222
+
+# Then connect:
+agent-browser --auto-connect open
+```
+
+Disruptive if the user has working tabs. Only suggest this if `--headed --profile` won't work.
+
+### Sharing a logged-in session across runs / CI
+
+Use `agent-browser state save` after a successful login and `agent-browser state load` in subsequent runs. Run `agent-browser skills get core` for the full auth-vault surface.
+
+## Driving with agent-browser
+
+Once a session is open, the browser persists across commands:
+
+```bash
+agent-browser snapshot -i # see interactive elements as @e1, @e2, ...
+agent-browser screenshot home.png # capture for inspection
+# ... interact with refs from the snapshot ...
+agent-browser close
+```
+
+For the full agent-browser surface (refs, waits, find-by-role, auth vault), run `agent-browser skills get core`.
+
+**Daemon flag-ignore gotcha**: when the agent-browser daemon is already running, `--headed` and `--profile` on a subsequent invocation are silently ignored:
+
+```
+⚠ --profile, --headed ignored: daemon already running.
+ Use 'agent-browser close' first to restart with new options.
+```
+
+Always run `agent-browser close` before changing launch flags.
+
+## Driving a local Vite dev server
+
+For UI iteration, run the app's own dev server and point agent-browser at it:
+
+```bash
+# In the app directory:
+npm run dev
+
+# In another shell, once Vite prints "Local: http://localhost:/":
+agent-browser open http://localhost:
+```
+
+No auth. No proxy. Just Vite (and, for AppKit, the backing tRPC server). This is the right path when you're iterating on UI code and don't need real platform auth, `X-Forwarded-*` headers, or OBO tokens. The exact port comes from Vite's startup output — don't hardcode it.
+
+## Edge case: testing platform proxy behavior locally (`databricks apps run-local`)
+
+Use this **only** when you need to verify how the app behaves under the deployed platform's auth-header proxy without actually deploying — e.g. checking that the app correctly reads `X-Forwarded-*`, behaves under prod-style service-principal-only execution, or is served the way the runtime serves it.
+
+It is **not** the right tool for normal UI iteration (use `npm run dev`) and it is **not** the right tool for full deployed-app verification (use the real deployed URL).
+
+### What the proxy does
+
+`run-local` starts an HTTP proxy on `localhost:` (default 8001) in front of the app (default `localhost:8000`). On every forwarded request it injects:
+
+| Header | Value |
+|---|---|
+| `X-Forwarded-Host` | `localhost` |
+| `X-Forwarded-User` | CLI user's `userName` |
+| `X-Forwarded-Email` | CLI user's primary email (or `userName` if none) |
+| `X-Forwarded-Preferred-Username` | CLI user's `displayName` |
+| `X-Real-Ip` | `127.0.0.1` |
+| `X-Request-Id` | fresh UUID per request |
+
+These match the headers the Apps platform's auth proxy sets in production, so AppKit (and any framework that reads `X-Forwarded-*`) treats the request as authenticated. Identity comes from `WorkspaceClient.CurrentUser.Me()` for the active profile.
+
+The proxy injects identity headers but **not** an OBO user token. Plugins or app code requiring an OBO token (anything calling `.asUser(req)` or reading a `user_api_scopes` token) will fail under `run-local` — drive the deployed app instead.
+
+### Pre-flight (run-local only)
+
+1. **App spec present** — `app.yaml` (AppKit) or `app.yml` in the working directory, OR pass `--entry-point `.
+2. **Proxy port free** — default 8001. If `lsof -i :8001` shows anything, pick a free port and pass `--port `.
+
+### Running
+
+```bash
+# AppKit apps use app.yaml:
+databricks apps run-local --entry-point app.yaml --profile
+
+# First-time, if Python deps aren't installed (requires `uv`; Node-only apps just need `npm install`):
+databricks apps run-local --prepare-environment --entry-point app.yaml --profile
+
+# Custom ports:
+databricks apps run-local --port 8001 --app-port 8000 --entry-point app.yaml --profile
+```
+
+If `app.yaml` declares env vars with `valueFrom` (referencing bundle resources like SQL warehouse IDs or Genie space IDs), `run-local` will exit with `... defined in app.yaml with valueFrom property and can't be resolved locally`. Pass each as `--env KEY=value`; values come from `databricks.yml` `targets..variables`.
+
+`run-local` runs in the foreground and prints `To access your app go to http://localhost:` once the proxy is listening. Run it in the background (or a separate shell), wait for the proxy to be reachable, then drive it:
+
+```bash
+until curl -fsS "http://localhost:8001/" -o /dev/null; do sleep 1; done
+agent-browser open http://localhost:8001
+```
+
+### Two-port summary (don't mix these up)
+
+- **`--port` (default 8001)** — the **proxy**. This is the URL you give to `agent-browser` and the URL printed by `run-local`. All traffic here gets the `X-Forwarded-*` headers.
+- **`--app-port` (default 8000)** — the **app's own bind port**. The proxy forwards to this. Hitting it directly skips auth header injection — usually not what you want.
+
+### Shutdown
+
+Send SIGINT (Ctrl+C) to `run-local`. It forwards SIGTERM to the app and waits up to **15 seconds** before SIGKILL — same grace window the Apps platform uses, so handlers behave the same locally and in prod. Then `agent-browser close` to terminate the daemon.
+
+## Gotchas
+
+| Symptom | Cause | Fix |
+|---|---|---|
+| Deployed mode: `No running Chrome instance found. Launch Chrome with --remote-debugging-port` | A regular Chrome window has no debug port. Relaunching Chrome with the flag while it's already running just opens a new tab in the existing instance (`Opening in existing browser session`) — it does NOT add the flag | Fully quit Chrome (`osascript -e 'quit app "Google Chrome"'`), then `open -a "Google Chrome" --args --remote-debugging-port=9222`. Or simpler: switch to `--headed --profile`. |
+| `⚠ --profile, --headed ignored: daemon already running` | A previous agent-browser run left the daemon up | `agent-browser close` first, then re-open with the desired flags. |
+| Deployed mode: SSO login loop in `--headed` | Profile dir was reused after a credential rotation, or the workspace requires a fresh device check | Delete the profile dir and re-run with `--headed` to re-login from scratch. |
+| `run-local` exits with `... defined in app.yaml with valueFrom property and can't be resolved locally` | `app.yaml` references bundle resources (warehouse, Genie space) that don't resolve outside a deployed bundle | Pass each `valueFrom` env var as `--env KEY=value`; values live in `databricks.yml` under `targets..variables`. |
+| `run-local`: `app.yaml` not found / spec not picked up | AppKit scaffolds use `app.yaml`; older defaults look for `app.yml` | Pass `--entry-point app.yaml`. |
+| `run-local`: AppKit app crashes with `AuthenticationError: Missing user token in request headers` | Proxy injects `X-Forwarded-*` identity but no OBO token; plugins requiring a user token reject this | Run `npm run dev` for UI iteration, or drive the **deployed** app for OBO behavior. The local proxy can't synthesize an OBO token. |
+| `run-local`: app redirects to OAuth instead of loading | Framework isn't honoring `X-Forwarded-*`, or you bypassed the proxy and hit `--app-port` directly | Hit the **proxy** port (`--port`, default 8001), not the app port (`--app-port`, default 8000). |
+| `run-local`: `address already in use` on start | Default port 8001 (or 8000) is taken | Pass `--port` and/or `--app-port` to free values. |
+| `run-local`: app keeps running after Ctrl+C | App ignored SIGTERM | Wait 15s — `run-local` escalates to SIGKILL. Fix the handler in the app. |
+| `run-local`: wrong user identity in the app | `databricks` is using a different profile than expected | Pass `--profile ` to `run-local`; verify with `databricks current-user me --profile `. |
+| `run-local`: `prepare-environment` fails | `uv` not installed | Install `uv`, or skip the flag and prepare deps yourself. For Node-only apps `npm install` is enough. |
diff --git a/skills/databricks-apps/references/appkit/overview.md b/skills/databricks-apps/references/appkit/overview.md
index a0874e3..a232e0b 100644
--- a/skills/databricks-apps/references/appkit/overview.md
+++ b/skills/databricks-apps/references/appkit/overview.md
@@ -130,6 +130,7 @@ Do not guess paths — run without args first, then pick from the index.
| Add Genie chat | [Genie](genie.md) — space creation, plugin setup, frontend components |
| Call ML model serving endpoints | [Model Serving](model-serving.md) — resource declaration, tRPC query pattern |
| Trigger / monitor Lakeflow Jobs from the app | [Jobs](jobs.md) — env discovery, JobHandle API, SSE streaming |
+| Render / drive the running app in a browser | [agent-browser](agent-browser.md) — primary path: drive a deployed app with `--headed --profile`; local Vite dev for UI iteration; `run-local` reserved as edge case |
## Critical Rules