Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
78d1713
feat(0.47.0): fresh-CREATE writeback + semantic-layer reads + sync/st…
ottomansky May 26, 2026
2f80aaa
fix(storage create-table --if-not-exists): report actual existing sch…
padak May 27, 2026
9a874dc
Fix Snowflake workspace login type (#351)
zajca May 28, 2026
3c5e545
docs(contributing): deprecate --hint requirement, make tool-matrix pe…
padak May 29, 2026
2ddd435
fix(sync push): resolve variable bindings + row values on fresh CREAT…
ottomansky May 29, 2026
4eadb2c
feat(feature): `kbagent feature` command group for Manage API feature…
padak May 29, 2026
6e74fe4
feat(dev-portal): kbagent Developer Portal support with no-bypass wri…
matyas-jirat-keboola May 29, 2026
cd3b19f
feat(headless): token-only invocation via `__env__` project (#359) (#…
padak May 29, 2026
374bdfd
feat(stream): `kbagent stream` command group for Data Streams (OTLP) …
padak May 29, 2026
c2d7279
fix(serve): document `stream` in OpenAPI + add Data Streams web UI (#…
padak Jun 1, 2026
bdd694b
feat(dev-portal): admin-role PATCH routing + MFA fixes + interactive …
matyas-jirat-keboola Jun 1, 2026
9008914
chore(deps-dev): bump vitest from 2.1.9 to 4.1.0 in /web/backend (#367)
dependabot[bot] Jun 1, 2026
8a765f0
chore(deps): bump urllib3 from 2.6.3 to 2.7.0 (#369)
dependabot[bot] Jun 1, 2026
417d4f3
chore(deps): bump idna from 3.11 to 3.15 (#370)
dependabot[bot] Jun 1, 2026
75b672b
feat(storage): `clone-table` + correct typify/swap dev-branch semanti…
padak Jun 1, 2026
0912e89
chore(deps): bump pip from 26.0.1 to 26.1 (#371)
dependabot[bot] Jun 1, 2026
f5a1b58
chore(deps): bump python-multipart from 0.0.26 to 0.0.27 (#372)
dependabot[bot] Jun 1, 2026
ef4d837
fix(storage): correct stale "dev branch only" swap-tables wording (#373)
padak Jun 1, 2026
1751dde
release(0.52.1): swap-tables wording fix + dependency bumps (#374)
padak Jun 1, 2026
3c1aee1
fix(sync): conflict-aware `pull --force` — no more silent baseline co…
padak Jun 2, 2026
644a8cc
feat(semantic-layer): add `reference-data` commands (Chart of Account…
Jun 3, 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.46.1",
"version": "0.53.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
60 changes: 59 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ plugins/kbagent/

```
# Global options: --json, --verbose, --no-color, --config-dir, --hint client|service (deprecated, use kbagent serve REST API), --deny-writes, --deny-destructive, --allow-env-manage-token
# Headless / token-only (0.50.0+): export KBAGENT_PROJECT_FROM_ENV=1 + KBC_TOKEN + KBC_STORAGE_API_URL to synthesize an in-memory `__env__` project (no `project add`, no config.json on disk; token never persisted). Use `--project __env__`. Same env setup also powers `kbagent serve`.

kbagent project add --project NAME --url URL --token TOKEN
kbagent project list
Expand Down Expand Up @@ -346,14 +347,15 @@ kbagent storage bucket-detail --project NAME --bucket-id ID [--branch ID]
kbagent storage tables [--project NAME ...] [--bucket-id ID] [--branch ID]
kbagent storage table-detail --project NAME --table-id ID [--branch ID]
kbagent storage create-bucket --project NAME --stage STAGE --name NAME [--description D] [--backend B] [--branch ID]
kbagent storage create-table --project NAME --bucket-id ID --name NAME --column COL:TYPE[(length)] [...] [--primary-key COL] [--not-null COL ...] [--default NAME=VALUE ...] [--branch ID]
kbagent storage create-table --project NAME --bucket-id ID --name NAME --column COL:TYPE[(length)] [...] [--primary-key COL] [--not-null COL ...] [--default NAME=VALUE ...] [--branch ID] [--if-not-exists]
kbagent storage upload-table --project NAME --table-id ID --file PATH [--incremental] [--branch ID]
kbagent storage download-table --project NAME --table-id ID [--output FILE] [--columns COL ...] [--limit N] [--branch ID]
kbagent storage delete-table --project NAME --table-id ID [--table-id ...] [--force] [--dry-run] [--yes] [--branch ID]
kbagent storage truncate-table --project NAME --table-id ID [--table-id ...] [--dry-run] [--yes] [--branch 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]
kbagent storage clone-table --project NAME --table-id ID --branch ID [--dry-run]
kbagent storage describe-bucket --project NAME --bucket-id ID [--text STR | --file PATH | --stdin] [--branch ID]
kbagent storage describe-table --project NAME --table-id ID [--text STR | --file PATH | --stdin] [--branch ID]
kbagent storage describe-column --project NAME --table-id ID --column NAME=DESC [--column ...] [--branch ID]
Expand All @@ -367,6 +369,16 @@ kbagent storage file-tag --project NAME --file-id ID [--add TAG ...] [--remove T
kbagent storage load-file --project NAME --file-id ID --table-id ID [--incremental] [--delimiter D] [--enclosure E] [--branch ID]
kbagent storage unload-table --project NAME --table-id ID [--columns COL ...] [--limit N] [--tag TAG ...] [--download] [--output FILE|DIR] [--file-type csv|parquet] [--branch ID]

# stream: Data Streams (OpenTelemetry/OTLP). Storage token from config (no manage token).
# Control plane = stream.<region> (derived from connection.<region>); the OTLP ingest URL
# (stream-in.<region>/otlp/<projectId>/<sourceName>/<secret>) is returned in source.otlp.url
# with the secret in the path -- MASKED by default, --reveal to print it. create-source --type otlp
# auto-provisions the logs/metrics/traces sinks (bucket in.c-otlp-<source>) so data lands; --no-sinks opts out.
kbagent stream list --project NAME [--branch ID]
kbagent stream create-source --project NAME --name NAME [--type otlp|http] [--branch ID] [--if-not-exists] [--no-sinks] [--reveal]
kbagent stream detail [SOURCE_ID | --name NAME] --project NAME [--branch ID] [--reveal]
kbagent stream delete SOURCE_ID --project NAME [--branch ID] [--dry-run] [--yes|--force]

kbagent lineage build --directory PATH --output PATH [--ai] [--refresh]
kbagent lineage show --load PATH [--upstream NODE] [--downstream NODE] [--column COL] [--columns] [--project ALIAS] [--depth N] [--format text|mermaid|html|er]
kbagent lineage info --load PATH
Expand All @@ -382,6 +394,15 @@ kbagent sharing edges [--project NAME]
kbagent org setup --org-id ID --url URL [--dry-run] [--yes] [--token-description PREFIX] [--refresh]
kbagent org setup --project-ids 1,2,3 --url URL [--dry-run] [--yes] [--token-description PREFIX] [--refresh]

# feature: requires a super-admin Manage API token (inline hidden prompt; never persisted; --allow-env-manage-token for CI). --project resolves the stack URL (+ project_id for project ops) from config.
kbagent feature list --project ALIAS
kbagent feature project-show --project ALIAS
kbagent feature project-add --project ALIAS --feature NAME [--dry-run] [--yes]
kbagent feature project-remove --project ALIAS --feature NAME [--dry-run] [--yes]
kbagent feature user-show --project ALIAS --email EMAIL
kbagent feature user-add --project ALIAS --email EMAIL --feature NAME [--dry-run] [--yes]
kbagent feature user-remove --project ALIAS --email EMAIL --feature NAME [--dry-run] [--yes]

kbagent tool list [--project NAME] [--branch ID]
kbagent tool call TOOL_NAME [--project NAME] [--input JSON|@file|-] [--branch ID]

Expand Down Expand Up @@ -426,12 +447,49 @@ kbagent component list [--project NAME] [--type TYPE] [--query QUERY]
kbagent component detail --component-id ID [--project NAME]
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]

# sync: GitOps -- configs as local files. init/pull/push/diff are filesystem-local (no serve REST surface).
kbagent sync init --project ALIAS [--directory DIR] [--git-branching] [--adopt-existing]
kbagent sync pull --project ALIAS [--all-projects] [--force] [--dry-run] [--with-samples] [--no-storage] [--no-jobs] [--job-limit N] [--branch ID]
# `sync pull --force` is conflict-aware (since 0.53.0): locally-modified config whose remote is UNCHANGED is preserved (delta stays pushable, never silently re-stamped); a true merge conflict (local AND remote both changed since last pull) aborts (exit 1, SYNC_CONFLICT, --json lists details.conflicts); local-untouched + remote-changed takes remote. Discard local edits on purpose by deleting the file/dir then pulling.
kbagent sync status [--directory DIR]
kbagent sync diff --project ALIAS [--all-projects] [--directory DIR] [--branch ID]
kbagent sync push --project ALIAS [--all-projects] [--dry-run] [--force] [--allow-plaintext-on-encrypt-failure] [--branch ID] [--no-name-drift-warnings]
kbagent sync branch-link --project ALIAS (--branch-id ID | --branch-name NAME) [--directory DIR]
kbagent sync branch-unlink [--directory DIR]
kbagent sync branch-status [--directory DIR]

kbagent dev-portal identity add --alias A --username U [--password P | --password-stdin]
[--role-hint vendor|admin] [--vendor V] [--portal-url URL]
kbagent dev-portal identity list
kbagent dev-portal identity remove --alias A
kbagent dev-portal identity edit --alias A [--username U] [--password P|--password-stdin]
[--role-hint H] [--vendor V] [--new-alias N]
kbagent dev-portal identity use ALIAS
kbagent dev-portal identity current
kbagent dev-portal identity verify [--identity A]

kbagent dev-portal list --vendor V [--identity A]
kbagent dev-portal get --app VENDOR.APP_ID [--identity A]

kbagent dev-portal create --vendor V --data FILE [--identity A] [--dry-run]
kbagent dev-portal patch --app VENDOR.APP_ID (--data FILE | --property KEY (--value V | --value-file F))
[--identity A] [--dry-run]
kbagent dev-portal upload-icon --app VENDOR.APP_ID --file PATH [--identity A] [--dry-run]
kbagent dev-portal publish --app VENDOR.APP_ID [--identity A] [--dry-run]
kbagent dev-portal deprecate --app VENDOR.APP_ID [--identity A] [--dry-run]
# All writes require an interactive random-code TTY confirm; no --yes / no env bypass.
# Since v0.51.1: --role-hint is validated (vendor/admin) and load-bearing -- admin identities route
# `patch` to PATCH /admin/apps/{app} (permissive schema). Vendor + admin-only field => fail-fast preflight.
# --password-stdin works on TTY (hidden prompt) AND on a pipe (reads to EOF).

kbagent encrypt values --project ALIAS --component-id ID --input JSON|@file|- [--output-file PATH]

kbagent semantic-layer model list --project P
kbagent semantic-layer model create --project P --name N [--description D] [--sql-dialect Snowflake]
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 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]
kbagent semantic-layer diff (--project-a A | --file-a PATH) (--project-b B | --file-b PATH) [--model-a M] [--model-b M]
Expand Down
15 changes: 5 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,11 +328,7 @@ When adding a new command (e.g., `kbagent storage create-foo`), you must update
- [ ] **Client method** in `client.py` (or `manage_client.py`) -- HTTP layer
- [ ] **Service method** in `services/` -- business logic, validation, orchestration
- [ ] **Command function** in `commands/` -- Typer options, formatter, error handling
- [ ] **`--hint` support** -- every command must support `--hint client` and `--hint service` code generation:
- [ ] **Hint definition** in `hints/definitions/` -- register a `CommandHint` with `ClientCall` + `ServiceCall` (see existing files for pattern)
- [ ] **Hint short-circuit** in the command function -- add `if should_hint(ctx): emit_hint(...)` **before** the service call
- [ ] **Verify** both modes produce valid Python: `kbagent --hint client <command> ...` and `kbagent --hint service <command> ...`
- [ ] **Exception -- infrastructure-level commands.** `--hint` only makes sense for commands that wrap a Keboola API client (Storage / Queue / Manage / AI Service / MCP). Commands that exist purely to manage kbagent itself, or to forward HTTP to another kbagent instance, are **deliberately excluded**: `doctor`, `context`, `init`, `serve`, `version`, `update`, `changelog`, `permissions`, and `http` (the four self-call verbs `http get/post/patch/delete` pass straight through `HttpForwarderService` to a running `kbagent serve` -- there is no Keboola client to mimic, and an `httpx.Client` recipe is already the canonical generic form). If you are adding a *new* command in this infrastructure category, skip the hint definition and note the exception in the PR description so reviewers don't file a BLOCKING finding against this rule.
- [ ] ~~**`--hint` support**~~ -- **DEPRECATED, do not add.** `--hint client` / `--hint service` code generation is superseded by the `kbagent serve` REST API. Do **not** add a new `hints/definitions/` entry or a `should_hint(ctx)` short-circuit for new commands, and do not teach `--hint` in new docs -- point readers at `kbagent serve` instead. Existing hint definitions are kept for backward compatibility but are no longer extended. Reviewers must **not** flag a missing hint definition.
- [ ] **Permission registration** in `permissions.py` (`OPERATION_REGISTRY` dict)
- [ ] **Service wiring** in `cli.py` if adding a new service class
- [ ] **HTTP API endpoint** in `src/keboola_agent_cli/server/routers/<group>.py` -- `kbagent serve` exposes the CLI as a REST API so external applications (Web UI, scheduled AI agents, Slack bots, Streamlit dashboards, CI pipelines) can call the platform without forking CLI subprocesses. The current convention is **1:1**: every command in a group has a matching endpoint in that group's router (e.g. `commands/flow.py` has 8 commands, `server/routers/flows.py` has 8 routes). If you add a new command, add the corresponding route. **Skip allowed** only for genuinely terminal-only commands (interactive prompts, Rich-rendered output that has no useful JSON shape, `doctor`/`init`/`update`-style infrastructure that manages kbagent itself rather than Keboola). Document any skip in the PR description with a one-line reason so reviewers don't flag it.
Expand Down Expand Up @@ -366,7 +362,7 @@ before the PR is mergeable.

- [ ] **`plugins/kbagent/agents/keboola-expert.md`** -- the subagent system prompt. **Highest silent-drift risk in the repo.** Update at minimum:
- [ ] **§1 Rule 6 VERSION GATE** examples (e.g. `flow update needs 0.22.0+`) when adding a command that introduces or relaxes a minimum-version requirement, or when an example version reference is now stale enough to mislead.
- [ ] **§2 Tool Selection Matrix** when adding any new write or destructive command -- give it a row with `First choice / Fallback / NEVER`. A missing row means the subagent will fall back to MCP `tool call` or refuse the task.
- [ ] **§2 Tool Selection Matrix** -- one row **per command GROUP**, not per command. When you add a new write/destructive *group* (e.g. `dev-portal`), give it a single row with `First choice / Fallback / NEVER`. Adding a command to an *existing* group needs no new row. Exhaustive per-command detail belongs in `AGENT_CONTEXT` (`kbagent context`), which is loaded dynamically on demand -- `keboola-expert.md` is a static system prompt loaded into every subagent run and carries a hard 60 KB budget, so it must stay a high-signal decision matrix, not a command catalogue. If a one-row addition would push the file over budget, trim stale content first; do **not** raise the cap. *Severity note:* authors are expected to add the group row, but `/kbagent:review` flags a missing row only **NON-BLOCKING** -- `AGENT_CONTEXT` (a BLOCKING surface above) is the authoritative command catalogue, so a missing matrix row degrades subagent ergonomics without making a command undiscoverable. Don't deprioritize it just because it's non-blocking.
- [ ] **§3 Inline Gotchas** when behavior changed in a way the agent will get wrong by default (e.g. dev-branch auto-materialization, native column-type whitelisting).
- [ ] **`plugins/kbagent/skills/kbagent/SKILL.md`** non-table portions -- update the `description:` trigger keywords when introducing a new topic area (so description-matching auto-triggers the skill); add a workflow row to the bottom table if you created a new `references/<topic>-workflow.md`.
- [ ] **`plugins/kbagent/skills/kbagent/references/commands-reference.md`** -- add the new command bullet under the appropriate section. Hand-maintained, NOT auto-generated. (Yes, this partly duplicates the auto-generated SKILL.md table -- the reference carries denser per-command notes, the table is the at-a-glance picker.)
Expand Down Expand Up @@ -412,7 +408,7 @@ release checklist below.
| `CLAUDE.md` (`## All CLI Commands`) | Adding/removing/renaming commands | NO |
| `plugins/kbagent/.claude-plugin/plugin.json` | Every release (auto-synced) | YES (`make version-check`; pre-commit auto-stages) |
| `plugins/kbagent/.claude-plugin/CLAUDE.md` | Changing delegation strategy / when-to-delegate rules | NO |
| `plugins/kbagent/agents/keboola-expert.md` | New write/destructive command (matrix); new minimum-version requirement (Rule 6 VERSION GATE); behavior change (gotchas) | NO -- **highest silent-drift risk** |
| `plugins/kbagent/agents/keboola-expert.md` | New write/destructive command **group** (one matrix row per group, not per command -- file has a hard 60 KB prompt budget); new minimum-version requirement (Rule 6 VERSION GATE); behavior change (gotchas) | NO -- **highest silent-drift risk** |
| `plugins/kbagent/commands/keboola.md` | `/keboola` slash-command UX change (rare) | NO |
| `plugins/kbagent/skills/kbagent/SKILL.md` -- table | Auto-generated by `make skill-gen` | YES (`make skill-check`; pre-commit auto-stages) |
| `plugins/kbagent/skills/kbagent/SKILL.md` -- description / rules / workflow links | New topic area in `description` triggers; new workflow file added to bottom table | NO |
Expand Down Expand Up @@ -499,8 +495,7 @@ courtesy that:

- catches the silent-drift gaps (`OPERATION_REGISTRY`, `gotchas.md`
version tags, `keboola-expert.md` matrix, `commands/context.py`
`AGENT_CONTEXT`, `commands-reference.md`, `--hint` definitions) that
CI does not check;
`AGENT_CONTEXT`, `commands-reference.md`) that CI does not check;
- demonstrates to the human reviewer that you have walked the
[Plugin synchronization map](#plugin-synchronization-map);
- saves a review round-trip when the reviewer would otherwise catch the
Expand Down Expand Up @@ -543,7 +538,7 @@ manual safety net for the silent-drift risks summarized in the
4. **Run `make skill-gen`** -- regenerates the decision table in `SKILL.md`. Idempotent if no commands changed since the previous release.
5. **Manually review `plugins/kbagent/agents/keboola-expert.md`**:
- **§1 Rule 6 VERSION GATE examples** -- if any feature this release shipped (or any feature shipped in a previous release that you missed) was previously missing-and-now-present, document it with the right minimum version. Remove stale "since X.Y.Z" mentions that no longer matter to live users.
- **§2 Tool Selection Matrix** -- did you add new write/destructive commands since last release? Are they present with `First choice / Fallback / NEVER`? A missing row means the subagent will silently fall back to MCP `tool call` or refuse the task.
- **§2 Tool Selection Matrix** -- did you add a new write/destructive command *group* since last release? Is it present with one `First choice / Fallback / NEVER` row (per group, not per command)? Mind the hard 60 KB prompt budget: trim stale content rather than raising the cap. New commands inside an existing group need no new row.
- **§3 Inline Gotchas** -- new behavior the agent would get wrong by default? Add it.
6. **Manually review `plugins/kbagent/skills/kbagent/references/gotchas.md`** -- every behavior introduced or changed this release that an AI agent would not infer from `--help` should have its own `(since vX.Y.Z)` entry. The version tag is non-optional.
7. **Manually review `CLAUDE.md` `## All CLI Commands`** -- diff against `kbagent --help` output (and against `kbagent context`). Hand-maintained; CI does not catch drift here.
Expand Down
Loading