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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"plugins": [
{
"name": "kbagent",
"version": "0.28.0",
"version": "0.29.0",
"source": "./plugins/kbagent",
"description": "AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, call MCP tools, manage dev branches, and debug SQL in workspaces",
"category": "development"
Expand Down
10 changes: 5 additions & 5 deletions docs/TUTORIAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ use `org setup --project-ids`. kbagent creates a Storage API token in
each listed project and registers them all locally, in parallel.

```bash
# Interactive (default since v0.28.0): kbagent prompts for the Manage API
# Interactive (default since v0.29.0): kbagent prompts for the Manage API
# token on stdin. No env var, no shell history.
kbagent org setup \
--project-ids 901,9621,10539 \
Expand Down Expand Up @@ -139,7 +139,7 @@ Flags worth knowing:
The command is **idempotent**: running it again skips projects that
are already registered. Safe to re-run after adding new project IDs.

**Security note (since v0.28.0)**: `KBC_MANAGE_API_TOKEN` is **ignored
**Security note (since v0.29.0)**: `KBC_MANAGE_API_TOKEN` is **ignored
by default** -- the env var is read only when the top-level
`--allow-env-manage-token` flag is passed. Without the flag, kbagent
prompts on stdin (hidden input). kbagent never accepts the token as a
Expand All @@ -156,7 +156,7 @@ If you are an org admin with a Manage API token, register **every**
project in an organization in one shot:

```bash
# Interactive (default since v0.28.0):
# Interactive (default since v0.29.0):
kbagent org setup \
--org-id 123 \
--url https://connection.keboola.com \
Expand Down Expand Up @@ -876,7 +876,7 @@ kbagent --json data-app create \
deploy. To retrieve it:

```bash
# Manage API token: interactive prompt by default (since v0.28.0). For CI,
# Manage API token: interactive prompt by default (since v0.29.0). For CI,
# add `--allow-env-manage-token` and set KBC_MANAGE_API_TOKEN in env.
kbagent --json data-app password \
--project prod --app-id 12345678 \
Expand Down Expand Up @@ -967,7 +967,7 @@ shapes, and the `--hint client|service` code-generation contract, see
| `kbagent: command not found` after `uv tool install` | Ensure `~/.local/bin` (or uv's tool dir) is on your PATH. `uv tool update-shell` can help. |
| `kbagent doctor` reports `warn` for plugin | Run the two `/plugin` commands shown in the warning, from inside Claude Code. |
| Plugin version != CLI version | In Claude Code: `/plugin update kbagent`. |
| `org setup` exits 2 with `Warning: KBC_MANAGE_API_TOKEN found in environment but ignored` | Default-deny since v0.28.0 -- pass `--allow-env-manage-token` (top-level flag) to opt in to env resolution, or run interactively to use the prompt. |
| `org setup` exits 2 with `Warning: KBC_MANAGE_API_TOKEN found in environment but ignored` | Default-deny since v0.29.0 -- pass `--allow-env-manage-token` (top-level flag) to opt in to env resolution, or run interactively to use the prompt. |
| `org setup` fails with `401 Unauthorized` | Your manage token is wrong for this stack or role. Manage tokens are stack-specific and require the right scope. |
| `org setup --org-id` fails with `403` | You are not an org admin. Use `--project-ids` with a Personal Access Token instead (works for any project member). |
| Changes from `kbagent config update` do not show in UI | You are on a dev branch. Run `kbagent branch list` and `kbagent project current` to verify the active branch; changes in a dev branch merge to production only via the UI merge step (`kbagent branch merge` returns the merge URL). |
Expand Down
2 changes: 1 addition & 1 deletion docs/e2e-scenarios.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ Skipped if `keboola-mcp-server` is not installed.

| Command | Reason |
|---------|--------|
| `project refresh` | Requires Manage API token (interactive prompt by default since v0.28.0; `--allow-env-manage-token` + `KBC_MANAGE_API_TOKEN` for non-interactive runners) |
| `project refresh` | Requires Manage API token (interactive prompt by default since v0.29.0; `--allow-env-manage-token` + `KBC_MANAGE_API_TOKEN` for non-interactive runners) |
| `org setup` | Requires Manage API token (same prompt-or-flag as above) + destructive (registers projects in org) |
| `sharing share/unshare` | Requires org-level permissions or second project |
| `sharing link/unlink` | Requires shared bucket from another project |
Expand Down
2 changes: 1 addition & 1 deletion plugins/kbagent/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kbagent",
"version": "0.28.0",
"version": "0.29.0",
"description": "AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, call MCP tools, manage dev branches, and debug SQL in workspaces",
"author": {
"name": "Keboola",
Expand Down
50 changes: 25 additions & 25 deletions plugins/kbagent/agents/keboola-expert.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ a critical failure.
need 0.27.0+, `config update` script[] auto-normalize against #245
trap needs 0.28.0+, `storage swap-tables` needs 0.28.0+,
env-var manage-token auth for `org setup` / `project refresh` /
`data-app password` needs 0.28.0+ with `--allow-env-manage-token`
(the env var is default-deny on 0.28.0+),
`data-app password` needs 0.29.0+ with `--allow-env-manage-token`
(the env var is default-deny on 0.29.0+),
`project invite` / `project member-*` / `project invitation-*`
need 0.26.1+,
`data-app secrets-* / validate-repo` need 0.28.0+,
need 0.29.0+,
`data-app secrets-* / validate-repo` need 0.29.0+,
`storage retype` is a future composite), you
MUST refuse the task and return a handoff message to the parent:
`"Cannot proceed safely on kbagent <version>. Missing: <commands>.
Expand Down Expand Up @@ -112,20 +112,20 @@ a critical failure.
| Roll out a new code or config version on a data app | `kbagent data-app deploy --project P --app-id N --wait` (0.27.0+) -- always sends the §9 trio | `kbagent --hint client data-app deploy ...` to inspect the generated `patch_app(desired_state=, config_version=, restart_if_running=True)` call | `tool call update_config` then `tool call run_component` (data apps are not jobs -- the queue runner does not deploy them) |
| Wake an auto-suspended data app | `kbagent data-app start --project P --app-id N` (0.27.0+) -- does NOT bump configVersion | hitting the app's URL (auto-restart triggers a 30-60s cold boot) | `kbagent data-app deploy` (overkill -- bumps the deployed configVersion unnecessarily) |
| Pause a running data app | `kbagent data-app stop --project P --app-id N` (0.27.0+) | -- | `kbagent data-app delete` (irreversible; cascades to Storage config) |
| Read the simpleAuth password for a password-gated app | `kbagent data-app password --project P --app-id N` (0.27.0+) -- needs Manage API token (interactive prompt by default; `--allow-env-manage-token` + `KBC_MANAGE_API_TOKEN` for CI on 0.28.0+) | -- | trying to "rotate" the password (not supported by the API; delete + recreate to mint a new one) |
| Read the simpleAuth password for a password-gated app | `kbagent data-app password --project P --app-id N` (0.27.0+) -- needs Manage API token (interactive prompt by default; `--allow-env-manage-token` + `KBC_MANAGE_API_TOKEN` for CI on 0.29.0+) | -- | trying to "rotate" the password (not supported by the API; delete + recreate to mint a new one) |
| Tear down a data app | `kbagent data-app delete --project P --app-id N` (0.27.0+) -- cascades to Storage config; URL retired | -- | manually `tool call delete_config keboola.data-apps` while leaving the deployment record orphaned |
| Invite a user to a project (single) | `kbagent project invite --project P --email E --role admin\|guest\|readOnly\|share` (0.26.1+) | raw `requests.post(/manage/projects/{id}/invitations)` only if version-gated out | `kbagent project invite` without `KBC_MANAGE_API_TOKEN` set; passing manage token via CLI flag |
| Invite many users (bulk) | `kbagent project invite --from-csv FILE [--default-role guest] [--workers N] [--dry-run]` (0.26.1+) | `--hint client` to generate a parallel script using `ManageClient` | per-row shell loop calling the CLI -- defeats the parallelism + idempotency the service already does |
| List active project members | `kbagent project member-list --project P [--include-pending]` (0.26.1+) | `tool call run_sync_action` against the Manage API | reading `.kbagent/config.json` to infer membership (it only stores the local user's token) |
| List pending invitations | `kbagent project invitation-list --project P` (0.26.1+) | -- | -- |
| Cancel a pending invitation | `kbagent project invitation-cancel --project P --email E --yes` (0.26.1+) | `--invitation-id ID` if email lookup is ambiguous | DELETE via raw HTTP without going through the service layer |
| Remove an active member | `kbagent project member-remove --project P --email E --yes` (0.26.1+, **destructive**) | `--hint client` for a script that removes by user_id directly | calling `member-remove` without `--yes` in non-interactive contexts (it will prompt and hang) |
| Change a member's role | `kbagent project member-set-role --project P --email E --role admin\|guest\|readOnly\|share` (0.26.1+) | -- | `PUT /manage/projects/{id}/users/{userId}` -- the API rejects PUT with 404, the kbagent client correctly uses **PATCH** |
| Set / rotate app-runtime secrets | `kbagent data-app secrets-set --project P --app-id N --secret '#KEY=VAL'` (0.28.0+) then `data-app deploy --wait` -- per-project KMS encryption, fail-closed, never auto-deploys | `kbagent encrypt values --component-id keboola.data-apps` + `tool call update_config` -- ONLY if you need to write secrets to a different shape than `parameters.dataApp.secrets` | raw `POST` to encryption + Storage without read-modify-write -- you will clobber sibling keys nested under `parameters.dataApp.secrets` (Storage `merge=True` is shallow at the top level only) |
| Inspect what secrets are set on a data app | `kbagent data-app secrets-list --project P --app-id N` (0.28.0+) -- metadata only, never decrypts | `tool call get_configs --component_id keboola.data-apps` then read `parameters.dataApp.secrets` keys (raw dict, no env-var derivation, may leak ciphertext into output) | trying to decrypt -- the Encryption API has no decrypt endpoint, the CLI cannot decrypt under any branch |
| Confirm one secret is present | `kbagent data-app secrets-get --project P --app-id N --key '#KEY'` (0.28.0+) -- returns metadata only | -- | trying to extract the plaintext value (impossible by design; not a CLI gap) |
| Remove a secret from a data app | `kbagent data-app secrets-remove --project P --app-id N --key '#KEY' --yes` (0.28.0+) -- idempotent; missing keys exit 0 with `removed: 0` | `tool call update_config` with the secrets sub-dict deleted -- ONLY for batch removes that need a custom change description | `kbagent config update --set 'parameters.dataApp.secrets={}'` -- replaces the whole sub-dict, dropping every secret instead of just the named ones |
| Pre-flight a data-app repo before create | `kbagent data-app validate-repo --git-repo URL --type python-js [--git-pat-env VAR]` (0.28.0+) -- BLOCKING / WARN / OK with help-doc citations; ≤5 GitHub API calls regardless of repo size | git-clone the repo locally and inspect by hand | `data-app create --dry-run` (only shows the request bodies; does not validate repo structure) |
| Invite a user to a project (single) | `kbagent project invite --project P --email E --role admin\|guest\|readOnly\|share` (0.29.0+) | raw `requests.post(/manage/projects/{id}/invitations)` only if version-gated out | `kbagent project invite` without `KBC_MANAGE_API_TOKEN` set; passing manage token via CLI flag |
| Invite many users (bulk) | `kbagent project invite --from-csv FILE [--default-role guest] [--workers N] [--dry-run]` (0.29.0+) | `--hint client` to generate a parallel script using `ManageClient` | per-row shell loop calling the CLI -- defeats the parallelism + idempotency the service already does |
| List active project members | `kbagent project member-list --project P [--include-pending]` (0.29.0+) | `tool call run_sync_action` against the Manage API | reading `.kbagent/config.json` to infer membership (it only stores the local user's token) |
| List pending invitations | `kbagent project invitation-list --project P` (0.29.0+) | -- | -- |
| Cancel a pending invitation | `kbagent project invitation-cancel --project P --email E --yes` (0.29.0+) | `--invitation-id ID` if email lookup is ambiguous | DELETE via raw HTTP without going through the service layer |
| Remove an active member | `kbagent project member-remove --project P --email E --yes` (0.29.0+, **destructive**) | `--hint client` for a script that removes by user_id directly | calling `member-remove` without `--yes` in non-interactive contexts (it will prompt and hang) |
| Change a member's role | `kbagent project member-set-role --project P --email E --role admin\|guest\|readOnly\|share` (0.29.0+) | -- | `PUT /manage/projects/{id}/users/{userId}` -- the API rejects PUT with 404, the kbagent client correctly uses **PATCH** |
| Set / rotate app-runtime secrets | `kbagent data-app secrets-set --project P --app-id N --secret '#KEY=VAL'` (0.29.0+) then `data-app deploy --wait` -- per-project KMS encryption, fail-closed, never auto-deploys | `kbagent encrypt values --component-id keboola.data-apps` + `tool call update_config` -- ONLY if you need to write secrets to a different shape than `parameters.dataApp.secrets` | raw `POST` to encryption + Storage without read-modify-write -- you will clobber sibling keys nested under `parameters.dataApp.secrets` (Storage `merge=True` is shallow at the top level only) |
| Inspect what secrets are set on a data app | `kbagent data-app secrets-list --project P --app-id N` (0.29.0+) -- metadata only, never decrypts | `tool call get_configs --component_id keboola.data-apps` then read `parameters.dataApp.secrets` keys (raw dict, no env-var derivation, may leak ciphertext into output) | trying to decrypt -- the Encryption API has no decrypt endpoint, the CLI cannot decrypt under any branch |
| Confirm one secret is present | `kbagent data-app secrets-get --project P --app-id N --key '#KEY'` (0.29.0+) -- returns metadata only | -- | trying to extract the plaintext value (impossible by design; not a CLI gap) |
| Remove a secret from a data app | `kbagent data-app secrets-remove --project P --app-id N --key '#KEY' --yes` (0.29.0+) -- idempotent; missing keys exit 0 with `removed: 0` | `tool call update_config` with the secrets sub-dict deleted -- ONLY for batch removes that need a custom change description | `kbagent config update --set 'parameters.dataApp.secrets={}'` -- replaces the whole sub-dict, dropping every secret instead of just the named ones |
| Pre-flight a data-app repo before create | `kbagent data-app validate-repo --git-repo URL --type python-js [--git-pat-env VAR]` (0.29.0+) -- BLOCKING / WARN / OK with help-doc citations; ≤5 GitHub API calls regardless of repo size | git-clone the repo locally and inspect by hand | `data-app create --dry-run` (only shows the request bodies; does not validate repo structure) |

If the table does not cover the user's task, **ask clarifying
questions** instead of guessing. Returning a targeted question is a
Expand Down Expand Up @@ -201,7 +201,7 @@ success, not a failure.
verification payload but do not treat it as a failure signal.
Production writes never materialize anything.

- **`project invite` "already invited / already member" is a no-op, not a failure** (0.26.1+):
- **`project invite` "already invited / already member" is a no-op, not a failure** (0.29.0+):
Re-inviting a user the project already knows returns HTTP 400 from the
Manage API. kbagent normalises both "...already been invited..." and
"...already a member..." to `status="noop"` with a `note` field, exit 0.
Expand All @@ -210,15 +210,15 @@ success, not a failure.
toward `noop`, not `failed`, in the summary; surface that distinction
to the user when reporting bulk results.

- **`project invite --from-csv` ordering is non-deterministic** (0.26.1+):
- **`project invite --from-csv` ordering is non-deterministic** (0.29.0+):
Bulk invitation parallelises via `ThreadPoolExecutor` (default 8 workers).
The `rows[]` array in the JSON result is in completion order, not CSV
order. When reporting per-row outcomes to the user, **match by `email`,
not by index**. Partial-success exits 0 with `failed > 0` reflected in
the JSON -- treat that as a soft failure that needs review, not a
catastrophe.

- **`project member-set-role` uses PATCH, not PUT** (0.26.1+): The Manage
- **`project member-set-role` uses PATCH, not PUT** (0.29.0+): The Manage
API endpoint is `PATCH /manage/projects/{id}/users/{userId}` with
`{"role": "..."}`. PUT returns 404 even on real members. kbagent's
`ManageClient.update_project_member_role` emits PATCH; if you write a
Expand Down Expand Up @@ -298,13 +298,13 @@ success, not a failure.
the round-trip does not return a `KBC::Project*` ciphertext.

- **`data-app create --auth public` writes the canonical `noneProxyAuthorization`
shape** (0.28.0+, fixes a v0.27.0 silent-503 bug): v0.27.0 wrote NO
shape** (0.29.0+, fixes a v0.27.0 silent-503 bug): v0.27.0 wrote NO
`authorization` block when `--auth public` -- the Keboola app-proxy
refused to route (HTTP 503) and the UI's Authentication Type selector
showed blank. v0.28.0 writes
showed blank. v0.29.0 writes
`{auth_providers: [], auth_rules: [{type: pathPrefix, value: /, auth_required: false}]}`
per the kbc-ui's `noneProxyAuthorization` constant. If a user reports a
v0.27.0 public app returning 503, the fix is to recreate on 0.28.0+
v0.27.0 public app returning 503, the fix is to recreate on 0.29.0+
(the URL is bound to the deployment record so it retires either way),
OR to patch the existing config in-place via
`kbagent config update --component-id keboola.data-apps --config-id ID
Expand All @@ -313,7 +313,7 @@ success, not a failure.
JumpCloud / Auth0) are not yet exposed by the CLI; tracked as a
follow-up issue.

- **`data-app secrets-* metadata-only`** (0.28.0+): `secrets-get` NEVER
- **`data-app secrets-* metadata-only`** (0.29.0+): `secrets-get` NEVER
echoes the decrypted plaintext under any branch -- the Encryption API
is one-way and the CLI does not attempt to decrypt. NOT_FOUND on an
absent key never enumerates sibling keys (avoids leaking neighbour
Expand All @@ -328,7 +328,7 @@ success, not a failure.
`parameters.dataApp.secrets`).

- **`data-app validate-repo` is GitHub-only**, `--type python-js` only
(0.28.0+): pre-flight Golden-Rule check via the GitHub Trees+Contents
(0.29.0+): pre-flight Golden-Rule check via the GitHub Trees+Contents
API. Total <=5 calls regardless of repo size. Use BEFORE
`data-app create` so the operator does not burn a deploy cycle on a
misconfigured repo. WARNs are advisory unless `--strict` is set;
Expand Down
2 changes: 1 addition & 1 deletion plugins/kbagent/skills/kbagent/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ kbagent --json project add --project prod --url https://connection.keboola.com -

# Or bulk-onboard from organization (org admin)
# Manage token: interactive prompt by default; for CI add --allow-env-manage-token
# alongside KBC_MANAGE_API_TOKEN (required since v0.28.0).
# alongside KBC_MANAGE_API_TOKEN (required since v0.29.0).
KBC_MANAGE_API_TOKEN=xxx kbagent --allow-env-manage-token --json org setup --org-id 123 --url https://connection.keboola.com --yes

# Or onboard specific projects (any project member, uses Personal Access Token)
Expand Down
Loading