Library / SDK
kubeflow/kale avatar
kubeflow/kale

Kubeflow Kale: cell tags instead of pipeline code

Kubeflow’s superfood for Data Scientists

704 stars161 forksPythonApache-2.0

At a glance

What is it?
Kale compiles a tagged Jupyter notebook into a Kubeflow Pipelines run, using cell tags to mark imports, functions, parameters, metrics and steps. The mechanism is genuinely useful for notebook-shaped work; it is also a source-to-source translator, and that is where its limits live.
Who is it for?
Adopt Kale if your working artefact is a notebook whose cells already map onto distinct stages, and you want that same file to be both the development surface and the deployed pipeline. Do not adopt it if your pipeline needs component reuse across teams, non-notebook languages, or step-level resource and image control that you intend to tune by hand.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap Kale targets: a notebook that has to become a scheduled pipeline

A notebook is a linear script with hidden state. A Kubeflow Pipeline is a directed graph of containerised steps with declared inputs and outputs. Moving from one to the other normally means learning the KFP SDK, splitting the notebook into components, and writing the glue that passes artefacts between them. Kale's claim is that this translation can be automated from annotations you add to cells you already have.

The audience is stated plainly in the repository description: data scientists. The README lists what it thinks that audience does not want to do, including learning the KFP SDK and restructuring code into components. That framing matters when judging the tool. Kale is not trying to be a general pipeline authoring system. It is trying to remove one specific rewrite for people whose work already lives in .ipynb files and who need it to run on a schedule or at scale on Kubernetes.

Cell tags are the interface: imports, functions, parameters, metrics, steps, skip

Kale's entire authoring surface is a set of cell tags. The README documents six. `imports` marks libraries needed by all steps. `functions` marks helper functions available to all steps. `pipeline-parameters` marks variables a user can tune between runs. `pipeline-metrics` marks metrics tracked in the KFP UI. `step:step_name` marks a pipeline step. `skip` marks exploratory code excluded from the pipeline.

The interesting part is what is not specified. The README says Kale automatically detects which variables flow between steps, and that you do not need to specify inputs and outputs. That is the core value proposition and also the core risk. Dependency detection on Python source means Kale parses the notebook, builds a graph from variable use across tagged cells, and emits a pipeline whose step order follows that graph. When the analysis matches your mental model, this is a large saving. When a variable is reassigned, mutated in place, or read inside a helper function rather than at cell top level, the graph it infers is the graph you get, and the README does not enumerate those edge cases. The FAQ file is linked as covering known limitations, which is a signal that the boundary exists and is documented somewhere other than the front page.

Two entry points: the JupyterLab sidebar and the kale CLI

There are two ways to trigger a compile. In JupyterLab, the README describes clicking the Kale icon in the left sidebar, toggling Enable to see the notebook rendered as a pipeline graph, then clicking Compile and Run. The graph view is the feedback loop: it is where you find out whether the dependencies Kale inferred match what you intended.

The CLI path is a single command. The README gives this example:

kale --nb examples/base/candies_sharing.ipynb --kfp_host http://localhost:8080 --run_pipeline

So `--nb` names the notebook, `--kfp_host` points at the Kubeflow Pipelines API endpoint, and `--run_pipeline` submits the compiled pipeline rather than stopping at compilation. That last flag is the difference between a dry compile you can inspect and an actual submission, and it is worth running without it first.

Installation has two routes. From PyPI:

pip install "jupyterlab>=4.0.0" kubeflow-kale[jupyter] jupyter lab

Or from source, using the Makefile targets the README lists: `make clean && make dev && make jupyter-kfp`. The README also notes that v2.0 was "coming soon to PyPI" at the time of writing, while the release list shows v2.2.0 dated 2026-08-05, so check which version the PyPI package actually resolves to before assuming the source and package paths are equivalent.

The Docker and port-forward path for talking to a real cluster

Running Kale against a local Kubeflow Pipelines install is one thing; running it against a cluster is another, and the README documents the second case explicitly. Build and run the image with `make docker-build` and `make docker-run`, which serves JupyterLab at http://localhost:8889. To connect that container to a real KFP deployment, the sequence given is `make kfp-serve` to serve the development wheel, then `kubectl port-forward -n kubeflow svc/ml-pipeline 8080:8888` to expose the pipeline API, then `make docker-run` again.

That port-forward is the piece worth understanding. Kale in the container reaches the KFP API over HTTP; the forwarding is what makes the cluster's ml-pipeline service appear at a local port. If you skip it, compilation may still succeed while submission fails, because the failure is at the network layer, not in the generated pipeline. The README's own CLI example uses http://localhost:8080 as the host, which is consistent with the forwarded port rather than with a service DNS name. Treat the host value as configuration you must get right per environment, not a default that travels.

Where the tag-and-compile model breaks down

The honest limitation is that Kale is a translator, and translators have grammars. Everything the README promises rests on the assumption that your notebook is structured as cells that can be partitioned into imports, shared functions, parameters, metrics and steps. A notebook that does not decompose that way has nothing for Kale to translate. If your preprocessing, training and evaluation are interleaved in one long cell with state carried in module-level globals, tagging will not rescue the structure; it will produce one step or an ambiguous graph.

A second constraint is the version floor. The README requires Python 3.11+ and Kubeflow Pipelines v2.16.0+. That is not a wide compatibility net. If you are on an older KFP installation, the tool is simply not available to you until you upgrade, and upgrading KFP is a cluster operation with its own consequences.

A third is that the generated pipeline is generated. Hand-written KFP components let you pin a container image, set resource requests, mount volumes, and reuse the same component from another pipeline. Kale's output is derived from your notebook, so those knobs are not the primary interface. If your requirement is a library of versioned, shared components used by several teams, the notebook is the wrong source of truth and Kale is the wrong tool for that job.

How this differs from writing KFP components directly

The real alternative is the Kubeflow Pipelines SDK itself, which the README names as the thing Kale removes the need to learn. The difference in approach is not cosmetic. With the SDK you write a Python function per component, decorate it, declare its inputs and outputs, and compose those components into a pipeline. The notebook is at most a place you developed the logic; the pipeline is a separate artefact with its own file, its own review process, and its own version history.

Kale inverts that. The notebook remains the single artefact, and the pipeline is derived from it on demand. You gain one source of truth and lose the explicit interface. In the SDK model, a mismatch between what a step consumes and what the previous step produces is a type error you see at authoring time. In the Kale model, that relationship is inferred from variable names across cells. The README's own framing of the trade is that you write natural notebook code and skip declaring inputs and outputs. That is a real convenience and a real transfer of responsibility from you to the analyser.

A second, quieter difference is portability of the pipeline definition. A KFP component written by hand can be shared, reviewed as code, and run by someone who has never opened the notebook. A Kale pipeline is regenerated from a notebook, so the notebook is the thing that must be shared, reviewed and kept working.

Maintenance, release cadence and the Apache-2.0 terms

The release history shows v2.2.0 on 2026-08-05, v2.1.1 on 2026-06-04, and a v2.1.1a1 pre-release two hours before it. The repository's last push is dated 2026-09-04, roughly a month after the v2.2.0 tag, and it is not archived. So this is a maintained project with a cadence measured in months, not days. For a tool you would put in front of a data science team, that cadence is workable, but it also means the KFP version floor moves with Kale's releases rather than independently of them.

The upgrade cost is bound to that coupling. Kale targets KFP 2.16.0 and above; a Kale upgrade may imply a KFP upgrade, which implies cluster work. Budget for that as a paired operation rather than treating the pip install as the whole change.

On licensing: the repository is Apache-2.0. That is a permissive licence, and the file is at LICENSE in the repository root. I am not giving legal advice, and I have not read the licence text beyond the identifier; if you are embedding Kale in a commercial product or redistributing a modified version, have your own counsel read the NOTICE and patent grant provisions rather than relying on the short name.

Editorial conclusion

Adopt Kale if your working artefact is a notebook whose cells already map onto distinct stages, and you want that same file to be both the development surface and the deployed pipeline. Do not adopt it if your pipeline needs component reuse across teams, non-notebook languages, or step-level resource and image control that you intend to tune by hand. Before committing, verify three things against your own cluster: that your Kubeflow Pipelines version is at least 2.16.0 as the README requires, that your Python is 3.11 or newer, and that the CLI path works end to end with kale --nb examples/base/candies_sharing.ipynb --kfp_host <your host> --run_pipeline. If the generated graph matches the dependencies you expected, the tool has earned its place; if it does not, the gap is in the translator, not in your notebook.

Official sources

  1. kubeflow/kale on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes