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.96.2",
"version": "0.97.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
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,7 @@ kbagent semantic-layer reference-data set --project P [--model M] --dimension D
kbagent semantic-layer reference-data delete --project P --id ID [--yes]
# Alias: `kbagent sl ...` (hidden) is equivalent to `kbagent semantic-layer ...`.
# semantic-layer READS work with any valid, non-disabled, non-expired Storage token
# (vNEXT, PSGO-282): the Metastore no longer requires a master token for GET/List. WRITES
# (0.97.0, PSGO-282): the Metastore no longer requires a master token for GET/List. WRITES
# (add/edit/remove/import/promote/build/scope add|remove|set) still need a project-admin token
# (master token or any admin-role user token) -- a non-admin token 403s on the write. Before
# PSGO-282 the Metastore's auth gate rejected EVERY valid non-master token, including reads,
Expand All @@ -1139,7 +1139,7 @@ kbagent semantic-layer reference-data delete --project P --id ID [--yes]
# a safety net for a deployment that predates the fix. Other unexplained 401s anywhere map to
# AUTH_REJECTED instead of the false "Invalid or expired token" (INVALID_TOKEN stays for 401s
# that DO blame the credential). Version gate for this entry lives in gotchas.md -- `(since
# vNEXT)` cannot be written on these `# ` comment lines (check_version_gates.py parses them as
# 0.97.0)` cannot be written on these `# ` comment lines (check_version_gates.py parses them as
# ATX headings).

kbagent http get PATH [--timeout SECONDS]
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.96.2",
"version": "0.97.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
4 changes: 2 additions & 2 deletions plugins/kbagent/agents/keboola-expert.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ been retired, so its absence is NOT a promise (see §1 Rule 6).
| Call the running `kbagent serve` from a scheduled-agent subprocess | `kbagent http get/post/patch/delete <PATH>` -- uses the `KBAGENT_SERVE_URL` + `KBAGENT_SERVE_TOKEN` the scheduler injects; `http get /openapi.json` discovers endpoints | forking `kbagent <command>` (also fine -- `KBAGENT_CONFIG_DIR` is propagated) | `curl $KBAGENT_SERVE_URL/...` by hand (loses the auth header, error mapping and JSON formatting `kbagent http` adds) |
| Launch the web UI for an end-user | `kbagent serve --ui [--port PORT]` -- one FastAPI process mounts the bundled React SPA and sets an HttpOnly `kbagent_session` cookie, so SSE works with no token in the URL or JS heap | the legacy Vite + Node BFF dev flow (`web/README.md`) | inventing a `--token-in-url` flag; running uvicorn directly against the dist (the cookie bootstrap only fires from `serve --ui`) |
| Schedule / manage Agent Tasks | `kbagent agent <verb>` -- CRUD, `run [--stream]`, history, `test`/`cron-preview`/`prompt-improve`. Local-only; cron firing needs `kbagent serve`. See [agent-tasks-cli-workflow](../skills/kbagent/references/agent-tasks-cli-workflow.md) | `kbagent http <verb> /agents...` inside scheduled subprocesses | hand-editing `agents.json` |
| Read a semantic-layer model (models, metrics, datasets, constraints) | `kbagent --json semantic-layer show --project P [--model M] [--type metric\|dataset\|relationship\|constraint\|glossary]`; `model list`; `search-context` / `get-context` for glob/id lookup; `validate [--deep]` before trusting one. Any valid, non-disabled, non-expired Storage token works for reads (vNEXT, PSGO-282 -- the metastore no longer requires a master token for GET/List); a stale `MISSING_MASTER_TOKEN` on a plain read means an outdated kbagent still carrying the old reclassification, not a real gate | -- | hand-rolled `httpx` loops against `metastore.*.keboola.com` (bypasses retry/backoff and the kbagent error envelope) |
| Read a semantic-layer model (models, metrics, datasets, constraints) | `kbagent --json semantic-layer show --project P [--model M] [--type metric\|dataset\|relationship\|constraint\|glossary]`; `model list`; `search-context` / `get-context` for glob/id lookup; `validate [--deep]` before trusting one. Any valid, non-disabled, non-expired Storage token works for reads (0.97.0, PSGO-282 -- the metastore no longer requires a master token for GET/List); a stale `MISSING_MASTER_TOKEN` on a plain read means an outdated kbagent still carrying the old reclassification, not a real gate | -- | hand-rolled `httpx` loops against `metastore.*.keboola.com` (bypasses retry/backoff and the kbagent error envelope) |
| ANY semantic-layer write (add / edit / remove / import / promote / build / scope add|remove|set|request-create) | `kbagent semantic-layer export` FIRST (the metastore has no soft-delete and no version history -- the snapshot is the only restore path), then the write, `--dry-run` where offered. Needs a token whose Storage Admin role is `admin` on the project (a master token qualifies, but so does any project-admin user token as of PSGO-282) -- a non-admin token still gets `MISSING_MASTER_TOKEN`/403 on writes, just not on reads. `Read` [semantic-layer-workflow.md](../skills/kbagent/references/semantic-layer-workflow.md) before starting: it carries the per-verb recipes, the rename cascade and the promote classification | `semantic-layer diff` (`--project-a/-b` or `--file-a/-b`) to confirm what a write would change | raw metastore REST (no rollback, no orphan scan, no modelUUID rewrite); a write with no export taken |
| Share a semantic-layer object across projects, or make it org-wide | **ASK THE USER which project(s) before EVER passing `--scope organization\|targeted` (on `model create`/`add <kind>`) or running `scope set --scope organization`/`scope request-create` -- never guess or default to widening visibility.** Once the user names the target(s): `--scope targeted --target-project ALIAS\|ID` grants specific projects; `scope add\|remove --project P --type T --context-id ID --target-project ALIAS\|ID` adjusts an existing item's grants from the owning project (a merge), `scope set --target-project ...` / `--clear` replaces the list; org-wide needs `scope request-create` then an org-admin's `scope set --scope organization --yes` (preview with `--dry-run`) -- **irreversible, no downgrade endpoint, destructive-class**. `add <kind>` without `--scope` inherits its model's scope. `scope get --type T --context-id ID` shows the current state first. See [metastore-scope-workflow.md](../skills/kbagent/references/metastore-scope-workflow.md) | `scope request-list --type T` to find items an org-admin should act on | passing `--scope organization\|targeted` or running `scope set --scope organization` without the user having named the target project(s) first; assuming `--scope organization` succeeds on a non-admin token (it 403s -- creating directly at organization scope needs the SAME organization-admin role as elevating) |
| User asks to "log in" / authenticate via browser / register a session's projects | ATTENDED session + a background shell: run `kbagent auth login --device-code --stack URL --register-projects` in a **BACKGROUND** shell (capture stdout+stderr, human mode -- `--json` puts the panel on stderr), relay the verification URL + user code to the user, then poll `kbagent --json auth status` (exit 0 = signed in, exit 3 = not yet). The human's part is approving in the browser, not typing the command. No background shell -> hand the plain `auth login --stack URL --register-projects` to the user's terminal. To register projects from an EXISTING session, `kbagent auth register-projects --all` or `--project-id ID` is non-interactive and agent-safe | -- | running `auth login` in a FOREGROUND tool shell (~120 s timeout kills it mid-flight); running it unattended (nobody can approve); re-running it blind without checking `auth status` first (orphans a session); the flagless `register-projects` picker unattended; reading the token out of `auth.json`; using a numeric project id as an alias |
Expand Down Expand Up @@ -252,7 +252,7 @@ its absence is NOT a promise the entry is version-independent (see §1 Rule 6).
- A 401 whose body names something other than a bad credential now raises
`AUTH_REJECTED`; the semantic-layer family's opaque metastore 401
reclassified to `MISSING_MASTER_TOKEN` on a write against a non-admin
token (see its matrix row) -- since PSGO-282 (vNEXT) a plain read never
token (see its matrix row) -- since PSGO-282 (0.97.0) a plain read never
hits this at all, any valid token passes. Exit code is unchanged (3) for
all three -- code checking `error.code == "INVALID_TOKEN"` alone still
misses two real cases; accept all three before concluding the credential
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ MFA login sends `challenge: SOFTWARE_TOKEN_MFA` explicitly to fix a 404 on perso
## Semantic Layer (Metastore)

-Reads `KBAGENT_SERVE_URL` + `KBAGENT_SERVE_TOKEN` env vars. The scheduler auto-injects these (plus `KBAGENT_CONFIG_DIR`) into every AI-agent / `cli_command` subprocess. Outside a serve subprocess context the command refuses to run with exit code 2. **Inside a scheduled-agent task, prefer `kbagent http get /openapi.json` then a typed call over forking another `kbagent` CLI -- the HTTP path always sees the operator's live config (not the global `~/.config/keboola-agent-cli/` one).**
Manage Keboola metastore models -- datasets, metrics, relationships, constraints, glossary terms. Metastore URL derived from the stack URL by replacing `connection.` with `metastore.` (cloud/region-agnostic). Auth: same `X-StorageApi-Token` as Storage -- **reads work with any valid, non-disabled, non-expired token** (vNEXT, PSGO-282); **writes** still need a project-admin token (master, or any other admin-role user token) -- a non-admin token gets the opaque 401 `Failed to create project scope` on a write, which kbagent reclassifies to `MISSING_MASTER_TOKEN` with the remedy (since 0.92.0, #711; see [gotchas.md](gotchas.md)). Hidden alias: `kbagent sl ...` is equivalent to `kbagent semantic-layer ...`. See [semantic-layer-workflow.md](semantic-layer-workflow.md) for full recipes.
Manage Keboola metastore models -- datasets, metrics, relationships, constraints, glossary terms. Metastore URL derived from the stack URL by replacing `connection.` with `metastore.` (cloud/region-agnostic). Auth: same `X-StorageApi-Token` as Storage -- **reads work with any valid, non-disabled, non-expired token** (0.97.0, PSGO-282); **writes** still need a project-admin token (master, or any other admin-role user token) -- a non-admin token gets the opaque 401 `Failed to create project scope` on a write, which kbagent reclassifies to `MISSING_MASTER_TOKEN` with the remedy (since 0.92.0, #711; see [gotchas.md](gotchas.md)). Hidden alias: `kbagent sl ...` is equivalent to `kbagent semantic-layer ...`. See [semantic-layer-workflow.md](semantic-layer-workflow.md) for full recipes.

- `semantic-layer model list --project P` -- list all models in a project. Output: `{models: [{id, name, sql_dialect, description}, ...]}`. Use to disambiguate when `--model` is required and the project has more than one model.
- `semantic-layer model create --project P --name N [--description D] [--sql-dialect Snowflake]` -- create a new model. `--sql-dialect` defaults to `Snowflake`. Returns the new model UUID; subsequent commands accept either name or UUID via `--model`.
Expand Down Expand Up @@ -440,7 +440,7 @@ Manage Keboola metastore models -- datasets, metrics, relationships, constraints

### Scope / target-project grants / elevation (`scope` sub-app, PSGO-140)

*(since vNEXT)* Every semantic-layer item carries a visibility `scope`: `project` (owner project only), `organization` (every project in the org), or `targeted` (owner + an explicit target-project grant list). `--scope`/`--target-project` are accepted by `model create` and every `add <kind>` command above. With `--scope` omitted, `model create` makes a `project` model and `add <kind>` **inherits its model's scope and target projects**. `--target-project` takes a registered alias or a numeric project ID (repeatable or comma-separated; an alias must be on the owner's stack) and needs `--scope targeted` (else exit 2). With `--scope targeted` and no `--target-project`: on a real terminal an interactive checkbox picker runs over the other projects on the stack; in `--json`/non-interactive mode it fails fast with `INVALID_ARGUMENT` (exit 2). **Always ask the user which project(s) before passing `--scope organization|targeted`** -- see `keboola-expert.md`'s scope rule; `--scope organization` is irreversible and gated as destructive. `edit`, `import --overwrite` and `promote` update the item in place (PUT), so an organization/targeted item keeps its scope, grants, id and pending elevation request.
*(since 0.97.0)* Every semantic-layer item carries a visibility `scope`: `project` (owner project only), `organization` (every project in the org), or `targeted` (owner + an explicit target-project grant list). `--scope`/`--target-project` are accepted by `model create` and every `add <kind>` command above. With `--scope` omitted, `model create` makes a `project` model and `add <kind>` **inherits its model's scope and target projects**. `--target-project` takes a registered alias or a numeric project ID (repeatable or comma-separated; an alias must be on the owner's stack) and needs `--scope targeted` (else exit 2). With `--scope targeted` and no `--target-project`: on a real terminal an interactive checkbox picker runs over the other projects on the stack; in `--json`/non-interactive mode it fails fast with `INVALID_ARGUMENT` (exit 2). **Always ask the user which project(s) before passing `--scope organization|targeted`** -- see `keboola-expert.md`'s scope rule; `--scope organization` is irreversible and gated as destructive. `edit`, `import --overwrite` and `promote` update the item in place (PUT), so an organization/targeted item keeps its scope, grants, id and pending elevation request.

- `semantic-layer scope get --project P --type model|dataset|metric|relationship|constraint|glossary --context-id ID` -- show an item's current `scope`, `target_project_ids`, and any pending `scope_elevation_requested_at`.
- `semantic-layer scope add|remove --project P --type T --context-id ID --target-project ALIAS|ID [--target-project ...]` -- attach / detach target projects of a `--scope targeted` item (alias or numeric ID; repeatable or comma-separated). A client-side **merge** (read the grants, apply the delta, PUT) -- **not atomic** against a concurrent grant change. Refused (exit 2) from a project that does not own the item -- the server hides the grants from a non-owner, so use `scope set --target-project` there.
Expand Down
12 changes: 6 additions & 6 deletions plugins/kbagent/skills/kbagent/references/gotchas.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ Versioning convention:
check `kbagent project info` -> `is_master_token`, and register a
project-admin token (`kbagent project edit --token ...`). Do NOT escalate
this one to support -- it is by design.
- **(updated vNEXT -- PSGO-282, go-monorepo#596):** the "every call"
- **(updated 0.97.0 -- PSGO-282, go-monorepo#596):** the "every call"
part above is now history. The Metastore no longer requires a master
token for a plain read (`show`, `model list`, `search-context`,
`get-context`, `validate`, `diff`, `scope get`, `scope request-list`) --
Expand Down Expand Up @@ -1181,7 +1181,7 @@ record per member. Consequences an agent must internalize:
and `set` the whole thing back. There is no per-member endpoint.
- **It uses the metastore's real `PUT`** (revisioned update, `meta.revision`
increments, history preserved) when a record for that dimension already
exists — as `edit metric|…` does since vNEXT (before, those used DELETE+POST).
exists — as `edit metric|…` does since 0.97.0 (before, those used DELETE+POST).
A brand-new dimension is `POST`-ed.
- **The envelope `name` is the dimension, unique per project per type, so
the `set`/`get` lookup is project-wide.** Because the dimension name is the
Expand Down Expand Up @@ -1609,7 +1609,7 @@ events and emits a final `done` SSE frame mirroring the same record.

- `kbagent semantic-layer edit metric --new-name NEW` updates the metric
and ALSO every constraint whose `metrics[]` referenced the old name
(`metrics[]` rewritten to the new name). *(updated vNEXT)* Each is an
(`metrics[]` rewritten to the new name). *(updated 0.97.0)* Each is an
in-place `PUT` -- same id, scope, grants and revision history, and a failed
update changes nothing; before, every "edit" was a delete-then-create with
a rollback re-POST.
Expand All @@ -1635,7 +1635,7 @@ events and emits a final `done` SSE frame mirroring the same record.
recommend running `semantic-layer validate` immediately.
- **Partial-state envelope signal (updated v0.41.10 -- closes #294)**:
the cascade is per-item only (each constraint is updated on its own;
*since vNEXT* a PUT, so there is nothing to roll back), NOT whole-operation atomicity. If the
*since 0.97.0* a PUT, so there is nothing to roll back), NOT whole-operation atomicity. If the
metric rename succeeds but M of N dependent constraints fail to
repoint, the response envelope sets `partial_state: true` and
`recovery_hint: "<text pointing at validate + manual re-cascade>"`
Expand Down Expand Up @@ -5750,7 +5750,7 @@ workspaces".

## Metastore no longer requires a master token for reads (PSGO-282)

*(since vNEXT)* Every `semantic-layer` read (`show`, `model list`,
*(since 0.97.0)* Every `semantic-layer` read (`show`, `model list`,
`search-context`, `get-context`, `validate`, `diff`, `scope get`, `scope
request-list`) works with any valid, non-disabled, non-expired Storage token --
programmatic (`kbc_at_*`/`kbc_pat_*`) included. Before this, the metastore
Expand All @@ -5777,7 +5777,7 @@ authorization failure:

## Metastore `scope` / `--target-project` / `scope set --scope organization` (PSGO-140)

*(since vNEXT)* `model create` / `add <kind>` gained `--scope
*(since 0.97.0)* `model create` / `add <kind>` gained `--scope
project|organization|targeted` + `--target-project ALIAS|ID ...`, and a new
`semantic-layer scope <get|add|remove|set|request-create|request-delete|request-list>`
sub-app (also `GET/PUT /semantic-layer/scope/...` over `kbagent serve`). See
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ override (a project-admin token that is not an org admin must pass
`--scope project` under an org-level model, or it gets a 403).

For one-line command reference, see
[commands-reference.md](commands-reference.md#scope--target-project-grants--elevation-scope-sub-app-since-vnext-psgo-140).
[commands-reference.md](commands-reference.md#scope--target-project-grants--elevation-scope-sub-app-psgo-140).
For the schema-version / replace-vs-merge / 403-vs-404 surprises, see
[gotchas.md](gotchas.md).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ of datasets, metrics, relationships, constraints, and glossary terms. It is
served from a separate API at `metastore.<stack>` (derived from
`connection.<stack>` by string-substitution; cloud/region-agnostic). Auth is
the same `X-StorageApi-Token` as Storage: **reads work with any valid,
non-disabled, non-expired token** (vNEXT, PSGO-282); **writes** (add /
non-disabled, non-expired token** (0.97.0, PSGO-282); **writes** (add /
edit / remove / import / promote / build / scope add|remove|set) still need
a project-admin token -- a master token qualifies, but so does any other
project-admin user's token. Before PSGO-282, the metastore's auth gate
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "keboola-cli"
version = "0.96.2"
version = "0.97.0"
description = "AI-friendly CLI for managing Keboola projects"
readme = "README.md"
requires-python = ">=3.12"
Expand Down
Loading
Loading