Summary
kbagent config new --component-id <c> --push --no-files --configuration-file body.json validates body.json against the component's configSchema as if body.json is configuration.parameters, but the actual Storage API POST sends body.json verbatim as the whole configuration object — without wrapping it in a parameters key.
For components whose configSchema describes parameters (e.g. kds-team.app-custom-python), this means:
- A correctly nested body (
{"storage": {...}, "parameters": {venv, source, code, ...}}) fails schema validation.
- An incorrectly flattened body (
{venv, source, code, ...} sitting at the JSON root, no parameters wrapper) passes validation and gets created — producing a live configuration that Keboola's UI/runtime can't read (it looks for configuration.parameters.*), silently falling back to a blank/default template. No error is ever raised; --push reports success.
Environment
- kbagent v0.79.0 (installed via the
uv tool path, keboola-cli package)
- Windows 11
Steps to reproduce
-
Dry-run with a correctly nested body:
{
"storage": {},
"parameters": {
"venv": "3.13",
"source": "code",
"code": "print(1)",
"packages": [],
"user_properties": {}
}
}
kbagent config new --component-id kds-team.app-custom-python --name "Test" \
--project <alias> --push --no-files --configuration-file body.json --dry-run
→ fails:
✗ Schema validation failed:
• <root>: 'venv' is a required property
• <root>: 'user_properties' is a required property
• <root>: 'source' is a required property
-
Remove the storage/parameters wrapper so venv/source/code/packages/user_properties sit directly at the JSON root → validation passes, --push (without --dry-run) succeeds and returns a created config id.
-
kbagent config detail --project <alias> --component-id kds-team.app-custom-python --config-id <id> → the returned configuration has no parameters key at all; venv/code/etc. sit directly under configuration.
-
Opening that config in the Keboola UI shows the component's default boilerplate (Python 3.14, default print(ci.configuration.parameters) sample code, empty packages) instead of the pushed content, because the UI/runtime reads configuration.parameters.*, which is empty.
Root cause (traced in the installed package)
keboola_agent_cli/services/config_service.py::_validate_config_body (called from create_config) validates the caller-supplied body directly against the component's AI-Service JSON schema, which describes the shape of configuration.parameters — so it expects venv/source/user_properties/etc. at the root of whatever is passed in.
keboola_agent_cli/services/config_service.py::create_config → keboola_agent_cli/client/configs.py::create_config sends that same body verbatim as the Storage API's configuration field:
data: dict[str, Any] = {
"name": name,
"description": description,
"configuration": json.dumps(configuration),
}
with no wrapping into {"parameters": ...}.
The two code paths disagree about what "the body" represents (bare parameters vs. the full configuration object), so there is no single body shape that is simultaneously schema-valid and correct for the real Storage API contract.
Suggested fix
Pick one contract and make both paths agree, e.g.:
- Treat
--configuration/--configuration-file as the full configuration object ({storage, parameters}) consistently, and validate only its .parameters sub-object against the component schema; or
- Treat it as
parameters-only consistently, and have create_config/client.create_config wrap it as {"parameters": body} (merging in any storage passed separately) before POSTing.
At minimum, validate the actual outgoing Storage API payload (post-transform) against the schema rather than the raw CLI input, so a mismatch between "what gets validated" and "what gets sent" can't silently pass.
Impact
Silent config-shape corruption: --push reports success and config detail looks superficially fine (it's just missing a parameters key, easy to overlook), but the resulting configuration is non-functional in the Keboola UI and would presumably fail at runtime too, since components read ci.configuration.parameters.
Found while building a kds-team.app-custom-python extractor config with kbagent as part of an AI-assisted workflow (Claude Code).
Summary
kbagent config new --component-id <c> --push --no-files --configuration-file body.jsonvalidatesbody.jsonagainst the component's configSchema as ifbody.jsonisconfiguration.parameters, but the actual Storage API POST sendsbody.jsonverbatim as the wholeconfigurationobject — without wrapping it in aparameterskey.For components whose configSchema describes
parameters(e.g.kds-team.app-custom-python), this means:{"storage": {...}, "parameters": {venv, source, code, ...}}) fails schema validation.{venv, source, code, ...}sitting at the JSON root, noparameterswrapper) passes validation and gets created — producing a live configuration that Keboola's UI/runtime can't read (it looks forconfiguration.parameters.*), silently falling back to a blank/default template. No error is ever raised;--pushreports success.Environment
uv toolpath,keboola-clipackage)Steps to reproduce
Dry-run with a correctly nested body:
{ "storage": {}, "parameters": { "venv": "3.13", "source": "code", "code": "print(1)", "packages": [], "user_properties": {} } }→ fails:
Remove the
storage/parameterswrapper sovenv/source/code/packages/user_propertiessit directly at the JSON root → validation passes,--push(without--dry-run) succeeds and returns a created config id.kbagent config detail --project <alias> --component-id kds-team.app-custom-python --config-id <id>→ the returnedconfigurationhas noparameterskey at all;venv/code/etc. sit directly underconfiguration.Opening that config in the Keboola UI shows the component's default boilerplate (Python 3.14, default
print(ci.configuration.parameters)sample code, empty packages) instead of the pushed content, because the UI/runtime readsconfiguration.parameters.*, which is empty.Root cause (traced in the installed package)
keboola_agent_cli/services/config_service.py::_validate_config_body(called fromcreate_config) validates the caller-supplied body directly against the component's AI-Service JSON schema, which describes the shape ofconfiguration.parameters— so it expectsvenv/source/user_properties/etc. at the root of whatever is passed in.keboola_agent_cli/services/config_service.py::create_config→keboola_agent_cli/client/configs.py::create_configsends that same body verbatim as the Storage API'sconfigurationfield:{"parameters": ...}.The two code paths disagree about what "the body" represents (bare
parametersvs. the fullconfigurationobject), so there is no single body shape that is simultaneously schema-valid and correct for the real Storage API contract.Suggested fix
Pick one contract and make both paths agree, e.g.:
--configuration/--configuration-fileas the fullconfigurationobject ({storage, parameters}) consistently, and validate only its.parameterssub-object against the component schema; orparameters-only consistently, and havecreate_config/client.create_configwrap it as{"parameters": body}(merging in anystoragepassed separately) before POSTing.At minimum, validate the actual outgoing Storage API payload (post-transform) against the schema rather than the raw CLI input, so a mismatch between "what gets validated" and "what gets sent" can't silently pass.
Impact
Silent config-shape corruption:
--pushreports success andconfig detaillooks superficially fine (it's just missing aparameterskey, easy to overlook), but the resulting configuration is non-functional in the Keboola UI and would presumably fail at runtime too, since components readci.configuration.parameters.Found while building a
kds-team.app-custom-pythonextractor config with kbagent as part of an AI-assisted workflow (Claude Code).