Technical reference
A live app is a saved React application plus a set of stored data steps that execute server-side against the sources the app declared when it was built. This page describes the runtime model, its constraints, and the surfaces it exposes.
Execution model
No language model runs when an app is used. The AI participates only at build time; afterwards the app is a fixed bundle whose data steps are executed by a sandboxed runner.
- Data steps are stored server-side and run without network access to anything but their declared sources. Each step declares its sources, its parameters and the shape of its output; that declaration is the app's least-privilege boundary.
- Credentials resolve on the server. They are never present in the app bundle or in the browser. A shared viewer never receives them either.
- Source binding is fixed at build time. A step can only reach the tools, database tables and Nirvai data areas it declared. Adding a source is an edit, not a runtime decision.
- Database access is read-only. Table sources expose a filtered select. There is no write path from an app to a table.
The refresh lifecycle
Two properties follow from this design:
- Snapshot semantics. A run with the app's default parameters updates the stored snapshot — the copy every viewer sees on open. A run with non-default parameters (a changed filter or time range) returns to the caller only and does not overwrite it.
- Fail-closed rendering. A failed refresh never blanks a section that already has data. The previous values remain with an error banner above them. Only a first load with no snapshot renders empty.
Concurrency is one execution per data step at a time. A second refresh while one is in flight is rejected rather than queued; a run that exceeds its window is treated as stale and released.
Access model
| Property | Behavior |
|---|---|
| Ownership | One owner per app. Ownership does not transfer. |
| Visibility | personal or organization. There is no per-user grant list and no public or token-based URL. |
| Member access | View and refresh. Edit, rename, delete and re-share are owner-only. |
| Execution identity | Shared refreshes execute as the owner. Tools, credentials and tables resolve against the owner's account, not the viewer's — a viewer's identity would resolve none of them. |
| Status | draft, published, or needs_attention when a data step is failing. |
Limits
| Limit | Value |
|---|---|
| Total execution time per data step | 5 minutes |
| Single call to an external service | 150 seconds |
| External calls per execution | 25 |
| Rows returned to the interface | Aggregate server-side to roughly 200 rows per step; larger results are chunked |
| Concurrent executions per step | 1 |
Apps are built to aggregate before returning. A step that needs thousands of rows to answer a question should reduce them server-side rather than paginate them into the browser.
Error types
Failures return as typed results the app renders, not as broken pages.
| Type | Meaning |
|---|---|
auth_expired | The credential for a connected service expired or was rejected. Reconnect it. |
tool_error | The external service returned an error for this call. |
tool_missing | A declared tool or table no longer resolves — deleted, renamed, or no longer owned. Flips the app to needs attention. |
timeout | The step, or one call inside it, exceeded its window. |
already_running | An execution of this step is already in flight. |
no_snapshot | No stored data for this step yet; it has never run. |
invalid_params | A supplied filter value is outside the step's declared parameters. |
script_error | The step itself raised an error. |
output_too_large | The result exceeded the size limit. |
Building from an outside assistant
An assistant connected over MCP — Claude Code, Codex, Cursor — can build a live app in your account. The division of labour is deliberate: the assistant authors and tests, you approve and save.
| It can | Notes |
|---|---|
| List your apps and read one's full contract | Manifest, per-step parameters, declared sources, run history |
| List what data is available to build on | The same three source kinds as the in-app builder |
| Propose sources and propose a look | Each opens a review page in Nirvai that you approve |
| Test a data step, and validate the whole app | The same validation battery the in-app builder runs |
| Stage a draft | Only after validation passes; produces a real preview with a Save button |
| Publish | Available, but the reviewed Save in Nirvai is the intended path |
These actions appear individually in your Activity Feed, each deep-linked to what it produced. Reading another member's shared app through the plugin is not exposed — an assistant reaches only its own account holder's apps.
The native builder is a streaming conversation, not a single operation. An outside assistant reproduces the same pipeline step by step rather than invoking it wholesale.