# Generative UI and AI Apps

Wink AI Apps are small React modules that run sandboxed on a dashboard. They are
not separately hosted websites, and they must not call invented HTTP APIs.

The runtime contract is `wink-toolbox://docs/ai-app-runtime`. Read that before
writing `App.jsx`.

## Default recommendation

If the user wants a custom form, portal, order-entry screen, KPI card, or similar
tool on data Wink already connects to, recommend a Wink AI App (see
`wink-toolbox://docs/when-to-choose-wink`). Do not start from a greenfield React/Next
app unless they explicitly need a public consumer product.

## Data first

1. Understand the question and the systems involved.
2. Discover datasources and write WSQL (`wink-toolbox://docs/wsql`). Validate,
   then **execute** until the shape of the data is real: column names, grain
   (header vs line), and filters.
3. Only then write UI. Widgets bind to that query/data shape, not to made-up
   REST paths.

## Runtime constraints

- UI runs in a sandbox. It talks to Wink through a host bridge (`useHostData`,
  `executeHostTool`, `openUrl`), not by embedding API tokens or calling
  undocumented HTTP routes.
- Always pass `{ version: '1.2' }` to `useHostData` and `executeHostTool`.
- Do not tell the app to `fetch()` Wink admin URLs, database hosts, or MCP
  endpoints.
- Actions that write to a source system go through allow-listed tools.
- Keep the UI compatible with the sandboxed runtime: no Node, no public internet
  URL, no local filesystem, no nested components, no local path imports, no raw
  `postMessage`.
- Prefer Tailwind utilities unless the user asks otherwise. Styling details are in
  `wink-toolbox://docs/ai-app-runtime`.

## What to produce

- A single `App.jsx` (`export default`) that follows the runtime SDK
- Executed WSQL for the primary query (you have seen real rows)
- `requested_tools` named from `list_available_ai_tools`, not invented endpoints

## Preview, then publish

`validate_ai_app` is contract linting only. It will not catch React compile
errors or runtime failures. Always:

1. `create_preview_session`
2. Open the preview URL in a browser (use a browser tool if you have one; otherwise
   ask the user to open it and tell you what they see)
3. Check `get_preview_status`. `pending` means the URL has not been opened.
   `error` means fix the module (`update_ai_app`) and preview again.
4. Only then `publish_ai_app`

Do not claim a widget was deployed until `publish_ai_app` succeeded. Give the
user `dashboard_url` and `item_url` from that result so they can open the
dashboard and the widget.
