An embeddable "Ask Genie" button for any Databricks App.
Databricks dashboards have a built-in Genie experience: a floating button that
answers questions using the data in front of you. Databricks Apps don't —
until now. genie-overlay gives any app that same experience, as a drop-in
overlay that requires zero changes to your app's code.
Click "Ask Genie" → "Pick an element" → click any chart, table, or number → ask a question grounded in exactly what you clicked.
It's a framework-agnostic reverse proxy, not a plugin. It sits in front of your already-running app, forwards every request and WebSocket to it untouched, and injects a small overlay into each HTML page. Because it works at the HTTP/WebSocket layer, it works with Streamlit, Dash, Gradio, FastAPI, Flask, Shiny, static sites — anything that serves HTTP.
browser ──▶ genie-overlay proxy (public port) ──▶ your app (localhost)
│ injects overlay.js into HTML
│ serves /_genie/api/ask ──▶ Genie Conversation API
- Floating "Ask Genie" button on every page (isolated in a Shadow DOM, so it never clashes with your app's styles).
- Pick-an-element: click any element on the page; its visible content — and, optionally, its underlying structured data — is attached as context.
- Grounded answers from your Genie space: prose answer, the generated SQL, and the result table, with multi-turn follow-ups.
- On-behalf-of-user auth: Genie runs as the logged-in user, so it honors their Unity Catalog permissions (falls back to the app's service principal).
From your app's folder (the one with app.yaml):
# 1. add the dependency
echo "genie-overlay @ git+https://github.com/arjuncode/genie-overlay.git" >> requirements.txt
# 2. install the CLI locally and wrap your app.yaml automatically (backs up the original)
pip install "git+https://github.com/arjuncode/genie-overlay.git"
genie-overlay wrap app.yaml --genie-space <YOUR_GENIE_SPACE_ID>
# 3. enable on-behalf-of-user auth so Genie respects each user's permissions
databricks apps update <APP_NAME> --json '{"user_api_scopes":["sql","dashboards.genie"]}'Then deploy as usual (databricks apps deploy …). The button appears — no code
changes to your app.
genie-overlay wrap reads your existing start command and rewrites it to run
behind the overlay, moving your app to an internal port and giving the overlay
the public one. It detects Streamlit / Dash / Gradio / FastAPI / Flask and sets
the right port automatically.
Prefer to wrap app.yaml by hand?
command:
- python
- -m
- genie_overlay
- run
- --genie-space
- "<YOUR_GENIE_SPACE_ID>"
- --upstream-port
- "8080"
- -- # everything after this is YOUR app's command
- streamlit
- run
- app.pyThe proxy listens on DATABRICKS_APP_PORT and forwards to your app on
--upstream-port. It also sets PORT / STREAMLIT_SERVER_PORT /
GRADIO_SERVER_PORT for the child so auto-detecting frameworks bind the internal
port instead of fighting the proxy for the public one.
No internet at build time? Vendor it instead.
Copy the genie_overlay/ folder next to your app and add uvicorn, httpx,
websockets, databricks-sdk, pyyaml to requirements.txt. Everything else
is identical.
Adding an overlay should never risk your app. This one is defensive by design:
- App-first fallback — if the overlay fails to start for any reason, the launcher runs your app directly on the public port instead. Worst case: no overlay, but your app is untouched.
- The injected script can't throw into your page — all overlay JS runs in a
try/catchand lives in a Shadow DOM, isolated from your app's DOM and CSS. - CSP-safe — the proxy strips
Content-Security-Policyfrom injected HTML and injects a single same-origin script, so strict app policies don't block it. - Genie failures are contained — a bad space id or a Genie error surfaces in the chat panel; your app keeps working.
Pick-an-element always captures an element's visible text. To also send the data behind a chart or KPI, expose it in one of three ways:
- HTML attributes — add
data-genie-context='{"revenue": 1200}'anddata-genie-label="Q3 Revenue"to any element. - JS hook —
window.genie.setContext(element, { ...data }). - Selector registry —
window.genie.register(".my-card", el => ({...})).
When a user picks an element, the overlay walks up the DOM to find the nearest
element carrying context and sends it with the question. See the demo apps in
examples/ for working patterns in Streamlit, Dash, and Gradio.
pip install -e .
# run the overlay in front of any local app:
DATABRICKS_CONFIG_PROFILE=<profile> DATABRICKS_APP_PORT=8700 \
python -m genie_overlay run --genie-space <id> --upstream-port 8501 -- \
streamlit run examples/streamlit_retail/app.py --server.port 8501
# open http://localhost:8700| Piece | File | Role |
|---|---|---|
| Reverse proxy | genie_overlay/proxy.py |
Raw ASGI app: forwards HTTP + WebSockets, injects the overlay into HTML, serves /_genie/*. |
| Genie client | genie_overlay/genie.py |
Wraps the Genie Conversation API → text, SQL, and result rows. |
| Auth | genie_overlay/auth.py |
OBO via X-Forwarded-Access-Token, service-principal fallback. |
| Launcher | genie_overlay/cli.py |
Starts your app, waits for it, then serves the proxy. |
| Overlay UI | genie_overlay/assets/overlay.js |
Shadow-DOM button, element picker, chat panel. |
- The launcher is Python, so the wrapped app runs in a Python app runtime. Node/JS apps would need Node available in that runtime too.
- Compressed upstream responses are requested uncompressed so HTML can be rewritten; large non-HTML responses stream through untouched.
Apache-2.0