feat(0.22.0): flow CRUD + schedule binding - #200
Conversation
…date/delete/schedule/schedule-remove) Eight new subcommands under `kbagent flow`: - list: all keboola.orchestrator + keboola.flow configs across projects - detail: full phase/task breakdown with DAG rendering - schema: YAML template for phases/tasks - new: create flow with optional phases/tasks from --file; DAG validated before create - update: partial update (name / description / phases+tasks); DAG validated before write - delete: hard delete with --yes confirmation guard - schedule: attach keboola.scheduler cron config; timezone + enabled/disabled - schedule-remove: remove all schedules for a flow; idempotent Schedules stored as keboola.scheduler Storage API configs (no new HTTP client). Client-side DAG validation (Kahn's algorithm) rejects cycles and unknown refs before any API call. Permissions registered; hints registered; context docs updated; SKILL.md regenerated; 50 unit tests + 3 E2E tests all pass.
…ed schedule, multi-project list
…ct YAML --file - set_flow_schedule now checks for an existing keboola.scheduler config targeting the flow and updates it in-place (status=updated) rather than always creating a new one, preventing duplicate schedules on repeated calls - _load_flow_yaml raises ValueError when YAML parses to a non-dict type (e.g. a YAML list), giving a clear error instead of an AttributeError deep in .get() - Add tests: upsert path, invalid YAML type exit-2
…reated vs updated)
…help + stale docs - remove_flow_schedule now wraps each delete in try/except: partial success returns deleted IDs; all-fail raises SCHEDULE_DELETE_FAILED (consistent with list_flows per-project error accumulation pattern) - flow detail --component-id help text warns about keboola.flow vs keboola.orchestrator mismatch so users know to pass --component-id keboola.flow for newer flows - context.py, flow-workflow.md, hints/definitions/flow.py updated to reflect upsert semantics (was stale 'creates one per call' wording) - Tests: partial-delete-succeeds, all-delete-fails paths
…e/delete/schedule-remove - flow_update, flow_delete, flow_schedule_remove were missing emit_hint blocks - hints/definitions/flow.py was missing registrations for flow.update, flow.delete, flow.schedule-remove - Narrow bare `except Exception` to (ConfigError, KeboolaApiError) in schedule-remove preview
Replacing with English version for broader team visibility.
padak
left a comment
There was a problem hiding this comment.
Changes requested — two blockers per CONTRIBUTING.md
The PR is architecturally clean (correctly reuses list_component_configs/update_config — no new HTTP client needed), DAG validation + upsert semantics are thoughtful, test coverage is excellent (27 service + 22 CLI + E2E). Before merge please also:
Required fixes
1. --dry-run on destructive operations (CONTRIBUTING.md line 221: "Destructive operations have --dry-run and --yes flags")
src/keboola_agent_cli/commands/flow.py:511-565(flow delete) — missing--dry-runsrc/keboola_agent_cli/commands/flow.py:653-731(flow schedule-remove) — missing--dry-run. Forschedule-removeit should print the list of scheduler configs (cron/timezone) without callingdelete_config.
Other destructive commands (storage delete-table/bucket/column/file-delete) do have --dry-run — this PR diverges from the convention.
2. Schema mismatch between flow schema and flow-workflow.md
commands/flow.py:36-74(theflow schemaoutput) shows a flat shape withcomponentId/configIddirectly on the task object.plugins/kbagent/skills/kbagent/references/flow-workflow.mduses the nested formtask: {mode, componentId, configId}.
The API accepts both, but it confuses users. Unify on one — I recommend the nested form (task: {...}), which matches the keboola-as-code convention.
Nice-to-have (follow-up)
commands/flow.py:374, 462—except (FileNotFoundError, Exception) as exc:ExceptionsubsumesFileNotFoundError, the tuple is misleading. Narrow to(OSError, yaml.YAMLError, ValueError).- Add to
gotchas.md:- The default
component_iddifference betweenflow new(keboola.flow) andflow detail/update/delete/schedule(keboola.orchestrator). A user who creates a flow vianewand then callsdetailwithout--component-idgetsNOT_FOUND. scheduleis an upsert (hence noschedule-update).
- The default
flow schedule-remove --dry-runcould ideally print the same list that's shown before the confirm prompt today.
Positives
- The architectural choice not to add a separate Scheduler HTTP client is correct —
scheduleiskeboola.schedulerconfig-sugar. _validate_dag(Kahn's topological sort) elegantly handles cycle detection + unknown refs.- Fix commits 783eeb8, 04bd64f nicely address upsert semantics (no duplicates on repeated calls).
- Complete documentation chain:
context.py+CLAUDE.md+SKILL.md+commands-reference.md+ newflow-workflow.md. Unlike a couple of other PRs 👍
…dule upsert semantics
|
Addressed both blockers + all nice-to-haves:
Targeted tests: 62/62 pass (4 new tests added for the dry-run and nested-schema behavior). |
New: kbagent flow list/detail/schema/new/update/delete/schedule/schedule-remove covering both keboola.orchestrator (classic) and keboola.flow (new) component types. Schedules stored as keboola.scheduler Storage API configs; client-side Kahn DAG validation rejects cycles and unknown phase refs before API write. Max's review fixes: --dry-run on delete + schedule-remove, nested task shape matching keboola-as-code convention, narrow except tuples, gotchas docs.
|
Integrated into Full integration PR coming as release/0.22.0 -> main. |
Summary
kbagent flowsubcommands:list,detail,schema,new,update,delete,schedule,schedule-removekeboola.orchestrator(classic) andkeboola.flow(new format) component IDskeboola.schedulerStorage API configs — no new HTTP client neededOPERATION_REGISTRY; hints registered inHintRegistry;kbagent contextupdated;SKILL.mdregenerated;flow-workflow.mdreference addedTest plan
tests/test_flow_service.py(helpers + all 8 service methods)tests/test_flow_cli.py(all 8 commands via CliRunner)tests/test_e2e.py::TestE2EFlowOperationsagainst real Keboola project:flow listwithout--projectreturns all projectsruff check+ruff format --checkclean