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
Binary file added public/data-apps/open-app-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions src/components/StageStrip.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
// Numbered dots on a line, the picture the Getting Started hub clip draws
// (public/getting-started/hub-explainer-poster.png), for a how-to whose reader
// walks through 3 to 6 stages. The dot-and-segment technique is CourseLine's
// (src/components/getting-started/CourseLine.astro, PR #1144); that component
// draws the course from its own data, this one takes a page's stages as children:
//
// <StageStrip label="Building by hand from a terminal, in four stages" caption="From a terminal">
// <li><strong><a href="#app-structure">Write the code</a></strong> A standard web app, plus a small configuration folder.</li>
// ...
// </StageStrip>
//
// One <li> per stage: the title in <strong> first (linked to the stage's heading
// when it has one), then 12 words or fewer. Keep the opening tag and each <li> on
// one line: the markdown twin (page-markdown.mjs) reads them line by line and
// prints the stages as a numbered list. Styles: .stage-strip in custom.css; the
// strip turns vertical when the content column is narrow (a container query).

interface Props {
/** Accessible name of the list; the markdown twin prints it in bold as the strip's heading. */
label?: string;
/** A short visible caption above the dots, for a strip that follows one of several routes. */
caption?: string;
}

const { label, caption } = Astro.props;
const raw = Astro.slots.has('default') ? await Astro.slots.render('default') : '';
// MDX wraps a multi-line <li> in <p>. The title is the item's first <strong>,
// tagged with a class because :first-child ignores text nodes (CLAUDE.md).
const html = raw
.replace(/<\/?p>/g, '')
.replace(/(<li(?:\s[^>]*)?>)\s*<strong>/g, '$1<strong class="stage-strip__title">');
const stages = (html.match(/<li\b/g) || []).length;
if (stages < 3 || stages > 6) console.warn(`StageStrip: ${stages} stages; a strip reads best with 3 to 6`);
---

<div class="stage-strip not-content">
{caption && <p class="stage-strip__caption">{caption}</p>}
<ol class="stage-strip__list" role="list" aria-label={label} set:html={html} />
</div>
2 changes: 1 addition & 1 deletion src/content/docs/data-apps/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Once an app is deployed, its URL is publicly available. Protect it so only the r
## Authentication methods

- **None (Public Access)** — the app is public to anyone with the URL. You can still add your own authorization inside the app; for Streamlit, use the [Streamlit authenticator](https://github.com/mkhorasani/Streamlit-Authenticator) ([example](https://github.com/keboola/mkt-bi-ocr/blob/master/Select_Invoices.py)).
- **Basic (Password)** — the **default** for new apps. Keboola generates a shared password; users enter it before the app opens. Once the app is deployed, the password is shown on the app's configuration page next to **Open App**, ready to copy — and when Kai builds an app, it shows the password as the last step.
- **Basic (Password)** — the **default** for new apps. Keboola generates a shared password; users enter it before the app opens. Once the app is deployed, click **Open App** on its configuration page: the dialog has the app's address and the password, each with a copy button. When Kai builds an app, it shows the password as the last step.
- **OIDC (Custom)** — users sign in with your identity provider (Google, Microsoft Entra ID, Okta, Auth0, or any other OIDC provider). Recommended for anything beyond a quick share.
- **GitHub** — restrict access with GitHub OAuth by organization, team, repository, or allowed users.
- **GitLab** — restrict access with GitLab OAuth by groups, projects, or roles.
Expand Down
29 changes: 25 additions & 4 deletions src/content/docs/data-apps/build-locally.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ redirect_from:

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Prereqs from '../../../components/Prereqs.astro';
import StageStrip from '../../../components/StageStrip.astro';

{/* 2026-09-29: "Build an app with an AI agent" (PR #1143) merged into this page after review (PRDCT-693); the old URL redirects here. Agent flow verified live on 2026-09-23 in project 264 (europe-west3) with Claude Code 2.1.280, kbagent 0.94.0 and dataapp-developer 1.6.1 from marketplace keboola-claude-kit 1.14.0 (App ID 74021867, about 11 minutes, including the Storage workaround below), and on 2026-09-25 with Codex CLI 0.157.0 (App ID 74022065). Michal Ševčík's Cursor review (2026-09-25): agent mode is the default, the route question appears, a prompt that names kbagent reads better, the password is the main friction. The example prompt was then revised to name kbagent and ask for a data check and the page link, and revised again to name the project and rule out MCP, after his run built in another project through an MCP sign-in; VERIFY(Michal Ševčík) that wording in Cursor. Claude Desktop, VS Code and the ChatGPT app screens: VERIFY the dataapp-developer install and the build flow. */}

Expand Down Expand Up @@ -54,6 +55,13 @@ To build inside Keboola instead, [Kai](/data-apps/getting-started/) does the sam

With the `dataapp-developer` plugin from Keboola's [AI Kit](/ai/ai-kit/), the agent reads your data, writes the code, creates the app with a Git repository that Keboola manages, pushes the code there and deploys it. You end up with a running app at its own URL, and the code in a repository you can keep changing.

<StageStrip label="Building with an AI agent, in four stages">
<li><strong><a href="#set-up-your-client">Set up your client</a></strong> Connect your project and add the app-building plugin.</li>
<li><strong><a href="#describe-the-app">Describe the app</a></strong> One prompt: what it shows, which data, where the code goes.</li>
<li><strong>The agent builds it</strong> It reads your data, writes code and deploys; you approve its commands.</li>
<li><strong><a href="#check-the-app">Check the app</a></strong> On its page in Keboola, Open App has the URL and password.</li>
</StageStrip>

### Set up your client

<Tabs syncKey="ai-client">
Expand Down Expand Up @@ -153,9 +161,15 @@ Through a Keboola MCP server, the agent doesn't run kbagent. It calls the server
### Check the app

- The agent finishes with the app's URL and its page in Keboola.
- The app asks for its password, which is on that page next to **Open App**.
- To let other people open it, see [Publish and share](/data-apps/publish-and-share/).
- The app asks for its password. On the app's page in Keboola, click **Open App**. The dialog has the app's address and its password, each with a copy button. Copy the password, then click **Open app** in the dialog.

![The Open app dialog on an app's page in Keboola: the App address and the Password, hidden, each with a copy button, above an Open app button](/data-apps/open-app-dialog.png)

- If the app opens without data, ask the agent to read the app's log. [Troubleshooting](/data-apps/troubleshooting/) lists the common causes, including `Promise.withResolvers is not a function` from a too-new `@keboola/api-client`.
- On [the MCP route](#the-mcp-route), you preview a draft at its own URL first. The production app gets **Open App** once you approve the draft and the agent deploys it.
- To let other people open it, see [Publish and share](/data-apps/publish-and-share/).

{/* Password location checked 2026-09-29 in project 264 on App ID 74021867, started for the check and stopped after: Open App opens a dialog with App address and Password (hidden, each with a copy button); a stopped app's page shows no password (its Open App dialog was not opened), and its Authentication section names only the method, Basic (Password). VERIFY(Nikita): not checked on a sleeping app. VERIFY(Nikita): seen on europe-west3 only; the UI bundles read between 22 and 29 Sep still had an older App Credentials modal (Host, Password, an Open App button), so check the labels on us-east4, where free projects live. The MCP-route bullet restates The MCP route section above and operate.md (Open App on a running app, Deploy App on one that never ran). VERIFY(Nikita): where a draft's password shows was not checked. */}

### What you get by default

Expand All @@ -165,7 +179,7 @@ The agent usually can't show you that password, because `kbagent data-app passwo

To make the app public, say so in the prompt. Anyone with its URL can then open it and see the data it shows. Changing an existing app's sign-in, including to single sign-on, belongs in its [Authentication](/data-apps/authentication/) settings.

{/* "Say so in the prompt": kbagent data-app create offers --auth public (0.95.0 help); no run has asked for a public app yet, VERIFY(Nikita). Defaults from the kbagent create dry run (2026-09-23; it printed the size as `tiny`, which the UI and Miro Cillik's review on PR #1146 call XSmall) and the skill's app-type choice (choosing-app-type.md: Node.js + static frontend is the dashboard default; Streamlit for Python-only teams and quick prototypes). The page URL pattern is the ui-detail link the Keboola MCP server returns for a data app. The password location follows authentication.mdx; VERIFY(Michal Ševčík): the MCP link title says to click OPEN DATA APP to see it, so confirm where it shows. Asking an agent to remove the password of an existing app (2026-09-25) set auth_required to false and redeployed, yet the proxy still asked for the password 6.5 minutes later; VERIFY(Michal Ševčík) whether that takes effect later or needs the UI. */}
{/* "Say so in the prompt": kbagent data-app create offers --auth public (0.95.0 help); no run has asked for a public app yet, VERIFY(Nikita). Defaults from the kbagent create dry run (2026-09-23; it printed the size as `tiny`, which the UI and Miro Cillik's review on PR #1146 call XSmall) and the skill's app-type choice (choosing-app-type.md: Node.js + static frontend is the dashboard default; Streamlit for Python-only teams and quick prototypes). The page URL pattern is the ui-detail link the Keboola MCP server returns for a data app. Asking an agent to remove the password of an existing app (2026-09-25) set auth_required to false and redeployed, yet the proxy still asked for the password 6.5 minutes later; VERIFY(Michal Ševčík) whether that takes effect later or needs the UI. */}

### Other agents

Expand Down Expand Up @@ -201,6 +215,13 @@ To add the skill to an agent by hand, download it below. The download is a copy

Write the code yourself, then create the app from a terminal with kbagent, which gives it a Keboola-managed repository, or, in the Keboola UI, connect a repository you host.

<StageStrip label="Building by hand from a terminal, in four stages" caption="From a terminal">
<li><strong><a href="#app-structure">Write the code</a></strong> A standard web app, plus a small configuration folder.</li>
<li><strong><a href="#from-a-terminal">Create the app</a></strong> kbagent creates it with a Keboola-managed repository.</li>
<li><strong>Push the code</strong> Commit and push it to the app's repository.</li>
<li><strong>Deploy and open</strong> Deploy, then click Open App on its page for the password.</li>
</StageStrip>

### App structure

A Keboola app is a standard web app. The typical scaffold is:
Expand Down Expand Up @@ -261,7 +282,7 @@ kbagent creates the app with a Keboola-managed repository, and you push your cod
kbagent data-app detail --project <alias> --app-id <id>
```

The password is on the app's page, `<Keboola URL>/admin/projects/<project-id>/data-apps/<config-id>`, next to **Open App**. With a Manage API token, `kbagent data-app password --project <alias> --app-id <id>` prints it too. If the app opens without data, `kbagent data-app logs --project <alias> --app-id <id>` shows its log; if it doesn't start at all, `kbagent data-app runs --project <alias> --app-id <id>` shows why.
The password is on the app's page, `<Keboola URL>/admin/projects/<project-id>/data-apps/<config-id>`: click **Open App** and copy it from the dialog. With a Manage API token, `kbagent data-app password --project <alias> --app-id <id>` prints it too. If the app opens without data, `kbagent data-app logs --project <alias> --app-id <id>` shows its log; if it doesn't start at all, `kbagent data-app runs --project <alias> --app-id <id>` shows why.

### Sync to your project

Expand Down
8 changes: 6 additions & 2 deletions src/content/docs/data-apps/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ When you're happy with the draft, click **Publish to Production**. Kai merges th

![The published app: the configuration page showing Active status, next to Kai's final message with the App URL, the generated password, and an Open App button](/data-apps/getting-started-deployed.png)

By default the app is protected with **Basic (Password)** authentication — the generated password also sits on the app's configuration page, ready to copy. To change who can access it (public, a password, SSO, GitHub, and more), see [Authentication](/data-apps/authentication/).
By default the app is protected with **Basic (Password)** authentication. The generated password is also on the app's configuration page: click **Open App** in the page header and copy it from the dialog.

{/* The Open App dialog (App address, Password, each with a copy button) was seen on 2026-09-29 on a running app built with kbagent (project 264, App ID 74021867). VERIFY(Nikita): the same on apps Kai built or created in the UI. */}

To change who can access it (public, a password, SSO, GitHub, and more), see [Authentication](/data-apps/authentication/).

Open the URL, enter the password, and your app is live — running on your governed data, served from its own address:

Expand Down Expand Up @@ -114,7 +118,7 @@ Prefer to set the app up yourself, without the chat? Manual creation lives on th

![The deploy/redeploy wizard: backend version, backend size and inactivity timeout](/data-apps/deploy-timeout-backedsize.png)

7. When the status turns **Active**, click **Open App** to open it at its public URL. Use **Redeploy** to apply any later config change; see [App actions](/data-apps/reference/#app-actions).
7. When the status turns **Active**, click **Open App**. For an app behind a password, copy the password from the dialog, then click **Open app** in it to open the app at its public URL. Use **Redeploy** to apply any later config change; see [App actions](/data-apps/reference/#app-actions).

From here on, the app is something you run rather than something you build: [Operate and update an app](/data-apps/operate/) covers shipping changes, secrets, sleeping and versions.

Expand Down
2 changes: 2 additions & 0 deletions src/content/docs/data-apps/operate.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Deploying, starting, stopping, deleting and setting secrets also work from a ter

## Read the app's state

<!-- VERIFY(Michal Ševčík): on 2026-09-29 a Python/JS app built with kbagent (project 264, App ID 74021867) showed Edit with Kai in the header, running and stopped, and Duplicate with Kai, Automate, Debug mode and Delete app in the ⋯ menu while stopped, not Modify with Kai and Copy app. The 2026-07-10 screenshots of the Kai-built app 74016144 show Modify with Kai and Copy app. Renamed since, or does it depend on who built the app? The stopped app also showed Open App next to Start App. -->

The header shows the app's status and the one or two actions that make sense for it: **Deploy App** for an app that has never run, **Start App** for a stopped one, **Open App** and **Redeploy App** for a running one, and **Modify with Kai** on apps Kai built. The **⋯** menu holds the rest, and its contents depend on the state too: **Copy app**, **Automate** (add it to a flow), **Debug mode** and **Delete app** are always there, with **Suspend app** on a running app.

The tabs below the header split the app's life into views: **Overview** (the app's settings and its App URL), **Advanced Settings** (environment variables and secrets, theme, data mappings), **All Runs** (every start attempt), **Terminal Logs** (stdout and stderr while it runs), **Versions** (the configuration history), and **Drafts** while Kai has a draft open. The **App Info** panel on the right shows the backend version and size, the auto-sleep timeout, the last change, the owner, and the App ID.
Expand Down
2 changes: 2 additions & 0 deletions src/content/docs/data-apps/publish-and-share.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Share the app URL — found on the app's **Overview** tab (the **App URL** block

## Manage a deployed app

<!-- VERIFY(Michal Ševčík): on 2026-09-29 a Python/JS app built with kbagent (project 264, App ID 74021867) showed Edit with Kai in the header, running and stopped, and Duplicate with Kai, Automate, Debug mode and Delete app in the ⋯ menu while stopped, not Modify with Kai and Copy app. The 2026-07-10 screenshots of the Kai-built app 74016144 show Modify with Kai and Copy app. Renamed since, or does it depend on who built the app? -->

From the app's header you can **Modify with Kai**, **Open App**, and **Start App** / **Redeploy App** depending on its state. The **⋯** menu holds the rest: **Copy app**, **Automate** (add it to a flow), **Debug mode** and **Delete app**, plus **Suspend app** while the app is running. [Operate and update an app](/data-apps/operate/) walks through each one.

![The app header with Modify with Kai / Open App / Start App and the ⋯ menu open showing Copy app, Automate, Debug mode, and Delete app](/data-apps/app-actions-menu.png)
Expand Down
4 changes: 3 additions & 1 deletion src/content/docs/data-apps/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Manage a deployed app from its actions menu.
![Actions menu](/data-apps/manage-redeploy.png)

- **Deploy App** — starts the app. Once the deployment job finishes, open the app's public URL with **Open App**.
- **Open App** — opens a new window with your app.
- **Open App** — opens your app in a new window. On a running app behind a password, it shows a dialog first, with the app's address and the password, each with a copy button; the dialog's **Open app** button opens the app.
- **Redeploy App** — apply changes made in the app configuration (they take effect only after a redeploy).
- **Start App** — brings a stopped app back with the same settings.
- **Modify with Kai** — opens the Builder, on apps Kai built.
Expand All @@ -190,6 +190,8 @@ Manage a deployed app from its actions menu.
- **Debug mode** — runs the app with extra diagnostics.
- **Delete app** — stops the deployment and deletes its configuration.

<!-- VERIFY(Michal Ševčík): on 2026-09-29 a Python/JS app built with kbagent (project 264, App ID 74021867) showed Edit with Kai in the header, running and stopped, and Duplicate with Kai, Automate, Debug mode and Delete app in the ⋯ menu while stopped, not Modify with Kai and Copy app. The 2026-07-10 screenshots of the Kai-built app 74016144 show Modify with Kai and Copy app. Renamed since, or does it depend on who built the app? The Open App dialog was seen on the same app while it ran; VERIFY(Nikita) that apps Kai built show it too. -->

Which of these the header and the **⋯** menu offer depends on the app's state. [Operate and update an app](/data-apps/operate/) walks through them in the order you meet them.

## Sleep and resume
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/data-apps/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Most app problems fall into a handful of patterns. Find where the evidence is fi

## Sign-in problems

- **Basic (Password):** the password is on the app's configuration page next to **Open App** once the app is deployed.
- **Basic (Password):** once the app is deployed, click **Open App** on its configuration page and copy the password from the dialog.
- **OIDC:** the Google, Entra, Okta and Auth0 tabs on [Authentication](/data-apps/authentication/) each end with an "If sign-in fails" list covering that provider's error texts, redirect-URI mismatches, and audience settings.
- **GitHub, GitLab, JumpCloud:** each has its own required fields and its own optional restrictions, which are the first thing to check when the right person is turned away. GitHub filters by organization, team, repository and allowed users; GitLab by group, project and allowed roles; JumpCloud by allowed roles. All three are in their sections of [Authentication](/data-apps/authentication/).
- **Nobody can get in after you changed the authentication settings:** the change takes effect on the next start. Click **Redeploy App** (running app) or **Start App** (stopped app).
Expand Down
Loading