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
88 changes: 14 additions & 74 deletions plugins/kbagent/skills/kbagent/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,20 @@
---
name: kbagent
description: >
Use when working with Keboola Connection projects via kbagent CLI.
Covers: exploring and searching configurations (extractors, writers, transformations),
browsing job history, analyzing cross-project data lineage, calling MCP tools
across multiple projects, managing development branches, debugging SQL in
temporary workspaces, bulk-onboarding organizations, syncing project configs
as local files (GitOps), git-branching with Keboola dev branch isolation,
sharing buckets across projects, linking shared data,
encrypting secrets for MCP tool call workflows,
uploading/downloading Storage Files with tag management,
and syncing storage metadata and job history. Triggers: kbagent, Keboola project,
keboola configs, keboola jobs, keboola lineage, keboola transformations,
keboola MCP tools, keboola workspace, SQL debugging, keboola branches,
keboola organization, keboola sharing, bucket sharing, link bucket,
keboola sync, keboola git,
keboola gitops, sync pull, sync push, sync diff, branch-link,
search configs, find in configurations, audit configurations,
input mapping migration, remove input mapping, Snowflake paths,
MULTI_STATEMENT_COUNT, statement count error, SQL transformation migration,
keboola encrypt, encrypt secrets, encrypt credentials, encrypt password,
keboola encryption API, #password, #api_token, KBC::ProjectSecure,
safe config write, dry-run preview, fresh fetch before edit,
stale local config file, config version overwrite,
default bucket, output bucket, default_bucket, storage.output,
raw mode bucket override, custom output bucket name,
data app, data apps, keboola data app, streamlit app, streamlit deployment,
flask app, fastapi app, node app, python-js, deploy data app,
data-app create, data-app deploy, data-app password, data-app start,
data-app logs, container logs, app logs, tail logs, build logs,
app stdout, app stderr, troubleshoot data app, debug data app,
app proxy, simpleAuth, app auto-suspend, configVersion, redeploy contract,
Data Science API, /apps endpoint, app password, KBC::Project ciphertext,
data-app secrets, app secrets, app runtime secrets, secrets-set,
secrets-list, secrets-get, secrets-remove, encrypt app secret,
app environment variable, validate repo, validate-repo,
data-app golden rule, pre-flight repo check, repo structure check,
managed git repo, use-managed-git-repo, Keboola-hosted repo,
git-credentials, git-credentials-create, git-repo,
deploy from git, managed repository,
data app runs, deploy attempts, deploy failure reason, why deploy stopped,
local workspace, project directory, kbagent init,
invite user, invite member, project invitation, manage members,
list members, remove member, change role, project role,
bulk invite, invite from CSV, project access, member management,
manage token prompt, --allow-env-manage-token, KBC_MANAGE_API_TOKEN,
feature flag, feature flags, list features, project features, user features,
enable feature, disable feature, set feature flag, add feature, remove feature,
early-adopter-preview, direct-access, pay-as-you-go, /manage/features,
super admin token, super-admin feature, stack feature catalogue,
data stream, data streams, keboola data streams, stream source, OTLP,
OpenTelemetry, otel, OTLP endpoint, OTEL_EXPORTER_OTLP_ENDPOINT, telemetry ingest,
logs metrics traces, stream create-source, stream detail, stream list,
stream delete, otlp source, http source, stream-in, ingest endpoint,
scoped token, scoped storage token, token create, token delete, token refresh,
mint token, revoke token, rotate token, short-lived token, expiring token,
bucket-write token, single-bucket write token, canManageTokens, device enrollment,
per-device credential, per-device token, per-device stream source,
create_scoped_token, create_stream_source, delete_token, refresh_token,
semantic-layer, semantic layer, semantic-layer model, metastore,
semantic-metric, semantic-dataset, semantic-relationship,
semantic-constraint, semantic-glossary, add metric, edit metric,
rename metric, remove metric, validate model, validate semantic layer,
promote model, semantic-layer build, semantic-layer export,
semantic-layer diff, semantic-layer import, semantic-layer token,
metric SQL, dataset FQN, constraint rule, threshold constraint,
4-band health, _critical _warning _healthy _review, CODE_METRIC,
DIM_METRIC_THRESHOLD, dangling metric FK, orphaned constraint,
phantom field, AGG on STRING, SUM on PCT, deep validate,
sl, kbagent sl, semantic layer wizard, sl-build, sl-add, sl-edit,
reference data, semantic-layer reference-data, chart of accounts, COA,
dimension members, account list, dimension data, member list,
developer portal, dev-portal, apps-api, register component, vendor app,
portal property, ui-options, encryption portal, defaultBucket portal,
app icon, configurationSchema portal, publish component, deprecate component,
kbagent dev-portal, portal identity, vendor login, service account portal.
Use when working with Keboola Connection projects via the kbagent CLI.
Covers: exploring and searching component configurations, job history and
job runs, cross-project data lineage, Keboola MCP tools, development
branches, SQL debugging in temporary workspaces, GitOps sync of configs as
local files (pull/push/diff/clone), bucket sharing and linking, encrypting
secrets, Storage tables and files, data apps (create/deploy/logs/secrets),
conditional flows and schedules, project members and invitations, feature
flags, OTLP data streams, scoped Storage tokens, the semantic layer
(models, datasets, metrics, constraints, reference data), and the Keboola
Developer Portal. Triggers: kbagent, Keboola, keboola config, keboola job,
keboola lineage, keboola sync, gitops, dev branch, workspace SQL, data app,
streamlit deploy, semantic layer, sl, dev-portal, data stream, OTLP,
scoped token, bucket sharing, encrypt secrets, feature flag, flow schedule,
invite member.
---

# kbagent -- Keboola Agent CLI
Expand Down
55 changes: 55 additions & 0 deletions tests/test_skill_frontmatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Static compliance tests for the kbagent skill frontmatter.

Claude Desktop (and the Agent Skills spec) enforce a hard limit of 1024
characters on the ``description`` field in SKILL.md frontmatter; a longer
description makes the whole skill fail to load with
"field 'description' in SKILL.md must be at most 1024 characters"
(issue #447). These tests keep the frontmatter within every consumer's
limits so the plugin stays loadable in Claude Desktop, Claude Code, and
claude.ai alike.
"""

from __future__ import annotations

import re
from pathlib import Path

import pytest
import yaml

REPO_ROOT = Path(__file__).parent.parent
SKILL_MD = REPO_ROOT / "plugins" / "kbagent" / "skills" / "kbagent" / "SKILL.md"

# Hard limit from the Agent Skills spec, enforced by Claude Desktop at
# skill-load time (issue #447).
DESCRIPTION_CHAR_LIMIT = 1024


@pytest.fixture(scope="module")
def frontmatter() -> dict:
text = SKILL_MD.read_text(encoding="utf-8")
match = re.match(r"^---\n(.*?)\n---\n", text, re.DOTALL)
assert match is not None, "SKILL.md is missing YAML frontmatter"
data = yaml.safe_load(match.group(1))
assert isinstance(data, dict), "SKILL.md frontmatter must be a YAML mapping"
return data


class TestSkillFrontmatter:
def test_skill_file_exists(self) -> None:
assert SKILL_MD.is_file(), f"SKILL.md missing at {SKILL_MD}"

def test_name_matches_directory(self, frontmatter: dict) -> None:
assert frontmatter.get("name") == "kbagent"

def test_description_present(self, frontmatter: dict) -> None:
description = frontmatter.get("description", "")
assert description.strip(), "SKILL.md description must not be empty"

def test_description_within_claude_desktop_limit(self, frontmatter: dict) -> None:
description = frontmatter["description"]
assert len(description) <= DESCRIPTION_CHAR_LIMIT, (
f"SKILL.md description is {len(description)} characters; Claude "
f"Desktop rejects skills whose description exceeds "
f"{DESCRIPTION_CHAR_LIMIT} characters (issue #447). Trim it."
)