feat(0.26.0): config set-default-bucket — discoverable storage.output.default_bucket override - #234
Conversation
cf2cb1a to
dd2a0b5
Compare
|
Rebased onto
Also picked up new mandatory surfaces I missed in the original PR:
|
dd2a0b5 to
75a24b5
Compare
|
Self-review pass complete (per CONTRIBUTING.md Blocking (fixed):
Also picked up while here:
Reviewed against the full |
75a24b5 to
fe7ea8b
Compare
…t.default_bucket override
Add a first-class CLI command for setting/clearing
configuration.storage.output.default_bucket without raw-mode JSON edits.
Surfaces the workaround documented in the support article (linked from
epic KBCP-108) as a discoverable command in --help, kbagent context, and
the SKILL decision table. Read-modify-write that preserves all sibling
keys; --dry-run for preview; same-value writes short-circuit with
{"changed": false}.
- Service: ConfigService.set_default_bucket() with validation, no-op
detection, dry-run shape mirroring update_config().
- Command: config set-default-bucket with --bucket/--clear (mutually
exclusive), --dry-run, --branch, hint short-circuit.
- Hint registered (client + service variants) in
hints/definitions/config.py.
- Permission "config.set-default-bucket": "write".
- Tests: 20 service+CLI unit tests + step 18c in test_e2e.py covering
set/dry-run/clear/no-op against a real config.
- Docs: AGENT_CONTEXT, CLAUDE.md All CLI Commands, commands-reference,
gotchas (tagged since 0.26.0), safe-write-workflow,
keboola-expert.md tool selection matrix, docs/e2e-scenarios.
- Live-validated end-to-end on three component types (GCS extractor /
CNB exchange rates / Generic extractor) -- output tables routed to
the configured bucket at job runtime in every case.
fe7ea8b to
3ec6f34
Compare
|
Review loop complete (head Iteration 1 (self-walk against Iteration 2 (independent review): found 2 BLOCKING + 3 NON-BLOCKING + 3 nits. Fixed all:
Iteration 3 (independent review): 0 BLOCKING + 0 NON-BLOCKING + 1 material nit. Fixed:
Iteration 4 (sign-off): zero findings. Loop terminated. PR is mergeable; CI re-running on |
Summary
Adds
kbagent config set-default-bucket --project P --component-id C --config-id ID (--bucket BUCKET_ID | --clear) [--dry-run] [--branch ID]— a first-class command for setting or clearingconfiguration.storage.output.default_bucketwithout raw-mode JSON edits.Surfaces the workaround documented at https://keboola.atlassian.net/wiki/spaces/SUP/pages/3770155030/ (epic KBCP-108 "Default bucket is not mandatory") as a discoverable command — visible in
--help,kbagent context, the SKILL decision table, and CLAUDE.md.storage.outputand the rest of the configuration--dry-runshows the diff without writing (same shape asconfig update --dry-run){"changed": false}— no API call, no version bump--clearremoves the key, leavesstorage.output: {}if no siblings (intentional, mirrorsset_nested_valueparent-creation semantics)kbagent config update --set 'storage.output.default_bucket=...'already worked, but it isn't discoverable. The new wrapper is what shows up when humans or AI agents look for "how do I change the default bucket".Live validation against a real project
Tested end-to-end against three different component types in throwaway dev branches — output tables routed to the configured bucket at job runtime in every case:
kds-team.ex-google-cloud-storage(existing, row-based)keboola.ex-cnb-exchange-rates(new config, root-only)cnb-ratestable landed in the configured bucketex-generic-v2(new config, REST→tables, multi-job)usersANDpoststables landed in the same configured bucketAlso validated: per-table
destinationoverride (the second method shown in the support article) works through existingkbagent config update --set 'storage.output.tables=[...]'— no new wrapper added there because per-table mappings have many fields and a single-purpose flag would be cramped.All test branches and configs were cleaned up after validation.
Changes
New code
services/config_service.py:ConfigService.set_default_bucket()— read-modify-write with validation, no-op detection, dry-run shape mirroringupdate_config()commands/config.py:config set-default-bucketTyper command with--bucket/--clear(mutually exclusive),--dry-run,--branch, hint short-circuit, dual JSON/human outputhints/definitions/config.py:CommandHintregistered withClientCall+ServiceCall(both--hint clientand--hint serviceproduce valid Python)permissions.py:"config.set-default-bucket": "write"Tests
tests/test_config_set_default_bucket.py(new): 20 service + CLI tests covering set/clear/no-op/dry-run/sibling-preservation/validation/branch propagation/client lifecycletests/test_e2e.py: step 18c added — set → detail → no-op → clear roundtrip against a real configDocs
commands/context.py— entry inAGENT_CONTEXTCLAUDE.md— line in## All CLI Commandsplugins/kbagent/skills/kbagent/SKILL.md— auto-regeneratedplugins/kbagent/skills/kbagent/references/commands-reference.md— Configuration Browsing sectionplugins/kbagent/skills/kbagent/references/gotchas.md— note aboutdefault_bucketsemantics + KBCP-108 linkplugins/kbagent/skills/kbagent/references/safe-write-workflow.md— listed as a safe pattern alongsideconfig update --setdocs/e2e-scenarios.md— step 18c row added (also caught a missing 18b row forconfig rename)changelog.py—0.22.0entryVersion
pyproject.toml:0.21.1→0.22.0plugins/kbagent/.claude-plugin/plugin.json: synced viamake version-syncuv.lock: package version updatedTest plan
make lint— cleanmake format-check— cleanmake test— 1871 passed, 4 skipped, 34 deselectedmake skill-check— clean (SKILL.md regenerated and matches)make version-check— clean (plugin.json at 0.22.0)make check(combined) — cleankbagent --hint client config set-default-bucket ...— produces valid Python with the correct stack URLkbagent --hint service config set-default-bucket ...— produces valid Python with proper service args (incl.--clearcorrectly omittingbucket)