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.98.0",
"version": "0.99.0",
"source": "./plugins/kbagent",
"description": "DEPRECATED — install from keboola/ai-kit: /plugin marketplace add keboola/ai-kit && /plugin install kbagent@keboola-claude-kit — AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, sync configs as files, manage dev branches, and debug SQL in workspaces",
"category": "development"
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ kbagent storage truncate-table --project NAME --table-id ID [--table-id ...] [--
kbagent storage delete-column --project NAME --table-id ID --column COL [--column ...] [--force] [--dry-run] [--yes] [--branch ID]
kbagent storage delete-bucket --project NAME --bucket-id ID [--bucket-id ...] [--force] [--dry-run] [--yes] [--branch ID]
kbagent storage swap-tables --project NAME --table-id ID --target-table-id ID --branch ID [--dry-run] [--yes] [--timeout SECONDS]
# --timeout SECONDS on create-table and swap-tables (since vNEXT, #713): both halves
# --timeout SECONDS on create-table and swap-tables (since 0.99.0, #713): both halves
# of the repartition path move real data yet used to inherit the 60s metadata-job
# budget, so a large BigQuery table reported STORAGE_JOB_TIMEOUT for a job that was
# still running and would succeed. Default is now 300s on both. A local timeout
Expand Down Expand Up @@ -825,7 +825,7 @@ kbagent token refresh --project NAME --token-id ID [--yes]
# is persisted. `permissions show` / `kbagent doctor` also generalized: they now flag ANY
# persisted pattern matching zero known operations, not only the retired tool:* namespace.
# PermissionEngine itself stays lenient at evaluation time -- only `permissions set` is strict.
# (since vNEXT, #655) The policy also firewalls the WHOLE `kbagent serve` REST surface: every
# (since 0.99.0, #655) The policy also firewalls the WHOLE `kbagent serve` REST surface: every
# route is classified in server/route_permissions.py and checked by one app-level dependency
# against the SERVED config dir's policy -> HTTP 403 error_code PERMISSION_DENIED, the same
# code the CLI exits on. On 0.98.0 and older only /auth/* (0.90.1+) and /merge-requests/*
Expand All @@ -841,7 +841,7 @@ kbagent token refresh --project NAME --token-id ID [--yes]
# the handlers of scope PUT, models, items/{kind} (per-kind leaf key), import, promote
# and build check `<key> --scope organization` (FLAG_ESCALATIONS) for a typed OR an
# inherited organization scope, like the CLI.
# `GET /permissions/show` (serve, since vNEXT) reports the EFFECTIVE policy (persisted block
# `GET /permissions/show` (serve, since 0.99.0) reports the EFFECTIVE policy (persisted block
# merged with the daemon's --deny-* flags); read-only by design -- no REST route can widen
# the policy that constrains it, so `permissions set|reset` stay terminal actions on the host.
kbagent permissions list [--category read|write|destructive|admin]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ On Windows, run the PowerShell install from the Windows section above as the sec

If `uv tool list` shows `keboola-cli` next to `keboola-agent-cli`, the update already worked. kbagent runs from `keboola-cli` and the old entry does no harm. Do not remove the old entry on its own: `uv tool uninstall keboola-agent-cli` also deletes the `kbagent` executable that `keboola-cli` uses, and the shell then reports `command not found`. To restore the executable, run `uv tool install --force --reinstall "keboola-cli[server] @ https://github.com/keboola/cli/releases/download/v<version>/keboola_cli-<version>-py3-none-any.whl"` with the latest version number from the [releases page](https://github.com/keboola/cli/releases/latest).

A failed startup update prints the last line of the uv output as `Cause:` (since vNEXT), then the recovery command.
A failed startup update prints the last line of the uv output as `Cause:` (since 0.99.0), then the recovery command.

## Web UI (optional)

Expand Down
10 changes: 5 additions & 5 deletions docs/web-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ read/audit half of `kbagent auth` *(since v0.90.1)* — `login` /
Going the other way, several CLI surfaces are deliberately CLI-only: `sync`
(filesystem-local by design), `init`, and the *write* half of `permissions`
(`set` / `reset`). The mirrors still considered missing are tracked in #657.
`GET /permissions/show` *(since vNEXT)* is the read half — see "The session
`GET /permissions/show` *(since 0.99.0)* is the read half — see "The session
firewall applies to every route" below.

Auto-generated OpenAPI spec at `/openapi.json`, Swagger UI at `/docs`.
Expand Down Expand Up @@ -486,7 +486,7 @@ including the `kbc-session://` sentinel.

`/auth/*` was the **first router to enforce the permission policy** (0.90.1):
every route above declares `Depends(require_permission(...))` at its own call
site. Since vNEXT that is no longer special — *every* route on the server is
site. Since 0.99.0 that is no longer special — *every* route on the server is
enforced (see "The session firewall applies to every route" below) — and the
three inline declarations survive only as the per-route override form.

Expand All @@ -501,7 +501,7 @@ you reach for a flag:
classified `admin`, and `--deny-writes` appends `cli:write`, which spans
write + destructive + admin — so the CLI callback blocks the `serve` command
itself (exit code 6, `Operation 'serve' is blocked by the active permission
policy`). `--deny-destructive` does start the server, and since vNEXT it
policy`). `--deny-destructive` does start the server, and since 0.99.0 it
blocks every destructive route (no `/auth/*` operation is destructive).
- **Use a persisted policy instead.** Run, on the host, in a real terminal
(`permissions set` requires a typed confirmation code — there is no `--yes`):
Expand Down Expand Up @@ -576,14 +576,14 @@ for `serve` to use.

### The session firewall applies to every route

*(since vNEXT — issue #655)*
*(since 0.99.0 — issue #655)*

`PermissionEngine` used to be built only in the Typer callback, so a persisted
`permissions set --mode deny` policy — and both `--deny-writes` and
`--deny-destructive` — protected the CLI process and nothing else. `kbagent
serve` exposed every route, `DELETE /storage/buckets` included, behind a single
all-or-nothing bearer token. 0.90.1 closed that for `/auth/*` and 0.94.0 for
`/merge-requests/*`; vNEXT closes it for the whole surface.
`/merge-requests/*`; 0.99.0 closes it for the whole surface.

**How it works.** One app-level dependency (`server/route_permissions.py`) runs
on every request, looks the matched route up by `(method, path template)` in
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.98.0",
"version": "0.99.0",
"description": "AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, sync configs as files, manage dev branches, and debug SQL in workspaces",
"author": {
"name": "Keboola",
Expand Down
6 changes: 3 additions & 3 deletions plugins/kbagent/agents/keboola-expert.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ been retired, so its absence is NOT a promise (see §1 Rule 6).
| Create typed table with native types | `kbagent storage create-table --column pk:VARCHAR(40) --column amount:NUMBER(18,2) --not-null pk --default amount=0` | -- | re-creating via raw REST to `tables-definition` |
| Add one column to an existing table | `kbagent storage add-column --project P --table-id in.c-foo.data --column status:VARCHAR(20) [--not-null] [--default active]` -- synchronous, same `name:TYPE(length)` grammar as `create-table` | -- | re-creating the whole table to add a field (loses data / PK / dependents) |
| Promote a rebuilt table into the original name | `kbagent storage swap-tables --project P --table-id in.c-foo.data --target-table-id in.c-foo.data_new --branch <ID> --yes` -- async `tableSwap`; the service refuses without a branch (any branch, prod included) | -- | renaming or delete + re-upload (loses history; every downstream config needs rewriting) |
| Repartition / recluster a populated BigQuery table | `kbagent storage create-table --source-table-id <src> --time-partitioning-type DAY --time-partitioning-field created_at --clustering-field tenant_id` (BigQuery only) to copy the data into the new layout, then `swap-tables` to flip it in. `--source-table-id` derives the schema, so `--column` is forbidden. Range partitioning: all four `--range-partitioning-*` flags together. VERIFY the result with `storage table-detail --json` -> `.definition.timePartitioning` / `.clustering` (0.88.0+) -- `create-table` only echoes the layout you REQUESTED, so it proves nothing. Both steps take `--timeout SECONDS` (vNEXT+, default 300); a `STORAGE_JOB_TIMEOUT` (exit 4, `retryable: false`) means kbagent stopped WATCHING, not that the job failed -- follow it with `storage job-detail --job-id ID --wait`, never re-run: a repeated swap swaps the tables back, a repeated create starts a second copy. See [storage-types-workflow.md](../skills/kbagent/references/storage-types-workflow.md) | -- | `CREATE TABLE ... AS SELECT` in a workspace (drops NOT NULL + primary key) |
| Repartition / recluster a populated BigQuery table | `kbagent storage create-table --source-table-id <src> --time-partitioning-type DAY --time-partitioning-field created_at --clustering-field tenant_id` (BigQuery only) to copy the data into the new layout, then `swap-tables` to flip it in. `--source-table-id` derives the schema, so `--column` is forbidden. Range partitioning: all four `--range-partitioning-*` flags together. VERIFY the result with `storage table-detail --json` -> `.definition.timePartitioning` / `.clustering` (0.88.0+) -- `create-table` only echoes the layout you REQUESTED, so it proves nothing. Both steps take `--timeout SECONDS` (0.99.0+, default 300); a `STORAGE_JOB_TIMEOUT` (exit 4, `retryable: false`) means kbagent stopped WATCHING, not that the job failed -- follow it with `storage job-detail --job-id ID --wait`, never re-run: a repeated swap swaps the tables back, a repeated create starts a second copy. See [storage-types-workflow.md](../skills/kbagent/references/storage-types-workflow.md) | -- | `CREATE TABLE ... AS SELECT` in a workspace (drops NOT NULL + primary key) |
| Re-seed a table without losing schema / PK / dependents | `kbagent storage truncate-table --project P --table-id in.c-foo.data [--dry-run] [--yes]` -- rows only, uniformly async-via-job on every branch; batch via repeated `--table-id` | -- | drop + recreate (loses descriptions, PK, sharing edges, and breaks every downstream reference); deleting rows via raw SQL in a workspace (bypasses the Storage audit trail) |
| Back up / restore a table around a risky change | `kbagent storage snapshot-create --table-id ...` then, to restore, `kbagent storage table-from-snapshot --snapshot-id ID --bucket-id B --name NEW` -- restore is always a NEW table (`--name` REQUIRED, no overwrite): verify it, then `swap-tables`. See [snapshot-workflow.md](../skills/kbagent/references/snapshot-workflow.md) | `storage snapshots` / `snapshot-detail` to find one | exporting to CSV as a "backup" (loses column types + PK); `create-table --snapshot-id` (not a thing) |
| Debug a failed job | `kbagent job detail --project P --job-id J --log-tail-lines 200 --json` | `kbagent workspace from-transformation` for SQL repro (on a dev branch it reads the branch's transformation only since 0.96.1, #807; older versions load production's input mapping) | "I think the issue is..." without reading logs; a new job run only to see its logs (a writer can send its data again) |
Expand Down Expand Up @@ -307,7 +307,7 @@ its absence is NOT a promise the entry is version-independent (see §1 Rule 6).
branch's tree -- `sync pull` to re-target, never push. Since 0.96.1 (#792)
`sync push` deletes only with `--force` (else `skipped_deletions`), and a
`- REMOTE DELETED` diff line = deleted on the remote, push never re-creates
it: `sync pull`, or `config restore` to keep it. vNEXT+: a `CONFLICT` on a
it: `sync pull`, or `config restore` to keep it. 0.99.0+: a `CONFLICT` on a
file with a config id and no manifest entry = no baseline: keep the edit
aside, `sync pull --theirs`, re-apply, push (sync-workflow.md). An
`ENCRYPTION_FAILED` push wrote nothing: fix the cause, push again. `sync
Expand Down Expand Up @@ -372,7 +372,7 @@ its absence is NOT a promise the entry is version-independent (see §1 Rule 6).
grep rules nothing out). `create` defaults it ON at **0.87.0+**; <= 0.86.0
patch + redeploy.
- **Managed-repo app `running` with no `WORKSPACE_ID`** (`data-app detail`
shows `Git: {}`): vNEXT+ `deploy` backfills `parameters.dataApp.git`; pass
shows `Git: {}`): 0.99.0+ `deploy` backfills `parameters.dataApp.git`; pass
`--git-branch` with the branch the code is on (an app with runs refuses
without it). Older: merge the block by hand, redeploy. data-app-workflow.md.
- **`data-app password` keeps the password out of the chat (0.96.1+)**: it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ has an account and should create the project in the Keboola UI instead.
redirect actually arrives, there is no fallback -- an error past that
point is terminal (e.g. a `state` mismatch, or the exchange itself
failing) and login simply fails; re-run the command.
- Before the browser wait starts, the CLI prints a notice (since vNEXT;
- Before the browser wait starts, the CLI prints a notice (since 0.99.0;
to stderr with `--json`): it waits up to 115 s for the browser to
return. If the browser shows the project list and not "Login
complete", the sign-in cannot return: press Ctrl+C and run the
Expand Down
Loading
Loading