Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
b443a77
fix(permissions): fail-closed MCP tool classification (#478 phase 0)
padak Jul 20, 2026
9d86e9c
fix(permissions): per-tool session firewall in tool call + registry e…
padak Jul 20, 2026
e613ed4
feat(docs): kbagent docs query -- Keboola documentation Q&A (#392)
padak Jul 20, 2026
7e1e3e0
feat(semantic-layer): schema command -- live JSON schemas per object …
padak Jul 20, 2026
b727879
docs(context): document docs query + semantic-layer schema (#392, #394)
padak Jul 20, 2026
8dbebf5
docs(plugin): commands-reference entries for docs query + semantic-la…
padak Jul 20, 2026
148cdb5
feat(component): sync-action + config examples (#393, #395)
padak Jul 20, 2026
fe13f2d
docs: document component sync-action + config examples (#393, #395)
padak Jul 20, 2026
3fd8304
fix(semantic-layer): schema resolves the default version to a real JS…
padak Jul 20, 2026
11d02e1
feat(transformation): create/show/edit command group -- SQL transform…
padak Jul 20, 2026
31f5a2c
feat(flow): examples command + authoritative bundled schema fallback …
padak Jul 20, 2026
ab1c0f2
chore(release): 0.73.0 version bump + doc-sync surfaces (flow example…
padak Jul 20, 2026
7922f5d
fix(checks): ty narrowing in tf-ops test, SemanticType in schema help…
padak Jul 20, 2026
5388346
test(e2e): live coverage for all six MCP parity commands (phase 38.5)
padak Jul 20, 2026
acf1843
docs(plugin): merge stale flow schema bullet with 0.73.0 bundled-fall…
padak Jul 20, 2026
6d2f71d
feat(serve): routes for all six parity commands (Devin finding 2, CON…
padak Jul 20, 2026
d82433b
docs: address kbagent-pr-reviewer findings on #508
padak Jul 21, 2026
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.72.0",
"version": "0.73.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
34 changes: 31 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,12 @@ kbagent data-app git-credentials-create --project NAME --app-id ID --type ssh_ke

kbagent component list [--project NAME] [--type TYPE] [--query QUERY]
kbagent component detail --component-id ID [--project NAME]
kbagent component sync-action ACTION_NAME --component-id ID --project ALIAS (--config-id ID [--row-id ID] | --config-data JSON|@file|-) [--branch ID] [--timeout N]
# sync-action (0.73.0+): POST sync-actions.{stack}/actions; ACTION_NAME freeform (component-defined,
# e.g. testConnection/getTables); --row-id shallow-merges row over root at TOP level only (row
# parameters/storage keys replace root wholesale, MCP parity -- NOT deep merge); --config-data
# sends explicit configData verbatim (skips fetch); branchId omitted from body for production.
kbagent config examples --component-id ID [--project NAME] [--row]
kbagent config new --component-id ID [--name NAME] [--project NAME] [--output-dir DIR] [--push --no-files --description D --configuration JSON|@file|- --configuration-file PATH --no-validate --branch ID --dry-run --allow-plaintext-on-encrypt-failure]

# sync: GitOps -- configs as local files. init/pull/push/diff are filesystem-local (no serve REST surface).
Expand Down Expand Up @@ -515,6 +521,7 @@ kbagent semantic-layer model create --project P --name N [--description D] [--sq
kbagent semantic-layer model delete --project P --model M [--yes]
kbagent semantic-layer show --project P [--model M] [--type dataset|metric|relationship|constraint|glossary]
kbagent semantic-layer search-context --project P [--pattern G ...] [--type model|dataset|metric|relationship|constraint|glossary|all] [--limit N]
kbagent semantic-layer schema --project P (--type model|dataset|metric|relationship|constraint|glossary[,TYPE...] | --all)
kbagent semantic-layer get-context --project P --context-id ID
kbagent semantic-layer validate --project P [--model M] [--deep]
kbagent semantic-layer export --project P [--model M] [--output PATH]
Expand Down Expand Up @@ -580,9 +587,26 @@ kbagent kai chat --message "msg" [--chat-id ID] [--project NAME]
kbagent kai chat-detail --chat-id ID [--project NAME]
kbagent kai history [--project NAME] [--limit N]

kbagent transformation create --project NAME --name NAME (--sql 'SELECT ...' | --sql-file PATH) [--created-table NAME ...] [--component-id ID] [--description D] [--branch ID] [--dry-run]
kbagent transformation show --project NAME --config-id ID [--component-id ID] [--branch ID]
kbagent transformation edit --project NAME --config-id ID --change-description TEXT (--op JSON ... | --op-file ops.json) [--storage JSON|@file|-] [--component-id ID] [--branch ID] [--dry-run]
# transformation (0.73.0+): native SQL-transformation editing (port of MCP create/update_sql_transformation, #396).
# create: component derived from the project default_backend (snowflake|bigquery; other backends need
# --component-id); SQL split one-statement-per-script[] element; single block "Blocks"/code "Code";
# each --created-table T maps to out.c-<cleaned-name>.<T>. show: synthetic positional ids b{i}/b{i}.c{j};
# when --component-id omitted, all known SQL transformation components are tried. edit: 9 ops
# (add/remove/rename block+code, set_code, add_script, str_replace) applied sequentially against
# batch-start ids -- ALWAYS `transformation show` first, ids renumber after structural ops;
# --storage REPLACES configuration.storage wholesale; --dry-run previews without PUT.

kbagent docs query "QUESTION" [--project NAME]
# (0.73.0+) Documentation Q&A via the AI Service (server-side RAG). Unlike kai ask it does NOT
# see project data; works with any token. --json emits {query, text, source_urls}.

kbagent flow list [--project NAME] [--branch ID] [--with-schedules]
kbagent flow detail --project NAME --flow-id ID [--branch ID]
kbagent flow schema [--full --project NAME]
kbagent flow schema [--full [--project NAME]]
kbagent flow examples [--component-id keboola.flow|keboola.orchestrator]
kbagent flow validate --file @flow.yaml|- [--project NAME]
kbagent flow new --project NAME --name NAME [--description D] [--file @path.yaml|-|JSON] [--branch ID]
kbagent flow update --project NAME --flow-id ID [--name N] [--description D] [--file @path.yaml|-|JSON] [--branch ID]
Expand All @@ -596,8 +620,12 @@ kbagent flow schedule-remove --project NAME --flow-id ID [--branch ID] [--yes]
# Schema-fetch failure (network/empty) does NOT block the write: structural check skipped,
# semantic checks still run, a "structural schema validation skipped" warning is surfaced.
# flow validate: with --project fetches the live schema (full validation; fetch failure ->
# semantic-only + note); without --project runs semantic-only + a note. flow schema --full
# requires --project (fetches live schema); plain flow schema is the offline YAML template.
# semantic-only + note); without --project runs semantic-only + a note. flow schema --full:
# with --project fetches the live schema (source=live); without --project serves the bundled
# authoritative snapshot (source=bundled, 0.73.0+). Plain flow schema is the offline YAML template.
# flow examples (0.73.0+): bundled example flow configs (vendored from keboola-mcp-server), offline.
# Default keboola.flow; keboola.orchestrator serves legacy examples informational-only (kbagent
# cannot create/edit orchestrator flows). --json emits the bare list of configs.
# flow schedule (0.66.1+) also activates the config on the Scheduler Service so the cron fires;
# activation failure keeps the config written, sets activated=false + warning, exit stays 0.
# flow schedule-remove deregisters from the service before deleting each config.
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.72.0",
"version": "0.73.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
15 changes: 13 additions & 2 deletions plugins/kbagent/agents/keboola-expert.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,15 @@ a critical failure.
|---|---|---|---|
| Author / edit a conditional flow (keboola.flow) | `kbagent flow validate --file @flow.yaml --project ALIAS` (fetches live schema; loop until clean) then `kbagent flow new`/`flow update --file` | fetch `flow detail`, merge phases/tasks locally, re-validate, push | `--component-id` (removed 0.57.0); integer ids (ids are STRINGS); `dependsOn` (use `next[].goto` + conditions); `keboola.orchestrator` (dropped 0.57.0); assuming `flow schema --full` works offline (now needs `--project`) |
| Schedule flow | `kbagent flow schedule --cron ... [--timezone]` | `tool call create_flow_schedule` | raw REST to `/storage/configurations/keboola.scheduler` |
| Create Snowflake transformation | `kbagent config new --component-id keboola.snowflake-transformation --name N --project P --push --no-files` (0.33.0+; one-shot, no scaffold, body defaults to `{}` and validation auto-skips for empty shell -- then `config update --set ...` to fill in script) **or** `kbagent config new --component-id keboola.snowflake-transformation --project P --output-dir D` + `config update --set ...` (scaffold-then-patch) | `tool call create_sql_transformation` (lower schema, avoids the MCP `create_config` Snowflake refusal) | `tool call create_config` (refuses keboola.snowflake-transformation) -- note: `config new --push` does NOT inherit this refusal because it wraps the raw Storage API directly |
| Update SQL transformation body (script[]) | `kbagent config update --project P --component-id keboola.snowflake-transformation --config-id K --configuration @body.json` (0.28.0+ auto-normalizes string `script` to array; SQL gets statement-level split, Python/R gets `[script]` wrap; envelope's `normalizations: [...]` records every change. 0.31.0+ also re-splits multi-statement LIST elements -- closes the #274 ODBC `statement count 2 vs desired 1` crash that survives the 0.28.0 string fix) | -- | `tool call update_sql_transformation` -- still vulnerable to BOTH the #245 string-vs-array AND #274 list-element runtime crashes because it pushes raw to Storage API; raw `PUT /v2/storage/components/.../configs/...` -- same trap |
| Create SQL transformation | `kbagent transformation create --project P --name N (--sql '...' \| --sql-file F) [--created-table T ...]` (0.73.0+; dialect from project default_backend, statement-split, output mapping derived from name) | `kbagent config new --component-id keboola.snowflake-transformation --name N --project P --push --no-files` then `config update --set ...` (< 0.73.0) | `tool call create_config` (refuses keboola.snowflake-transformation) |
| Edit SQL transformation blocks/codes | `kbagent transformation show` (fresh ids!) then `kbagent transformation edit --config-id K --change-description T --op '{"op":"set_code",...}'` (0.73.0+; 9 ops, batch-start ids b{i}/b{i}.c{j}; --storage REPLACES wholesale) | `kbagent config update --configuration @body.json` (0.28.0+ auto-normalizes string `script` to array; 0.31.0+ re-splits multi-statement LIST elements -- #274) | `tool call update_sql_transformation` -- vulnerable to the #245/#274 runtime crashes (raw push); raw `PUT /v2/storage/...` -- same trap; `transformation edit` without a fresh `show` (positional ids renumber) |
| Run a job (and wait) | `kbagent job run --project P --component-id C --config-id K --wait` | `tool call run_component` | `job run` without `--wait` when user expects the result |
| Provision / read an OTLP Data Streams endpoint | `kbagent stream create-source -p P --name N --type otlp [--if-not-exists]` (auto-creates logs/metrics/traces sinks) then `stream detail N -p P --reveal` for endpoint+secret (0.50.0+) | `stream list`; `--no-sinks` for a bare source | deriving the `stream-in` URL yourself (use `source.otlp.url`); printing the secret unasked (masked by default) |
| Mint / rotate / revoke a scoped Storage token (e.g. a device-enrollment token) | `kbagent token create -p P -d DESC [--bucket-write B ...] [--expires-in N]` / `token refresh --token-id ID` / `token delete --token-id ID` (0.66.0+) -- acting token needs `canManageTokens`; secret shown ONCE (persist only `id`+`expires`). Same ops on the SDK facade: `Client.create_scoped_token / refresh_token / delete_token` (+ `create_stream_source`) | -- | assuming a token upload needs `--component-access`/`--can-read-all-file-uploads` (uploads need `--bucket-write` on the sink bucket; those flags gate READING others' uploads, not uploading); telling the user `stream create-source` needs a master token (it uses the normal Storage token) |
| Search items by name across projects | `kbagent search QUERY [--project P] [--type table\|bucket\|config\|flow\|data-app\|transformation] [--search-type textual\|config-based] [--limit N] [--regex]` (0.30.0+); `--regex` (0.67.0+) opts into case-insensitive whole-term regex on entity names — `report` does NOT match `monthly_report`, write `.*report.*`; textual mode marks `table` results matched via a column name with `matched_columns` in `--json` (0.67.0+; always present, `[]` when the name itself matched; always `[]` under `--regex` — regex never matches column names) | `tool call search_tables` / `tool call search_configurations` (one resource-type per call) | chaining multiple `tool call` for different types; `--regex` with `--search-type config-based` (exit 2); `--regex` below 0.67.0 |
| Search config JSON bodies | `kbagent search QUERY --search-type config-based [--project P]` (0.30.0+) | `kbagent config search --query Q` (config-body only, no tables/buckets) | repeated `tool call get_config` to grep locally |
| Browse configs (exploration) | `kbagent config list` / `kbagent config search --query Q` | `tool call list_configs` | full-project pull via MCP just to grep locally |
| Answer a Keboola-documentation question ("how do I configure incremental loading?") | `kbagent docs query "QUESTION" [--project P]` (0.73.0+; AI-service RAG, returns answer + source URLs) | -- | `kai ask` (project-scoped assistant, not docs Q&A); `tool call docs_query` (deprecated 0.74.0) |
| Fetch a specific config | `kbagent config detail --project P --component-id C --config-id K --json` | `tool call get_config` | re-using an earlier JSON dump |
| Override the auto-derived output bucket on a config | `kbagent config set-default-bucket --bucket in.c-name` (0.26.0+) -- read-modify-write of `storage.output.default_bucket`, preserves siblings; `--clear` removes it | `kbagent config update --set 'storage.output.default_bucket=in.c-name'` (works pre-0.26.0 but not discoverable) | editing the raw JSON in the UI; full-config replace with `--configuration` (wipes other storage keys) |
| Cross-project migration | `kbagent sync pull` + edit files locally + `kbagent sync push --dry-run` | -- | repeated `tool call` loops, one per resource |
Expand Down Expand Up @@ -227,6 +228,16 @@ read it when a trigger fires. Each `(X.Y.Z+)` tag is the version floor.
dirs; `is_disabled: true` in `_config.yml` = config disabled (absent =
enabled); a `never_fetched` warning on diff/push = run `sync pull` first.
`sync status` is local-only -- audit real drift with `sync diff`.
- **MCP passthrough is deprecating; firewall is fail-closed** (0.73.0+):
prefer native parity commands over `tool call` -- `docs query`,
`config examples`, `semantic-layer schema`, `component sync-action`,
`transformation create|show|edit`, `flow examples`; `workspace query`
replaces `query_data`. Unknown MCP tool names classify DESTRUCTIVE
(blocked by --deny-writes AND --deny-destructive, never multi-project);
`run_job`/`run_sync_action`/`modify_*`/`deploy_*` are writes now.
**VERSION GATE**: < 0.73.0 these commands do not exist and the firewall
fails OPEN for unknown tools. `component sync-action --row-id` merges
SHALLOW (row top-level keys replace root wholesale).
- **Native types** (0.25.0+): `--column amount:NUMBER(18,2)` passes through;
`BOOLEAN` defaults must be lowercase; `INTEGER(10)` is invalid (use
`NUMBER(3,0)`); `--not-null` / `--default` must name a defined `--column`.
Expand Down
Loading