zenml Documentation

ZenML 🙏: One AI Platform from Pipelines to Agents.

5,620 stars Python Python 101 files · ~137,466 tokens #agentops#agents#ai#automl#data-science#deep-learning#devops-tools#genai
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy zenml on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name zenml -p 3306:3306 --restart always mysql:8.4
Configured Services & Ports
⚙️ db
image: mysql:8.4
🔌 Ports: 3306:3306
⚙️ zenml_server
image: build locally
🔌 Ports: 80:8080
docker-compose.yml
yaml (docker-compose.yml)
x-admin-creds: &admin-creds
  ZENML_DEFAULT_USER_NAME: admin
  ZENML_DEFAULT_USER_PASSWORD: password

services:

  # Database
  db:
    image: mysql:8.4
    container_name: db
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
      interval: 10s
      timeout: 10s
      retries: 3
    restart: unless-stopped

  # The ZenML Server
  zenml_server:
    # To use the official image, uncomment the following line and
    # comment out the build section below.
    #
    # image: zenmldocker/zenml-server:latest
    build:
      context: ./
      dockerfile: docker/zenml-server-dev.Dockerfile
      args:
        INSTALL_DEBUG_TOOLS: true
      # NOTE: use the local-runtime target to run the API in dev mode from the
      # mounted source code (will automatically refresh when code changes are
      # made); If the target is not set, the container will have all sources
      # pre-packaged into the image (no need to mount the source code).
      #
      target: local-runtime
    container_name: server
    platform: linux/amd64
    ports:
      - 80:8080
    volumes:
      - ./src:/zenml/src
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: [ "CMD", "python", "-c", "import requests; requests.get('http://localhost:8080/health').raise_for_status()" ]
      interval: 10s
      timeout: 10s
      retries: 3
    restart: on-failure
    environment:
      ZENML_LOGGING_VERBOSITY: DEBUG
      ZENML_ANALYTICS_OPT_IN: false

      ZENML_SERVER_DEPLOYMENT_TYPE: docker
      ZENML_SERVER_AUTO_ACTIVATE: true
      ZENML_SERVER_SERVER_URL: http://localhost
      ZENML_SECRETS_STORE_TYPE: sql
      ZENML_SECRETS_STORE_ENCRYPTION_KEY: dummy_zenml_secrets_store_encryption_key
      ZENML_SERVER_JWT_SECRET_KEY: dummy_zenml_server_api_jwt_key

      ZENML_STORE_TYPE: sql
      ZENML_STORE_PASSWORD: password
      ZENML_STORE_URL: mysql://root@db/zenml # <- Docker replaces `db` with IP_Address

      <<: *admin-creds

volumes:
  mysql_data:

Technical Documentation: zenml-io/zenml

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (README.md)

PyPi
PyPi
PyPi
Contributors
License


ZenML is built for ML or AI Engineers working on traditional ML use-cases, LLM workflows, or agents, in a company setting.

At it's core, ZenML allows you to write workflows (pipelines) that run on any infrastructure backend (stacks). You can embed any Pythonic logic within these pipelines, like training a model, or running an agentic loop. ZenML then operationalizes your application by:

  1. Automatically containerizing and tracking your code.
  2. Tracking individual runs with metrics, logs, and metadata.
  3. Abstracting away infrastructure complexity.
  4. Integrating your existing tools and infrastructure e.g. MLflow, Langgraph, Langfuse, Sagemaker, GCP Vertex, etc.
  5. Allowing you to quickly iterate on experiments with an observable layer, in development and in production.

...amongst many other features.

ZenML is used by thousands of companies to run their AI workflows. Here are some featured ones:

(please email [email protected] if you want to be featured)

🚀 Get Started (5 minutes)

bash
# Install ZenML with server capabilities
pip install "zenml[server]"  # pip install zenml will install a slimmer client

# Initialize your ZenML repository
zenml init

# Start local server or connect to a remote one
zenml login

You can then explore any of the examples in this repo. We recommend starting with the quickstart, which demonstrates core ZenML concepts: pipelines, steps, artifacts, snapshots, and deployments.

🏗️ Architecture Overview

ZenML uses a client-server architecture with an integrated web dashboard (zenml-io/zenml-dashboard):

  • Local Development: pip install "zenml[local]" - runs both client and server locally
  • Production: Deploy server separately, connect with pip install zenml + zenml login <server-url>

🎮 Demo

Here is a short demo:

🖼️ Resources

The best way to learn about ZenML is through our comprehensive documentation and tutorials:

📚 More examples

  1. Agent Architecture Comparison - Compare AI agents with LangGraph workflows, LiteLLM integration, and automatic visualizations via custom materializers
  2. Deploying ML Models - Deploy classical ML models as production endpoints with monitoring and versioning
  3. Deploying Agents - Document analysis service with pipelines, evaluation, and embedded web UI
  4. E2E Batch Inference - Complete MLOps pipeline with feature engineering
  5. LLM RAG Pipeline - Production RAG with evaluation loops
  6. Agentic Workflow (Deep Research) - Orchestrate your agents with ZenML
  7. Fine-tuning Pipeline - Fine-tune and deploy LLMs

🗣️ Chat With Your Pipelines: ZenML MCP Server

Stop clicking through dashboards to understand your ML workflows. The ZenML MCP Server lets you query your pipelines, analyze runs, and trigger deployments using natural language through Claude Desktop, Cursor, or any MCP-compatible client.

text
💬 "Which pipeline runs failed this week and why?"
📊 "Show me accuracy metrics for all my customer churn models"  
🚀 "Trigger the latest fraud detection pipeline with production data"

Quick Setup:

  1. Download the .dxt file from zenml-io/mcp-zenml
  2. Drag it into Claude Desktop settings
  3. Add your ZenML server URL and API key
  4. Start chatting with your ML infrastructure

The MCP (Model Context Protocol) integration transforms your ZenML metadata into conversational insights, making pipeline debugging and analysis as easy as asking a question. Perfect for teams who want to democratize access to ML operations without requiring dashboard expertise.

🤖 Kitaru: Replay-Based Evals for AI Agents

Running AI agents in production and wondering whether the cheaper model would have held, or whether the new prompt fixes Tuesday's failure? Kitaru is our open-source sister project for agents: traces you can run, not just read.

  • Every run is a recording — wrap your agent once (PydanticAI today), or import the Langfuse traces you already collect
  • Replay is re-execution — the run happens again against your real code, with recorded tool calls answered from the recording, so nothing touches live systems
  • Fork with one thing changed — a cheaper model, a new prompt, the fix in your working tree — and trust the diff
  • Scale the decision — freeze real traffic into cohorts, run experiments, gate CI on the result
  • Self-hosted, by design — one small server on your infrastructure; replays execute on workers in your environment

The split is clean: ZenML is for ML pipelines, Kitaru is for agents.

bash
pip install kitaru

👉 kitaru.ai · GitHub · Docs

🎓 Books & Resources

ZenML is featured in these comprehensive guides to production AI systems.

🤝 Join ML Engineers Building the Future of AI

Contribute:

Stay Updated:

  • 🗺 Public Roadmap - See what's coming next
  • 📰 Blog - Best practices and case studies
  • 🎙 Slack - Talk with AI practitioners

❓ FAQs from ML Engineers Like You

Q: "Do I need to rewrite my agents or models to use ZenML?"

A: No. Wrap your existing code in a @step. Keep using scikit-learn, PyTorch, LangGraph, LlamaIndex, or raw API calls. ZenML orchestrates your tools, it doesn't replace them.

Q: "How is this different from LangSmith/Langfuse?"

A: They provide excellent observability for LLM applications. We orchestrate the full MLOps lifecycle for your entire AI stack. With ZenML, you manage both your classical ML models and your AI agents in one unified framework, from development and evaluation all the way to production deployment.

Q: "Can I use my existing MLflow/W&B setup?"

A: Yes! ZenML integrates with both MLflow and Weights & Biases. Your experiments, our pipelines.

Q: "Is this just MLflow with extra steps?"

A: No. MLflow tracks experiments. We orchestrate the entire development process – from training and evaluation to deployment and monitoring – for both models and agents.

Q: "How do I configure ZenML with Kubernetes?"

A: ZenML integrates with Kubernetes through the native Kubernetes orchestrator, Kubeflow, and other K8s-based orchestrators. See our Kubernetes orchestrator guide and Kubeflow guide, plus deployment documentation.

Q: "What about cost? I can't afford another platform."

A: ZenML's open-source version is free forever. You likely already have the required infrastructure (like a Kubernetes cluster and object storage). We just help you make better use of it for MLOps.

🛠 VS Code / Cursor Extension

Manage pipelines directly from your editor:

🖥️ VS Code Extension in Action!

Install from VS Code Marketplace.

📜 License

ZenML is distributed under the terms of the Apache License Version 2.0. See
LICENSE for details.



README (`docs/README.md`)

ZenML Docs

General documentation

We write our documentation in Markdown files and use GitBook to build it.
The documentation source files can be found in this repository at docs/book

  • You can edit the docs by simply editing the markdown files. Once the changes
    get merged into main, the docs will be automatically refreshed. (Note: you
    might need to refresh your browser.)
  • If you're adding a new page, make sure to add a reference to it inside the tables of contents docs/book/toc.md
  • Make sure to be consistent with the existing docs (similar style/messaging, reuse existing images if they fit your use case)

SDK Docs

The ZenML SDK docs are generated from our Python docstrings using mkdocs.
The SDK docs will be automatically updated each release using a Github workflow and can be found
athttps://sdkdocs.zenml.io.

Building the SDK Docs locally

To build them locally follow these steps:

  • Clone the repository
  • Install ZenML and Jinja2 dependencies
bash
pip3 install -e ".[server,dev]"
pip3 install "Jinja2==3.0.3"
  • Modify docs/mkdocs.yml as follows:
yaml
watch:
  - ../src/zenml
yaml
watch:
  - src/zenml
  • Run python3 docs/mkdocstrings_helper.py
  • Run:
bash
rm -rf src/zenml/zen_stores/migrations/env.py
rm -rf src/zenml/zen_stores/migrations/versions
rm -rf src/zenml/zen_stores/migrations/script.py.mako
  • Run mkdocs serve -f docs/mkdocs.yml -a localhost: from the repository root -
    running it from elsewhere can lead to unexpected errors. This script will compose the docs hierarchy
    and serve it (http://127.0.0.1:/).

The link_checker.py script is a utility tool for managing and validating links in our documentation.
It helps maintain the quality of our documentation by:

  • Finding broken or outdated links
  • Converting relative links to absolute URLs
  • Validating link accessibility
  • Supporting both directory-wide and file-specific scanning

Usage

The script supports several modes of operation:

bash
# Find all links containing 'docs.zenml.io' in a directory
python link_checker.py --dir docs/book --substring docs.zenml.io

# Check specific files for links containing 'how-to'
python link_checker.py --files file1.md file2.md --substring how-to

# Preview link replacements without making changes
python link_checker.py --files file1.md --replace-links --dry-run

# Replace and validate links
python link_checker.py --files file1.md --replace-links --validate-links

# Transform paths using custom URL mappings
python link_checker.py --dir docs/book --replace-links --url-mapping user-guide=user-guides

Features

  1. Link Detection:

    • Scans for various link types (inline, reference-style, HTML, bare URLs)
    • Supports substring-based filtering
    • Works with both directories and individual files
  2. Link Transformation:

    • Converts relative documentation links to absolute URLs
    • Handles README.md files and various link formats
    • Preserves fragments and query parameters
    • Supports custom URL path mappings to transform specific path segments
  3. Link Validation:

    • Validates links via HTTP requests
    • Parallel validation for better performance
    • Detailed error reporting
    • Uses narrow default CI policies for external domains that block automated checks. These policies are status-specific: approved bot-hostile URLs or domains may accept specific statuses such as 403, 406, 429, or 502, while non-exempt hard failures such as 404 and 410 still fail.

Requirements

For link validation functionality, the requests package is required:

bash
pip install requests

Contributors

We welcome and recognize all contributions. You can see a list of current contributors here.


Book Api Docs README (`docs/book/api-docs/README.md`)


The ZenML API provides programmatic access to ZenML services beyond what's available in the Python SDK.

Overview

Welcome to the ZenML API documentation. This guide provides information about both the open-source (OSS) and Pro API endpoints available in the ZenML platform.

OSS API Open-source API endpoints for core ZenML functionality oss-api.png oss-api
Pro API Enhanced API endpoints for our pro features pro-api.png pro-api

Use Cases

While the ZenML Python SDK covers most workflow requirements, the Server API offers additional utility for:

  • Automated scaling of operations in production environments.
  • Integration with external monitoring and logging systems.
  • Programmatic management and audit of resources and configurations.
  • Enterprise team management and access control (Pro).

By leveraging the ZenML API, users can enhance the robustness and control of their machine learning workflows, ensuring operations are both efficient and scalable.


Book Sdk Docs README (`docs/book/sdk-docs/README.md`)



Overview

ZenML and Kitaru each provide SDKs for working with their APIs:

  • ZenML provides a Python SDK and CLI for building, managing, and deploying production-ready ML pipelines.
  • Kitaru provides Python and TypeScript SDKs for recording, replaying, and improving AI agents. Its CLI ships with the Python package.

ZenML SDK

The ZenML SDK provides Python tools and interfaces for building, managing, and deploying production-ready machine learning pipelines. This documentation helps you get the most out of ZenML's features.

SDK Documentation Complete API documentation for all ZenML modules, classes, and functions. sdk.png https://sdkdocs.zenml.io
CLI Methods Command-line tools for managing ZenML pipelines, stacks, and deployments. cli.png https://sdkdocs.zenml.io/latest/cli.html
ZenML Client Python client for interacting with ZenML projects, repositories, and services. client.png https://sdkdocs.zenml.io/latest/core_code_docs/core-client.html
Integrations Connect ZenML with popular ML tools, orchestrators, and cloud services. integrations.png https://sdkdocs.zenml.io/latest/integration_code_docs/integrations-airflow.html

Kitaru SDK

Kitaru is ZenML's sibling project for recording, replaying, and improving AI agents: traces you can run, not just read. Its Python and TypeScript SDKs talk to the same Kitaru server over the same REST API. Framework adapters support Python and TypeScript agents. The generated Python SDK and CLI reference is published on a dedicated site.

Python SDK & CLI Reference Complete generated API reference for the Kitaru Python SDK and command-line interface. https://sdkdocs.kitaru.ai
Python & TypeScript SDK Guide How both SDKs connect, authenticate, expose resources, and hand work to Kitaru workers. https://docs.zenml.io/kitaru/get-help/sdks
Python Client Programmatic interface to a Kitaru server: sessions, replays, evaluators, cohorts, and experiments. kitaru/client.md

Book User Guide README (`docs/book/user-guide/README.md`)



Learn ZenML

Discover how to build production-ready ML pipelines with ZenML and evaluate agentic systems with Kitaru through our curated learning resources. Whether you're looking for step-by-step instructions, complete project implementations, or specific examples, you'll find resources to accelerate your workflow.

Kitaru is ZenML's sibling project for evals and improvement loops for agentic systems. It works from recorded or imported production traces through investigation, cohorts, evaluators, replay experiments, regression testing, and CI. ZenML orchestrates pipelines; Kitaru runs this workflow on its own server and workers.

Guides

Step-by-step instructions to help you master ZenML concepts and features.

Starter Guide Get started with ZenML fundamentals and set up your first pipeline starter.png starter-guide
Production Guide Move your ML pipelines from development to production prod.png production-guide
LLMOps Guide Build and deploy Large Language Model pipelines llm.png llmops-guide
Agent evals → Kitaru Turn production traces into investigations, evaluators, cohorts, replay experiments, and regression checks in the Kitaru docs. kitaru.png Kitaru docs
Tutorials Deep dives into advanced topics prod.png tutorials

Projects

Complete end-to-end implementations that showcase ZenML in real-world scenarios.
See all projects in our website →

FloraCast A production-ready MLOps pipeline for time series forecasting using ZenML and Darts, featuring TFT-based training and scheduled batch inference. zencoder.jpg https://www.zenml.io/projects/floracast
LLM-Complete Guide Production-ready RAG pipelines from basic retrieval to advanced LLMOps with embeddings finetuning and evals. llm-complete-guide.jpg https://github.com/zenml-io/zenml-projects/tree/main/llm-complete-guide
Retail Forecast A robust MLOps pipeline for retail sales forecasting designed for retail data scientists and ML engineers. nightwatch.jpg https://www.zenml.io/projects/retail-forecast
Research Radar Automates research paper discovery and classification for specialized research domains. researchradar.jpg
OncoClear A production-ready MLOps pipeline for accurate breast cancer classification using machine learning. magicphoto.jpg https://www.zenml.io/projects/oncoclear
Sign Language Detection with YOLOv5 End-to-end computer vision pipeline yolo.jpg https://www.zenml.io/projects/sign-language-detection-with-yolov5
ZenML Support Agent A production-ready agent that can help you with your ZenML questions. support.jpg https://www.zenml.io/projects/zenml-support-agent
OmniReader A scalable multi-model OCR workflow framework for batch document processing and model evaluation. gamesense.jpg https://www.zenml.io/projects/omnireader
EuroRate Predictor Turn European Central Bank data into actionable interest rate forecasts with this comprehensive MLOps solution. eurorate.jpg https://www.zenml.io/projects/eurorate-predictor

Examples

Focused code snippets and templates that address specific ML workflow challenges.
See all examples in GitHub →

Quickstart Bridging Local Development and Cloud Deployment example-01.png https://github.com/zenml-io/zenml/blob/main/examples/quickstart
End-to-End Batch Inference Supervised ML project built with the ZenML framework and its integration. example-02.png https://github.com/zenml-io/zenml/tree/main/examples/e2e
Agent Architecture Comparison Compare AI agents with LangGraph workflows, LiteLLM integration, and automatic visualizations. example-06.png https://github.com/zenml-io/zenml/blob/main/examples/agent_comparison
Agent Framework Integrations Production-ready integrations for 11 popular agent frameworks including LangChain, CrewAI, AutoGen, and more. example-06.png https://github.com/zenml-io/zenml/tree/main/examples/agent_framework_integrations
Deploying Agents Document analysis service with pipelines, evaluation, and embedded web UI. example-07.png https://github.com/zenml-io/zenml/blob/main/examples/deploying_agent
Agent Outer Loop Agent training and evaluation loop: evolve a generic agent into a specialized support system through intent classification and model training. example-07.png https://github.com/zenml-io/zenml/blob/main/examples/agent_outer_loop
Basic NLP with BERT Build NLP models with production-ready ML pipeline framework example-03.png https://github.com/zenml-io/zenml/tree/main/examples/e2e_nlp
Computer Vision with YoloV8 End-to-end computer vision pipeline with modular design example-04.png https://github.com/zenml-io/zenml/tree/main/examples/computer_vision
LLM Finetuning LLM fine-tuning pipeline with PEFT approach example-05.png https://github.com/zenml-io/zenml/tree/main/examples/llm_finetuning
Replay-Based Agent Evals (Kitaru) Runnable Kitaru starter: turn real traces from a PydanticAI returns agent into replayable evals, with human review and bounded replay. https://github.com/zenml-io/kitaru-template

Book Component Guide Alerters README (`docs/book/component-guide/alerters/README.md`)


icon: message-exclamation

Alerters

Alerters allow you to send messages to chat services (like Slack, Discord, Mattermost, etc.) from within your
pipelines. This is useful to immediately get notified when failures happen, for general monitoring/reporting, and also
for building human-in-the-loop ML.

Alerter Flavors

Currently, the SlackAlerter and DiscordAlerter are the available alerter integrations. However, it is straightforward to
extend ZenML and build an alerter for other chat services.

Alerter Flavor Integration Notes
Slack slack slack Interacts with a Slack channel
Discord discord discord Interacts with a Discord channel
Custom Implementation custom Extend the alerter abstraction and provide your own implementation

{% hint style="info" %}
If you would like to see the available flavors of alerters in your terminal, you can use the following command:

shell
zenml alerter flavor list

{% endhint %}

How to use Alerters with ZenML

Each alerter integration comes with specific standard steps that you can use out of the box.

However, you first need to register an alerter component in your terminal:

shell
zenml alerter register <ALERTER_NAME> ...

Then you can add it to your stack using

shell
zenml stack register ... -al <ALERTER_NAME>

{% hint style="info" %}
Stacks can have multiple alerters attached. ZenML treats the first attached alerter as the default one, and singular accessors such as Client().active_stack.alerter resolve to that default alerter.
{% endhint %}

Afterward, you can import the alerter standard steps provided by the respective integration and directly use them in
your pipelines.

Using the Ask Step for Human-in-the-Loop Workflows

All alerters provide an ask() method and corresponding ask steps that enable human-in-the-loop workflows. These are essential for:

  • Getting approval before deploying models to production
  • Confirming critical pipeline decisions
  • Manual intervention points in automated workflows

How Ask Steps Work

Ask steps (like discord_alerter_ask_step and slack_alerter_ask_step):

  1. Post a message to your chat service with your question
  2. Wait for user response containing specific approval or disapproval keywords
  3. Return a boolean - True if approved, False if disapproved or timeout
python
from zenml import step, pipeline
from zenml.integrations.slack.steps.slack_alerter_ask_step import slack_alerter_ask_step

@step
def train_model():
    # Training logic here - this is a placeholder function
    return "trained_model_object"

@step
def deploy_model(model, approved: bool) -> None:
    if approved:
        # Deploy the model to production
        print("Deploying model to production...")
        # deployment logic here
    else:
        print("Deployment cancelled by user")

@pipeline
def deployment_pipeline():
    trained_model = train_model()
    # Ask for human approval before deployment
    approved = slack_alerter_ask_step("Deploy model to production?")
    deploy_model(trained_model, approved)

Default Response Keywords

By default, alerters recognize these response options:

Approval: approve, LGTM, ok, yes
Disapproval: decline, disapprove, no, reject

Customizing Response Keywords

You can customize the approval and disapproval keywords using alerter parameters:

python
from zenml.integrations.slack.steps.slack_alerter_ask_step import slack_alerter_ask_step
from zenml.integrations.slack.alerters.slack_alerter import SlackAlerterParameters

# Use custom approval/disapproval keywords
params = SlackAlerterParameters(
    approve_msg_options=["deploy", "ship it", "✅"],
    disapprove_msg_options=["stop", "cancel", "❌"]
)

approved = slack_alerter_ask_step(
    "Deploy model to production?", 
    params=params
)

Important Notes

  • Return Type: Ask steps return a boolean value - ensure your pipeline logic handles this correctly
  • Keywords: Response keywords are case-sensitive (except Slack, which converts to lowercase)
  • Timeout: If no valid response is received within the timeout period, the step returns False
  • Permissions: Ensure your bot has permissions to read messages in the target channel

Book Component Guide Annotators README (`docs/book/component-guide/annotators/README.md`)


icon: expand

Annotators

Annotators are a stack component that enables the use of data annotation as part of your ZenML stack and pipelines. You
can use the associated CLI command to launch annotation, configure your datasets and get stats on how many labeled tasks
you have ready for use.

Data annotation/labeling is a core part of MLOps that is frequently left out of the conversation. ZenML will
incrementally start to build features that support an iterative annotation workflow that sees the people doing
labeling (and their workflows/behaviors) as integrated parts of their ML process(es).

There are a number of different places in the ML lifecycle where this can happen:

  • At the start: You might be starting out without any data, or with a ton of data but no clear sense of which parts
    of it are useful to your particular problem. It’s not uncommon to have a lot of data but to be lacking accurate labels
    for that data. So you can start and get great value from bootstrapping your model: label some data, train your model,
    and use your model to suggest labels allowing you to speed up your labeling, iterating on and on in this way. Labeling
    data early on in the process also helps clarify and condense down your specific rules and standards. For example, you
    might realize that you need to have specific definitions for certain concepts so that your labeling efforts are
    consistent across your team.
  • As new data comes in: New data will likely continue to come in, and you might want to check in with the labeling
    process at regular intervals to expose yourself to this new data. (You’ll probably also want to have some kind of
    automation around detecting data or concept drift, but for certain kinds of unstructured data you probably can never
    completely abandon the instant feedback of actual contact with the raw data.)
  • Samples generated for inference: Your model will be making predictions on real-world data being passed in. If you
    store and label this data, you’ll gain a valuable set of data that you can use to compare your labels with what the
    model was predicting, another possible way to flag drifts of various kinds. This data can then (subject to
    privacy/user consent) be used in retraining or fine-tuning your model.
  • Other ad hoc interventions: You will probably have some kind of process to identify bad labels, or to find the
    kinds of examples that your model finds really difficult to make correct predictions. For these, and for areas where
    you have clear class imbalances, you might want to do ad hoc annotation to supplement the raw materials your model has
    to learn from.

ZenML currently offers standard steps that help you tackle the above use cases, but the stack component and abstraction
will continue to be developed to make it easier to use.

When to use it

The annotator is an optional stack component in the ZenML Stack. We designed our abstraction to fit into the larger ML
use cases, particularly the training and deployment parts of the lifecycle.

The core parts of the annotation workflow include:

  • using labels or annotations in your training steps in a seamless way
  • handling the versioning of annotation data
  • allow for the conversion of annotation data to and from custom formats
  • handle annotator-specific tasks, for example, the generation of UI config files that Label Studio requires for the web
    annotation interface

List of available annotators

For production use cases, some more flavors can be found in specific integrations modules. In terms of annotators,
ZenML features integrations with the following tools.

Annotator Flavor Integration Notes
ArgillaAnnotator argilla argilla Connect ZenML with Argilla
LabelStudioAnnotator label_studio label_studio Connect ZenML with Label Studio
PigeonAnnotator pigeon pigeon Connect ZenML with Pigeon. Notebook only & for image and text classification tasks.
ProdigyAnnotator prodigy prodigy Connect ZenML with Prodigy
Custom Implementation custom Extend the annotator abstraction and provide your own implementation

If you would like to see the available flavors for annotators, you can use the command:

shell
zenml annotator flavor list

How to use it

The available implementation of the annotator is built on top of the Label
Studio integration, which means that using an annotator currently is no
different from what's described on the Label Studio page: How to use
it?
. (Pigeon is also supported, but has a
very limited functionality and only works within Jupyter notebooks.)

A note on names

The various annotation tools have mostly standardized around the naming of key concepts as part of how they build their
tools. Unfortunately, this hasn't been completely unified so ZenML takes an opinion on which names we use for our stack
components and integrations. Key differences to note:

  • Label Studio refers to the grouping of a set of annotations/tasks as a 'Project', whereas most other tools use the
    term 'Dataset', so ZenML also calls this grouping a 'Dataset'.
  • The individual meta-unit for 'an annotation + the source data' is referred to in different ways, but at ZenML (and
    with Label Studio) we refer to them as 'tasks'.

The remaining core concepts ('annotation' and 'prediction', in particular) are broadly used among annotation tools.


Book Component Guide Artifact Stores README (`docs/book/component-guide/artifact-stores/README.md`)


icon: folder-closed

Artifact Stores

The Artifact Store is a central component in any MLOps stack. As the name suggests, it acts as a data persistence layer where artifacts (e.g. datasets, models) ingested or generated by the machine learning pipelines are stored.

ZenML automatically serializes and saves the data circulated through your pipelines in the Artifact Store: datasets, models, data profiles, data and model validation reports, and generally any object that is returned by a pipeline step. This is coupled with tracking in ZenML to provide extremely useful features such as caching and provenance/lineage tracking and pipeline reproducibility.

{% hint style="info" %}
Not all objects returned by pipeline steps are physically stored in the Artifact Store, nor do they have to be. How artifacts are serialized and deserialized and where their contents are stored are determined by the particular implementation of the Materializer associated with the artifact data type. The majority of Materializers shipped with ZenML use the Artifact Store which is part of the active Stack as the location where artifacts are kept.

If you need to store a particular type of pipeline artifact in a different medium (e.g. use an external model registry to store model artifacts, or an external data lake or data warehouse to store dataset artifacts), you can write your own Materializer to implement the custom logic required for it. In contrast, if you need to use an entirely different storage backend to store artifacts, one that isn't already covered by one of the ZenML integrations, you can extend the Artifact Store abstraction to provide your own Artifact Store implementation.
{% endhint %}

In addition to pipeline artifacts, the Artifact Store may also be used as storage backed by other specialized stack components that need to store their data in the form of persistent object storage. The Great Expectations Data Validator is such an example.

Related concepts:

  • the Artifact Store is a type of Stack Component that needs to be registered as part of your ZenML Stack.
  • the objects circulated through your pipelines are serialized and stored in the Artifact Store using Materializer. Materializers implement the logic required to serialize and deserialize the artifact contents and to store them and retrieve their contents to/from the Artifact Store.

When to use it

The Artifact Store is a mandatory component in the ZenML stack. It is used to store all artifacts produced by pipeline runs, and you are required to configure it in all of your stacks.

Artifact Store Flavors

Out of the box, ZenML comes with a local artifact store already part of the default stack that stores artifacts on your local filesystem. Additional Artifact Stores are provided by integrations:

Artifact Store Flavor Integration URI Schema(s) Notes
Local local built-in None This is the default Artifact Store. It stores artifacts on your local filesystem. Should be used only for running ZenML locally.
Amazon S3 s3 s3 s3:// Uses AWS S3 as an object store backend
Backblaze B2 b2 b2 s3:// Uses Backblaze B2 through its S3-compatible API
Google Cloud Storage gcp gcp gs:// Uses Google Cloud Storage as an object store backend
Azure azure azure abfs://, az:// Uses Azure Blob Storage as an object store backend
Alibaba Cloud OSS s3 s3 s3:// Uses S3 integration to connect to Alibaba Cloud OSS
MinIO s3 s3 s3:// Uses S3 integration to connect to self-hosted MinIO
Custom Implementation custom custom Extend the Artifact Store abstraction and provide your own implementation

If you would like to see the available flavors of Artifact Stores, you can use the command:

shell
zenml artifact-store flavor list

{% hint style="info" %}
Every Artifact Store has a path attribute that must be configured when it is registered with ZenML. This is a URI pointing to the root path where all objects are stored in the Artifact Store. It must use a URI schema that is supported by the Artifact Store flavor. For example, the S3 Artifact Store will need a URI that contains the s3:// schema:

shell
zenml artifact-store register s3_store -f s3 --path s3://my_bucket

{% endhint %}

How to use it

The Artifact Store provides low-level object storage services for other ZenML mechanisms. When you develop ZenML pipelines, you normally don't even have to be aware of its existence or interact with it directly. ZenML provides higher-level APIs that can be used as an alternative to store and access artifacts:

  • return one or more objects from your pipeline steps to have them automatically saved in the active Artifact Store as pipeline artifacts.
  • retrieve pipeline artifacts from the active Artifact Store after a pipeline run is complete.

You will probably need to interact with the low-level Artifact Store API directly:

  • if you implement custom Materializers for your artifact data types
  • if you want to store custom objects in the Artifact Store

The Artifact Store API

All ZenML Artifact Stores implement the same IO API that resembles a standard file system. This allows you to access and manipulate the objects stored in the Artifact Store in the same manner you would normally handle files on your computer and independently of the particular type of Artifact Store that is configured in your ZenML stack.

Accessing the low-level Artifact Store API can be done through the following Python modules:

  • zenml.io.fileio provides low-level utilities for manipulating Artifact Store objects (e.g. open, copy, rename , remove, mkdir). These functions work seamlessly across Artifact Stores types. They have the same signature as the Artifact Store abstraction methods ( in fact, they are one and the same under the hood).
  • zenml.utils.io_utils includes some higher-level helper utilities that make it easier to find and transfer objects between the Artifact Store and the local filesystem or memory.

{% hint style="info" %}
When calling the Artifact Store API, you should always use URIs that are relative to the Artifact Store root path, otherwise, you risk using an unsupported protocol or storing objects outside the store. You can use the Repository singleton to retrieve the root path of the active Artifact Store and then use it as a base path for artifact URIs, e.g.:

python
import os
from zenml.client import Client
from zenml.io import fileio

root_path = Client().active_stack.artifact_store.path

artifact_contents = "example artifact"
artifact_path = os.path.join(root_path, "artifacts", "examples")
artifact_uri = os.path.join(artifact_path, "test.txt")
fileio.makedirs(artifact_path)
with fileio.open(artifact_uri, "w") as f:
    f.write(artifact_contents)

When using the Artifact Store API to write custom Materializers, the base artifact URI path is already provided. See the documentation on Materializers for an example.
{% endhint %}

The following are some code examples showing how to use the Artifact Store API for various operations:

  • creating folders, writing and reading data directly to/from an artifact store object
python
import os
from zenml.utils import io_utils
from zenml.io import fileio

from zenml.client import Client

root_path = Client().active_stack.artifact_store.path

artifact_contents = "example artifact"
artifact_path = os.path.join(root_path, "artifacts", "examples")
artifact_uri = os.path.join(artifact_path, "test.txt")
fileio.makedirs(artifact_path)
io_utils.write_file_contents_as_string(artifact_uri, artifact_contents)
python
import os
from zenml.utils import io_utils

from zenml.client import Client

root_path = Client().active_stack.artifact_store.path

artifact_path = os.path.join(root_path, "artifacts", "examples")
artifact_uri = os.path.join(artifact_path, "test.txt")
artifact_contents = io_utils.read_file_contents_as_string(artifact_uri)
  • using a temporary local file/folder to serialize and copy in-memory objects to/from the artifact store (heavily used in Materializers to transfer information between the Artifact Store and external libraries that don't support writing/reading directly to/from the artifact store backend):
python
import os
import tempfile
import external_lib
from zenml.client import Client
from zenml.io import fileio

root_path = Client().active_stack.artifact_store.path

artifact_path = os.path.join(root_path, "artifacts", "examples")
artifact_uri = os.path.join(artifact_path, "test.json")
fileio.makedirs(artifact_path)

with tempfile.NamedTemporaryFile(
        mode="w", suffix=".json", delete=True
) as f:
    external_lib.external_object.save_to_file(f.name)
    # Copy it into artifact store
    fileio.copy(f.name, artifact_uri)
python
import os
import tempfile
import external_lib
from zenml.client import Client
from zenml.io import fileio

root_path = Client().active_stack.artifact_store.path

artifact_path = os.path.join(root_path, "artifacts", "examples")
artifact_uri = os.path.join(artifact_path, "test.json")

with tempfile.NamedTemporaryFile(
        mode="w", suffix=".json", delete=True
) as f:
    # Copy the serialized object from the artifact store
    fileio.copy(artifact_uri, f.name)
    external_lib.external_object.load_from_file(f.name)

Book Component Guide Container Registries README (`docs/book/component-guide/container-registries/README.md`)


icon: box

Container Registries

The container registry is an essential part of most remote MLOps stacks. It is used to store container images that are built to run machine learning pipelines in remote environments. Containerization of the pipeline code creates a portable environment that allows code to run in an isolated manner.

When to use it

The container registry is needed whenever other components of your stack need to push or pull container images. Currently, this is the case for most of ZenML's remote orchestrators , step operators, and some model deployers. These containerize your pipeline code and therefore require a container registry to store the resulting Docker images. Take a look at the documentation page of the component you want to use in your stack to see if it requires a container registry or even a specific container registry flavor.

Container Registry Flavors

ZenML comes with a few container registry flavors that you can use:

  • Default flavor: Allows any URI without validation. Use this if you want to use a local container registry or when using a remote container registry that is not covered by other flavors.
  • Specific flavors: Validates your container registry URI and performs additional checks to ensure you're able to push to the registry.

{% hint style="warning" %}
We highly suggest using the specific container registry flavors in favor of the default one to make use of the additional URI validations.
{% endhint %}

Container Registry Flavor Integration URI example
DefaultContainerRegistry default built-in -
DockerHubContainerRegistry dockerhub built-in docker.io/zenml
GCPContainerRegistry gcp built-in gcr.io/zenml
AzureContainerRegistry azure built-in zenml.azurecr.io
GitHubContainerRegistry github built-in ghcr.io/zenml
AWSContainerRegistry aws aws 123456789.dkr.ecr.us-east-1.amazonaws.com

If you would like to see the available flavors of container registries, you can use the command:

shell
zenml container-registry flavor list

Book Component Guide Data Validators README (`docs/book/component-guide/data-validators/README.md`)


How to enhance and maintain the quality of your data and the performance of your models with data profiling and validation icon: chart-column

Data Validators

Without good data, even the best machine learning models will yield questionable results. A lot of effort goes into ensuring and maintaining data quality not only in the initial stages of model development, but throughout the entire machine learning project lifecycle. Data Validators are a category of ML libraries, tools and frameworks that grant a wide range of features and best practices that should be employed in the ML pipelines to keep data quality in check and to monitor model performance to keep it from degrading over time.

Data profiling, data integrity testing, data and model drift detection are all ways of employing data validation techniques at different points in your ML pipelines where data is concerned: data ingestion, model training and evaluation and online or batch inference. Data profiles and model performance evaluation results can be visualized and analyzed to detect problems and take preventive or correcting actions.

Related concepts:

  • the Data Validator is an optional type of Stack Component that needs to be registered as part of your ZenML Stack.
  • Data Validators used in ZenML pipelines usually generate data profiles and data quality check reports that are versioned and stored in the Artifact Store and can be retrieved and visualized later.

When to use it

Data-centric AI practices are quickly becoming mainstream and using Data Validators are an easy way to incorporate them into your workflow. These are some common cases where you may consider employing the use of Data Validators in your pipelines:

  • early on, even if it's just to keep a log of the quality state of your data and the performance of your models at different stages of development.
  • if you have pipelines that regularly ingest new data, you should use data validation to run regular data integrity checks to signal problems before they are propagated downstream.
  • in continuous training pipelines, you should use data validation techniques to compare new training data against a data reference and to compare the performance of newly trained models against previous ones.
  • when you have pipelines that automate batch inference or if you regularly collect data used as input in online inference, you should use data validation to run data drift analyzes and detect training-serving skew, data drift and model drift.

Data Validator Flavors

Data Validator are optional stack components provided by integrations. The following table lists the currently available Data Validators and summarizes their features and the data types and model types that they can be used with in ZenML pipelines:

Data Validator Validation Features Data Types Model Types Notes Flavor/Integration
Deepchecks data qualitydata driftmodel driftmodel performance tabular: pandas.DataFrameCV: torch.utils.data.dataloader.DataLoader tabular: sklearn.base.ClassifierMixinCV: torch.nn.Module Add Deepchecks data and model validation tests to your pipelines deepchecks
Evidently data qualitydata driftmodel driftmodel performance tabular: pandas.DataFrame N/A Use Evidently to generate a variety of data quality and data/model drift reports and visualizations evidently
Great Expectations data profilingdata quality tabular: pandas.DataFrame N/A Perform data testing, documentation and profiling with Great Expectations great_expectations
Whylogs/WhyLabs data drift tabular: pandas.DataFrame N/A Generate data profiles with whylogs. Hosted WhyLabs platform is being discontinued after Apple's acquisition—see the integration page for OSS deployment options. whylogs

If you would like to see the available flavors of Data Validator, you can use the command:

shell
zenml data-validator flavor list

How to use it

Every Data Validator has different data profiling and testing capabilities and uses a slightly different way of analyzing your data and your models, but it generally works as follows:

  • first, you have to configure and add a Data Validator to your ZenML stack
  • every integration includes one or more builtin data validation steps that you can add to your pipelines. Of course, you can also use the libraries directly in your own custom pipeline steps and simply return the results (e.g. data profiles, test reports) as artifacts that are versioned and stored by ZenML in its Artifact Store.
  • you can access the data validation artifacts in subsequent pipeline steps, or fetch them afterwards to process them or visualize them as needed.

Consult the documentation for the particular Data Validator flavor that you plan on using or are using in your stack for detailed information about how to use it in your ZenML pipelines.


Book Component Guide Deployers README (`docs/book/component-guide/deployers/README.md`)


icon: rocket-launch

Deployers

Pipeline deployment is the process of making ZenML pipelines available as long-running HTTP services for real-time execution. Unlike traditional batch execution through orchestrators, deployers create persistent web services that can handle on-demand pipeline invocations through HTTP requests.

Deployers are stack components responsible for managing the deployment of pipelines as containerized HTTP services that expose REST APIs for pipeline execution.

A deployed pipeline becomes a web service that can be invoked multiple times in parallel, receiving parameters through HTTP requests and returning pipeline outputs as JSON responses. This enables real-time inference, interactive workflows, and integration with web applications.

When to use it?

Deployers are optional components in the ZenML stack. They are useful in the following scenarios:

  • Real-time Pipeline Execution: Execute pipelines on-demand through HTTP requests rather than scheduled batch runs
  • Interactive Workflows: Build applications that need immediate pipeline responses
  • API Integration: Expose ML workflows as REST APIs for web applications or microservices
  • Real-time Inference: Serve ML models through pipeline-based inference workflows
  • Agent-based Systems: Create AI agents that execute pipelines in response to external events

Use deployers when you need request-response patterns, and orchestrators for scheduled, batch, or long-running workflows.

Deployer Flavors

Out of the box, ZenML comes with a local deployer already part of the default stack that deploys pipelines on your local machine in the form of background processes. Additional Deployers are provided by integrations:

Deployer Flavor Integration Notes
Local local built-in This is the default Deployer. It deploys pipelines on your local machine in the form of background processes. Should be used only for running ZenML locally.
Docker docker Built-in Deploys pipelines as locally running Docker containers
Kubernetes kubernetes kubernetes Deploys pipelines to any Kubernetes cluster with full control over resources, networking, and scaling
GCP Cloud Run gcp gcp Deploys pipelines to Google Cloud Run for serverless execution
AWS App Runner aws aws Deploys pipelines to AWS App Runner for serverless execution
Hugging Face huggingface huggingface Deploys pipelines to Hugging Face Spaces as Docker Spaces

If you would like to see the available flavors of deployers, you can use the command:

shell
zenml deployer flavor list

How to use it

You don't need to directly interact with the ZenML deployer stack component in your code. As long as the deployer that you want to use is part of your active ZenML stack, you can simply deploy a pipeline or snapshot using the ZenML CLI or the ZenML SDK. The resulting deployment can be managed using the ZenML CLI or the ZenML SDK.

Examples:

  • just use the default stack - it has a default local deployer that will deploy the pipeline on your local machine in the form of a background process:
bash
zenml stack set default
  • or set up a new stack with a deployer in it:
bash
zenml deployer register docker --flavor=local
zenml stack register docker_deployment -a default -o default -D docker --set
  • deploy a pipeline with the ZenML SDK:
python
from zenml import pipeline

@step
def my_step(name: str) -> str:
    return f"Hello, {name}!"

@pipeline
def my_pipeline(name: str = "John") -> str:
    return my_step(name=name)

if __name__ == "__main__":
    # Deploy the pipeline `my_pipeline` as a deployment named `my_deployment`
    deployment = my_pipeline.deploy(deployment_name="my_deployment")
    print(f"Deployment URL: {deployment.url}")
  • deploy the same pipeline with the CLI:
bash
zenml pipeline deploy --name my_deployment my_module.my_pipeline
  • send a request to the deployment with the ZenML CLI:
bash
zenml deployment invoke my_deployment --name="Alice"
  • or with curl:
bash
curl -X POST http://localhost:8000/invoke \
  -H "Content-Type: application/json" \
  -d '{"parameters": {"name": "Alice"}}'
  • alternatively, set up a snapshot and deploy it instead of a pipeline:
bash
zenml pipeline snapshot create --name my_snapshot my_module.my_pipeline
zenml pipeline snapshot deploy my_snapshot --deployment my_deployment

Pipeline Requirements for Deployment

Not all pipelines are suitable for deployment as HTTP services. To be deployable, pipelines should follow these guidelines:

Parameter Requirements:

  • Pipelines should accept explicit parameters with default values
  • Parameters must be JSON-serializable types (int, float, str, bool, list, dict, Pydantic models)
  • Parameter names should match step input names

Output Requirements:

  • Pipelines should return meaningful values for HTTP responses
  • Return values must be JSON-serializable
  • It's recommended to use type annotations to specify output artifact names

Example Deployable Pipeline:

python
from typing import Annotated
from zenml import pipeline, step

@step
def process_weather(city: str, temperature: float) -> Annotated[str, "weather_analysis"]:
    return f"The weather in {city} is {temperature} degrees Celsius."

@pipeline
def weather_pipeline(city: str = "Paris", temperature: float = 20.0) -> str:
    """A deployable pipeline that processes weather data."""
    analysis = process_weather(city=city, temperature=temperature)
    return analysis

For more information, see the Deployable Pipeline Requirements section of the tutorial.

Deployment Lifecycle Management

The Deployment object represents a pipeline that has been deployed to a serving environment. The Deployment object is saved in the ZenML database and contains information about the deployment configuration, status, and connection details. Deployments are standalone entities that can be managed independently of the active stack through the Deployer stack components that were originally used to provision them.

Some example of how to manage deployments:

  • listing deployments with the CLI:
bash
$ zenml deployment list
┏━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃         NAME         │ PIPELINE                             │ URL                            │ STATUS                   ┃
┠──────────────────────┼──────────────────────────────────────┼────────────────────────────────┼──────────────────────────┨
┃  weather_service     │ weather_pipeline                     │ http://localhost:8001          │ ⚙ RUNNING               ┃
┠──────────────────────┼──────────────────────────────────────┼────────────────────────────────┼──────────────────────────┨
┃  ml_inference_api    │ inference_pipeline                   │ http://k8s-cluster/ml-api      │ ⚙ RUNNING               ┃
┗━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  • listing deployments with the SDK:
python
from zenml.client import Client

client = Client()
deployments = client.list_deployments()
for deployment in deployments:
    print(f"{deployment.name}: {deployment.status}")
  • showing detailed information about a deployment with the CLI:
text
/* Detailed source-code truncated for AI context efficiency. */
  • showing detailed information about a deployment with the SDK:
python
from zenml.client import Client
deployment = client.get_deployment("my_deployment")
print(deployment)
  • deprovision and delete a deployment with the CLI:
bash
$ zenml deployment delete my_deployment
  • deprovisioning and deleting a deployment with the SDK:
python
from zenml.client import Client
client = Client()
client.delete_deployment("my_deployment")
  • sending a request to a deployment with the CLI:
bash
$ zenml deployment invoke my_deployment --name="John"

Invoked deployment 'my_deployment' with response:
{
  "success": true,
  "outputs": {
    "output": "Hello, John!"
  },
  "execution_time": 3.2781872749328613,
  "metadata": {
    "deployment_id": "95d60dcf-7c37-4e62-a923-a341601903e5",
    "deployment_name": "my_deployment",
    "snapshot_id": "f3122ed4-aa13-4113-9f60-a80545f56244",
    "snapshot_name": "my_snapshot",
    "pipeline_name": "my_pipeline",
    "run_id": "ea448522-d5bf-411e-971e-d4550fdbe713",
    "run_name": "my_pipeline-2025_09_30-12_52_01_012491",
    "parameters_used": {}
  },
  "error": null
}
  • sending a request to a deployment with the SDK:
python
from zenml.deployers.utils import invoke_deployment

response = invoke_deployment(
    deployment_name_or_id="my_deployment",
    name="John",
)
print(response)

By default, invoking a deployment blocks until the pipeline run finishes and returns its outputs. To submit the run for background execution and get the run ID back immediately instead, pass --no-wait on the CLI or submit=True with the SDK:

bash
$ zenml deployment invoke my_deployment --name="John" --no-wait
python
response = invoke_deployment(
    deployment_name_or_id="my_deployment",
    name="John",
    submit=True,
)

Specifying deployment resources

If your steps require additional hardware resources, you can specify them on your steps as described here.


Book Component Guide Experiment Trackers README (`docs/book/component-guide/experiment-trackers/README.md`)


icon: clipboard

Experiment Trackers

Experiment trackers let you track your ML experiments by logging extended information about your models, datasets, metrics, and other parameters and allowing you to browse them, visualize them and compare them between runs. In the ZenML world, every pipeline run is considered an experiment, and ZenML facilitates the storage of experiment results through Experiment Tracker stack components. This establishes a clear link between pipeline runs and experiments.

Related concepts:

  • the Experiment Tracker is an optional type of Stack Component that needs to be registered as part of your ZenML Stack.
  • ZenML already provides versioning and tracking for the pipeline artifacts by storing artifacts in the Artifact Store.

When to use it

ZenML already records information about the artifacts circulated through your pipelines by means of the mandatory Artifact Store.

However, these ZenML mechanisms are meant to be used programmatically and can be more difficult to work with without a visual interface.

Experiment Trackers on the other hand are tools designed with usability in mind. They include extensive UIs providing users with an interactive and intuitive interface that allows them to browse and visualize the information logged during the ML pipeline runs.

You should add an Experiment Tracker to your ZenML stack and use it when you want to augment ZenML with the visual features provided by experiment tracking tools.

How they experiment trackers slot into the stack

Here is an architecture diagram that shows how experiment trackers fit into the overall story of a remote stack.

Experiment Tracker Flavors

Experiment Trackers are optional stack components provided by integrations:

Experiment Tracker Flavor Integration Notes
Comet comet comet Add Comet experiment tracking and visualization capabilities to your ZenML pipelines
MLflow mlflow mlflow Add MLflow experiment tracking and visualization capabilities to your ZenML pipelines
Neptune neptune neptune Add Neptune experiment tracking and visualization capabilities to your ZenML pipelines
Weights & Biases wandb wandb Add Weights & Biases experiment tracking and visualization capabilities to your ZenML pipelines
Trackio trackio trackio Add Trackio experiment tracking and visualization capabilities to your ZenML pipelines
Custom Implementation custom custom

If you would like to see the available flavors of Experiment Tracker, you can use the command:

shell
zenml experiment-tracker flavor list

How to use it

Every Experiment Tracker has different capabilities and uses a different way of logging information from your pipeline steps, but it generally works as follows:

  • first, you have to configure and add an Experiment Tracker to your ZenML stack
  • next, you have to explicitly enable the Experiment Tracker for individual steps in your pipeline by decorating them with the included decorator
  • in your steps, you have to explicitly log information (e.g. models, metrics, data) to the Experiment Tracker same as you would if you were using the tool independently of ZenML
  • finally, you can access the Experiment Tracker UI to browse and visualize the information logged during your pipeline runs. You can use the following code snippet to get the URL of the experiment tracker UI for the experiment linked to a certain step of your pipeline run:

{% hint style="info" %}
Stacks can have multiple experiment trackers attached. If you enable tracking with @step(experiment_tracker=True), ZenML activates all attached experiment trackers for that step. If you want to use only one tracker, specify it explicitly by name in the @step decorator.
{% endhint %}

python
from zenml.client import Client

pipeline_run = Client().get_pipeline_run("<PIPELINE_RUN_NAME>")
step = pipeline_run.steps["<STEP_NAME>"]
experiment_tracker_url = step.run_metadata["experiment_tracker_url"].value

{% hint style="info" %}
Experiment trackers will automatically declare runs as failed if the corresponding ZenML pipeline step fails.
{% endhint %}

Consult the documentation for the particular Experiment Tracker flavor that you plan on using or are using in your stack for detailed information about how to use it in your ZenML pipelines.


Book Component Guide Feature Stores README (`docs/book/component-guide/feature-stores/README.md`)


icon: database

Feature Stores

Feature stores allow data teams to serve data via an offline store and an online low-latency store where data is kept in
sync between the two. It also offers a centralized registry where features (and feature schemas) are stored for use
within a team or wider organization.

As a data scientist working on training your model, your requirements for how you access your batch / 'offline' data
will almost certainly be different from how you access that data as part of a real-time or online inference setting.
Feast solves the problem of developing train-serve skew where those two
sources of data diverge from each other.

Feature stores are a relatively recent addition to commonly-used machine learning stacks.

When to use it

The feature store is an optional stack component in the ZenML Stack. The feature store as a technology should be used to
store the features and inject them into the process on the server side. This includes

  • Productionalize new features
  • Reuse existing features across multiple pipelines and models
  • Achieve consistency between training and serving data (Training Serving Skew)
  • Provide a central registry of features and feature schemas

List of available feature stores

For production use cases, some more flavors can be found in specific integrations modules. In terms of features
stores, ZenML features an integration of feast.

Feature Store Flavor Integration Notes
FeastFeatureStore feast feast Connect ZenML with already existing Feast
Custom Implementation custom Extend the feature store abstraction and provide your own implementation

If you would like to see the available flavors for feature stores, you can use the command:

shell
zenml feature-store flavor list

How to use it

The available implementation of the feature store is built on top of the feast integration, which means that using a
feature store is no different from what's described on the feast page: How to use it?.


Book Component Guide Image Builders README (`docs/book/component-guide/image-builders/README.md`)


icon: box-open

Image Builders

The image builder is an essential part of most remote MLOps stacks. It is used to build container images such that your machine-learning pipelines and steps can be executed in remote environments.

When to use it

The image builder is needed whenever other components of your stack need to build container images. Currently, this is the case for most of ZenML's remote orchestrators , step operators, and some model deployers. These containerize your pipeline code and therefore require an image builder to build Docker images.

Image Builder Flavors

Out of the box, ZenML comes with a local image builder that builds OCI images on your client machine using Docker or Podman, depending on your global container engine setting. Additional image builders are provided by integrations:

Image Builder Flavor Integration Notes
LocalImageBuilder local built-in Builds images locally (Docker or Podman).
KanikoImageBuilder kaniko kaniko Builds your Docker images in Kubernetes using Kaniko. Note: Kaniko project was archived in June 2025.
GCPImageBuilder gcp gcp Builds your Docker images using Google Cloud Build.
AWSImageBuilder aws aws Builds your Docker images using AWS Code Build.
Custom Implementation custom Extend the image builder abstraction and provide your own implementation

If you would like to see the available flavors of image builders, you can use the command:

shell
zenml image-builder flavor list

How to use it

You don't need to directly interact with any image builder in your code. As long as the image builder that you want to use is part of your active ZenML stack, it will be used automatically by any component that needs to build container images.


Book Component Guide Log Stores README (`docs/book/component-guide/log-stores/README.md`)


icon: file-lines

Log Stores

The log store is a stack component responsible for collecting, storing, and retrieving logs generated during pipeline and step execution. It captures everything from standard logging output to print statements and any messages written to stdout/stderr, making it easy to debug and monitor your ML workflows.

How it works

ZenML's log capture system is designed to be comprehensive and non-intrusive. Here's what happens under the hood:

  1. stdout/stderr wrapping: ZenML wraps the standard output and error streams to capture all printed messages and any output directed to these streams.

  2. Root logger handler: A custom handler is added to Python's root logger to capture all log messages with proper metadata from loggers that propagate to the root.

  3. Log routing: All captured messages are routed through a LoggingContext to the active log store in your stack.

This approach ensures that you don't miss any output from your pipeline steps, including:

  • Standard Python logging messages
  • print() statements
  • Output from third-party libraries
  • Messages from subprocesses that write to stdout/stderr

When to use it

The Log Store is automatically used in every ZenML stack. If you don't explicitly configure a log store, ZenML will use an Artifact Log Store by default, which stores logs in your artifact store.

You should consider configuring a dedicated log store when:

  • You want to use a centralized logging backend like Datadog, Jaeger, Grafana Tempo, Honeycomb, Lightstep or Dash0 for log aggregation and analysis
  • You need advanced log querying capabilities beyond what file-based storage provides
  • You're running pipelines at scale and need better log management
  • You want to integrate with your organization's existing observability infrastructure

How to use it

By default, if no log store is explicitly configured in your stack, ZenML automatically creates an Artifact Log Store that uses your artifact store for log storage. This means logging works out of the box without any additional configuration.

To use a different log store, you need to register it and add it to your stack:

shell
# Register a log store (example with Datadog)
zenml log-store register <LOG_STORE_NAME> \
    --flavor=datadog \
    --api_key=<DATADOG_API_KEY> \
    --application_key=<DATADOG_APPLICATION_KEY>

# Add it to your stack
zenml stack register <STACK_NAME> -a <ARTIFACT_STORE> -o <ORCHESTRATOR> --log_store <LOG_STORE_NAME> --set

Once configured, logs are automatically captured during pipeline execution.

Viewing Logs

You can view step logs in the ZenML dashboard or in your logging provider's UI. To retrieve them programmatically, use the Python SDK or REST API.

Python SDK

Use the log store that captured the logs:

python
from zenml.client import Client
from zenml.utils.logging_utils import search_logs_by_source

client = Client()

run = client.get_pipeline_run("<RUN_NAME_OR_ID>")
step_run = run.steps["<STEP_NAME>"]
logs = search_logs_by_source(step_run.log_collection or [], "step")
if logs is None:
    raise ValueError("This step has no execution log stream.")

log_store = client.active_stack.log_store
page = log_store.fetch(logs_model=logs, limit=1000)

for entry in page.items:
    print(f"[{entry.level}] {entry.message}")

fetch() returns a page with entries in items, ordered from oldest to newest. Set start="oldest" or start="newest" to choose the first page, or omit it to use the backend's default: newest for Datadog, oldest for the artifact log store.

For backends with pagination, pass the returned before cursor to read older entries or after to read newer ones. Only directions supported by the backend's native tokens are available; None means there is no continuation in that direction.

For example, with Datadog, filter the first request and use its cursor to continue:

python
from zenml.models import LogsEntriesFilter

page = log_store.fetch(
    logs_model=logs,
    start="newest",
    filter_=LogsEntriesFilter(level="ERROR", search="ValueError"),
)
while True:
    for entry in page.items:
        print(entry.message)
    if page.before is None:
        break
    page = log_store.fetch(logs_model=logs, before=page.before)

Datadog cursors retain the filters, page size, and fixed time bounds. Search follows the backend's matching rules, which may differ from a literal substring match.

The artifact log store returns one batch for client-side filtering and pagination. It does not support these filters or start="newest".

Each entry has a UUID id. IDs remain stable for Datadog events and structured artifact logs. Deduplicate entries within a stream by (id, chunk_index) to preserve chunks of the same message. Shared log types, including LogEntry, are available from zenml.models.

REST API

GET /api/v1/logs/{logs_id}/entries accepts start, limit, before, after, search, level, since, and until as query parameters. For example:

http
GET /api/v1/logs/<LOGS_ID>/entries?start=newest&limit=50
GET /api/v1/logs/<LOGS_ID>/entries?before=<CURSOR>

Invalid query values return 422; unsupported parameters and cursors rejected by ZenML return 400. Backends without log retrieval return 501. Shared log store errors return 429 for throttling, 503 for unavailability, or 502 for other backend errors. When provided, Retry-After specifies the delay in seconds before retrying the original request. Direct SDK calls raise the corresponding LogStoreError subclass.

Runner logs return one batch through the workload manager. Apply filtering and pagination in the client; unsupported runner filters or cursors return 400.

The existing run and step log endpoints continue to return a single list of entries. Use the dedicated entries endpoint for pagination.

Log Store Flavors

ZenML provides several log store flavors out of the box:

Log Store Flavor Integration Notes
ArtifactLogStore artifact built-in Default log store that writes logs to your artifact store. Zero configuration required.
OtelLogStore otel built-in Generic OpenTelemetry log store for any OTEL-compatible backend. Does not support log fetching.
DatadogLogStore datadog built-in Exports logs to Datadog's log management platform with full fetch support.
Custom Implementation custom Extend the log store abstraction and provide your own implementation.

If you would like to see the available flavors of log stores, you can use the command:

shell
zenml log-store flavor list

{% hint style="info" %}
If you're interested in understanding the base abstraction and how log stores work internally, check out the Develop a Custom Log Store page for a detailed explanation of the architecture.
{% endhint %}


Book Component Guide Model Deployers README (`docs/book/component-guide/model-deployers/README.md`)


icon: rocket

Model Deployers

{% hint style="warning" %}
DEPRECATION NOTICE

The Model Deployer stack component is deprecated in favor of the more flexible Deployer component and Pipeline Deployments.

The Model Deployer abstraction focused exclusively on single-model serving, but modern ML workflows often require multi-step pipelines with preprocessing, tool integration, and custom business logic. The new Pipeline Deployment paradigm provides:

  • Unified approach: Deploy any pipeline—classical ML inference, agentic workflows, or hybrid systems—as a long-running HTTP service
  • Greater flexibility: Customize your deployment with full FastAPI control, add middleware, custom routes, and even frontend interfaces
  • Simpler mental model: One primitive for all deployment scenarios instead of separate abstractions for models vs. pipelines
  • Better extensibility: Deploy to Docker, AWS App Runner, GCP Cloud Run, and other platforms with consistent patterns

Migration Path: Instead of using Model Deployer-specific steps, wrap your model inference logic in a regular ZenML pipeline and deploy it using zenml pipeline deploy. See the Pipeline Deployment guide for examples of deploying ML models as HTTP services.

While Model Deployer integrations remain available for backward compatibility, we strongly recommend migrating to Pipeline Deployments for new projects.
{% endhint %}

Model Deployment is the process of making a machine learning model available to make predictions and decisions on
real-world data. Getting predictions from trained models can be done in different ways depending on the use case, a
batch prediction is used to generate predictions for a large amount of data at once, while a real-time prediction is
used to generate predictions for a single data point at a time.

Model deployers are stack components responsible for serving models on a real-time or batch basis.

Online serving is the process of hosting and loading machine-learning models as part of a managed web service and
providing access to the models through an API endpoint like HTTP or GRPC. Once deployed, model inference can be
triggered at any time, and you can send inference requests to the model through the web service's API and receive fast,
low-latency responses.

Batch inference or offline inference is the process of making a machine learning model make predictions on a batch of
observations. This is useful for generating predictions for a large amount of data at once. The predictions are usually
stored as files or in a database for end users or business applications.

When to use it?

The model deployers are optional components in the ZenML stack. They are used to deploy machine learning models to a
target environment, either a development (local) or a production (Kubernetes or cloud) environment. The model deployers are mainly used to deploy models for real-time inference use cases. With the model deployers and other stack components, you can build pipelines that are continuously trained and deployed to production.

How model deployers slot into the stack

Here is an architecture diagram that shows how model deployers fit into the overall story of a remote stack.

Model Deployers Flavors

ZenML comes with a local MLflow model deployer which is a simple model deployer that deploys models to a local MLflow
server. Additional model deployers that can be used to deploy models on production environments are provided by
integrations:

Model Deployer Flavor Integration Notes
MLflow mlflow mlflow Deploys ML Model locally
BentoML bentoml bentoml Build and Deploy ML models locally or for production grade (Cloud, K8s)
Seldon Core seldon seldon Core Built on top of Kubernetes to deploy models for production grade environment
Hugging Face huggingface huggingface Deploys ML model on Hugging Face Inference Endpoints
Databricks databricks databricks Deploying models to Databricks Inference Endpoints with Databricks
vLLM vllm vllm Deploys LLM using vLLM locally
Custom Implementation custom Extend the Artifact Store abstraction and provide your own implementation

{% hint style="info" %}
Every model deployer may have different attributes that must be configured in order to interact with the model serving
tool, framework, or platform (e.g. hostnames, URLs, references to credentials, and other client-related configuration
parameters). The following example shows the configuration of the MLflow and Seldon Core model deployers:

shell
# Configure MLflow model deployer
zenml model-deployer register mlflow --flavor=mlflow

# Configure Seldon Core model deployer
zenml model-deployer register seldon --flavor=seldon \
--kubernetes_context=zenml-eks --kubernetes_namespace=zenml-workloads \
--base_url=http://abb84c444c7804aa98fc8c097896479d-377673393.us-east-1.elb.amazonaws.com
...

{% endhint %}

The role that a model deployer plays in a ZenML Stack

  • Seamless Model Deployment: Facilitates the deployment of machine learning models to various serving environments, such as local servers, Kubernetes clusters, or cloud platforms, ensuring that models can be deployed and managed efficiently in accordance with the specific requirements of the serving infrastructure by holds all the stack-related configuration attributes required to interact with the remote model serving tool, service, or platform (e.g. hostnames, URLs, references to credentials, and other client-related configuration parameters). The following are examples of configuring the MLflow and Seldon Core Model Deployers and registering them as a Stack component:

    bash
    zenml integration install mlflow
    zenml model-deployer register mlflow --flavor=mlflow
    zenml stack register local_with_mlflow -m default -a default -o default -d mlflow --set
    bash
    zenml integration install seldon
    zenml model-deployer register seldon --flavor=seldon \
    --kubernetes_context=zenml-eks --kubernetes_namespace=zenml-workloads \
    --base_url=http://abb84c444c7804aa98fc8c097896479d-377673393.us-east-1.elb.amazonaws.com
    ...
    zenml stack register seldon_stack -m default -a aws -o default -d seldon
  • Lifecycle Management: Provides mechanisms for comprehensive lifecycle management of model servers, including the ability to start, stop, and delete model servers, as well as to update existing servers with new model versions, thereby optimizing resource utilization and facilitating continuous delivery of model updates. Some core methods that can be used to interact with the remote model server include:

    • deploy_model - Deploys a model to the serving environment and returns a Service object that represents the deployed model server.
    • find_model_server - Finds and returns a list of Service objects that
      represent model servers that have been deployed to the serving environment,
      the services are stored in the DB and can be used as a reference to know what and where the model is deployed.
    • stop_model_server - Stops a model server that is currently running in the serving environment.
    • start_model_server - Starts a model server that has been stopped in the serving environment.
    • delete_model_server - Deletes a model server from the serving environment and from the DB.

{% hint style="info" %}
ZenML uses the Service object to represent a model server that has been deployed to a serving environment. The Service object is saved in the DB and can be used as a reference to know what and where the model is deployed. The Service object consists of 2 main attributes, the config and the status. The config attribute holds all the deployment configuration attributes required to create a new deployment, while the status attribute holds the operational status of the deployment, such as the last error message, the prediction URL, and the deployment status.
{% endhint %}

python
from zenml.integrations.huggingface.model_deployers import HuggingFaceModelDeployer

model_deployer = HuggingFaceModelDeployer.get_active_model_deployer()
services = model_deployer.find_model_server(
    pipeline_name="LLM_pipeline",
    pipeline_step_name="huggingface_model_deployer_step",
    model_name="LLAMA-7B",
)
if services:
    if services[0].is_running:
        print(
            f"Model server {services[0].config['model_name']} is running at {services[0].status['prediction_url']}"
           )
     else:
         print(f"Model server {services[0].config['model_name']} is not running")
         model_deployer.start_model_server(services[0])
 else:
     print("No model server found")
     service = model_deployer.deploy_model(
         pipeline_name="LLM_pipeline",
         pipeline_step_name="huggingface_model_deployer_step",
         model_name="LLAMA-7B",
         model_uri="s3://zenprojects/huggingface_model_deployer_step/output/884/huggingface",
         revision="main",
         task="text-classification",
         region="us-east-1",
         vendor="aws",
         token="huggingface_token",
         namespace="zenml-workloads",
         endpoint_type="public",
     )
     print(f"Model server {service.config['model_name']} is deployed at {service.status['prediction_url']}")

How to Interact with a model deployer after deployment?

When a Model Deployer is part of the active ZenML Stack, it is also possible to interact with it from the CLI to list,
start, stop, or delete the model servers that is managed:

text
/* Detailed source-code truncated for AI context efficiency. */

In Python, you can alternatively discover the prediction URL of a deployed model by inspecting the metadata of the step
that deployed the model:

python
from zenml.client import Client

pipeline_run = Client().get_pipeline_run("<PIPELINE_RUN_NAME>")
deployer_step = pipeline_run.steps["<NAME_OF_MODEL_DEPLOYER_STEP>"]
deployed_model_url = deployer_step.run_metadata["deployed_model_url"].value

The ZenML integrations that provide Model Deployer stack components also include standard pipeline steps that can
directly be inserted into any pipeline to achieve a continuous model deployment workflow. These steps take care of all
the aspects of continuously deploying models to an external server and saving the Service configuration into the
Artifact Store, where they can be loaded at a later time and re-create the initial conditions used to serve a particular
model.


Book Component Guide Model Registries README (`docs/book/component-guide/model-registries/README.md`)


icon: table-rows

Model Registries

Model registries are centralized storage solutions for managing and tracking machine learning models across various stages of development and deployment. They help track the different versions and configurations of each model and enable reproducibility. By storing metadata such as version, configuration, and metrics, model registries help streamline the management of trained models. In ZenML, model registries are Stack Components that allow for the easy retrieval, loading, and deployment of trained models. They also provide information on the pipeline in which the model was trained and how to reproduce it.

Model Registry Concepts and Terminology

ZenML provides a unified abstraction for model registries through which it is possible to handle and manage the concepts of model groups, versions, and stages in a consistent manner regardless of the underlying registry tool or platform being used. The following concepts are useful to be aware of for this abstraction:

  • RegisteredModel: A logical grouping of models that can be used to track different versions of a model. It holds information about the model, such as its name, description, and tags, and can be created by the user or automatically created by the model registry when a new model is logged.
  • RegistryModelVersion: A specific version of a model identified by a unique version number or string. It holds information about the model, such as its name, description, tags, and metrics, and a reference to the model artifact logged to the model registry. In ZenML, it also holds a reference to the pipeline name, pipeline run ID, and step name. Each model version is associated with a model registration.
  • ModelVersionStage: A model version stage is a state in that a model version can be. It can be one of the following: None, Staging, Production, Archived. The model version stage is used to track the lifecycle of a model version. For example, a model version can be in the Staging stage while it is being tested and then moved to the Production stage once it is ready for deployment.

When to use it

ZenML provides a built-in mechanism for storing and versioning pipeline artifacts through its mandatory Artifact Store. While this is a powerful way to manage artifacts programmatically, it can be challenging to use without a visual interface.

Model registries, on the other hand, offer a visual way to manage and track model metadata, particularly when using a remote orchestrator. They make it easy to retrieve and load models from storage, thanks to built-in integrations. A model registry is an excellent choice for interacting with all the models in your pipeline and managing their state in a centralized way.

Using a model registry in your stack is particularly useful if you want to interact with all the logged models in your pipeline, or if you need to manage the state of your models in a centralized way and make it easy to retrieve, load, and deploy these models.

How model registries fit into the ZenML stack

Here is an architecture diagram that shows how a model registry fits into the overall story of a remote stack.

Model Registry Flavors

Model Registries are optional stack components provided by integrations:

Model Registry Flavor Integration Notes
MLflow mlflow mlflow Add MLflow as Model Registry to your stack
Custom Implementation custom custom

If you would like to see the available flavors of Model Registry, you can use the command:

shell
zenml model-registry flavor list

How to use it

Model registries are an optional component in the ZenML stack that is tied to the experiment tracker. This means that a model registry can only be used if you are also using an experiment tracker. If you're not using an experiment tracker, you can still store your models in ZenML, but you will need to manually retrieve model artifacts from the artifact store. More information on this can be found in the documentation on the fetching runs.

To use model registries, you first need to register a model registry in your stack with the same flavor as your experiment tracker. Then, you can register your trained model in the model registry using one of three methods:

  • (1) using the built-in step in the pipeline.
  • (2) using the ZenML CLI to register the model from the command line.
  • (3) registering the model from the model registry UI. Finally, you can use the model registry to retrieve and load your models for deployment or further experimentation.

Book Component Guide Orchestrators README (`docs/book/component-guide/orchestrators/README.md`)


icon: train-track

Orchestrators

The orchestrator is an essential component in any MLOps stack as it is responsible for running your machine learning pipelines. To do so, the orchestrator provides an environment that is set up to execute the steps of your pipeline. It also makes sure that the steps of your pipeline only get executed once all their inputs (which are outputs of previous steps of your pipeline) are available.

{% hint style="info" %}
Many of ZenML's remote orchestrators build Docker images in order to transport and execute your pipeline code. If you want to learn more about how Docker images are built by ZenML, check out this guide.
{% endhint %}

When to use it

The orchestrator is a mandatory component in the ZenML stack. It is used to store all artifacts produced by pipeline runs, and you are required to configure it in all of your stacks.

Orchestrator Flavors

Out of the box, ZenML comes with a local orchestrator already part of the default stack that runs pipelines locally. Additional orchestrators are provided by integrations:

Orchestrator Flavor Integration Notes
LocalOrchestrator local built-in Runs your pipelines locally.
LocalDockerOrchestrator local_docker built-in Runs your pipelines locally using Docker.
KubernetesOrchestrator kubernetes kubernetes Runs your pipelines in Kubernetes clusters.
ModalOrchestrator modal modal Runs your pipelines in Modal Sandboxes.
KubeflowOrchestrator kubeflow kubeflow Runs your pipelines using Kubeflow.
VertexOrchestrator vertex gcp Runs your pipelines in Vertex AI.
SagemakerOrchestrator sagemaker aws Runs your pipelines in Sagemaker.
AzureMLOrchestrator azureml azure Runs your pipelines in AzureML.
TektonOrchestrator tekton tekton Runs your pipelines using Tekton.
AirflowOrchestrator airflow airflow Runs your pipelines using Airflow.
SkypilotAWSOrchestrator vm_aws skypilot[aws] Runs your pipelines in AWS VMs using SkyPilot
SkypilotGCPOrchestrator vm_gcp skypilot[gcp] Runs your pipelines in GCP VMs using SkyPilot
SkypilotAzureOrchestrator vm_azure skypilot[azure] Runs your pipelines in Azure VMs using SkyPilot
SSHOrchestrator ssh ssh Runs your pipelines on a remote host via SSH and Docker Compose.
HyperAIOrchestrator hyperai hyperai Deprecated — use the SSH orchestrator. Runs your pipeline in HyperAI.ai instances.
Custom Implementation custom Extend the orchestrator abstraction and provide your own implementation

If you would like to see the available flavors of orchestrators, you can use the command:

shell
zenml orchestrator flavor list

How to use it

You don't need to directly interact with any ZenML orchestrator in your code. As long as the orchestrator that you want to use is part of your active ZenML stack, using the orchestrator is as simple as executing a Python file that runs a ZenML pipeline:

shell
python file_that_runs_a_zenml_pipeline.py

Inspecting Runs in the Orchestrator UI

If your orchestrator comes with a separate user interface (for example Kubeflow, Airflow, Vertex), you can get the URL to the orchestrator UI of a specific pipeline run using the following code snippet:

python
from zenml.client import Client

pipeline_run = Client().get_pipeline_run("<PIPELINE_RUN_NAME>")
orchestrator_url = pipeline_run.run_metadata["orchestrator_url"].value

Specifying per-step resources

If your steps require the orchestrator to execute them on specific hardware, you can specify them on your steps as described here.

If your orchestrator of choice or the underlying hardware doesn't support this, you can also take a look at step operators.


Book Component Guide Sandboxes README (`docs/book/component-guide/sandboxes/README.md`)


icon: box-archive

Sandboxes

A Sandbox is a stack component that provides an isolated environment (container, microVM, or pod) in which a ZenML step can execute code. It's primarily designed for AI-agent workloads: an agent running inside a step uses the active stack's Sandbox to execute generated code as a tool, possibly across many turns of an agent loop.

A Sandbox is fundamentally different from a Step Operator:

  • A Step Operator runs the step itself on a remote backend.
  • A Sandbox is a tool the step consumes. The step still runs wherever the orchestrator placed it, and you can run code in the sandbox from within your step code.

The two compose: a step running on, say, the SageMaker step operator can still grab the active stack's Sandbox and use it for code execution.

Concepts

Term What it is
Sandbox component (BaseSandbox) The stack-component entity. Long-lived, configured once, registered in your stack. One Sandbox component can mint many live Sessions.
Sandbox Session (SandboxSession) A live, bounded interaction with a single isolated environment. Has an id, accepts many exec calls, can be snapshotted, is explicitly closed.
Sandbox Process (SandboxProcess) A handle to one running command inside a Session. Exposes line-delimited stdout/stderr iterators, wait() for the exit code, kill() to terminate.
Sandbox Snapshot (SandboxSnapshot) A serializable, provider-specific handle to a captured Session state. Round-trips through session.create_snapshot() and sandbox.restore(snapshot).

How to use it from a step

A Sandbox is reached for from inside a step via the active stack:

python
from zenml import step
from zenml.client import Client


@step
def agent_step(prompt: str) -> str:
    sandbox = Client().active_stack.sandbox
    if sandbox is None:
        raise RuntimeError("No sandbox configured in the active stack.")

    with sandbox.create_session() as session:
        process = session.exec(["python", "-c", "print(1 + 1)"])
        output = "".join(process.stdout())
        process.wait()
        return output

If your stack contains more than one Sandbox component, address them by name through Client().active_stack.sandboxes (a Dict[str, BaseSandbox]). The .sandbox accessor returns the default (first attached).

Streaming output

SandboxProcess.stdout() and stderr() yield strings one line at a time as the underlying command produces them — the standard pattern for streaming an agent's tool output back to a UI or to the step logs.

Snapshots, restore, and attach

A Session can optionally be snapshotted (provider-dependent — not all backends support full state capture). The returned SandboxSnapshot is a Pydantic model that's safe to persist as a ZenML artifact:

python
snap = session.create_snapshot()
zenml.save_artifact(snap, name="agent_checkpoint")
# ... later, possibly in a different pipeline run:
snap = zenml.load_artifact("agent_checkpoint")
session = stack.sandbox.restore(snap)        # new session, state restored

restore always returns a new Session (fresh id); the original Session is unaffected.

For the common subagent / cross-pipeline reuse case where the original Session is still alive, use attach() instead — no snapshot required, the parent just persists the session id as an artifact and the child reconnects to it:

python
# Parent step
session_id = session.id
zenml.save_artifact(session_id, name="agent_session")

# Child step (possibly in a child pipeline run)
session = stack.sandbox.attach(zenml.load_artifact("agent_session"))

Closing vs destroying

  • session.close() releases the local handle. The sandbox keeps running on the provider until its TTL expires. Use this when a subagent or follow-up step might still want to attach to the same Session.
  • session.destroy() terminates the sandbox on the provider. After this, the id is invalid and attach() will fail.

ZenML does not auto-close Sessions on step exit. Either use a with block (__exit__ calls close()) or call close() / destroy() explicitly.

Configuration

Per-step settings

Step writers can configure sandbox behavior on individual @step invocations via BaseSandboxSettings (or a flavor-specific subclass):

Setting Purpose
sandbox_environment Environment variables to set inside the Session.

Flavors that boot a container or microVM add their own settings (for example image selection and a provider TTL) on a flavor-specific BaseSandboxSettings subclass.

Sandbox logs

Sandbox stdout/stderr automatically lands on the active step as a dedicated sandbox:<session_id> log source. Each session.exec(...) writes a $ <command> marker, then the process output (stdout at INFO, stderr at ERROR), then a trailing OK/FAIL exit code <code> in <seconds>s marker — reads like a shell session. ZenML's own step-level Python logger calls stay in the regular step source: the sandbox source is dedicated to actual sandbox-execution events, no false attribution.

Multi-session steps don't clobber: each session's metadata (flavor, dashboard URL when the flavor exposes one) is keyed by session id (sandbox..flavor, sandbox..dashboard_url).

Security considerations

Every value you put in a Session's environment (sandbox_environment) is readable by code running inside the Session. If you run LLM-generated code in the Sandbox and care about credential isolation, treat the Session environment as visible to the agent.

Available flavors

  • Local — subprocess-based; no isolation; built-in. Intended for examples, unit tests, and development against the abstraction.
  • Kubernetes — pod-backed sessions executed through Kubernetes exec.

Develop a custom Sandbox

To build a flavor for a new backend, subclass BaseSandbox, SandboxSession, SandboxProcess, and optionally SandboxSnapshot. The minimal required surface is:

  • BaseSandbox.create_session(settings=None) -> SandboxSession
  • SandboxSession.exec(...) -> SandboxProcess
  • SandboxSession.close()
  • SandboxProcess.stdout() / stderr() / wait() / kill() / exit_code

Everything else (attach, create_snapshot, restore, aexec, upload_file, download_file, destroy) is opt-in — the base raises NotImplementedError and you override only what your backend supports. Register your flavor via the standard Integration.flavors() hook.


Book Component Guide Step Operators README (`docs/book/component-guide/step-operators/README.md`)


icon: arrow-progress

Step Operators

The step operator enables the execution of individual pipeline steps in specialized runtime environments that are optimized for certain workloads. These specialized environments can give your steps access to resources like GPUs or distributed processing frameworks like Spark.

{% hint style="info" %}
Comparison to orchestrators: The orchestrator is a mandatory stack component that is responsible for executing all steps of a pipeline in the correct order and providing additional features such as scheduling pipeline runs. The step operator on the other hand is used to only execute individual steps of the pipeline in a separate environment in case the environment provided by the orchestrator is not feasible.
{% endhint %}

When to use it

A step operator should be used if one or more steps of a pipeline require resources that are not available in the runtime environments provided by the orchestrator. An example would be a step that trains a computer vision model and requires a GPU to run in a reasonable time, combined with a Kubeflow orchestrator running on a Kubernetes cluster that does not contain any GPU nodes. In that case, it makes sense to include a step operator like SageMaker, Vertex, or AzureML to execute the training step with a GPU.

Step Operator Flavors

Step operators to execute steps on one of the big cloud providers are provided by the following ZenML integrations:

Step Operator Flavor Integration Dynamic Pipelines Notes
AzureML azureml azure ✅ Uses AzureML to execute steps
Baseten baseten baseten ✅ Uses Baseten training jobs, incl. multi-node, to execute steps
Databricks databricks databricks ✅ Uses Databricks one-time jobs to execute selected steps
Kubernetes kubernetes kubernetes ✅ Uses Kubernetes Pods to execute steps
Modal modal modal ✅ Uses Modal to execute steps
SageMaker sagemaker aws ✅ Uses SageMaker to execute steps
Run:AI runai runai ✅ Uses Run:AI to execute steps
SSH ssh ssh ❌ Runs steps on a remote host via SSH + Docker
Spark spark spark ❌ Uses Spark on Kubernetes to execute steps in a distributed manner
Vertex vertex gcp ✅ Uses Vertex AI to execute steps
Custom Implementation custom Extend the step operator abstraction and provide your own implementation

If you would like to see the available flavors of step operators, you can use the command:

shell
zenml step-operator flavor list

How to use it

You don't need to directly interact with any ZenML step operator in your code. As long as the step operator that you want to use is part of your active ZenML stack, you can simply specify it in the @step decorator of your step.

{% hint style="info" %}
Stacks can have multiple step operators attached. If you use @step(step_operator=True), ZenML uses the default attached step operator, which is the first step operator in the stack. If you want to use a non-default step operator, specify it explicitly by name in the @step decorator.
{% endhint %}

python
from zenml import step


@step(step_operator=True)
def my_step(...) -> ...:
    ...

Specifying per-step resources

If your steps require additional hardware resources, you can specify them on your steps as described here.

Enabling CUDA for GPU-backed hardware

Note that if you wish to use step operators to run steps on a GPU, you will need to follow the instructions on this page to ensure that it works. It requires adding some extra settings customization and is essential to enable CUDA for the GPU to give its full acceleration.


Book Getting Started Deploying Zenml README (`docs/book/getting-started/deploying-zenml/README.md`)


icon: rocket-launch

Deploy

Moving your ZenML Server to a production environment offers several benefits over staying local:

  1. Scalability: Production environments are designed to handle large-scale workloads, allowing your models to process more data and deliver faster results.
  2. Reliability: Production-grade infrastructure ensures high availability and fault tolerance, minimizing downtime and ensuring consistent performance.
  3. Collaboration: A shared production environment enables seamless collaboration between team members, making it easier to iterate on models and share insights.

Despite these advantages, transitioning to production can be challenging due to the complexities involved in setting up the needed infrastructure.

Components

A ZenML deployment consists of multiple infrastructure components:

You can read more in-depth about the system architecture of ZenML here.
This documentation page will focus on the components required to deploy ZenML OSS.

Details on the ZenML Python Client

The ZenML client is a Python package that you can install on your machine. It is used to interact with the ZenML server. You can install it using the pip command as outlined here.

This Python package gives you the zenml command-line interface which you can use to interact with the ZenML server for common tasks like managing stacks, setting up secrets, and so on. It also gives you the general framework that lets you author and deploy pipelines and so forth.

If you want to have more fine-grained control and access to the metadata that ZenML manages, you can use the Python SDK to access the API. This allows you to create your own custom automations and scripts and is the most common way teams access the metadata stored in the ZenML server. The full documentation for the Python SDK can be found here. The full HTTP API documentation can also be found by adding the/doc suffix to the URL when accessing your deployed ZenML server.

Deployment scenarios

When you first get started with ZenML, you have the following architecture on your machine.

The SQLite database that you can see in this diagram is used to store information about pipelines, pipeline runs, stacks, and other configurations. This default setup allows you to get started and try out the core features, but you won't be able to use cloud-based components like serverless orchestrators and so on.

Users can run the zenml login --local command to spin up a local ZenML OSS server to serve the dashboard. For the local OSS server option, the zenml login --local command implicitly connects the client to the server. The diagram for this looks as follows:

In order to move into production, the ZenML server needs to be deployed somewhere centrally so that the different cloud stack components can read from and write to the server. Additionally, this also allows all your team members to connect to it and share stacks and pipelines.

You connect to your deployed ZenML server using the zenml login command, and then you have the full benefits and power of ZenML. You can use all the cloud-based components, your metadata will be stored and synchronized across all the users of the server, and you can leverage features like centralized logs storage and pipeline artifact visualization.

How to deploy ZenML

Deploying the ZenML Server is a crucial step towards transitioning to a production-grade environment for your machine learning projects. By setting up a deployed ZenML Server instance, you gain access to powerful features, allowing you to use stacks with remote components, centrally track progress, collaborate effectively, and achieve reproducible results.

Currently, there are two main options to access a deployed ZenML server:

  1. Managed deployment: With ZenML Pro offering you can utilize a control plane to create ZenML servers, also known as workspaces. These workspaces are managed and maintained by ZenML's dedicated team, alleviating the burden of server management from your end. Importantly, your data remains securely within your stack, and ZenML's role is primarily to handle tracking of metadata and server maintenance.
  2. Self-hosted Deployment: Alternatively, you have the ability to deploy ZenML on your own self-hosted environment. This can be achieved through various methods, including using Docker, Helm, or HuggingFace Spaces. We also offer our Pro version for self-hosted deployments, so you can use our full paid feature set while staying fully in control with an air-gapped solution on your infrastructure.

Both options offer distinct advantages, allowing you to choose the deployment approach that best aligns with your organization's needs and infrastructure preferences. Whichever path you select, ZenML facilitates a seamless and efficient way to take advantage of the ZenML Server and enhance your machine learning workflows for production-level success.

Options for deploying ZenML

Documentation for the various deployment strategies can be found in the following pages below (in our 'how-to' guides):

Deploying ZenML using ZenML Pro Deploying ZenML using ZenML Pro. zenml-pro.png https://docs.zenml.io/pro/deployments/scenarios
Deploy with Docker Deploying ZenML in a Docker container. docker.png deploy-with-docker.md
Deploy with Helm Deploying ZenML in a Kubernetes cluster with Helm. helm.png deploy-with-helm.md
Deploy with HuggingFace Spaces Deploying ZenML to Hugging Face Spaces. hugging-face.png deploy-using-huggingface-spaces.md

Book Getting Started Zenml Pro README (`docs/book/getting-started/zenml-pro/README.md`)


cover: .gitbook/assets/procover.png
coverY: 0
layout:
width: default
cover:
visible: true
size: hero
title:
visible: true
visible: true
tableOfContents:
visible: true
outline:
visible: true
pagination:
visible: true
metadata:
visible: true


Introduction

What is ZenML Pro?

The Pro version of ZenML extends the Open Source product with advanced features for enterprise-grade MLOps. It provides multi-user collaboration, role-based access control, flexible deployment options, and professional support to help teams scale their ML operations.

{% hint style="info" %}
To get access to ZenML Pro, book a call.
{% endhint %}

ZenML OSS vs Pro Feature Comparison

Feature Category ZenML OSS ZenML Pro
User Management Single-user mode Multi-user support with SSO, organizations, and teams
Access Control ❌ No RBAC Full role-based access control with customizable permissions
Multi-tenancy ❌ No workspaces/projects Workspaces and projects for team and resource isolation
ZenML Web UI Basic pipeline and run visualization Pro UI with Model Control Plane, Artifact Control Plane, and comparison views
Pipeline Execution Run pipelines via SDK/CLI Run pipelines from the UI, manage schedules through the UI, triggers
Stack Configuration User-managed stacks Advanced stack configurations with workspace/project-level restrictions for platform teams
Security Community updates Prioritized security patches, SOC 2 and ISO 27001 certification
Deployment Self-hosted only SaaS, Hybrid, or Self-hosted options
Support Community support Professional support included (SaaS deployments)
Reporting Basic run tracking Advanced usage reports and analytics
Core Features ✅ Run pipelines on stacks✅ Full observability over runs✅ Artifact tracking ✅ All OSS features✅ Run Snapshots✅ Model Control Plane✅ Artifact Control Plane✅ Enhanced filtering and search

Security & Compliance

All ZenML Pro deployments include:

  • ✅ SOC 2 Type II certification
  • ✅ ISO 27001 certification
  • ✅ Vulnerability Assessment Reports available on request
  • ✅ Software Bill of Materials (SBOM) available on request

Documentation Guide

This documentation is organized to help you understand, deploy, and manage ZenML Pro:

Section Description
System Architecture How ZenML Pro services (Control Plane, Workspace Server, Workload Manager) communicate and interact
Scenarios Decision guide to help you choose between SaaS, Hybrid, and Self-hosted deployments
Deployment Details Reference for configurable options, environment variables, and permissions for each component
Upgrades and Updates How to upgrade each ZenML Pro component
Core Concepts Organizations, Workspaces, Projects, Teams, and Hierarchy
Access Management Roles, Permissions, Service Accounts, and Secrets

Pro Feature Details

Workspaces Isolated environments for teams and projects pro-workspaces.png workspaces.md
Organizations Top-level entity for managing users and teams pro-organizations.png organization.md
Teams Group users for simplified access management pro-teams.png teams.md
Roles Customizable role-based access control pro-roles.png roles.md
Projects Organize work within workspaces pro-projects.png projects.md
Snapshots Trigger pipelines from dashboard, SDK, CLI, or REST API pro-workload-managers.png snapshots.md
Deployment Options SaaS, Hybrid, or Full On-Prem deployments pro-self-host.png scenarios.md

Book User Guide Llmops Guide README (`docs/book/user-guide/llmops-guide/README.md`)


icon: robot

LLMOps guide

Welcome to the ZenML LLMOps Guide, where we dive into the exciting world of Large Language Models (LLMs) and how to integrate them seamlessly into your MLOps pipelines using ZenML. This guide is designed for ML practitioners and MLOps engineers looking to harness the potential of LLMs while maintaining the robustness and scalability of their workflows.

ZenML simplifies the development and deployment of LLM-powered MLOps pipelines.

In this guide, we'll explore various aspects of working with LLMs in ZenML, including:

To follow along with the examples and tutorials in this guide, ensure you have a Python environment set up with ZenML installed. Familiarity with the concepts covered in the Starter Guide and Production Guide is recommended.

We'll showcase a specific application over the course of this LLM guide, showing how you can work from a simple RAG pipeline to a more complex setup that involves finetuning embeddings, reranking retrieved documents, and even finetuning the LLM itself. We'll do this all for a use case relevant to ZenML: a question answering system that can provide answers to common questions about ZenML. This will help you understand how to apply the concepts covered in this guide to your own projects.

By the end of this guide, you'll have a solid understanding of how to leverage LLMs in your MLOps workflows using ZenML, enabling you to build powerful, scalable, and maintainable LLM-powered applications. First up, let's take a look at a super simple implementation of the RAG paradigm to get started.


Book User Guide Production Guide README (`docs/book/user-guide/production-guide/README.md`)


icon: tree

Production guide

The ZenML production guide builds upon the Starter guide and is the next step in the MLOps Engineer journey with ZenML. If you're an ML practitioner hoping to implement a proof of concept within your workplace to showcase the importance of MLOps, this is the place for you.

ZenML simplifies development of MLOps pipelines that can span multiple production stacks.

This guide will focus on shifting gears from running pipelines locally on your machine, to running them in production in the cloud. We'll cover:

Like in the starter guide, make sure you have a Python environment ready and virtualenv installed to follow along with ease. As now we are dealing with cloud infrastructure, you'll also want to select one of the major cloud providers (AWS, GCP, Azure), and make sure the respective CLIs are installed and authorized.

By the end, you will have completed an end-to-end MLOps project that you can use as inspiration for your own work. Let's get right into it!

{% hint style="info" %}
Throughout this guide, we will be referencing internal ZenML functions and classes, which are more easily discoverable in the SDK Docs. Consult the SDK docs if you're ever stuck!
{% endhint %}


Book User Guide Starter Guide README (`docs/book/user-guide/starter-guide/README.md`)


icon: seedling

Starter guide

Welcome to the ZenML Starter Guide! If you're an MLOps engineer aiming to build robust ML platforms, or a data scientist interested in leveraging the power of MLOps, this is the perfect place to begin. Our guide is designed to provide you with the foundational knowledge of the ZenML framework and equip you with the initial tools to manage the complexity of machine learning operations.

Embarking on MLOps can be intricate. ZenML simplifies the journey.

Throughout this guide, we'll cover essential topics including:

Before jumping in, make sure you have a Python environment ready and virtualenv installed to follow along with ease. By the end, you will have completed a starter project, marking the beginning of your journey into MLOps with ZenML.

Let this guide be not only your introduction to ZenML but also a foundational asset in your MLOps toolkit. Prepare your development environment, and let's get started!

{% hint style="info" %}
Throughout this guide, we will be referencing internal ZenML functions and classes, which are more easily discoverable in the SDK Docs. Consult the SDK docs if you're ever stuck!
{% endhint %}


Book Api Docs Oss Api Oss Api README (`docs/book/api-docs/oss-api/oss-api/README.md`)


icon: github-alt

OSS API


Book Api Docs Oss Api Oss Api Getting Started (`docs/book/api-docs/oss-api/oss-api/getting-started.md`)


icon: person-from-portal

Getting Started

The ZenML OSS server is a FastAPI application, therefore the OpenAPI-compliant docs are available at /docs or /redoc of your ZenML server:

{% hint style="info" %}
In the local case (i.e. using zenml login --local, the docs are available on http://127.0.0.1:8237/docs)
{% endhint %}

{% hint style="info" %}
Difference between OpenAPI docs and ReDoc

The OpenAPI docs (/docs) provide an interactive interface where you can try out the API endpoints directly from the browser. It is useful for testing and exploring the API functionalities.

ReDoc (/redoc), on the other hand, offers a more static and visually appealing documentation. It is designed for better readability and is ideal for understanding the API structure and reference.
{% endhint %}

Accessing the ZenML OSS API

For OSS users: The server_url is the root URL of your ZenML server deployment.

If you are using the ZenML OSS server API using the methods displayed above, it is enough to be logged in to your ZenML account in the same browser session. However, in order to do this programmatically, you can use one of the methods documented in the following sections.

{% hint style="info" %}
Choosing a method:

Using a service account and an API key

You can use a service account's API key to authenticate to the ZenML server's REST API programmatically. This is particularly useful when you need a long-term, secure way to make authenticated HTTP requests to the ZenML API endpoints.

Start by creating a service account and an API key, e.g.:

text
```shell
zenml service-account create myserviceaccount
```

Then, there are two methods to authenticate with the API using the API key - one is simpler but less secure, the other is secure and recommended but more complex:

{% tabs %}
{% tab title="Direct API key authentication" %}

{% hint style="warning" %}
This approach, albeit simple, is not recommended because the long-lived API key is exposed with every API request, which makes it easier to be compromised. Use it only in low-risk circumstances.
{% endhint %}

Use the API key directly to authenticate your API requests by including it in the Authorization header. For example, you can use the following command to check your current user:

  • using curl:

    bash
    curl -H "Authorization: Bearer YOUR_API_KEY" https://your-zenml-server/api/v1/current-user
  • using wget:

    bash
    wget -qO- --header="Authorization: Bearer YOUR_API_KEY" https://your-zenml-server/api/v1/current-user
  • using python:

    python
    import requests
    
    response = requests.get(
        "https://your-zenml-server/api/v1/current-user",
        headers={"Authorization": f"Bearer {YOUR_API_KEY}"}
    )
    
    print(response.json())

{% endtab %}

{% tab title="Token exchange authentication" %}

Reduce the risk of API key exposure by periodically exchanging the API key for a short-lived API token.

  1. To obtain a short-lived API token using your API key, send a POST request to the /api/v1/login endpoint. Here are examples using common HTTP clients:
    • using curl:

      bash
      curl -X POST -d "password=<YOUR_API_KEY>" https://your-zenml-server/api/v1/login
    • using wget:

      bash
      wget -qO- --post-data="password=<YOUR_API_KEY>" \
          --header="Content-Type: application/x-www-form-urlencoded" \
          https://your-zenml-server/api/v1/login
    • using python:

      python
      import requests
      import json
      
      response = requests.post(
          "https://your-zenml-server/api/v1/login",
          data={"password": "<YOUR_API_KEY>"},
          headers={"Content-Type": "application/x-www-form-urlencoded"}
      )
      
      print(response.json())

This will return a response like this (the short-lived API token is the access_token field):

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3MGJjZTg5NC1hN2VjLTRkOTYtYjE1Ny1kOTZkYWY5ZWM2M2IiLCJpc3MiOiJmMGQ5NjI1Ni04YmQyLTQxZDctOWVjZi0xMmYwM2JmYTVlMTYiLCJhdWQiOiJmMGQ5NjI1Ni04YmQyLTQxZDctOWVjZi0xMmYwM2JmYTVlMTYiLCJleHAiOjE3MTk0MDk0NjAsImFwaV9rZXlfaWQiOiIzNDkyM2U0NS0zMGFlLTRkMjctODZiZS0wZGRhNTdkMjA5MDcifQ.ByB1ngCPtBenGE6UugsWC6Blga3qPqkAiPJUSFDR-u4",
  "token_type": "bearer",
  "expires_in": 3600,
  "refresh_token": null,
  "scope": null
}
  1. Once you have obtained a short-lived API token, you can use it to authenticate your API requests by including it in the Authorization header. When the short-lived API token expires, simply repeat the steps above to obtain a new one. For example, you can use the following command to check your current user:
    • using curl:

      bash
      curl -H "Authorization: Bearer YOUR_API_TOKEN" https://your-zenml-server/api/v1/current-user
    • using wget:

      bash
      wget -qO- --header="Authorization: Bearer YOUR_API_TOKEN" https://your-zenml-server/api/v1/current-user
    • using python:

      python
      import requests
      
      response = requests.get(
          "https://your-zenml-server/api/v1/current-user",
          headers={"Authorization": f"Bearer {YOUR_API_TOKEN}"}
      )
      
      print(response.json())

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Important notes

  • Short-lived API tokens are scoped to the service account that created them and inherit their permissions
  • Tokens are temporary and will expire after a configured duration (typically 1 hour, but it depends on how the server is configured)
  • You can request a new short-lived API token at any time using the same API key
  • For security reasons, you should handle short-lived API tokens carefully and never share them
  • If your API key is compromised, you can rotate it using the ZenML dashboard or by running the zenml service-account api-key <SERVICE_ACCOUNT_NAME> rotate command
    {% endhint %}

Book Api Docs Pro Api Pro Api README (`docs/book/api-docs/pro-api/pro-api/README.md`)


icon: rectangle-pro

Pro API


Book Api Docs Pro Api Pro Api Getting Started (`docs/book/api-docs/pro-api/pro-api/getting-started.md`)


icon: person-from-portal

Getting Started

The ZenML Pro API extends the open-source API with additional features designed for enterprise users, including:

  • Enhanced team collaboration features
  • Advanced role-based access control
  • Enterprise-grade security features

Whether you're using the SaaS version or a self-hosted ZenML Pro instance, you can leverage the API to manage workspaces, organizations, users, roles, and more.

Understanding the Two APIs in ZenML Pro

ZenML Pro includes two distinct APIs:

  1. Workspace API: This is similar to the OSS API but includes additional endpoints (for example to run snapshots). Each workspace in ZenML Pro has its own API.
  2. ZenML Pro API: This is the management API for ZenML Pro and handles organization-level resources like workspaces, users, and roles.

Server URL

For Pro users, the server_url for the Workspace API is the URL of your workspace, which can be found in the ZenML Pro dashboard:

Note: The workspace URL can be found in the ZenML Pro dashboard and typically looks like https://1bfe8d94-zenml.cloudinfra.zenml.io.

The SaaS version of ZenML Pro API is hosted at https://cloudapi.zenml.io.

API Overview

The ZenML Pro API is a RESTful API that follows OpenAPI 3.1.0 specifications. It provides endpoints for various resources and operations, including:

  • Workspace management
  • Organization management
  • Project management
  • User management
  • Role-based access control (RBAC)
  • Authentication and authorization

Authentication

To use the ZenML Pro API, you need to authenticate your requests. If you are logged in to your ZenML Pro account, you can use the same browser window to authenticate requests to your ZenML Pro API, directly in the OpenAPI docs.

For example, for the SaaS variant, you can access the docs here: https://cloudapi.zenml.io.

Programmatic access with Personal Access Tokens

Personal Access Tokens are long-lived credentials scoped to your own user account that can be used to authenticate to the ZenML Pro API and the Workspace API across all the organizations and workspaces that your account has access to. See Personal Access Tokens for setup and examples.

Programmatic access with service accounts and API keys

Service accounts and API keys can be used to authenticate to the ZenML Pro API and the Workspace API across all workspaces in your organization. See Service Accounts for setup and examples.

When to Use Which API

Task Use This API Authentication Method
Managing organizations, workspaces, users ZenML Pro API (cloudapi.zenml.io) Personal Access Tokens
Accessing the ZenML Pro API programmatically from external systems ZenML Pro API (cloudapi.zenml.io) Service Accounts + API keys (recommended for automation)
Running snapshots, pipeline operations Workspace API (your workspace URL) Service Accounts + API keys (recommended for automation)
Pipeline development, artifact management Workspace API (your workspace URL) Personal Access Tokens or Service Accounts + API Keys

See the high‑level overview: Connect to a server.

Workspace API Authentication

The Workspace API is different from the ZenML Pro API and supports different authentication methods. This is the API you'll use for running snapshots and other pipeline operations.

Workspace API Authentication Methods

Programmatic access to the ZenML Pro workspace API is achieved mostly the same way as the ZenML OSS server API. This is because the Workspace API in ZenML Pro is an extension of the OSS API with some additional endpoints. For automation, use ZenML Pro service accounts and API keys (see Service Accounts).

You can use one of these two methods to authenticate with your workspace API:

When making requests to the Workspace API, make sure to use your workspace URL as the base URL. This is different from the ZenML Pro API URL (cloudapi.zenml.io), which is used for organization-level operations.

Please consult the indicated sections for more information.

Key API Endpoints

Here are some important endpoints you can use with ZenML Pro:

ZenML Pro API Endpoints

These endpoints are available at the ZenML Pro API (e.g., https://cloudapi.zenml.io):

Organization Management

  • List organizations: GET /organizations
  • Create an organization: POST /organizations
  • Get organization details: GET /organizations/{organization_id}
  • Update an organization: PATCH /organizations/{organization_id}

Workspace Management

  • List workspaces: GET /workspaces
  • Create a workspace: POST /workspaces
  • Get workspace details: GET /workspaces/{workspace_id}
  • Update a workspace: PATCH /workspaces/{workspace_id}

User Management

  • List users: GET /users
  • Get current user: GET /users/me
  • Update user: PATCH /users/{user_id}

Role-Based Access Control

  • Create a role: POST /roles
  • Assign a role: POST /roles/{role_id}/assignments
  • Check permissions: GET /permissions

Remember to refer to the complete API documentation available at https://cloudapi.zenml.io for detailed information about all available endpoints, request/response schemas, and additional features.

Workspace API Endpoints

The Workspace API includes all OSS API endpoints plus some additional Pro-specific endpoints. These are available at your workspace URL at the /docs path (e.g., https://1bfe8d94-zenml.cloudinfra.zenml.io/docs):

Running snapshots (Pro-specific)

Snapshots allow you to start pipeline runs from external systems using HTTP requests.

  • List snapshots: GET /pipeline_snapshots
  • Get snapshot details: GET /pipeline_snapshots/<SNAPSHOT-ID>
  • Update a snapshot: PATCH /pipeline_snapshots/<SNAPSHOT-ID>
  • Run a snapshot: POST /pipeline_snapshots/<SNAPSHOT-ID>/runs

{% hint style="success" %}
For Snapshot Automation

When running snapshots from external systems or CI/CD pipelines, we strongly recommend using service accounts with API keys. Service accounts provide:

  • Long-term credentials that don't expire hourly
  • Dedicated authentication for automation (not tied to individual users)
  • Consistent access even when team members leave

See the service account documentation for setup instructions.
{% endhint %}

For a complete list of API endpoints available in the Workspace API, refer to the OSS API documentation.

Error Handling

The API uses standard HTTP status codes to indicate the success or failure of requests. In case of errors, the response body will contain more details about the error, including a message and sometimes additional information.

Rate Limiting

Be aware that the ZenML Pro API may have rate limiting in place to ensure fair usage. If you exceed the rate limit, you may receive a 429 (Too Many Requests) status code. Implement appropriate backoff and retry logic in your applications to handle this scenario.

Troubleshooting Authentication

"Which API and credentials should I use?"

Use this decision tree to determine the right approach:

What do you want to do? Which API? Authentication Method Why?
Run snapshots from CI/CD or external systems Workspace API (your workspace URL) Service account + API key Long-lived, automation-friendly, not tied to users
Manage organizations, create workspaces, invite users ZenML Pro API (cloudapi.zenml.io) Personal Access Tokens Administrative operations need user-level permissions
Access the ZenML Pro API programmatically from external systems ZenML Pro API (cloudapi.zenml.io) Service accounts + API keys (recommended for automation) Long-lived, automation-friendly, not tied to users
Develop pipelines, explore artifacts Workspace API (your workspace URL) Personal Access Tokens or Service Accounts + API keys Flexible for development needs
One-off pipeline operations Workspace API (your workspace URL) Personal Access Tokens Quick and easy for manual tasks

Common Issues

"My API calls are getting 401 Unauthorized"

  • ✅ Check that you're using the correct API URL (workspace URL vs cloudapi.zenml.io)
  • ✅ Verify your credentials haven't expired (see next issue)
  • ✅ Ensure you're using Bearer <token> format in the Authorization header

"My automation keeps failing after an hour"

  • ✅ Check what type of authentication you are using (Personal Access Tokens or service account API keys)
  • ✅ Check the expiration date of the credentials you are using and rotate them if they have expired. Optionally adjust the expiration time during rotation.

"I can't find the endpoint to run a snapshot"

  • ✅ Running snapshots is only possible using the Workspace API, not the ZenML Pro API
  • ✅ Use your workspace URL + /docs to see the full API documentation

Book Component Guide Service Connectors Connector Types README (`docs/book/component-guide/service-connectors/connector-types/README.md`)


icon: album-collection

Connector Types


Book How To Infrastructure Deployment Infrastructure As Code README (`docs/book/how-to/infrastructure-deployment/infrastructure-as-code/README.md`)


icon: network-wired

Infrastructure as code with Terraform

Infrastructure as Code (IaC) is
the practice of managing and provisioning infrastructure through code
instead of through manual processes.

In this section, we will show you how to integrate ZenML with popular
IaC tools such as Terraform.

Terraform is a powerful tool for managing infrastructure as code, and is by far the
most popular IaC tool. Many companies already have existing Terraform setups,
and it is often desirable to integrate ZenML with this setup.

We already got a glimpse on how to deploy a cloud stack with Terraform
using existing Terraform modules that are maintained by the ZenML team. While this
is a great solution for quickly getting started, it might not always be suitable for
your use case.

This guide is for advanced users who want to manage their own custom Terraform code but
want to use ZenML to manage their stacks. For this, the
ZenML provider is a better choice.

Understanding the Two-Phase Approach

When working with ZenML stacks, there are two distinct phases:

  1. Infrastructure Deployment: Creating cloud resources (typically handled by platform teams)
  2. ZenML Registration: Registering these resources as ZenML stack components

While our official modules (zenml-stack/aws, zenml-stack/gcp, zenml-stack/azure) handle both phases, you might already have infrastructure deployed. Let's explore how to register existing infrastructure with ZenML.

Phase 1: Infrastructure Deployment

You likely already have this handled in your existing Terraform configurations:

hcl
# Example of existing GCP infrastructure
resource "google_storage_bucket" "ml_artifacts" {
  name     = "company-ml-artifacts"
  location = "US"
}

resource "google_artifact_registry_repository" "ml_containers" {
  repository_id = "ml-containers"
  format        = "DOCKER"
}

Phase 2: ZenML Registration

Setup the ZenML Provider

First, configure the ZenML provider to communicate with your ZenML server:

hcl
terraform {
  required_providers {
    zenml = {
      source = "zenml-io/zenml"
    }
  }
}

provider "zenml" {
  # Configuration options will be loaded from environment variables:
  # ZENML_SERVER_URL (for Pro users, this should be your Workspace URL from the dashboard)
  # ZENML_API_KEY
}

{% hint style="info" %}
**For ZenML Pro users:** The `ZENML_SERVER_URL` should be your Workspace URL, which can be found in your dashboard. It typically looks like: `https://1bfe8d94-zenml.cloudinfra.zenml.io`. Make sure you use the complete URL of your workspace, not just the domain. The `ZENML_API_KEY` should be [the ZenML Pro API key](https://docs.zenml.io/pro/access-management/service-accounts) or [Personal Access Token](https://docs.zenml.io/pro/access-management/personal-access-tokens).
{% endhint %}

To generate an API key for an OSS server, use the command:

bash
zenml service-account create <SERVICE_ACCOUNT_NAME>

This will create a service account and generate an API key that you can use to authenticate with the ZenML server.

{% hint style="info" %}
The API key is shown only once during creation. Make sure to save it securely, as you cannot retrieve it later. If you lose it, you'll need to create a new key.
{% endhint %}

You can learn more about how to generate a ZENML_API_KEY via service accounts
here.

If you're using a ZenML Pro server, you will need to create a Personal Access Token or an organization-level service account and an API key for it. You can find more about Personal Access Tokens here and organization-level service accounts and API keys here.

Create the service connectors

The key to successful registration is proper authentication between the components.
Service connectors are ZenML's way of managing this:

hcl
# First, create a service connector
resource "zenml_service_connector" "gcp_connector" {
  name        = "gcp-${var.environment}-connector"
  type        = "gcp"
  auth_method = "service-account"  
  
  configuration = {
    project_id = var.project_id
    service_account_json = file("service-account.json")
  }
}

# Create a stack component referencing the connector
resource "zenml_stack_component" "artifact_store" {
  name   = "existing-artifact-store"
  type   = "artifact_store"
  flavor = "gcp"
  
  configuration = {
    path = "gs://${google_storage_bucket.ml_artifacts.name}"
  }
  
  connector_id = zenml_service_connector.gcp_connector.id
}

Register the stack components

Register different types of components:

hcl
# Generic component registration pattern
locals {
  component_configs = {
    artifact_store = {
      type = "artifact_store"
      flavor = "gcp"
      configuration = {
        path = "gs://${google_storage_bucket.ml_artifacts.name}"
      }
    }
    container_registry = {
      type = "container_registry"
      flavor = "gcp"
      configuration = {
        uri = "${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.ml_containers.repository_id}"
      }
    }
    orchestrator = {
      type = "orchestrator"
      flavor = "vertex"
      configuration = {
        project = var.project_id
        region  = var.region
      }
    }
  }
}

# Register multiple components
resource "zenml_stack_component" "components" {
  for_each = local.component_configs
  
  name          = "existing-${each.key}"
  type          = each.value.type
  flavor        = each.value.flavor
  configuration = each.value.configuration
  
  connector_id = zenml_service_connector.env_connector.id
}

Assemble the stack

Finally, assemble the components into a stack:

hcl
resource "zenml_stack" "ml_stack" {
  name = "${var.environment}-ml-stack"
  
  components = {
    for k, v in zenml_stack_component.components : k => v.id
  }
}

Practical Walkthrough: Registering Existing GCP Infrastructure

Let's see a complete example of registering an existing GCP infrastructure stack with ZenML.

Prerequisites

  • A GCS bucket for artifacts
  • An Artifact Registry repository
  • A service account for ML operations
  • Vertex AI enabled for orchestration

Step 1: Variables Configuration

hcl
# variables.tf
variable "zenml_server_url" {
  description = "URL of the ZenML server (for Pro users, this is your Workspace URL)"
  type        = string
}

variable "zenml_api_key" {
  description = "API key for ZenML server authentication"
  type        = string
  sensitive   = true
}

variable "project_id" {
  description = "GCP project ID"
  type        = string
}

variable "region" {
  description = "GCP region"
  type        = string
  default     = "us-central1"
}

variable "environment" {
  description = "Environment name (e.g., dev, staging, prod)"
  type        = string
}

variable "gcp_service_account_key" {
  description = "GCP service account key in JSON format"
  type        = string
  sensitive   = true
}

Step 2: Main Configuration

text
/* Detailed source-code truncated for AI context efficiency. */

Step 3: Outputs Configuration

hcl
# outputs.tf
output "stack_id" {
  description = "ID of the created ZenML stack"
  value       = zenml_stack.gcp_stack.id
}

output "stack_name" {
  description = "Name of the created ZenML stack"
  value       = zenml_stack.gcp_stack.name
}

output "artifact_store_path" {
  description = "GCS path for artifacts"
  value       = "${google_storage_bucket.artifacts.name}/artifacts"
}

output "container_registry_uri" {
  description = "URI of the container registry"
  value       = "${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.containers.repository_id}"
}

Step 4: terraform.tfvars Configuration

Create a terraform.tfvars file (remember to never commit this to version control):

hcl
zenml_server_url = "https://your-zenml-server.com"  # For Pro users: your Workspace URL from dashboard
project_id       = "your-gcp-project-id"
region           = "us-central1"
environment      = "dev"

Store sensitive variables in environment variables:

bash
export TF_VAR_zenml_api_key="your-zenml-api-key"
export TF_VAR_gcp_service_account_key=$(cat path/to/service-account-key.json)

Usage Instructions

  1. Install required providers and initializing Terraform:
bash
terraform init
  1. Install required ZenML integrations:
bash
zenml integration install gcp
  1. Review the planned changes:
bash
terraform plan
  1. Apply the configuration:
bash
terraform apply
  1. Set the newly created stack as active:
bash
zenml stack set $(terraform output -raw stack_name)
  1. Verify the configuration:
bash
zenml stack describe

This complete example demonstrates:

  • Setting up necessary GCP infrastructure
  • Creating a service connector with proper authentication
  • Registering stack components with the infrastructure
  • Creating a complete ZenML stack
  • Proper variable management and output configuration
  • Best practices for sensitive information handling

The same pattern can be adapted for AWS and Azure infrastructure by adjusting the provider configurations and resource types accordingly.

Remember to:

  • Use appropriate IAM roles and permissions
  • Follow your organization's security practices for handling credentials
  • Consider using Terraform workspaces for managing multiple environments
  • Regular backup of your Terraform state files
  • Version control your Terraform configurations (excluding sensitive files)

To learn more about the ZenML terraform provider, visit the
ZenML provider.


Book How To Manage Zenml Server Connecting To Zenml README (`docs/book/how-to/manage-zenml-server/connecting-to-zenml/README.md`)


icon: globe-pointer

Connect to a server

Once ZenML is deployed, there are various ways to connect to it.

Choose how to connect

Use this quick guide to pick the right method based on your context:

Context Use Credentials Docs
You are a human using the CLI and browser Interactive login (device flow) Your user session (24h/30d) Connect with your user
Script/notebook needs to make quick API calls to an OSS server Service account + API key Long‑lived API key Connect with a service account
Script/notebook needs to make quick API calls to a ZenML Pro workspace ZenML Pro Personal Access Token Long‑lived PAT Connect with a personal access token
CI/CD or long‑lived automation calling an OSS server Service account + API key Long‑lived API key Connect with a service account
CI/CD or long‑lived automation calling a ZenML Pro workspace ZenML Pro API service account + API key Long‑lived API key Connect with a ZenML Pro service account
CI/CD or long‑lived automation calling the ZenML Pro management API (cloudapi.zenml.io) ZenML Pro service account + API key Long-lived API key Connect with a ZenML Pro service account

{% hint style="warning" %}
Which base URL should you call?

  • Workspace/OSS API: your server or workspace URL (e.g., https://<workspace-id>.zenml.io).
  • ZenML Pro management API: https://cloudapi.zenml.io.

In ZenML Pro, use Personal Access Tokens or ZenML Pro service accounts and API keys. These credentials can be used for both the Workspace API and the Pro management API. See ZenML Pro Personal Access Tokens and ZenML Pro Service Accounts.
{% endhint %}

Common pitfalls

  • 401 Unauthorized: verify you’re using the correct base URL, the token hasn’t expired, and the header is Authorization: Bearer <token>.
  • Automation fails after 1 hour: check the expiration date of the PAT or API key and rotate it if it has expired.
  • Can’t find Run Template endpoints: they exist on the Workspace/OSS API, not on cloudapi.zenml.io.

Book User Guide Llmops Guide Evaluation README (`docs/book/user-guide/llmops-guide/evaluation/README.md`)



Evaluation and metrics

In this section, we'll explore how to evaluate the performance of your RAG pipeline using metrics and visualizations. Evaluating your RAG pipeline is crucial to understanding how well it performs and identifying areas for improvement. With language models in particular, it's hard to evaluate their performance using traditional metrics like accuracy, precision, and recall. This is because language models generate text, which is inherently subjective and difficult to evaluate quantitatively.

Our RAG pipeline is a whole system, moreover, not just a model, and evaluating it requires a holistic approach. We'll look at various ways to evaluate the performance of your RAG pipeline but the two main areas we'll focus on are:

  • Retrieval evaluation, so checking that the retrieved documents or document chunks are relevant to the query.
  • Generation evaluation, so checking that the generated text is coherent and helpful for our specific use case.

In the previous section we built out a basic RAG pipeline for our documentation question-and-answer use case. We'll use this pipeline to demonstrate how to evaluate the performance of your RAG pipeline.

Everything that follows starts from a dataset you assembled and score offline, which is the right shape for a RAG pipeline. An agent already serving traffic gives you the opposite starting point: real runs, some of which went wrong. Kitaru, ZenML's sibling project for agents, replays one of those recorded runs against your real code with a single thing changed — a cheaper model, a different prompt — and diffs the pair, so a failure you saw once becomes a check you can rerun. See building a regression suite from production for that workflow and evaluators for how Kitaru scores sessions.

{% hint style="info" %}
If you were running this in a production setting, you might want to set up evaluation to check the performance of a raw LLM model (i.e. without any retrieval / RAG components) as a baseline, and then compare this to the performance of your RAG pipeline. This will help you understand how much value the retrieval and generation components are adding to your system. We won't cover this here, but it's a good practice to keep in mind.
{% endhint %}

What are we evaluating?

When evaluating the performance of your RAG pipeline, your specific use case and the extent to which you can tolerate errors or lower performance will determine what you need to evaluate. For instance, if you're building a user-facing chatbot, you might need to evaluate the following:

  • Are the retrieved documents relevant to the query?
  • Is the generated answer coherent and helpful for your specific use case?
  • Does the generated answer contain hate speech or any sort of toxic language?

These are just examples, and the specific metrics and methods you use will depend on your use case. The generation evaluation functions as an end-to-end evaluation of the RAG pipeline, as it checks the final output of the system. It's during these end-to-end evaluations that you'll have most leeway to use subjective metrics, as you're evaluating the system as a whole.

Before we dive into the details, let's take a moment to look at a short high-level code example showcasing the two main areas of evaluation. Afterwards the following sections will cover the two main areas of evaluation in more detail as well as offer practical guidance on when to run these evaluations and what to look for in the results.


Book User Guide Llmops Guide Finetuning Embeddings README (`docs/book/user-guide/llmops-guide/finetuning-embeddings/README.md`)



We previously learned how to use RAG with ZenML to build a production-ready RAG pipeline. In this section, we will explore how to optimize and maintain your embedding models through synthetic data generation and human feedback. So far, we've been using off-the-shelf embeddings, which provide a good baseline and decent performance on standard tasks. However, you can often significantly improve performance by finetuning embeddings on your own domain-specific data.

Our RAG pipeline uses a retrieval-based approach, where it first retrieves the most relevant documents from our vector database, and then uses a language model to generate a response based on those documents. By finetuning our embeddings on a dataset of technical documentation similar to our target domain, we can improve the retrieval step and overall performance of the RAG pipeline.

The work of finetuning embeddings based on synthetic data and human feedback is a multi-step process. We'll go through the following steps:

Besides ZenML, we will do this by using two open source libraries: argilla and distilabel. Both of these libraries focus optimizing model outputs through improving data quality, however, each one of them takes a different approach to tackle the same problem. distilabel provides a scalable and reliable approach to distilling knowledge from LLMs by generating synthetic data or providing AI feedback with LLMs as judges. argilla enables AI engineers and domain experts to collaborate on data projects by allowing them to organize and explore data through within an interactive and engaging UI. Both libraries can be used individually but they work better together. We'll showcase their use via ZenML pipelines.

To follow along with the example explained in this guide, please follow the instructions in the llm-complete-guide repository where the full code is also available. This specific section on embeddings finetuning can be run locally or using cloud compute as you prefer.


Book User Guide Llmops Guide Finetuning Llms README (`docs/book/user-guide/llmops-guide/finetuning-llms/README.md`)



Finetuning LLMs with ZenML

So far in our LLMOps journey we've learned how to use RAG with ZenML, how to evaluate our RAG systems, how to use reranking to improve retrieval, and how tofinetune embeddings to support and improve our RAG systems. In this section we will explore LLM finetuning itself. So far we've been using APIs like OpenAI and Anthropic, but there are some scenarios where it makes sense to finetune an LLM on your own data. We'll get into those scenarios and how to finetune an LLM in the pages that follow.

While RAG systems are excellent at retrieving and leveraging external knowledge, there are scenarios where finetuning an LLM can provide additional benefits even with a RAG system in place. For example, you might want to finetune an LLM to improve its ability to generate responses in a specific format, to better understand domain-specific terminology and concepts that appear in your retrieved content, or to reduce the length of prompts needed for consistent outputs. Finetuning can also help when you need the model to follow very specific patterns or protocols that would be cumbersome to encode in prompts, or when you want to optimize for latency by reducing the context window needed for good performance.

We'll go through the following steps in this guide:

This guide is slightly different from the others in that we don't follow a specific use case as the model for finetuning LLMs. The actual steps needed to finetune an LLM are not that complex, but the important part is to understand when you might need to finetune an LLM, how to evaluate the performance of what you do as well as decisions around what data to use and so on.

To follow along with the example explained in this guide, please follow the instructions in the llm-lora-finetuning repository where the full code is also available. This code can be run locally (if you have a GPU attached to your machine) or using cloud compute as you prefer.


Book User Guide Llmops Guide Rag With Zenml README (`docs/book/user-guide/llmops-guide/rag-with-zenml/README.md`)



RAG Pipelines with ZenML

Retrieval-Augmented Generation (RAG) is a powerful technique that combines the
strengths of retrieval-based and generation-based models. In this guide, we'll
explore how to set up RAG pipelines with ZenML, including data ingestion, index
store management, and tracking RAG-associated artifacts.

LLMs are a powerful tool, as they can generate human-like responses to a wide
variety of prompts. However, they can also be prone to generating incorrect or
inappropriate responses, especially when the input prompt is ambiguous or
misleading. They are also (currently) limited in the amount of text they can
understand and/or generate. While there are some LLMs like Google's Gemini 1.5
Pro

that can consistently handle 1 million tokens (small units of text), the vast majority (particularly
the open-source ones currently available) handle far less.

The first part of this guide to RAG pipelines with ZenML is about understanding
the basic components and how they work together. We'll cover the following
topics:

  • why RAG exists and what problem it solves
  • how to ingest and preprocess data that we'll use in our RAG pipeline
  • how to leverage embeddings to represent our data; this will be the basis for
    our retrieval mechanism
  • how to store these embeddings in a vector database
  • how to track RAG-associated artifacts with ZenML

At the end, we'll bring it all together and show all the components working
together to perform basic RAG inference.


Book User Guide Llmops Guide Reranking README (`docs/book/user-guide/llmops-guide/reranking/README.md`)



Rerankers are a crucial component of retrieval systems that use LLMs. They help
improve the quality of the retrieved documents by reordering them based on
additional features or scores. In this section, we'll explore how to add a
reranker to your RAG inference pipeline in ZenML.

In previous sections, we set up the overall workflow, from data ingestion and
preprocessing to embeddings generation and retrieval. We then set up some basic
evaluation metrics to assess the performance of our retrieval system. A reranker
is a way to squeeze a bit of extra performance out of the system by reordering
the retrieved documents based on additional features or scores.

As you can see, reranking is an optional addition we make to what we've already
set up. It's not strictly necessary, but it can help improve the relevance and
quality of the retrieved documents, which in turn can lead to better responses
from the LLM. Let's dive in!


Book Api Docs Oss Api Docs V1 Artifact Versions README (`docs/book/api-docs/oss-api-docs/v1/artifact-versions/README.md`)

Artifact versions

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/artifact_versions" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/artifact_versions" method="post" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/artifact_versions" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/artifact_versions/{artifact_version_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/artifact_versions/{artifact_version_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/artifact_versions/{artifact_version_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Model Versions README (`docs/book/api-docs/oss-api-docs/v1/model-versions/README.md`)

Model versions

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/model_versions" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/model_versions/{model_version_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/model_versions/{model_version_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/model_versions/{model_version_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Models README (`docs/book/api-docs/oss-api-docs/v1/models/README.md`)

Models

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/models" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/models/{model_name_or_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/models/{model_name_or_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/models/{model_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Pipelines README (`docs/book/api-docs/oss-api-docs/v1/pipelines/README.md`)

Pipelines

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/pipelines" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/pipelines/{pipeline_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/pipelines/{pipeline_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/pipelines/{pipeline_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Run Templates README (`docs/book/api-docs/oss-api-docs/v1/run-templates/README.md`)

Run templates

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/run_templates" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/run_templates/{template_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/run_templates/{template_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/run_templates/{template_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Runs README (`docs/book/api-docs/oss-api-docs/v1/runs/README.md`)

Runs

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/runs" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/runs/{run_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/runs/{run_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/runs/{run_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Service Accounts README (`docs/book/api-docs/oss-api-docs/v1/service-accounts/README.md`)

Service accounts

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts" method="post" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_name_or_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_name_or_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_name_or_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Service Connectors README (`docs/book/api-docs/oss-api-docs/v1/service-connectors/README.md`)

Service connectors

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_connectors" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_connectors/{connector_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_connectors/{connector_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_connectors/{connector_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Steps README (`docs/book/api-docs/oss-api-docs/v1/steps/README.md`)

Steps

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/steps" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/steps" method="post" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/steps/{step_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/steps/{step_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Users README (`docs/book/api-docs/oss-api-docs/v1/users/README.md`)

Users

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/users" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/users/{user_name_or_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Pro Api Docs Api Reference Auth README (`docs/book/api-docs/pro-api-docs/api-reference/auth/README.md`)

Auth


Book Api Docs Pro Api Docs Api Reference Devices README (`docs/book/api-docs/pro-api-docs/api-reference/devices/README.md`)

Devices

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/devices" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/devices/{device_id_or_user_code}" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/devices/{device_id}" method="put" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/devices/{device_id}" method="delete" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Pro Api Docs Api Reference Organizations README (`docs/book/api-docs/pro-api-docs/api-reference/organizations/README.md`)

Organizations

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/organizations" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/organizations" method="post" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/organizations/{organization_id_or_name}" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/organizations/{organization_id}" method="delete" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/organizations/{organization_id}" method="patch" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Pro Api Docs Api Reference Rbac README (`docs/book/api-docs/pro-api-docs/api-reference/rbac/README.md`)

Rbac


Book Api Docs Pro Api Docs Api Reference Roles README (`docs/book/api-docs/pro-api-docs/api-reference/roles/README.md`)

Roles

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/roles" method="post" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/roles/{role_id}" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/roles/{role_id}" method="delete" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/roles/{role_id}" method="patch" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Pro Api Docs Api Reference Server README (`docs/book/api-docs/pro-api-docs/api-reference/server/README.md`)

Server


Book Api Docs Pro Api Docs Api Reference Teams README (`docs/book/api-docs/pro-api-docs/api-reference/teams/README.md`)

Teams

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/teams" method="post" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/teams/{team_id}" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/teams/{team_id}" method="delete" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/teams/{team_id}" method="patch" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Pro Api Docs Api Reference Tenants README (`docs/book/api-docs/pro-api-docs/api-reference/tenants/README.md`)

Tenants

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/tenants" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/tenants" method="post" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/tenants" method="delete" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/tenants/{tenant_id_or_name}" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/tenants/{tenant_id}" method="delete" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/tenants/{tenant_id}" method="patch" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Pro Api Docs Api Reference Users README (`docs/book/api-docs/pro-api-docs/api-reference/users/README.md`)

Users

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/users" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/users/{user_id_or_email}" method="get" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/users/{user_id}" method="delete" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://cloudapi.zenml.io/openapi.json" path="/users/{user_id}" method="patch" %}
https://cloudapi.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Oss Api Docs V1 Service Accounts Api Keys README (`docs/book/api-docs/oss-api-docs/v1/service-accounts/api-keys/README.md`)

Api keys

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_id}/api_keys" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_id}/api_keys" method="post" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_id}/api_keys/{api_key_name_or_id}" method="get" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_id}/api_keys/{api_key_name_or_id}" method="put" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}

{% openapi src="https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json" path="/api/v1/service_accounts/{service_account_id}/api_keys/{api_key_name_or_id}" method="delete" %}
https://1cf18d95-zenml.cloudinfra.zenml.io/openapi.json
{% endopenapi %}


Book Api Docs Pro Api Docs Api Reference Organizations Validation README (`docs/book/api-docs/pro-api-docs/api-reference/organizations/validation/README.md`)

Validation


Book AGENTS (`docs/book/AGENTS.md`)

Documentation Agent Guidelines

This file applies to changes in docs/book/ and below. For detailed
GitBook URL examples, link-checking notes, and docs workflow recipes, use
the repo-root .agents/skills/zenml-repo-workflows/SKILL.md.

Source of Truth

  • docs/book/ is the source of truth for documentation content.
  • Other docs directories such as docs/mkdocs/ and docs/site/ contain
    generated output; do not edit those directly.
  • Docs changes can affect the API docs buildability check in fast CI.

Structure

  • Multiple docs sections have their own toc.md; update the relevant toc.md
    when adding, moving, or removing pages.
  • Assets belong in a .gitbook folder at the same level as the relevant
    toc.md.
  • GitBook URLs follow TOC hierarchy, not filesystem paths.
  • Use absolute https://docs.zenml.io/... links when linking across major docs
    sections such as OSS docs and Pro docs.

Style

  • Include metadata fields at the top of pages when existing nearby pages do so.
  • Match the tone and structure of nearby documentation.
  • Prioritize readable prose over dense bullet lists.
  • Write documentation from the product user's perspective. Describe public
    behavior, user-facing concepts, and the information needed to complete the
    task. Do not expose database relationships, internal resource types,
    implementation mechanics, or lifecycle details unless users must understand
    them to use or troubleshoot the feature. Express observable consequences in
    product terminology instead.
  • Include code examples, cross-references, and usage guidance where they help
    users complete the task.

Verification

  • For changed relative markdown links, run the relevant local link checks.
  • For absolute docs URLs, check the current URL or inspect the relevant
    toc.md.
  • Use Lychee when the change affects many links:
    lychee --offline --no-progress 'docs/book/**/*.md'.

Book Introduction (`docs/book/introduction.md`)


icon: torii-gate
layout:
title:
visible: true
visible: true
tableOfContents:
visible: true
outline:
visible: false
pagination:
visible: false


Welcome to ZenML

ZenML is an open-source framework for orchestrating production ML and LLM pipelines, including pipelines that run agentic workloads.

That story has two open-source projects behind it:

  • ZenML is the MLOps framework: portable, production-ready pipelines for ML and LLM workloads, with versioned artifacts, caching, and infrastructure abstracted behind stacks.
  • Kitaru is for evaluating and improving agentic systems. It turns recorded or imported production traces into sessions for investigation, cohorts, evaluators, replay experiments, regression testing, and CI.

Each works on its own. ZenML orchestrates pipelines; Kitaru provides evals and improvement loops for agentic systems. Kitaru runs its own lightweight server, with workers that execute replays in your environment.

What are you building?

Pick the path that matches your work. Neither path requires the other, and adopting the second one later doesn't mean starting over.

ML Pipelines → ZenML Build, version, and deploy classical ML and LLM pipelines. Start with Hello World, then the Starter guide. how-to.png hello-world.md
Agent evals → Kitaru Investigate production traces, define evaluators and cohorts, and test changes through replay experiments. Start with the Kitaru quickstart. llm.png Kitaru quickstart

How these docs are organized

The documentation is split into spaces — the tabs at the top of this page. Knowing what lives where saves you a lot of searching:

Space What you'll find there
ZenML (you are here) The pipelines framework: installation, core concepts, deployment, and how-to guides
Kitaru Agent evals and improvement loops: production sessions, investigations, cohorts, evaluators, replay experiments, and regression testing
Learn Narrative ZenML guides: Starter, Production, and LLMOps, plus tutorials and best practices
Stacks The infrastructure components — orchestrators, artifact stores, and more — that ZenML pipelines run on
SDK reference / API reference Client and REST API references, organized per project
Changelog Release notes, version by version

First steps

Whichever path you picked, the first steps are the same shape: install, run something real, then learn the concepts.

ML Pipelines (ZenML) Agent Evals (Kitaru)
Install Installation Installation
First run Hello World Quickstart
Concepts Core Concepts Core Concepts

If you use AI coding tools, see LLM tooling for ZenML's MCP server and Agent Skills (including zenml-scoping and zenml-pipeline-authoring).

Guides

Starter Guide Get started with ZenML fundamentals and set up your first pipeline starter.png Starter guide
Production Guide Move your ML pipelines from development to production prod.png Production guide
Kitaru Replay a real run with one change, and improve agents across a cohort of real runs llm.png Kitaru docs

Book Toc (`docs/book/toc.md`)

Table of contents

Getting Started

Deploying ZenML

Concepts

Reference


Changelog Items Info (`docs/changelog-items/info.md`)

Adding a New Changelog Item


This guide explains how to add a new announcement/changelog item to the ZenML Changelog Widget.

Schema Overview

Each changelog item is a JSON object with the following fields. The announcements are stored as an array of these objects.

Required Fields

`id` (number)

  • Type: Number
  • Required: Yes
  • Description: Unique identifier for the announcement
  • Example: 1, 2, 3

`slug` (string)

  • Type: String
  • Required: Yes
  • Description: URL-friendly identifier for the announcement
  • Example: "new-pipeline-feature", "bugfix-artifact-loading"

`title` (string)

  • Type: String
  • Required: Yes
  • Description: The headline/title of the announcement
  • Example: "New Pipeline Visualization Feature"

`description` (string)

  • Type: String
  • Required: Yes
  • Description: Detailed description of the change or feature, can use markdown
  • Example: "We've added a new interactive pipeline visualization that helps you understand your ML workflows better."

`published_at` (string)

  • Type: ISO 8601 datetime string
  • Required: Yes
  • Description: The date and time when the announcement should be published
  • Format: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ssZ
  • Example: "2025-11-10T14:30:00Z", "2025-11-10T14:30:00.000Z"

Optional Fields

`feature_image_url` (string)

  • Type: String
  • Required: No
  • Description: URL to a feature image/screenshot for the announcement
  • Example: "<https://zenml.io/assets/feature-image.png>"

`learn_more_url` (string)

  • Type: Valid URL string
  • Required: No
  • Validation: Must be a valid URL format
  • Description: Link to a blog post, article, or additional information
  • Example: "<https://blog.zenml.io/new-feature>"

`docs_url` (string)

  • Type: Valid URL string
  • Required: No
  • Validation: Must be a valid URL format
  • Description: Link to documentation for the feature
  • Example: "<https://docs.zenml.io/user-guide/pipelines>"

`published` (boolean)

  • Type: Boolean
  • Required: No
  • Default: true
  • Description: Whether the announcement should be visible to users
  • Example: true, false

`highlight_until` (string)

  • Type: ISO 8601 datetime string
  • Required: No
  • Description: Date until which the announcement should be highlighted
  • Format: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ssZ
  • Example: "2025-11-20T00:00:00Z"

`should_highlight` (boolean)

  • Type: Boolean
  • Required: No
  • Default: false
  • Description: Whether to prominently highlight this announcement
  • Example: true, false

`video_url` (string)

  • Type: String
  • Required: No
  • Description: URL to a video demonstration or explanation
  • Example: "<https://www.youtube.com/watch?v=example>"

`audience` (enum)

  • Type: Enum (one of the specified values)
  • Required: No
  • Default: "all"
  • Allowed Values:
    • "pro" - Show only to ZenML Pro users
    • "oss" - Show only to open-source users
    • "all" - Show to all users
  • Example: "all"

`labels` (array of strings)

  • Type: Array of strings
  • Required: No
  • Default: [] (empty array)
  • Allowed Values: Only the following labels are recognized:
    • "feature" - For new features
    • "improvement" - For enhancements to existing functionality
    • "bugfix" - For bug fixes
    • "deprecation" - For deprecated features or warnings
  • Note: Any labels not in the allowed list will be filtered out automatically
  • Example: ["feature"], ["bugfix", "improvement"]

Complete Example

json
{
	"id": 42,
	"slug": "new-artifact-visualization",
	"title": "Enhanced Artifact Visualization",
	"description": "We've completely redesigned how artifacts are displayed in the dashboard, making it easier to explore your ML artifacts and their metadata.",
	"feature_image_url": "<https://zenml.io/assets/artifact-viz.png>",
	"learn_more_url": "<https://blog.zenml.io/artifact-visualization>",
	"docs_url": "<https://docs.zenml.io/user-guide/artifacts>",
	"published": true,
	"published_at": "2025-11-10T10:00:00Z",
	"highlight_until": "2025-11-17T23:59:59Z",
	"should_highlight": true,
	"video_url": "<https://www.youtube.com/watch?v=example>",
	"audience": "all",
	"labels": ["feature", "improvement"]
}

Minimal Example

json
{
	"id": 43,
	"slug": "minor-ui-fix",
	"title": "Fixed Button Alignment Issue",
	"description": "Resolved a visual bug where buttons were misaligned in the settings page.",
	"published_at": "2025-11-10T15:30:00Z"
}

Tips

  1. ID Management: Ensure each announcement has a unique ID. Use the next available number in sequence.
  2. Datetime Format: Always use ISO 8601 format for dates. It should be in UTC, including the Z suffix
  3. URLs: All URL fields (learn_more_url, docs_url) must be valid URLs or the schema validation will fail.
  4. Labels: Use appropriate labels to help users filter and understand the type of change. Multiple labels are allowed.
  5. Highlighting: Use should_highlight: true and highlight_until for important announcements that need extra visibility.

Mkdocs Cli (`docs/mkdocs/cli.md`)

Cli

::: zenml.cli
handler: python
selection:
members:
- "init.py"
rendering:
show_root_heading: true
show_source: true


Book Api Docs Toc (`docs/book/api-docs/toc.md`)

Table of contents

OSS API

Pro API


Book Component Guide Component Guide (`docs/book/component-guide/component-guide.md`)



Overview

If you are new to the world of MLOps, it is often daunting to be immediately faced with a sea of tools that seemingly all promise and do the same things. It is useful in this case to try to categorize tools in various groups in order to understand their value in your toolchain in a more precise manner.

What is a stack?

The stack is a fundamental component of the ZenML framework. Put simply, a stack represents the configuration of the infrastructure and tooling that defines where and how a pipeline executes.

A stack comprises different stack components, where each component is responsible for a specific task. For example, a stack might have a container registry, a Kubernetes cluster as an orchestrator, an artifact store, an experiment tracker like MLflow and so on.

Each pipeline run that you execute with ZenML will require a stack and each stack will be required to include at least an orchestrator and an artifact store. Apart from these two, the other components are optional and to be added as your pipeline evolves in MLOps maturity.

{% hint style="info" %}
Stacks are a ZenML concept. Kitaru, ZenML's sibling project for replaying and improving AI agents, deliberately does not use them — it runs a lightweight server of its own, with replays executing on workers in your environment.
{% endhint %}

Stacks as a way to organize your execution environment

With ZenML, you can run your pipelines on more than one stacks with ease. This pattern helps you test your code across different environments effortlessly.

This enables a case like this: a data scientist starts experimentation locally on their system and then once they are satisfied, move to a cloud environment on your staging cloud account to test more advanced features of your pipeline. Finally, when all looks good, they can mark the pipeline ready for production and have it run on a production-grade stack in your production cloud account.

Having separate stacks for these environments helps:

  • avoid wrongfully deploying your staging pipeline to production
  • curb costs by running less powerful resources in staging and testing locally first
  • control access to environments by granting permissions for only certain stacks to certain users

How to manage credentials for your stacks

Most stack components require some form of credentials to interact with the underlying infrastructure. For example, a container registry needs to be authenticated to push and pull images, a Kubernetes cluster needs to be authenticated to deploy models as a web service, and so on.

The preferred way to handle credentials in ZenML is to use Service Connectors. Service connectors are a powerful feature of ZenML that allow you to abstract away credentials and sensitive information from your team.

Ideally, you would want that only the people who deal with and have direct access to your cloud resources are the ones that are able to create Service Connectors. This is useful for a few reasons:

  • Less chance of credentials leaking: the more people that have access to your cloud resources, the higher the chance that some of them will be leaked.
  • Instant revocation of compromised credentials: folks who have direct access to your cloud resources can revoke the credentials instantly if they are compromised, making this a much more secure setup.
  • Easier auditing: you can have a much easier time auditing and tracking who did what if you have a clear separation between the people who can create Service Connectors (who have direct access to your cloud resources) and those who can only use them.

Here's an approach you can take that is a good balance between convenience and security:

  • Have a limited set of people that have permissions to create Service Connectors. These are ideally people that have access to your cloud accounts and know what credentials to use.
  • You can create one connector for your development or staging environment and let your data scientists use that to register their stack components.
  • When you are ready to go to production, you can create another connector with permissions for your production environment and create stacks that use it. This way you can ensure that your production resources are not accidentally used for development or staging.

If you follow this approach, you can keep your data scientists free from the hassle of figuring out the best authentication mechanisms for the different cloud services, having to manage credentials locally, and keep your cloud accounts safe, while still giving them the freedom to run their experiments in the cloud.

{% hint style="info" %}
Please note that restricting permissions for users through roles is a ZenML Pro feature. You can read more about it here. Sign up for a free trial here: https://zenml.io/pro.
{% endhint %}

How to deploy and manage stacks

Deploying and managing a MLOps stack is tricky.

  • Each tool comes with a certain set of requirements. For example, a Kubeflow installation will require you to have a Kubernetes cluster, and so would a Seldon Core deployment.
  • Figuring out the defaults for infra parameters is not easy. Even if you have identified the backing infra that you need for a stack component, setting up reasonable defaults for parameters like instance size, CPU, memory, etc., needs a lot of experimentation to figure out.
  • Many times, standard tool installations don't work out of the box. For example, to run a custom pipeline in Vertex AI, it is not enough to just run an imported pipeline. You might also need a custom service account that is configured to perform tasks like reading secrets from your secret store or talking to other GCP services that your pipeline might need.
  • Some tools need an additional layer of installations to enable a more secure, production-grade setup. For example, a standard MLflow tracking server deployment comes without an authentication frontend which might expose all of your tracking data to the world if deployed as-is.
  • All the components that you deploy must have the right permissions to be able to talk to each other. For example, your workloads running in a Kubernetes cluster might require access to the container registry or the code repository, and so on.
  • Cleaning up your resources after you're done with your experiments is super important yet very challenging. For example, if your Kubernetes cluster has made use of Load Balancers, you might still have one lying around in your account even after deleting the cluster, costing you money and frustration.

All of these points make taking your pipelines to production a more difficult task than it should be. We believe that the expertise in setting up these often-complex stacks shouldn't be a prerequisite to running your ML pipelines.

This docs section consists of information that makes it easier to provision, configure, and extend stacks and components in ZenML.

Stack Components Guide

Here is a full list of all stack components currently supported in ZenML, with a description of the role of that component in the MLOps process:

Orchestrator Orchestrating the runs of your pipeline orchestrator.png orchestrators
Deployer Deploying pipelines as long-running HTTP services deployer.png deployers
Artifact Store Storage for the artifacts created by your pipelines artifact-store.png artifact-stores
Container Registry Store for your containers container-registry.png container-registries
Data Validator Data and model validation data-validator.png data-validators
Experiment Tracker Tracking your ML experiments experiment-tracker.png experiment-trackers
Model Deployer Services/platforms responsible for online model serving model-deployer.png model-deployers
Step Operator Execution of individual steps in specialized runtime environments step-operator.png step-operators
Alerter Sending alerts through specified channels alerter.png alerters
Image Builder Builds container images. image-builder.png image-builders
Annotator Labeling and annotating data annotator.png annotators
Model Registry Manage and interact with ML Models model-registry.png model-registries
Feature Store Management of your data/features feature-store.png feature-stores

Custom Implementations

You can take control of how ZenML behaves by creating your own components. This is done by writing custom component flavors.

Component Flavors How to write a custom stack component flavor flavors.png Implement a custom stack component
Custom orchestrator guide Learn how to develop a custom orchestrator custom-orchestrator.png custom.md

Book Component Guide Integrations (`docs/book/component-guide/integrations.md`)


icon: box-archive

Integrations

Categorizing the MLOps stack is a good way to write abstractions for an MLOps pipeline and standardize your processes. But ZenML goes further and also provides concrete implementations of these categories by integrating with various tools for each category. Once code is organized into a ZenML pipeline, you can supercharge your ML workflows with the best-in-class solutions from various MLOps areas.

For example, you can orchestrate your ML pipeline workflows using Airflow or Kubeflow, track experiments using MLflow Tracking or Weights & Biases, and transition seamlessly from a local MLflow deployment to a deployed model on Kubernetes using Seldon Core.

There are lots of moving parts for all the MLOps tooling and infrastructure you require for ML in production and ZenML brings them all together and enables you to manage them in one place. This also allows you to delay the decision of which MLOps tool to use in your stack as you have no vendor lock-in with ZenML and can easily switch out tools as soon as your requirements change.

Available integrations

We have a dedicated webpage that indexes all supported ZenML integrations and their categories.

Another easy way of seeing a list of integrations is to see the list of directories in the integrations directory on our GitHub.

Installing dependencies for integrations and stacks

ZenML provides a way to export the package requirements for both individual integrations and entire stacks, enabling you to install the necessary dependencies manually. This approach gives you full control over the versions and the installation process.

Exporting integration requirements

You can export the requirements for a specific integration using the zenml integration export-requirements command. To write the requirements to a file and install them via pip, run:

bash
zenml integration export-requirements <INTEGRATION_NAME> --output-file integration_requirements.txt
pip install -r integration_requirements.txt

If you prefer to see the requirements without writing them to a file, omit the --output-file flag:

bash
zenml integration export-requirements <INTEGRATION_NAME>

This will print the list of dependencies to the console, which you can then pipe to pip:

bash
zenml integration export-requirements <INTEGRATION_NAME> | xargs pip install

Exporting stack requirements

To install all dependencies for a specific ZenML stack at once, you can export your stack's requirements:

bash
zenml stack export-requirements <STACK_NAME> --output-file stack_requirements.txt
pip install -r stack_requirements.txt

Omitting --output-file will print the requirements to the console:

bash
zenml stack export-requirements <STACK_NAME>

You can also pipe the output directly to pip:

bash
zenml stack export-requirements <STACK_NAME> | xargs pip install

{% hint style="info" %}
If you use a different package manager such as uv, you can install the exported requirements by replacing pip install -r … with your package manager's equivalent command.
{% endhint %}

Help us with integrations!

There are countless tools in the ML / MLOps field. We have made an initial prioritization of which tools to support with integrations that are visible on our public roadmap.

We also welcome community contributions. Check our Contribution Guide and External Integration Guide for more details on how to best contribute to new integrations.


Book Component Guide Toc (`docs/book/component-guide/toc.md`)

Table of contents

Stack Components

Service Connectors

Deployment

Contribute


Book Getting Started Core Concepts (`docs/book/getting-started/core-concepts.md`)


icon: lightbulb

Core concepts

ZenML is a unified, extensible, open-source MLOps framework for creating portable, production-ready MLOps pipelines. It's built for data scientists, ML Engineers, and MLOps Developers to collaborate as they develop to production. By extending the battle-tested principles you rely on for classical ML to the new world of AI agents, ZenML serves as one platform to develop, evaluate, and deploy your entire AI portfolio - from decision trees to complex multi-agent systems. In order to achieve this goal, ZenML introduces various concepts for different aspects of ML workflows and AI agent development, and we can categorize these concepts under three different threads:

1. Development As a developer, how do I design my machine learning workflows? #1-development development.png
2. Execution While executing, how do my workflows utilize the large landscape of MLOps tooling/infrastructure? #2-execution execution.png
3. Management How do I establish and maintain a production-grade and efficient solution? #3-management management.png

{% embed url="https://www.youtube.com/embed/iCB4KNjl5vs" %}
If you prefer visual learning, this short video demonstrates the key concepts covered below.
{% endembed %}

1. Development

First, let's look at the main concepts that play a role during the development stage of ML workflows and AI agent pipelines with ZenML.

Step

Steps are functions annotated with the @step decorator. The easiest one could look like this.

python
from zenml import step

@step
def step_1() -> str:
    """Returns a string."""
    return "world"

These functions can also have inputs and outputs. For ZenML to work properly, these should preferably be typed.

python
from zenml import step

@step(enable_cache=False)
def step_2(input_one: str, input_two: str) -> str:
    """Combines the two strings passed in."""
    combined_str = f"{input_one} {input_two}"
    return combined_str

@step
def evaluate_agent_response(prompt: str, test_query: str) -> dict:
    """Evaluates an AI agent's response to a test query."""
    response = call_llm_agent(prompt, test_query)
    return {"query": test_query, "response": response, "quality_score": 0.95}

Pipelines

At its core, ZenML follows a pipeline-based workflow for your projects. A pipeline consists of a series of steps, organized in any order that makes sense for your use case.

As seen in the image, a step might use the outputs from a previous step and thus must wait until the previous step is completed before starting. This is something you can keep in mind when organizing your steps.

Pipelines and steps are defined in code using Python decorators or classes. This is where the core business logic and value of your work live, and you will spend most of your time defining these two things.

Even though pipelines are simple Python functions, you are only allowed to call steps within this function. The inputs for steps called within a pipeline can either be the outputs of previous steps or alternatively, you can pass in values directly or map them onto pipeline parameters (as long as they're JSON-serializable). Similarly, you can return values from a pipeline that are step outputs as long as they are JSON-serializable.

python
from zenml import pipeline

@pipeline
def my_pipeline():
    output_step_one = step_1()
    step_2(input_one="hello", input_two=output_step_one)

@pipeline
def agent_evaluation_pipeline(query: str = "What is machine learning?") -> str:
    """An AI agent evaluation pipeline."""
    prompt = "You are a helpful assistant. Please answer: {query}"
    evaluation_result = evaluate_agent_response(prompt, query)
    return evaluation_result

{% hint style="info" %}
If you use an AI coding agent, ZenML Agent Skills can help you scope a pipeline architecture (zenml-scoping) and then implement steps and pipelines correctly (zenml-pipeline-authoring). See LLM tooling.
{% endhint %}

Executing the Pipeline is as easy as calling the function that you decorated with the @pipeline decorator.

python
if __name__ == "__main__":
    my_pipeline()
    agent_evaluation_pipeline(query="What is an LLM?")

Artifacts

Artifacts represent the data that goes through your steps as inputs and outputs, and they are automatically tracked and stored by ZenML in the artifact store. They are produced by and circulated among steps whenever your step returns an object or a value. This means the data is not passed between steps in memory. Rather, when the execution of a step is completed, they are written to storage, and when a new step gets executed, they are loaded from storage.

Artifacts can be traditional ML data (datasets, models, metrics) or AI agent components (prompt templates, agent configurations, evaluation results). The same artifact system seamlessly handles both use cases.

The serialization and deserialization logic of artifacts is defined by Materializers.

Models

Models are used to represent the outputs of a training process along with all metadata associated with that output. In other words: models in ZenML are more broadly defined as the weights as well as any associated information. This includes traditional ML models (scikit-learn, PyTorch, etc.) and AI agent configurations (prompt templates, tool definitions, multi-agent system architectures). Models are first-class citizens in ZenML and as such viewing and using them is unified and centralized in the ZenML API, client, as well as on the ZenML Pro dashboard.

Materializers

Materializers define how artifacts live in between steps. More precisely, they define how data of a particular type can be serialized/deserialized, so that the steps are able to load the input data and store the output data.

All materializers use the base abstraction called the BaseMaterializer class. While ZenML comes built-in with various implementations of materializers for different datatypes, if you are using a library or a tool that doesn't work with our built-in options, you can write your own custom materializer to ensure that your data can be passed from step to step.

Parameters & Settings

When we think about steps as functions, we know they receive input in the form of artifacts. We also know that they produce output (in the form of artifacts, stored in the artifact store). But steps also take parameters. The parameters that you pass into the steps are also (helpfully!) stored by ZenML. This helps freeze the iterations of your experimentation workflow in time, so you can return to them exactly as you run them. On top of the parameters that you provide for your steps, you can also use different Settings to configure runtime configurations for your infrastructure and pipelines.

Model and model versions

ZenML exposes the concept of a Model, which consists of multiple different model versions. A model version represents a unified view of the ML models that are created, tracked, and managed as part of a ZenML project. Model versions link all other entities to a centralized view.

2. Execution

Once you have implemented your workflow by using the concepts described above, you can focus your attention on the execution of the pipeline run.

Stacks & Components

When you want to execute a pipeline run with ZenML, Stacks come into play. A Stack is a collection of stack components, where each component represents the respective configuration regarding a particular function in your MLOps pipeline, such as pipeline orchestration or deployment systems, artifact repositories and container registries.

Pipelines can be executed in two ways: in batch mode (traditional execution through an orchestrator) or in online mode (long-running HTTP servers that can be invoked via REST API calls). Deploying pipelines for online mode execution allows you to serve your ML workflows as real-time endpoints, making them accessible for live inference and interactive use cases.

For instance, if you take a close look at the default local stack of ZenML, you will see two components that are required in every stack in ZenML, namely an orchestrator and an artifact store. Additional components like deployers can be added to enable specific functionality such as deploying pipelines as HTTP endpoints.

{% hint style="info" %}
Keep in mind that each one of these components is built on top of base abstractions and is completely extensible.
{% endhint %}

Orchestrator

An Orchestrator is a workhorse that coordinates all the steps to run in a pipeline in batch mode. Since pipelines can be set up with complex combinations of steps with various asynchronous dependencies between them, the orchestrator acts as the component that decides what steps to run and when to run them.

ZenML comes with a default local orchestrator designed to run on your local machine. This is useful, especially during the exploration phase of your project. You don't have to rent a cloud instance just to try out basic things.

Artifact Store

An Artifact Store is a component that houses all data that passes through the pipeline as inputs and outputs. Each artifact that gets stored in the artifact store is tracked and versioned and this allows for extremely useful features like data caching, which speeds up your workflows.

Similar to the orchestrator, ZenML comes with a default local artifact store designed to run on your local machine. This is useful, especially during the exploration phase of your project. You don't have to set up a cloud storage system to try out basic things.

Deployer

A Deployer is a stack component that manages the deployment of pipelines as long-running HTTP servers useful for online mode execution. Unlike orchestrators that execute pipelines in batch mode, deployers can create and manage persistent services that wrap your pipeline in a web application, usually containerized, allowing it to be invoked through HTTP requests.

ZenML comes with a Docker deployer that can run deployments on your local machine as Docker containers, making it easy to test and develop real-time pipeline endpoints before moving to production infrastructure.

Flavor

ZenML provides a dedicated base abstraction for each stack component type. These abstractions are used to develop solutions, called Flavors, tailored to specific use cases/tools. With ZenML installed, you get access to a variety of built-in and integrated Flavors for each component type, but users can also leverage the base abstractions to create their own custom flavors.

Stack Switching

When it comes to production-grade solutions, it is rarely enough to just run your workflow locally without including any cloud infrastructure.

Thanks to the separation between the pipeline code and the stack in ZenML, you can easily switch your stack independently from your code. For instance, all it would take you to switch from an experimental local stack running on your machine to a remote stack that employs a full-fledged cloud infrastructure is a single CLI command.

Pipeline Snapshot

A Pipeline Snapshot is an immutable snapshot of your pipeline that includes the pipeline DAG, code, configuration, and container images. Snapshots can be run from the server or dashboard, and can also be deployed.

Pipeline Run

A Pipeline Run is a record of a pipeline execution. When you run a pipeline using an orchestrator, a pipeline run is created tracking information about the execution such as the status, the artifacts and metadata produced by the pipeline and all its steps. When a pipeline is deployed for online mode execution, a pipeline run is similarly created for every HTTP request made to it.

Deployment

A Deployment is a running instance of a pipeline deployed as an HTTP endpoint. When you deploy a pipeline using a deployer, it becomes a long-running service that can be invoked through REST API calls. Each HTTP request to a deployment triggers a new pipeline run, creating the same artifacts and metadata tracking as traditional batch pipeline executions. This enables real-time inference, interactive ML workflows, and seamless integration with web applications and external services.

3. Management

In order to benefit from the aforementioned core concepts to their fullest extent, it is essential to deploy and manage a production-grade environment that interacts with your ZenML installation.

ZenML Server

To use stack components that are running remotely on a cloud infrastructure, you need to deploy a ZenML Server so it can communicate with these stack components and run your pipelines. The server is also responsible for managing ZenML business entities like pipelines, steps, models, etc.

Server Deployment

In order to benefit from the advantages of using a deployed ZenML server, you can either choose to use the ZenML Pro SaaS offering, which provides a control plane for you to create managed instances of ZenML servers, or deploy it in your self-hosted environment.

Metadata Tracking

On top of the communication with the stack components, the ZenML Server also keeps track of all the bits of metadata around a pipeline run. With a ZenML server, you are able to access all of your previous experiments with the associated details. This is extremely helpful in troubleshooting.

Secrets

The ZenML Server also acts as a centralized secrets store that safely and securely stores sensitive data, such as credentials used to access the services that are part of your stack. It can be configured to use a variety of different backends for this purpose, such as the AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, and Hashicorp Vault.

Secrets are sensitive data that you don't want to store in your code or configure alongside your stacks and pipelines. ZenML includes a centralized secrets store that you can use to store and access your secrets securely.

Collaboration

Collaboration is a crucial aspect of any MLOps team as they often need to bring together individuals with diverse skills and expertise to create a cohesive and effective workflow for machine learning projects and AI agent development. A successful MLOps team requires seamless collaboration between data scientists, engineers, and DevOps professionals to develop, train, deploy, and maintain both traditional ML models and AI agent systems.

With a deployed ZenML Server, users have the ability to create their own teams and project structures. They can easily share pipelines, runs, stacks, and other resources, streamlining the workflow and promoting teamwork across the entire AI development lifecycle.

Dashboard

The ZenML Dashboard also communicates with the ZenML Server to visualize your pipelines, stacks, and stack components. The dashboard serves as a visual interface to showcase collaboration with ZenML. You can invite users and share your stacks with them.

When you start working with ZenML, you'll start with a local ZenML setup, and when you want to transition, you will need to deploy ZenML. Don't worry though, there is a one-click way to do it, which we'll learn about later.

VS Code Extension

ZenML also provides a VS Code extension that allows you to interact with your ZenML stacks, runs, and server directly from your VS Code editor. If you're working on code in your editor, you can easily switch and inspect the stacks you're using, delete and inspect pipelines as well as even switch stacks.


Book Getting Started Hello World (`docs/book/getting-started/hello-world.md`)


Your first ML pipeline with ZenML - from local development to cloud deployment in minutes. icon: hand-wave

Hello World

This guide will help you build and deploy your first ZenML pipeline, starting locally and then transitioning to the cloud without changing your code. The same principles you'll learn here apply whether you're building classical ML models or AI agents.

{% stepper %}
{% step %}

Install ZenML

Start by installing ZenML in a fresh Python environment:

bash
pip install 'zenml[server]'
zenml login

This gives you access to both the ZenML Python SDK and CLI tools. It also surfaces the
ZenML dashboard + connects it to your local client.
{% endstep %}

{% step %}

Write your first pipeline

Create a simple run.py file with a basic workflow:

from zenml import step, pipeline

@step
def basic_step() -> str:
"""A simple step that returns a greeting message."""
return "Hello World!"

@pipeline
def basic_pipeline() -> str:
"""A simple pipeline with just one step."""
greeting = basic_step()
return greeting

if name == "main":
basic_pipeline()

Run this pipeline in batch mode locally:

bash
python run.py

You will see ZenML automatically tracks the execution and stores artifacts. View these on the CLI or on the dashboard.

{% endstep %}

{% step %}

Before deploying, you can create a snapshot - an immutable, reproducible version of your pipeline including code, configuration, and container images:

bash
# Create a snapshot of your pipeline
zenml pipeline snapshot create run.basic_pipeline --name my_snapshot

Snapshots are powerful because they:

  • Freeze your pipeline state - Ensure the exact same pipeline always runs
  • Enable parameterization - Run the same snapshot with different inputs
  • Support team collaboration - Share ready-to-use pipeline configurations
  • Integrate with automation - Trigger from dashboards, APIs, or CI/CD systems

Learn more about Snapshots
{% endstep %}

{% step %}

Deploy your pipeline as a real-time service

ZenML can deploy your pipeline (or snapshot) as a persistent HTTP service for real-time inference:

bash
# Deploy your pipeline directly
zenml pipeline deploy run.basic_pipeline --name my_deployment

# OR deploy a snapshot (if you created one above)
zenml pipeline snapshot deploy my_snapshot --deployment my_deployment

Your pipeline now runs as a production-ready service! This is perfect for serving predictions to web apps, powering AI agents, or handling real-time requests.

Key insight: When you deploy a pipeline directly with zenml pipeline deploy, ZenML automatically creates an implicit snapshot behind the scenes, ensuring reproducibility.

Learn more about Pipeline Deployments
{% endstep %}

{% step %}

Set up a ZenML Server (For Remote Infrastructure)

To use remote infrastructure (cloud deployers, orchestrators, artifact stores), you need to deploy a ZenML server to manage your pipelines centrally. You can use ZenML Pro (managed, 14-day free trial) or deploy it yourself (self-hosted, open-source).

Connect your local environment:

bash
zenml login
zenml project set <PROJECT_NAME>

Once connected, you'll have a centralized dashboard to manage infrastructure, collaborate with team members, and schedule pipeline runs.
{% endstep %}

{% step %}

Create your first remote stack (Optional)

A "stack" in ZenML represents the infrastructure where your pipelines run. You can now scale from local development to cloud infrastructure without changing any code.

Stack deployment options

Remote stacks can include:

The fastest way to create a cloud stack is through the Infrastructure-as-Code option, which uses Terraform to deploy cloud resources and register them as a ZenML stack.

You'll need:

  • Terraform version 1.9+ installed locally
  • Authentication configured for your preferred cloud provider (AWS, GCP, or Azure)
  • Appropriate permissions to create resources in your cloud account
bash
# Create a remote stack using the deployment wizard
zenml stack register <STACK_NAME> \
  --deployer <DEPLOYER_NAME> \
  --orchestrator <ORCHESTRATOR_NAME> \
  --artifact-store <ARTIFACT_STORE_NAME>

The wizard will guide you through each step.
{% endstep %}

{% step %}

Deploy and run on remote infrastructure

Once you have a remote stack, you can:

  1. Deploy your service to the cloud - Your deployment runs on managed cloud infrastructure:
bash
zenml stack set <REMOTE_STACK_NAME>
zenml pipeline deploy run.basic_pipeline --name my_production_deployment
  1. Run batch pipelines at scale - Use the same code with a cloud orchestrator:
bash
zenml stack set <REMOTE_STACK_NAME>
python run.py  # Automatically runs on cloud infrastructure

ZenML handles packaging code, building containers, orchestrating execution, and tracking artifacts automatically across all cloud providers.

Your pipeline in the ZenML Pro Dashboard
{% endstep %}

{% step %}

What's next?

Congratulations! You've just experienced the core value proposition of ZenML:

  • Write Once, Run Anywhere: The same code runs locally during development and in the cloud for production
  • Unified Framework: Use the same MLOps principles for both classical ML models and AI agents
  • Separation of Concerns: Infrastructure configuration and ML code are completely decoupled, enabling independent
    evolution of each
  • Full Tracking: Every run, artifact, and model is automatically versioned and tracked - whether it's a scikit-learn model or a multi-agent system

To continue your ZenML journey, explore these key topics:

For All AI Workloads:

  • AI-assisted pipeline building: Use ZenML Agent Skills like zenml-scoping (architecture planning) and zenml-pipeline-authoring (implementation guidance) — see LLM tooling
  • Pipeline Development: Discover advanced features like scheduling and caching
  • Artifact Management: Learn how ZenML stores, versions, and tracks your data automatically
  • Organization: Use tags and metadata to keep your AI projects structured

For LLMs and AI Agents:

  • LLMOps Guide: Write your first AI pipeline for agent development patterns
  • Deploying Agents: To see an example of a deployed document extraction agent, see the deploying agents example
  • Agent Outer Loop: See the Agent Outer Loop example to learn about training classifiers and improving agents through feedback loops
  • Agent Evaluation: Learn to systematically evaluate and compare different agent architectures
  • Prompt Management: Version and track prompts, tools, and agent configurations as artifacts

Infrastructure & Deployment:


Book Getting Started Installation (`docs/book/getting-started/installation.md`)


icon: cauldron

Installation

{% stepper %}
{% step %}

Install ZenML

ZenML currently supports Python 3.10, 3.11, 3.12, 3.13, and 3.14. Please make sure that you are using a supported Python version.

{% tabs %}
{% tab title="Base package" %}
ZenML is a Python package that can be installed using pip or other Python package managers:

shell
pip install zenml

{% hint style="warning" %}
Installing the base package only allows you to connect to a deployed ZenML server. If you want to use ZenML purely locally, install it with the local extra:

shell
pip install 'zenml[local]'

{% endhint %}
{% endtab %}

{% tab title="Local Dashboard" %}
If you want to use the ZenML dashboard locally, install ZenML with the server extra:

shell
pip install 'zenml[server]'

{% hint style="warning" %}
If you want to run a local server while running on a Mac with Apple Silicon (M1, M2, M3, M4), you should set the following environment variable:

bash
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

You can read more about this here.
{% endhint %}

{% endtab %}

{% tab title="Jupyter Notebooks" %}
If you write your ZenML pipelines ins Jupyter notebooks, we recommend installing ZenML with the jupyter extra which includes improved CLI output and logs:

shell
pip install 'zenml[jupyter]'

{% endtab %}

{% endtabs %}
{% endstep %}

{% step %}

Verifying Installations

Once the installation is completed, you can check whether the installation was successful either through Bash or Python:

{% tabs %}
{% tab title="Bash" %}

bash
zenml version

{% endtab %}

{% tab title="Python" %}

python
import zenml

print(zenml.__version__)

{% endtab %}
{% endtabs %}

If you would like to learn more about the current release, please visit our PyPi package page.
{% endstep %}
{% endstepper %}

Running with Docker

zenml is also available as a Docker image hosted publicly on DockerHub. Use the following command to get started in a bash environment with zenml available:

shell
docker run -it zenmldocker/zenml /bin/bash

If you would like to run the ZenML server with Docker:

shell
docker run -it -d -p 8080:8080 zenmldocker/zenml-server

Starting the local server

By default, ZenML runs without a server connected to a local database on your machine. If you want to access the dashboard locally, you need to start a local server:

shell
# Make sure to have the `server` extra installed
pip install "zenml[server]"
zenml login --local  # opens the dashboard locally

However, advanced ZenML features are dependent on a centrally deployed ZenML server accessible to other MLOps stack components. You can read more about it here. For the deployment of ZenML, you have the option to either self-host it or register for a free ZenML Pro account.


Book Getting Started System Architectures (`docs/book/getting-started/system-architectures.md`)


icon: building-columns

System Architecture

This guide walks through the various ways that ZenML can be deployed, from self-hosted OSS to
SaaS to self-hosted ZenML Pro!

ZenML OSS (Self-hosted)

{% hint style="info" %}
This page is intended as a high-level overview. To learn more about how to deploy ZenML OSS, read this guide.
{% endhint %}

A ZenML OSS deployment consists of the following moving pieces:

  • ZenML OSS Server: This is a FastAPI app that manages metadata of pipelines, artifacts, stacks, etc. Note: In ZenML Pro, the notion of a ZenML server is replaced with what is known as a "Workspace". For all intents and purposes, consider a ZenML Workspace to be a ZenML OSS server that comes with more functionality.
  • OSS Metadata Store: This is where all ZenML workspace metadata is stored, including ML metadata such as tracking and versioning information about pipelines and models.
  • OSS Dashboard: This is a ReactJS app that shows pipelines, runs, etc.
  • Secrets Store: All secrets and credentials required to access customer infrastructure services are stored in a secure secrets store. The ZenML Pro API has access to these secrets and uses them to access customer infrastructure services on behalf of the ZenML Pro. The secrets store can be hosted either by the ZenML Pro or by the customer.

ZenML OSS is free with Apache 2.0 license. Learn how to deploy it here.

{% hint style="info" %}
To learn more about the core concepts for ZenML OSS, go here.
{% endhint %}

ZenML Pro (SaaS or Self-hosted)

{% hint style="info" %}
If you're interested in assessing ZenML Pro SaaS, you can create a free account.

If you would like to self-host ZenML Pro, please book a demo.
{% endhint %}

The above deployment can be augmented with the ZenML Pro components:

  • ZenML Pro Control Plane: This is the central controlling entity of all workspaces.
  • Pro Dashboard: This is a dashboard that builds on top of the OSS dashboard and adds further functionality.
  • Pro Metadata Store: This is a PostgreSQL database where all ZenML Pro-related metadata is stored, such as roles, permissions, teams, and workspace management-related data.
  • Pro Add-ons: These are Python modules injected into the OSS Server for enhanced functionality.
  • Identity Provider: ZenML Pro offers flexible authentication options. In cloud-hosted deployments, it integrates with Auth0, allowing users to log in via social media or corporate credentials. For self-hosted deployments, customers can configure their own identity management solution, with ZenML Pro supporting custom OIDC provider integration. This allows organizations to leverage their existing identity infrastructure for authentication and authorization, whether using the cloud service or deploying on-premises.

ZenML Pro offers many additional features to increase your team's productivity. No matter your specific needs, the hosting options for ZenML Pro range from easy SaaS integration to completely air-gapped deployments on your own infrastructure.

You might have noticed that this architecture builds on top of the ZenML OSS system architecture. Therefore, if you already have ZenML OSS deployed, it is easy to enroll it as part of a ZenML Pro deployment!

The above components interact with other MLOps stack components, secrets, and data in the following scenarios described below.

{% hint style="info" %}
To learn more about the core concepts for ZenML Pro, go here
{% endhint %}

ZenML Pro SaaS Architecture

For the ZenML Pro SaaS deployment case, all ZenML services are hosted on infrastructure hosted by the ZenML Team. Customer secrets and credentials required to access customer infrastructure are stored and managed by the ZenML Pro Control Plane.

On the ZenML Pro infrastructure, only ML metadata (e.g. pipeline and model tracking and versioning information) is stored. All the actual ML data artifacts (e.g. data produced or consumed by pipeline steps, logs and visualizations, models) are stored on the customer cloud. This can be set up quite easily by configuring an artifact store with your MLOps stack.

Your workspace only needs permissions to read from this data to display artifacts on the ZenML dashboard. The workspace also needs direct access to parts of the customer infrastructure services to support dashboard control plane features such as CI/CD, triggering and running pipelines, triggering model deployments and so on.

The advantage of this setup is that it is a fully-managed service, and is very easy to get started with. However, for some clients, even some metadata can be sensitive; these clients should refer to the other architecture diagram.

ZenML Pro Hybrid SaaS

The partially self-hosted architecture offers a balanced approach that combines the benefits of cloud-hosted control with on-premises data sovereignty. In this configuration, while the ZenML Pro control plane remains hosted by ZenML (handling user management, authentication, RBAC and global workspace coordination), all other components - including services, data, and secrets - are deployed within your own cloud infrastructure.

This hybrid model is particularly well-suited for organizations with:

  • A centralized MLOps or Platform team responsible for standardizing ML practices
  • Multiple business units or teams that require autonomy over their data and infrastructure
  • Strict security requirements where workspaces must operate behind VPN/corporate firewalls
  • Compliance requirements that mandate keeping sensitive data and ML artifact metadata within company infrastructure
  • Need for customization of workspace configurations while maintaining centralized governance

The key advantages of this setup include:

  • Simplified user management through the ZenML-hosted control plane
  • Complete data sovereignty - sensitive data and ML artifacts remain within your infrastructure
  • Secure networking - workspaces communicate through outbound-only connections via VPN/private networks
  • Ability to customize and configure workspaces according to specific team needs
  • Reduced operational overhead compared to fully self-hosted deployments
  • Reduced maintenance burden - all control plane updates and maintenance are handled by ZenML
    This architecture strikes a balance between convenience and control, making it a popular choice for enterprises looking to standardize their MLOps practices while maintaining sovereignty.

ZenML Pro Self-Hosted Architecture

In the case of self-hosting ZenML Pro, all services, data, and secrets are deployed on the customer
cloud. This is meant for customers who require completely air-gapped deployments, for the tightest security standards. Reach out to us if you want to set this up.

Detailed Architecture Diagram for self-hosted ZenML Pro deployment

Are you interested in ZenML Pro? Sign up and get access with a free trial now!

Data Implications Across Deployment Scenarios

Deployment Scenario Data Location Data Movement Data Access Data Isolation
ZenML OSS (Self-hosted) All data remains on customer infrastructure: both ML metadata in OSS Metadata Store and actual ML data artifacts in customer Artifact Store Data stays within customer boundary; moves between pipeline steps via the Orchestrator Accessible only through customer infrastructure; no ZenML-managed components have access Complete data isolation from ZenML-managed services
ZenML Pro SaaS ML metadata in ZenML-hosted DB; Actual ML data artifacts in customer Artifact Store; Secrets in ZenML-managed Secret Store Metadata flows to ZenML Pro Control Plane; ML data artifacts stay on customer infrastructure; ZenML services access customer infrastructure using stored credentials ZenML Pro has access to the customer secrets that are explicitly stored; Workspace optionally needs read access to artifact store for dashboard display; No actual ML data moves to ZenML infrastructure unless explicitly shared Only metadata and credentials are stored on ZenML infrastructure; actual ML data remains isolated on customer infrastructure
ZenML Pro Hybrid SaaS Control Plane on ZenML infrastructure; Workspace, DB, Secret Store, Orchestrator, and Artifact Store on customer infrastructure Only authentication/authorization data flows to ZenML; All ML data and metadata stays on customer infrastructure ZenML Control Plane has limited access to user management data; No access to actual ML data or metadata; Customer maintains all data access controls Strong data isolation with only authentication events crossing boundary. Allows securing access via VPN/private networks.
ZenML Pro Self-Hosted All components run on customer infrastructure All data movement contained within customer infrastructure boundary No external access to any data; completely air-gapped operation possible Complete data isolation; ZenML has no access to any customer data

Book Getting Started Your First Ai Pipeline (`docs/book/getting-started/your-first-ai-pipeline.md`)


icon: rocket

Your First AI Pipeline

ZenML pipelines work the same for classical ML, AI agents, and hybrid approaches. Choose your path below to get started:

{% hint style="info" %}
Why ZenML pipelines?

  • Reproducible & portable: Run the same code locally or on the cloud by switching stacks.
  • One approach for models and agents: Steps, pipelines, and artifacts work for sklearn, classical ML, and LLMs alike.
  • Observe by default: Lineage and step metadata (e.g., latency, tokens, metrics) are tracked and visible in the dashboard.
    {% endhint %}

{% hint style="info" %}
Plan and build pipelines with AI coding agents: If you use Claude Code, Codex, Copilot, Cursor, or similar tools, ZenML provides Agent Skills that can scope your idea into a realistic multi-pipeline plan (zenml-scoping) and help you implement steps and pipelines (zenml-pipeline-authoring). See LLM tooling for installation instructions.
{% endhint %}


What do you want to build?

Choose one of the paths below. The same ZenML pipeline pattern works for all of them—the difference is in your steps and how you orchestrate them.


Path 1: Build AI Agents

Use large language models, prompts, and tools to build intelligent autonomous agents that can reason, take action, and interact with your systems.

{% hint style="info" %}
Evaluating production agents. This path runs your agent inside a ZenML pipeline, which is useful for orchestrated batch workloads and evaluations. If your agent runs elsewhere in production, Kitaru can record or import its traces as sessions. You can investigate those sessions, define cohorts and evaluators, and use replay experiments to test changes and build regression checks. Kitaru does not use ZenML pipelines or stacks for this workflow.
{% endhint %}

Architecture example

mermaid
---
config:
  layout: elk
  theme: mc
---
flowchart TB
  U["CLI / curl / web UI"] --> D["ZenML Deployment<br/>(doc_analyzer)"]

  subgraph PIPE["Pipeline: doc_analyzer"]
    I["ingest_document_step"]
    A["analyze_document_step"]
    R["render_analysis_report_step"]
    I --> A --> R
  end

  D --> PIPE

  subgraph STACK["Stack"]
    OR[("Deployer")]
    AR[("Artifact Store")]
  end

  PIPE --> AR
  D --> OR

View Quick Start & Examples

Quick start

bash
git clone --depth 1 https://github.com/zenml-io/zenml.git
cd zenml/examples/deploying_agent
uv pip install -r requirements.txt

Then follow the guide in examples/deploying_agent:

  1. Define your steps: Use LLM APIs (OpenAI, Claude, etc.) to build reasoning steps
  2. Deploy as HTTP service: Turn your agent into a managed endpoint
  3. Invoke and monitor: Use the CLI, curl, or the embedded web UI to interact with your agent
  4. Inspect traces: View agent reasoning, tool calls, and metadata in the ZenML dashboard

Example output

  • Automated document analysis (see deploying_agent)
  • Multi-turn chatbots with context
  • Autonomous workflows with tool integrations
  • Agentic RAG systems with retrieval steps

Path 2: Build Classical ML Pipelines

Use scikit-learn, TensorFlow, PyTorch, or other ML frameworks to build data processing, feature engineering, training, and inference pipelines.

Architecture example

mermaid
---
config:
  layout: elk
  theme: mc
---
flowchart TB
  subgraph TRAIN["Training"]
    D["generate_churn_data"]
    T["train_churn_model"]
    D --> T
  end

  subgraph INFER["Inference"]
    P["predict_churn"]
  end

  U["Customer Features<br/>(curl / SDK)"] --> INFER

  subgraph STACK["Stack"]
    OR[("Orchestrator")]
    AR[("Artifact Store")]
    DE[("Deployer")]
  end

  TRAIN --> AR
  TRAIN --> OR
  INFER --> DE
  INFER --> AR

View Quick Start & Examples

Quick start

bash
git clone --depth 1 https://github.com/zenml-io/zenml.git
cd zenml/examples/deploying_ml_model
uv pip install -r requirements.txt

Then follow the guide in examples/deploying_ml_model:

  1. Build your pipeline: Data loading → preprocessing → training → evaluation
  2. Deploy the model: Serve your trained model as a real-time HTTP endpoint
  3. Monitor performance: Track predictions, latency, and data drift in the dashboard
  4. Iterate: Retrain and redeploy without code changes—just switch your orchestrator

Example output

  • Predictive models (regression, classification)
  • Time series forecasting
  • NLP pipelines (sentiment analysis, text classification)
  • Computer vision workflows
  • Model scoring and ranking systems
  • e2e: End-to-end ML pipeline with data validation and model deployment
  • e2e_nlp: Domain-specific NLP pipeline example
  • mlops_starter: Production-ready MLOps setup with monitoring and governance

Path 3: Build Hybrid Systems

Combine classical ML models and AI agents in a single pipeline. For example, use a classifier to route requests to specialized agents, or use agents to augment ML predictions.

Architecture example

mermaid
---
config:
  layout: elk
  theme: mc
---
flowchart TB
  U["Customer Input<br/>(curl / SDK)"] --> SA["Agent Service"]

  subgraph TRAIN["Training"]
    D["load_data"]
    T["train_classifier"]
    D --> T
  end

  subgraph SERVE["Serving"]
    C["classify_intent"]
    R["generate_response"]
    C --> R
  end

  SA --> SERVE

  subgraph STACK["Stack"]
    OR[("Orchestrator")]
    AR[("Artifact Store")]
    DE[("Deployer")]
  end

  TRAIN --> AR
  TRAIN --> OR
  SERVE --> AR
  SERVE --> DE

View Quick Start & Examples

Quick start

bash
git clone --depth 1 https://github.com/zenml-io/zenml.git
cd zenml/examples/agent_outer_loop
uv pip install -r requirements.txt

Then follow the guide in examples/agent_outer_loop:

  1. Define both components: Classical ML classifier + AI agent steps
  2. Wire them together: Use the classifier output to influence agent behavior
  3. Deploy as one service: The entire hybrid system becomes a single endpoint
  4. Monitor both: Track ML metrics and agent traces in the same dashboard

Example output

  • Intent classification with specialized agent handling
  • Upgrade paths: generic agent → train classifier → automatic routing
  • Ensemble systems combining multiple models and agents
  • Fact-checking pipelines with verification steps

Common Next Steps

Once you've chosen your path and gotten your first pipeline running:

Deploy remotely

All three paths use the same deployment pattern. Configure a remote stack and deploy:

bash
# Create a remote stack (e.g., AWS)
zenml stack register my-remote-stack \
  --orchestrator aws-sagemaker \
  --artifact-store s3-bucket \
  --deployer aws

# Set it and deploy—your code doesn't change
zenml stack set my-remote-stack

Run in batch mode with:

bash
python run.py

Deploy as a real-time endpoint with:

bash
zenml pipeline deploy pipelines.my_pipeline.my_pipeline --config deploy_config.yaml

See Deploying ZenML for cloud setup details.

View the dashboard

Start the dashboard to explore your pipeline runs:

bash
zenml login

In the dashboard, you'll see:

  • Pipeline DAGs: Visual representation of your steps and data flow
  • Artifacts: Versioned outputs from each step (models, reports, traces)
  • Metadata: Latency, tokens, metrics, or custom metadata you track
  • Timeline view: Compare step durations and identify bottlenecks

Core Concepts Recap

Regardless of which path you choose:

  • Pipelines - Orchestrate your workflow steps with automatic tracking
  • Steps - Modular, reusable units (data loading, model training, LLM inference, etc.)
  • Artifacts - Versioned outputs (models, predictions, traces, reports) with automatic logging
  • Stacks - Switch execution environments (local, remote, cloud) without code changes
  • Deployments - Turn pipelines into HTTP services with built-in UIs and monitoring

For deeper dives, explore the Concepts section in the docs.


Book Reference Community And Content (`docs/book/reference/community-and-content.md`)


icon: heart

Community & content

The ZenML team and community have put together a list of references that can be used to get in touch with the development team of ZenML and develop a deeper understanding of the framework.

Slack Channel: Get help from the community

The ZenML Slack channel is the main gathering point for the community. Not only is it the best place to get in touch with the core team of ZenML, but it is also a great way to discuss new ideas and share your ZenML projects with the community. If you have a question, there is a high chance someone else might have already answered it on Slack!

Social Media: Bite-sized updates

We are active on LinkedIn (linkedin.com/company/zenml/) and Twitter / X (@zenml_io), where we post bite-sized updates on releases, events, and MLOps in general. Follow us to interact and stay up to date! We would appreciate it if you could comment on and share our posts so more people can benefit from our work at ZenML!

YouTube Channel: Video tutorials, workshops, and more

Our YouTube channel features a growing set of videos that take you through the entire framework. Go here if you are a visual learner, and follow along with some tutorials.

Public roadmap

The feedback from our community plays a significant role in the development of ZenML. That's why we have a public roadmap that serves as a bridge between our users and our development team. If you have ideas regarding any new features or want to prioritize one over the other, feel free to share your thoughts here or vote on existing ideas.

Blog

On our Blog page, you can find various articles written by our team. We use it as a platform to share our thoughts and explain the implementation process of our tool, its new features, and the thought process behind them.

Podcast

We also have a Podcast series that brings you interviews and discussions with industry leaders, top technology professionals, and others. We discuss the latest developments in machine learning, deep learning, and artificial intelligence, with a particular focus on MLOps, or how trained models are used in production.

Newsletter

You can also subscribe to our Newsletter, where we share what we learn as we develop open-source tooling for production machine learning. You will also get all the exciting news about ZenML in general.


Book Reference Environment Variables (`docs/book/reference/environment-variables.md`)


icon: earth-africa

Environment Variables

There are a few pre-defined environmental variables that can be used to control the behavior of ZenML. See the list below with default values and options:

Logging verbosity

bash
export ZENML_LOGGING_VERBOSITY=INFO

Choose from INFO, WARN, ERROR, CRITICAL, DEBUG.

Console logging format

bash
export ZENML_CONSOLE_LOGGING_FORMAT=console

Choose from console (default), json, or any valid Python %-style logging format string such as %(asctime)s - %(message)s for custom console output. The console format uses a default compact layout for client-side INFO+ logs and full structured text layout for DEBUG and server logs. The json format emits JSON formatted console/stdout logs.

This controls terminal log formatting only; stored logs keep their raw message and structured metadata. The older ZENML_LOGGING_FORMAT environment variable is still supported as a deprecated alias.

See this page for more information.

Disable step logs

Usually, ZenML stores step logs in the artifact store, but this can sometimes cause performance bottlenecks, especially if the code utilizes progress bars.

If you want to configure whether logged output from steps is stored or not, set the ZENML_DISABLE_STEP_LOGS_STORAGE environment variable to true. Note that this will mean that logs from your steps will no longer be stored and thus won't be visible on the dashboard anymore.

bash
export ZENML_DISABLE_STEP_LOGS_STORAGE=true

File copy chunk size

When copying files between different filesystems (e.g. uploading or downloading artifacts, models or code archives to/from a remote artifact store), ZenML streams the file in chunks to keep memory usage bounded. The default chunk size is 8 MiB and can be adjusted:

bash
export ZENML_FILEIO_COPY_CHUNK_SIZE=16777216  # 16 MiB

Non-positive values are ignored and the default is used instead.

ZenML repository path

To configure where ZenML will install and look for its repository, set the environment variable ZENML_REPOSITORY_PATH.

bash
export ZENML_REPOSITORY_PATH=/path/to/somewhere

Analytics

Please see our full page on what analytics are tracked and how you can opt out, but the quick summary is that you can set this to false if you want to opt out of analytics.

bash
export ZENML_ANALYTICS_OPT_IN=false

Debug mode

Setting to true switches to developer mode. This redirects all ZenML analytics events to the development ZenML analytics server instead of the official ZenML analytics server. Should not be used in production environments.

bash
export ZENML_DEBUG=true

Active stack

Setting the ZENML_ACTIVE_STACK_ID to a specific UUID will make the corresponding stack the active stack:

bash
export ZENML_ACTIVE_STACK_ID=<UUID-OF-YOUR-STACK>

Prevent pipeline execution

When true, this prevents a pipeline from executing:

bash
export ZENML_PREVENT_PIPELINE_EXECUTION=false

Disable rich traceback

Set to false to disable the rich traceback:

bash
export ZENML_ENABLE_RICH_TRACEBACK=true

Disable colorful logging

Console logs use colors by default. If you wish to disable colorful logging,
set the following environment variable:

bash
ZENML_LOGGING_COLORS_DISABLED=true

Note that setting this on the client environment (e.g. your local machine which runs the pipeline) will automatically disable colorful logging on remote orchestrators. If you wish to disable it locally, but turn on for remote orchestrators, you can set the ZENML_LOGGING_COLORS_DISABLED environment variable in your orchestrator's environment as follows:

python
docker_settings = DockerSettings(environment={"ZENML_LOGGING_COLORS_DISABLED": "false"})

# Either add it to the decorator
@pipeline(settings={"docker": docker_settings})
def my_pipeline() -> None:
    my_step()

# Or configure the pipelines options
my_pipeline = my_pipeline.with_options(
    settings={"docker": docker_settings}
)

Server OpenTelemetry export

Set ZENML_SERVER_OTEL_EXPORTER_OTLP_ENDPOINT to export ZenML server traces, metrics, and logs to an OpenTelemetry-compatible backend using OTLP/HTTP. The standard OTEL_EXPORTER_OTLP_ENDPOINT environment variable is also supported as a fallback:

bash
export ZENML_SERVER_OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
# OR
# export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318

The endpoint should be the base OTLP/HTTP endpoint. ZenML appends /v1/traces, /v1/metrics, and /v1/logs for each signal. Standard per-signal OTLP/HTTP endpoint variables are also supported and take precedence:

bash
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel-collector:4318/v1/traces
export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://otel-collector:4318/v1/metrics
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://otel-collector:4318/v1/logs

You can use the matching ZenML-specific names instead: ZENML_SERVER_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, ZENML_SERVER_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, and ZENML_SERVER_OTEL_EXPORTER_OTLP_LOGS_ENDPOINT.

If no base or per-signal endpoint is set, server OpenTelemetry instrumentation is disabled.

Each signal is enabled by default when the endpoint is configured. You can disable individual signals with:

bash
export ZENML_SERVER_OTEL_TRACES_ENABLED=false
export ZENML_SERVER_OTEL_METRICS_ENABLED=false
export ZENML_SERVER_OTEL_LOGS_ENABLED=false

You can also customize the service name reported in OpenTelemetry resource attributes. The standard OTEL_SERVICE_NAME environment variable is supported as well as a fallback. If unset, it defaults to zenml-server for self-hosted deployments, or to the ZenML Pro workspace name for cloud deployments.

bash
export ZENML_SERVER_OTEL_SERVICE_NAME=zenml-server
# OR
# export OTEL_SERVICE_NAME=zenml-server

Standard OTLP headers, timeout, compression, trace sampler, and resource attribute environment variables are handled by the OpenTelemetry Python SDK and OTLP/HTTP exporters where supported. OTLP/gRPC protocol environment variables are not supported because ZenML configures OTLP/HTTP exporters directly. You can read more about the OpenTelemetry environment variables and SDK configuration here.

Disable stack validation

If you wish to disable stack validation, set the following environment variable:

bash
ZENML_SKIP_STACK_VALIDATION=true

Ignore untracked code repository files

When using code repositories,
ZenML will by default require the local checkout to have no uncommitted or untracked files
in order to use the code repository to track the commit and download files. If you want to ignore untracked files, you can set
the ZENML_CODE_REPOSITORY_IGNORE_UNTRACKED_FILES environment variable to True. When doing this, you're responsible that
the files committed to the repository includes everything necessary to run your pipeline.

ZenML global config path

To set the path to the global config file, used by ZenML to manage and store the state for a number of settings, set the environment variable as follows:

bash
export ZENML_CONFIG_PATH=/path/to/somewhere

CLI output formatting

Default output format

Set the default output format for all CLI list commands:

bash
export ZENML_DEFAULT_OUTPUT=json

Choose from table (default), json, yaml, csv, or tsv. This applies to commands like zenml stack list, zenml pipeline list, etc.

Terminal width override

Override the automatic terminal width detection for table rendering:

bash
export ZENML_CLI_COLUMN_WIDTH=120

This is useful when running ZenML in CI/CD environments or when you want to control table formatting regardless of your terminal size.

Server configuration

For more information on server configuration, see the ZenML Server documentation for more, especially the section entitled "ZenML server configuration options".

Client configuration

Setting the ZENML_STORE_URL, ZENML_STORE_API_KEY and ZENML_ACTIVE_PROJECT_ID environment variables automatically connects your ZenML Client to the specified server for a specific project. This method is particularly useful when you are using the ZenML client in an automated CI/CD workload environment like GitHub Actions or GitLab CI or in a containerized environment like Docker or Kubernetes:

bash
export ZENML_STORE_URL=https://...
export ZENML_STORE_API_KEY=<API_KEY>
export ZENML_ACTIVE_PROJECT_ID=<PROJECT_ID>

Book Reference Faq (`docs/book/reference/faq.md`)


icon: circle-question

FAQ

This page addresses common questions about ZenML, including general information about the project and how to accomplish specific tasks.

About ZenML

Why did you build ZenML?

We built it because we scratched our own itch while deploying multiple machine-learning models in production over the past three years. Our team struggled to find a simple yet production-ready solution whilst developing large-scale ML pipelines. We built a solution for it that we are now proud to share with all of you! Read more about this backstory on our blog here.

Is ZenML just another orchestrator like Airflow, Kubeflow, Flyte, etc?

Not really! An orchestrator in MLOps is the system component that is responsible for executing and managing the execution of an ML pipeline. ZenML is a framework that allows you to run your pipelines on whatever orchestrator you like, and we coordinate with all the other parts of an ML system in production. There are standard orchestrators that ZenML supports out-of-the-box, but you are encouraged to write your own orchestrator in order to gain more control as to exactly how your pipelines are executed!

Can I use the tool `X`? How does the tool `Y` integrate with ZenML?

Take a look at our documentation (in particular the component guide), which contains instructions and sample code to support each integration that ZenML supports out of the box. You can also check out our integration test code to see active examples of many of our integrations in action.

The ZenML team and community are constantly working to include more tools and integrations to the above list (check out the roadmap for more details).

Most importantly, ZenML is extensible, and we encourage you to use it with whatever other tools you require as part of your ML process and system(s). Check out our documentation on how to get started with extending ZenML to learn more!

Which license does ZenML use?

ZenML is distributed under the terms of the Apache License Version 2.0. A complete version of the license is available in the LICENSE.md in this repository. Any contribution made to this project will be licensed under the Apache License Version 2.0.

Platform Support

Do you support Windows?

ZenML officially supports Windows if you're using WSL. Much of ZenML will also work on Windows outside a WSL environment, but we don't officially support it, and some features don't work (notably anything that requires spinning up a server process).

Do you support Macs running on Apple Silicon?

Yes, ZenML does support Macs running on Apple Silicon. You just need to make sure that you set the following environment variable:

bash
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

This is a known issue with how forking works on Macs running on Apple Silicon, and it will enable you to use ZenML and the server. This environment variable is needed if you are working with a local server on your Mac, but if you're just using ZenML as a client / CLI and connecting to a deployed server, then you don't need to set it.

Common Use Cases and How-To's

How do I contribute to ZenML's open-source codebase?

We develop ZenML together with our community! To get involved, the best way to get started is to select any issue from the good-first-issue label.

Please read our Contribution Guide for more information. For small features and bug fixes, please open a pull request as described in the guide. For anything bigger, it is worth posting a message in Slack or creating an issue so we can best discuss and support your plans.

How do I add custom components to ZenML?

Please start by reading the general documentation page on implementing a custom stack component, which offers some general advice on what you'll need to do.

From there, each of the custom stack component types has a dedicated section about adding your own custom components. For example, to add a custom orchestrator, you would visit this page.

How do I mitigate dependency clashes with ZenML?

Check out our dedicated documentation page on some ways you can try to solve these dependency and versioning issues.

How do I deploy cloud infrastructure and/or MLOps stacks?

ZenML is designed to be stack-agnostic, so you can use it with any cloud infrastructure or MLOps stack. Each of the documentation pages for stack components explain how to deploy these components on the most popular cloud providers.

How do I deploy ZenML on my internal company cluster?

Read the documentation on self-hosted ZenML deployments, in which several options are presented.

How do I implement hyperparameter tuning?

Our dedicated documentation guide on implementing this is the place to learn more.

How do I reset things when something goes wrong?

To reset your ZenML client, you can run zenml clean which will wipe your local metadata database and reset your client. Note that this is a destructive action, so feel free to reach out to us on Slack before doing this if you are unsure.

How do I create dynamic pipelines and steps?

Please read our general information on how to compose steps + pipelines together to start with. You might also find the code examples in our guide to implementing hyperparameter tuning which is related to this topic.

How do I use templates and starter code with ZenML?

Project templates allow you to get going quickly with ZenML. We recommend the Starter template (starter) for most use cases, which gives you a basic scaffold and structure around which you can write your own code. You can also build templates for others inside a Git repository and use them with ZenML's templates functionality.

How do I upgrade my ZenML client and/or server?

Upgrading your ZenML client package is as simple as running pip install --upgrade zenml in your terminal. For upgrading your ZenML server, please refer to the dedicated documentation section, which covers most of the ways you might do this as well as common troubleshooting steps.

How do I use a specific stack component?

For information on how to use a specific stack component, please refer to the component guide, which contains all our tips and advice on how to use each integration and component with ZenML.

Community and Support

How can I speak with the community?

The first point of contact should be our Slack group. Ask your questions about bugs or specific use cases, and someone from the core team will respond.


Book Reference Global Settings (`docs/book/reference/global-settings.md`)


icon: gear

Global settings

The information about the global settings of ZenML on a machine is kept in a folder commonly referred to as the ZenML Global Config Directory or the ZenML Config Path. The location of this folder depends on the operating system type and the current system user, but is usually located in the following locations:

  • Linux: ~/.config/zenml
  • Mac: ~/Library/Application Support/zenml
  • Windows: C:\Users\%USERNAME%\AppData\Local\zenml

The default location may be overridden by setting the ZENML_CONFIG_PATH environment variable to a custom value. The current location of the global config directory used on a system can be retrieved by running the following commands:

shell
# The output will tell you something like this:
# Using configuration from: '/home/stefan/.config/zenml'
zenml status

python -c 'from zenml.utils.io_utils import get_global_config_directory; print(get_global_config_directory())'

{% hint style="warning" %}
Manually altering or deleting the files and folders stored under the ZenML global config directory is not recommended, as this can break the internal consistency of the ZenML configuration. As an alternative, ZenML provides CLI commands that can be used to manage the information stored there:

  • zenml analytics - manage the analytics settings
  • zenml clean - to be used only in case of emergency, to bring the ZenML configuration back to its default factory state
  • zenml downgrade - downgrade the ZenML version in the global configuration to match the version of the ZenML package installed in the current environment. Read more about this in the ZenML Version Mismatch section.
    {% endhint %}

The first time that ZenML is run on a machine, it creates the global config directory and initializes the default configuration in it, along with a default Stack:

text
Initializing the ZenML global configuration version to 0.13.2
Creating default user 'default' ...
Creating default stack for user 'default'...
The active stack is not set. Setting the active stack to the default stack.
Using the default store for the global config.
Unable to find ZenML repository in your current working directory (/tmp/folder) or any parent directories. If you want to use an existing repository which is in a different location, set the environment variable 'ZENML_REPOSITORY_PATH'. If you want to create a new repository, run zenml init.
Running without an active repository root.
Using the default local database.
┏━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┓
┃ ACTIVE │ STACK NAME │ SHARED │ OWNER   │ ARTIFACT_STORE │ ORCHESTRATOR ┃
┠────────┼────────────┼────────┼─────────┼────────────────┼──────────────┨
┃   👉   │ default    │ ❌     │ default │ default        │ default      ┃
┗━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━┷━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┛

{% hint style="info" %}
The output can be customized with an --output (json, yaml, csv, tsv, table) option and a --columns selection. See environment variables for more details.
{% endhint %}

The following is an example of the layout of the global config directory immediately after initialization:

text
/home/stefan/.config/zenml   <- Global Config Directory
├── config.yaml              <- Global Configuration Settings
└── local_stores             <- Every Stack component that stores information 
    |                           locally will have its own subdirectory here.              
    ├── a1a0d3d0-d552-4a80-be09-67e5e29be8ee   <- e.g. Local Store path for the 
    |                                             `default` local Artifact Store                                           
    └── default_zen_store
        |
        └── zenml.db         <- SQLite database where ZenML data (stacks, 
                                components, etc) are stored by default.

As shown above, the global config directory stores the following information:

  1. The config.yaml file stores the global configuration settings: the unique ZenML client ID, the active database configuration, the analytics-related options, and the active Stack. This is an example of the config.yaml file contents immediately after initialization:

    yaml
    active_stack_id: ...
    analytics_opt_in: true
    store:
      database: ...
      url: ...
      username: ...
      ...
    user_id: d980f13e-05d1-4765-92d2-1dc7eb7addb7
    version: 0.13.2
  2. The local_stores directory is where some "local" flavors of stack components, such as the local artifact store or a local MLFlow experiment tracker, persist data locally. Every local stack component will have its own subdirectory here named after the stack component's unique UUID. One notable example is the local artifact store flavor that, when part of the active stack, stores all the artifacts generated by pipeline runs in the designated local directory.

  3. The zenml.db in the default_zen_store directory is the default SQLite database where ZenML stores all information about the stacks, stack components, custom stack component flavors, etc.

In addition to the above, you may also find the following files and folders under the global config directory, depending on what you do with ZenML:

  • kubeflow - this is where the Kubeflow orchestrators that are part of a stack store some of their configuration and logs.

Usage analytics

In order to help us better understand how the community uses ZenML, the pip package reports anonymized usage statistics. You can always opt out by using the CLI command:

bash
zenml analytics opt-out

Why does ZenML collect analytics? [](#motivation)

In addition to the community at large, ZenML is created and maintained by a startup based in Munich, Germany, called ZenML GmbH. We're a team of techies that love MLOps and want to build tools that fellow developers would love to use in their daily work. This is us if you want to put faces to the names!

However, in order to improve ZenML and understand how it is being used, we need to use analytics to have an overview of how it is used 'in the wild'. This not only helps us find bugs but also helps us prioritize features and commands that might be useful in future releases. If we did not have this information, all we really get is pip download statistics and chatting with people directly, which, while being valuable, is not enough to seriously better the tool as a whole.

How does ZenML collect these statistics? [](#implementation)

We use Segment as the data aggregation library for all our analytics. However, before any events get sent to Segment, they first go through a central ZenML analytics server. This added layer allows us to put various countermeasures to incidents such as getting spammed with events and enables us to have a more optimized tracking process.

The client code is entirely visible and can be seen in the analytics module of our main repository.

If I share my email, will you spam me?

No, we won't. Our sole purpose of contacting you will be to ask for feedback (e.g. in the shape of a user interview). These interviews help the core team understand usage better and prioritize feature requests. If you have any concerns about data privacy and the usage of personal information, please contact us, and we will try to alleviate any concerns as soon as possible.

Version mismatch (downgrading)

If you've recently downgraded your ZenML version to an earlier release or installed a newer version on a different environment on the same machine, you might encounter an error message when running ZenML that says:

shell
`The ZenML global configuration version (%s) is higher than the version of ZenML 
currently being used (%s).`

We generally recommend using the latest ZenML version. However, there might be cases where you need to match the global configuration version with the version of ZenML installed in the current environment. To do this, run the following command:

shell
zenml downgrade

{% hint style="warning" %}
Note that downgrading the ZenML version may cause unexpected behavior, such as model schema validation failures or even data loss. In such cases, you may need to purge the local database and re-initialize the global configuration to bring it back to its default factory state. To do this, run the following command:

shell
zenml clean

{% endhint %}


Book Reference Legacy Docs (`docs/book/reference/legacy-docs.md`)


icon: user-bounty-hunter

Legacy docs

0.97.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.97.0/
0.96.4 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.96.4/
0.96.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.96.3/
0.96.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.96.2/
0.96.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.96.1/
0.96.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.96.0/
0.95.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.95.1/
0.95.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.95.0/
0.94.6 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.94.6/
0.94.5 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.94.5/
0.94.4 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.94.4/
0.94.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.94.3/
0.94.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.94.2/
0.94.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.94.1/
0.94.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.94.0/
0.93.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.93.3/
0.93.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.93.2/
0.93.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.93.1/
0.93.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.93.0/
0.92.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.92.0/
0.91.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.91.2/
0.91.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.91.1/
0.91.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.91.0/
0.90.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.90.0/
0.85.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.85.0/
0.84.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.84.3/
0.84.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.84.2/
0.84.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.84.1/
0.84.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.84.0/
0.83.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.83.1/
0.83.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.83.0/
0.82.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.82.0/
0.81.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.81.0/
0.80.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.80.2/
0.80.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.80.1/
0.80.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.80.0/
0.75.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.75.0/
0.74.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.74.0/
0.73.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.73.0/
0.72.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.72.0
0.71.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/0.71.0
0.70.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/0.70.0
0.68.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/0.68.1
0.68.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.68.0/
0.67.0 https://app.gitbook.com/o/-MCl1Hlw9oU4xibZ-ymf/s/IAT17KUXNgudlhTyCPn4/
0.66.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/0.66.0
0.65.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.65.0/
0.64.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.64.0/
0.63.0 https://app.gitbook.com/o/-MCl1Hlw9oU4xibZ-ymf/s/N7uiChp9LXuqoNrLj3U3/
0.62.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.62.0/
0.61.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.61.0
0.60.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.60.0/
0.58.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.58.2/
0.58.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.58.1/
0.58.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.58.0
0.57.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.57.1
0.57.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.57.0
0.56.4 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.56.4
0.56.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.56.3
0.56.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.56.2
0.56.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.56.1
0.55.5 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.55.5
0.55.4 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.55.4
0.55.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.55.3
0.55.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.55.2
0.55.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.55.1
0.55.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.55.0
0.54.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.54.1
0.54.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.54.0
0.53.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.53.1
0.53.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.53.0
0.52.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.52.0
0.51.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.51.0
0.50.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.50.0
0.47.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.47.0-legacy
0.46.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.46.1-legacy
0.46.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.46.0-legacy
0.45.6 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.45.6-legacy
0.45.5 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.45.5-legacy
0.45.4 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.45.4-legacy
0.45.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.45.3-legacy
0.45.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.45.2-legacy
0.44.4 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.44.4-legacy
0.44.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.44.3-legacy
0.44.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.44.2-legacy
0.44.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.44.1-legacy
0.43.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.43.1-legacy
0.43.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.43.0-legacy
0.42.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.42.2-legacy
0.42.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.42.1-legacy
0.42.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.42.0-legacy
0.41.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.41.0-legacy
0.40.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.40.3-legacy
0.40.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.40.2-legacy
0.40.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.40.1-legacy
0.40.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.40.0-legacy
0.39.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.39.1-legacy
0.39.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.39.0-legacy
0.38.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.38.0-legacy
0.37.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.37.0-legacy
0.36.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.36.1-legacy
0.36.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.36.0-legacy
0.35.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.35.1-legacy
0.35.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.35.0-legacy
0.34.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.34.0-legacy
0.33.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.33.0-legacy
0.32.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.32.1-legacy
0.32.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.32.0-legacy
0.31.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.31.1-legacy
0.31.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.31.0-legacy
0.30.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.30.0-legacy
0.20.5 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.20.5-legacy
0.20.4 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.20.4-legacy
0.20.3 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.20.3-legacy
0.20.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.20.2-legacy
0.20.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.20.0-legacy
0.13.2 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.13.2
0.13.1 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.13.1
0.13.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.13.0
0.12.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.12.0
0.11.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.11.0
0.10.0 https://zenml-io.gitbook.io/zenml-legacy-documentation/v/0.10.0

Book Reference Llms Txt (`docs/book/reference/llms-txt.md`)


icon: robot

LLM Tooling

ZenML provides multiple ways to enhance your AI-assisted development workflow:

  • MCP servers for real-time doc queries and server interaction
  • llms.txt for grounding LLMs with ZenML documentation
  • Agent Skills for guided implementation of ZenML features

About llms.txt

The llms.txt file format was proposed by llmstxt.org as a standard way to provide information to help LLMs answer questions about a product/website. From their website:

We propose adding a /llms.txt markdown file to websites to provide LLM-friendly content. This file offers brief background information, guidance, and links to detailed markdown files. llms.txt markdown is human and LLM readable, but is also in a precise format allowing fixed processing methods (i.e. classical programming techniques such as parsers and regex).

ZenML's llms.txt

ZenML's documentation is now made available to LLMs at the following link:

text
https://docs.zenml.io/llms.txt

This file contains a comprehensive summary of the ZenML documentation
(containing links and descriptions) that LLMs can use to answer questions about
ZenML's features, functionality, and usage.

How to use the llms.txt file

When working with LLMs (like ChatGPT, Claude, or others), you can use this file to help the model provide more accurate answers about ZenML:

  • Point the LLM to the docs.zenml.io/llms.txt URL when asking questions about ZenML
  • While prompting, instruct the LLM to only provide answers based on information contained in the file to avoid hallucinations
  • For best results, use models with sufficient context window to process the entire file

Use llms-full.txt for complete documentation context

The llms-full.txt file contains the entire ZenML documentation in a single, concatenated markdown file optimized for LLMs. Use it when you want to load all docs as context at once (for example, a one-shot grounding pass) rather than querying individual pages. Access it here: https://docs.zenml.io/llms-full.txt. For interactive, selective queries from your IDE, the built-in MCP server is still the recommended option.

ZenML docs are also exposed through a native GitBook MCP server that IDE agents can query in real time.

Quick setup

Claude Code (VS Code)

Run the following command in your terminal to add the server:

bash
claude mcp add zenmldocs --transport http https://docs.zenml.io/~gitbook/mcp

Cursor

Add the server via Cursor's JSON settings (Settings → search "MCP" → Configure via JSON):

json
{
  "mcpServers": {
    "zenmldocs": {
      "transport": {
        "type": "http",
        "url": "https://docs.zenml.io/~gitbook/mcp"
      }
    }
  }
}

Why use it

  • Live doc queries directly from your IDE agent
  • Syntax-aware, source-of-truth answers with fewer hallucinations
  • Faster feature discovery across guides, APIs, and examples

The MCP server indexes the latest released documentation, not the develop branch.

{% hint style="info" %}
Looking to chat with your ZenML server data? ZenML also provides its own MCP server that connects directly to your ZenML server, allowing you to query pipelines, analyze runs, and trigger executions through natural language. See the MCP Chat with Server guide for setup instructions.
{% endhint %}

Prefer the native GitBook MCP server above for the best experience; if you prefer working directly with llms.txt or need alternative workflows, the following tools are helpful:

To use the llms.txt file in partnership with an MCP client, you can use the
following tools:

  • GitMCP - A way to quickly create an MCP server for a github repository (e.g. for zenml-io/zenml)
  • mcp-llms - This shows how to use an MCP server to iteratively explore the llms.txt file with your MCP client
  • mcp-llms-txt-explorer - A tool to help you explore and discover websites that have llms.txt files

ZenML Agent Skills

Agent Skills are modular capabilities that help AI coding agents perform specific tasks. ZenML publishes skills through a plugin marketplace that works with many popular agentic coding tools.

Supported tools

ZenML skills work with tools that support the Agent Skills format:

Tool Type Skills support
Claude Code Anthropic's CLI agent Native plugin marketplace
OpenAI Codex CLI OpenAI's terminal agent Native skills support
GitHub Copilot IDE coding assistant Agent Skills integration
OpenCode Open source AI agent Native skills support
Amp AI coding assistant Agent Skills integration
Cursor AI-powered IDE Via settings configuration
Gemini CLI Google's terminal agent Skills support

Installing ZenML skills

Claude Code

bash
# Add the ZenML marketplace (one-time setup)
/plugin marketplace add zenml-io/skills

# Install any available skill (repeat for each skill you want)
/plugin install zenml-scoping@zenml
/plugin install zenml-pipeline-authoring@zenml
/plugin install zenml-quick-wins@zenml

OpenAI Codex CLI

bash
# Add the ZenML marketplace
codex plugin add zenml-io/skills

# Install skills
codex plugin install zenml-scoping@zenml
codex plugin install zenml-pipeline-authoring@zenml
codex plugin install zenml-quick-wins@zenml

Available skills

Skill What it's for When to use it
zenml-scoping Structured interview to turn a big ML/LLM idea into a realistic multi-pipeline ZenML architecture When requirements are fuzzy, ambitious, or likely "too much in one pipeline"
zenml-pipeline-authoring Hands-on guidance to write/refactor ZenML steps/pipelines, config, Docker settings, materializers, metadata, secrets, and visualizations When you're actively implementing a pipeline (or debugging "works local, fails on cloud")
zenml-quick-wins Repo/stack-aware recommendations of high-impact ZenML improvements, then guided implementation When you already have a project and want best-practice upgrades fast

`zenml-scoping`

Scopes and decomposes ML workflow ideas into realistic ZenML pipeline architectures through an in-depth interview process. Produces a pipeline_architecture.md spec you can implement incrementally.

Use when:

  • You have an "end-to-end" idea (ingest → train → deploy → monitor → retrain) and need a sane MVP
  • You're unsure what should be one pipeline vs multiple pipelines
  • You want explicit cross-pipeline data flow (e.g., via the Model Control Plane)

What it does:

  1. Interviews you to capture goals, data sources, and operational needs
  2. Classifies components (pipeline vs deployed pipeline vs not-a-pipeline)
  3. Produces a decomposed architecture with an MVP recommendation (pipeline_architecture.md)

Example prompts:

text
Use zenml-scoping to turn my idea into a realistic ZenML pipeline architecture and write pipeline_architecture.md.

Use zenml-scoping to decide whether this should be one pipeline or multiple pipelines, and propose the MVP.

`zenml-pipeline-authoring`

Authors ZenML pipelines with steps, artifacts, Docker settings, materializers, metadata logging, secrets management, YAML configuration, and custom visualizations.

Use when:

  • You want to write or refactor ZenML @step / @pipeline code with correct artifact flow and typing
  • You're implementing dynamic pipelines (@pipeline(dynamic=True))
  • You're moving from local to remote execution (Kubernetes / Vertex / SageMaker) and hit portability issues

What it does:

  1. Clarifies requirements (static vs dynamic, local vs remote, data sources, custom types)
  2. Guides step/pipeline structure and artifact flow
  3. Helps with configuration (YAML), Docker settings, materializers, metadata, and secrets

Example prompts:

text
Use zenml-pipeline-authoring to implement the MVP pipeline described in pipeline_architecture.md.

Use zenml-pipeline-authoring to refactor this pipeline so it works on Kubernetes/Vertex/SageMaker (fix artifact flow + Docker settings).

`zenml-quick-wins`

Guides you through discovering and implementing high-impact ZenML features. The skill investigates your current setup, recommends priorities based on your stack, and helps implement improvements interactively.

Use when:

  • You want to improve your ZenML setup
  • You're looking for MLOps best practices to adopt
  • You need help with features like experiment tracking, alerting, scheduling, or model governance

What it does:

  1. Investigate - Analyzes your stack configuration and codebase
  2. Recommend - Prioritizes quick wins based on your current setup
  3. Implement - Helps you apply selected improvements
  4. Verify - Confirms the implementation works

Example prompts:

text
Use zenml-quick-wins to analyze this repo and recommend the top 3 quick wins.

Implement metadata logging and tags across my pipelines.

Set up Slack alerts for pipeline failures.

See the Quick Wins guide for the full catalog of improvements this skill can help implement.

Coming soon

We're developing additional skills to help with common ZenML workflows:

  • Stack setup - Guided stack component configuration
  • Debugging - Investigating pipeline failures and performance issues
  • Migration - Migrating from other MLOps platforms and orchestrators to ZenML

Combining MCP + Skills

For the best AI-assisted ZenML development experience, combine:

  1. GitBook MCP server (https://docs.zenml.io/~gitbook/mcp) - For doc-grounded answers
  2. ZenML server MCP (setup guide) - For querying your live pipelines, runs, and stacks
  3. Agent Skills - For guided implementation of features

This gives your AI assistant access to documentation, your actual ZenML data, and structured workflows for making changes.

Kitaru's coding-agent tooling

Everything above covers ZenML pipelines. Kitaru, ZenML's sibling project for recording and replaying AI agent runs, has its own equivalents, and they're worth installing separately if you work on agents: reviewing a session, freezing a cohort and running a replay experiment is a long loop that your coding assistant can drive end to end.

  • MCP server — uv add "kitaru[mcp]" gives you the kitaru-mcp executable, which exposes typed Kitaru operations to Claude Code, Cursor, and other MCP clients. Tools are gated by a capability mode (read-only by default, then standard, then destructive), so an assistant only sees the operations you've allowed.
  • Agent Skills — published from zenml-io/kitaru-skills and installable with npx skills add zenml-io/kitaru-skills or the Claude Code plugin marketplace. They cover the workflow itself: investigating sessions, running a replay experiment, and building an adapter or importer for an unsupported framework.

See Set up your coding agent for the full setup, including the server URL and capability-mode settings that most often trip people up.


Book Sdk Docs Toc (`docs/book/sdk-docs/toc.md`)

Table of contents

ZenML

Kitaru


Book User Guide Toc (`docs/book/user-guide/toc.md`)

Table of contents

Tutorials [](#tutorial)

Best practices

Examples


Book .Gitbook Includes Stacks (`docs/book/.gitbook/includes/stacks.md`)


title: Stacks

Orchestrator Orchestrating the runs of your pipeline orchestrator.png Orchestrators
Artifact Store Storage for the artifacts created by your pipelines artifact-store.png Artifact Stores
Container Registry Store for your containers container-registry.png Container Registries
Data Validator Data and model validation data-validator.png Data Validators
Experiment Tracker Tracking your ML experiments experiment-tracker.png Experiment Trackers
Model Deployer Services/platforms responsible for online model serving model-deployer.png Model Deployers
Step Operator Execution of individual steps in specialized runtime environments step-operator.png Step Operators
Alerter Sending alerts through specified channels alerter.png Alerters
Image Builder Builds container images image-builder.png Image Builders
Annotator Labeling and annotating data annotator.png Annotators
Model Registry Manage and interact with ML Models model-registry.png Model Registries
Feature Store Management of your data/features feature-store.png Feature Stores

Book .Gitbook Includes Untitled (`docs/book/.gitbook/includes/untitled.md`)


title: Untitled


Book Component Guide Alerters Custom (`docs/book/component-guide/alerters/custom.md`)



Develop a Custom Alerter

{% hint style="info" %}
Before diving into the specifics of this component type, it is beneficial to familiarize yourself with our general guide to writing custom component flavors in ZenML. This guide provides an essential understanding of ZenML's component flavor concepts.
{% endhint %}

Base Abstraction

The base abstraction for alerters is very basic, as it only defines two abstract methods that subclasses should implement:

  • post() takes a string, posts it to the desired chat service, and returns True if the operation succeeded, else False.
  • ask() does the same as post(), but after sending the message, it waits until someone approves or rejects the operation from within the chat service (e.g., by sending "approve" / "reject" to the bot as a response). ask() then only returns True if the operation succeeded and was approved, else False.

The ask() method is particularly useful for implementing human-in-the-loop workflows. When implementing this method, you should:

  • Wait for user responses containing approval keywords (like "approve", "yes", "ok", "LGTM")
  • Wait for user responses containing disapproval keywords (like "reject", "no", "cancel", "stop")
  • Return True only when explicit approval is received
  • Return False for disapproval, timeout, or any errors
  • Consider implementing configurable approval/disapproval keywords via parameters

Then base abstraction looks something like this:

python
from abc import ABC
from typing import Optional
from zenml.stack import StackComponent
from zenml.alerter import BaseAlerterStepParameters

class BaseAlerter(StackComponent, ABC):
    """Base class for all ZenML alerters."""

    def post(
            self, message: str, params: Optional[BaseAlerterStepParameters]
    ) -> bool:
        """Post a message to a chat service."""
        return True

    def ask(
            self, question: str, params: Optional[BaseAlerterStepParameters]
    ) -> bool:
        """Post a message to a chat service and wait for approval."""
        return True

{% hint style="info" %}
This is a slimmed-down version of the base implementation. To see the full docstrings and imports, please check the source code on GitHub.
{% endhint %}

Building your own custom alerter

Creating your own custom alerter can be done in four steps:

  1. Create a class that inherits from the BaseAlerter and implement the post() and ask() methods.

    text

/* Detailed source-code truncated for AI context efficiency. */

text
2.  If you need to configure your custom alerter, you can also implement a config object.

    ```python
    from zenml.alerter.base_alerter import BaseAlerterConfig


    class MyAlerterConfig(BaseAlerterConfig):
        my_param: str 
    ```

3.  Optionally, you can create custom parameter classes to support configurable approval/disapproval keywords:

    ```python
    from typing import List, Optional
    from zenml.alerter.base_alerter import BaseAlerterStepParameters


    class MyAlerterParameters(BaseAlerterStepParameters):
        """Custom parameters for MyAlerter."""
        
        # Custom approval/disapproval message options
        approve_msg_options: Optional[List[str]] = None
        disapprove_msg_options: Optional[List[str]] = None
        
        # Any other custom parameters for your alerter
        custom_channel: Optional[str] = None
    ```
4.  Finally, you can bring the implementation and the configuration together in a new flavor object.

    ```python
    from typing import Type, TYPE_CHECKING

    from zenml.alerter import BaseAlerterFlavor

    if TYPE_CHECKING:
        from zenml.stack import StackComponent, StackComponentConfig


    class MyAlerterFlavor(BaseAlerterFlavor):
        @property
        def name(self) -> str:
            return "my_alerter"

        @property
        def config_class(self) -> Type[StackComponentConfig]:
            from my_alerter_config import MyAlerterConfig

            return MyAlerterConfig

        @property
        def implementation_class(self) -> Type[StackComponent]:
            from my_alerter import MyAlerter

            return MyAlerter

    ```

Once you are done with the implementation, you can register your new flavor through the CLI. Please ensure you **point to the flavor class via dot notation**:

```shell
zenml alerter flavor register <path.to.MyAlerterFlavor>

For example, if your flavor class MyAlerterFlavor is defined in flavors/my_flavor.py, you'd register it by doing:

shell
zenml alerter flavor register flavors.my_flavor.MyAlerterFlavor

{% hint style="warning" %}
ZenML resolves the flavor class by taking the path where you initialized zenml (via zenml init) as the starting point of resolution. Therefore, please ensure you follow the best practice of initializing zenml at the root of your repository.

If ZenML does not find an initialized ZenML repository in any parent directory, it will default to the current working directory, but usually, it's better to not have to rely on this mechanism and initialize zenml at the root.
{% endhint %}

Afterward, you should see the new custom alerter flavor in the list of available alerter flavors:

shell
zenml alerter flavor list

{% hint style="warning" %}
It is important to draw attention to when and how these abstractions are coming into play in a ZenML workflow.

  • The MyAlerterFlavor class is imported and utilized upon the creation of the custom flavor through the CLI.
  • The MyAlerterConfig class is imported when someone tries to register/update a stack component with the my_alerter flavor. Especially, during the registration process of the stack component, the config will be used to validate the values given by the user. As Config objects are inherently pydantic objects, you can also add your own custom validators here.
  • The MyAlerter only comes into play when the component is ultimately in use.

The design behind this interaction lets us separate the configuration of the flavor from its implementation. This way we can register flavors and components even when the major dependencies behind their implementation are not installed in our local setting (assuming the MyAlerterFlavor and the MyAlerterConfig are implemented in a different module/path than the actual MyAlerter).
{% endhint %}


Book Component Guide Alerters Discord (`docs/book/component-guide/alerters/discord.md`)



Discord Alerter

The DiscordAlerter enables you to send messages to a dedicated Discord channel directly from within your ZenML pipelines.

The discord integration contains the following two standard steps:

  • discord_alerter_post_step takes a string message, posts it to a Discord channel, and returns whether the operation was successful.
  • discord_alerter_ask_step also posts a message to a Discord channel, but waits for user feedback, and only returns True if a user explicitly approved the operation from within Discord (e.g., by sending "approve" / "reject" to the bot in response).

Interacting with Discord from within your pipelines can be very useful in practice:

  • The discord_alerter_post_step allows you to get notified immediately when failures happen (e.g., model performance degradation, data drift, ...),
  • The discord_alerter_ask_step allows you to integrate a human-in-the-loop into your pipelines before executing critical steps, such as deploying new models.

How to use it

Requirements

Before you can use the DiscordAlerter, you first need to install ZenML's discord integration:

shell
zenml integration install discord -y

{% hint style="info" %}
See the Integrations page for more details on ZenML integrations and how to install and use them.
{% endhint %}

Setting Up a Discord Bot

In order to use the DiscordAlerter, you first need to have a Discord workspace set up with a channel that you want your pipelines to post to. This is the <DISCORD_CHANNEL_ID> you will need when registering the discord alerter component.

Then, you need to create a Discord App with a bot in your server .

{% hint style="info" %}
Note in the bot token copy step, if you don't find the copy button then click on reset token to reset the bot and you will get a new token which you can use. Also, make sure you give necessary permissions to the bot required for sending and receiving messages.
{% endhint %}

Registering a Discord Alerter in ZenML

Next, you need to register a discord alerter in ZenML and link it to the bot you just created. You can do this with the following command:

shell
zenml alerter register discord_alerter \
    --flavor=discord \
    --discord_token=<DISCORD_TOKEN> \
    --default_discord_channel_id=<DISCORD_CHANNEL_ID>

{% hint style="info" %}
Using Secrets for Token Management: Instead of passing your Discord token directly, it's recommended to store it as a ZenML secret and reference it in your alerter configuration. This approach keeps sensitive information secure:

shell
# Create a secret for your Discord token
zenml secret create discord_secret --discord_token=<DISCORD_TOKEN>

# Register the alerter referencing the secret
zenml alerter register discord_alerter \
    --flavor=discord \
    --discord_token={{discord_secret.discord_token}} \
    --default_discord_channel_id=<DISCORD_CHANNEL_ID>

Learn more about referencing secrets in stack component attributes and settings.
{% endhint %}

After you have registered the discord_alerter, you can add it to your stack like this:

shell
zenml stack register ... -al discord_alerter

Here is where you can find the required parameters:

DISCORD\_CHANNEL\_ID

Open the discord server, then right-click on the text channel and click on the 'Copy Channel ID' option.

{% hint style="info" %}
If you don't see any 'Copy Channel ID' option for your channel, go to "User Settings" > "Advanced" and make sure "Developer Mode" is active.
{% endhint %}

DISCORD\_TOKEN

This is the Discord token of your bot. You can find the instructions on how to set up a bot, invite it to your channel, and find its token here.

{% hint style="warning" %}
When inviting the bot to your channel, make sure it has at least the following permissions:

  • Read Messages/View Channels
  • Send Messages
  • Send Messages in Threads
    {% endhint %}

How to Use the Discord Alerter

After you have a DiscordAlerter configured in your stack, you can directly import the discord_alerter_post_step and discord_alerter_ask_step steps and use them in your pipelines.

Since these steps expect a string message as input (which needs to be the output of another step), you typically also need to define a dedicated formatter step that takes whatever data you want to communicate and generates the string message that the alerter should post.

As an example, adding discord_alerter_ask_step() to your pipeline could look like this:

python
from zenml.integrations.discord.steps.discord_alerter_ask_step import discord_alerter_ask_step
from zenml import step, pipeline


@step
def my_formatter_step(artifact_to_be_communicated) -> str:
    return f"Here is my artifact {artifact_to_be_communicated}!"


@step
def process_approval_response(artifact, approved: bool) -> None:
    if approved:
        # Proceed with the operation
        print(f"User approved! Processing {artifact}")
        # Your logic here
    else:
        print("User disapproved. Skipping operation.")


@pipeline
def my_pipeline(...):
    ...
    artifact_to_be_communicated = ...
    message = my_formatter_step(artifact_to_be_communicated)
    approved = discord_alerter_ask_step(message)
    process_approval_response(artifact_to_be_communicated, approved)

if __name__ == "__main__":
    my_pipeline()

Using Custom Approval Keywords

You can customize which words trigger approval or disapproval by using DiscordAlerterParameters:

python
from zenml.integrations.discord.steps.discord_alerter_ask_step import discord_alerter_ask_step
from zenml.integrations.discord.alerters.discord_alerter import DiscordAlerterParameters

# Custom approval/disapproval keywords
params = DiscordAlerterParameters(
    approve_msg_options=["deploy", "ship it", "✅"],
    disapprove_msg_options=["stop", "cancel", "❌"]
)

approved = discord_alerter_ask_step(
    "Deploy model to production?", 
    params=params
)

Default Response Keywords

By default, the Discord alerter recognizes these keywords:

Approval: approve, LGTM, ok, yes
Disapproval: decline, disapprove, no, reject

Important Notes:

  • The ask step returns a boolean (True for approval, False for disapproval/timeout)
  • Keywords are case-sensitive - you must respond with exact case (e.g., LGTM not lgtm)
  • If no valid response is received, the step returns False

{% hint style="warning" %}
Discord Case Sensitivity: The Discord alerter implementation requires exact case matching for approval keywords. Make sure to respond with the exact case specified (e.g., LGTM, not lgtm).
{% endhint %}

For more information and a full list of configurable attributes of the Discord alerter, check out the SDK Docs .


Book Component Guide Alerters Slack (`docs/book/component-guide/alerters/slack.md`)



Slack Alerter

The SlackAlerter enables you to send messages or ask questions within a
dedicated Slack channel directly from within your ZenML pipelines and steps.

How to Create

Set up a Slack app

In order to use the SlackAlerter, you first need to have a Slack workspace
set up with a channel that you want your pipelines to post to.

Then, you need to create a Slack App
with a bot in your workspace. Make sure to give it the following permissions in
the OAuth & Permissions tab under Scopes:

  • chat:write,
  • channels:read
  • channels:history

In order to be able to use the ask() functionality, you need to invite the app
to your channel. You can either use the /invite command directly in the
desired channel or add it through the channel settings:

{% hint style="warning" %}
It might take some time for your app to register within your workspace and
show up in the available list of applications.
{% endhint %}

Registering a Slack Alerter in ZenML

To create a SlackAlerter, you first need to install ZenML's slack
integration:

shell
zenml integration install slack -y

Once the integration is installed, you can use the ZenML CLI to create a
secret and register an alerter linked to the app you just created:

shell
zenml secret create slack_token --oauth_token=<SLACK_TOKEN>
zenml alerter register slack_alerter \
    --flavor=slack \
    --slack_token={{slack_token.oauth_token}} \
    --slack_channel_id=<SLACK_CHANNEL_ID>

{% hint style="info" %}
Using Secrets for Token Management: The example above demonstrates the recommended approach of storing your Slack token as a ZenML secret and referencing it using the {{secret_name.key}} syntax. This keeps sensitive information secure and follows security best practices.

Learn more about referencing secrets in stack component attributes and settings.
{% endhint %}

Here is where you can find the required parameters:

  • <SLACK_CHANNEL_ID>: The channel ID can be found in the channel details.
    It starts with C.....
  • <SLACK_TOKEN>: This is the Slack token of your bot. You can find it in the
    Slack app settings under OAuth & Permissions.

After you have registered the slack_alerter, you can add it to your stack
like this:

shell
zenml stack register ... -al slack_alerter --set

How to Use

In ZenML, you can use alerters in various ways.

Use the `post()` and `ask()` directly

You can use the client to fetch the active alerter within your stack and
use the post and ask methods directly:

python
from zenml import pipeline, step
from zenml.client import Client


@step
def post_statement() -> None:
    Client().active_stack.alerter.post("Step finished!")

@step
def ask_question() -> bool:
    return Client().active_stack.alerter.ask("Should I continue?")


@pipeline(enable_cache=False)
def my_pipeline():
    # Step using alerter.post
    post_statement()

    # Step using alerter.ask
    ask_question()


if __name__ == "__main__":
    my_pipeline()

{% hint style="warning" %}
In case of an error, the output of the ask() method default to False.
{% endhint %}

Use it with custom settings

The Slack alerter comes equipped with a set of options that you can set during
runtime:

python
from zenml import pipeline, step
from zenml.client import Client


# E.g, You can use a different channel ID through the settings. However, if you 
# want to use the `ask` functionality, make sure that you app is invited to 
# this channel first.
@step(settings={"alerter": {"slack_channel_id": "YOUR_SLACK_CHANNEL_ID"}})
def post_statement() -> None:
    alerter = Client().active_stack.alerter
    alerter.post("Posting to another channel!")


@pipeline(enable_cache=False)
def my_pipeline():
    # Using alerter.post
    post_statement()


if __name__ == "__main__":
    my_pipeline()

Use it with `SlackAlerterParameters` and `SlackAlerterPayload`

You can use these additional classes to further edit your messages:

text
/* Detailed source-code truncated for AI context efficiency. */

Use the predefined steps

If you want to only use it in a simple manner, you can also use the steps
slack_alerter_post_step and slack_alerter_ask_step, that are built-in to
the Slack integration of ZenML:

python
from zenml import pipeline, step
from zenml.integrations.slack.steps.slack_alerter_post_step import (
    slack_alerter_post_step
)
from zenml.integrations.slack.steps.slack_alerter_ask_step import (
    slack_alerter_ask_step,
)

@step
def process_approval_response(approved: bool) -> None:
    if approved:
        print("Operation approved!")
    else:
        print("Operation declined.")

@pipeline(enable_cache=False)
def my_pipeline():
    slack_alerter_post_step("Posting a statement.")
    approved = slack_alerter_ask_step("Asking a question. Should I continue?")
    process_approval_response(approved)


if __name__ == "__main__":
    my_pipeline()

Default Response Keywords and Ask Step Behavior

The ask() method and slack_alerter_ask_step recognize these keywords by default:

Approval: approve, LGTM, ok, yes
Disapproval: decline, disapprove, no, reject

Important Notes:

  • The ask step returns a boolean (True for approval, False for disapproval/timeout)
  • Response keywords are case-insensitive - keywords are converted to lowercase before matching (e.g., both LGTM and lgtm work)
  • If no valid response is received within the timeout period, the step returns False
  • The default timeout is 300 seconds (5 minutes) but can be configured

{% hint style="info" %}
Slack Case Handling: The Slack alerter implementation automatically converts all response keywords to lowercase before matching, making responses case-insensitive. You can respond with LGTM, lgtm, or Lgtm - they'll all work.
{% endhint %}

For more information and a full list of configurable attributes of the Slack
alerter, check out the SDK Docs .


Book Component Guide Annotators Argilla (`docs/book/component-guide/annotators/argilla.md`)



Argilla

Argilla is a collaboration tool for AI engineers and domain experts who need to build high-quality datasets for their projects. It enables users to build robust language models through faster data curation using both human and machine feedback, providing support for each step in the MLOps cycle, from data labeling to model monitoring.

Argilla distinguishes itself for its focus on specific use cases and human-in-the-loop approaches. While it does offer programmatic features, Argilla's core value lies in actively involving human experts in the tool-building process, setting it apart from other competitors.

When would you want to use it?

If you need to label textual data as part of your ML workflow, that is the point at which you could consider adding the Argilla annotator stack component as part of your ZenML stack.

We currently support the use of annotation at the various stages described inthe main annotators docs page. The Argilla integration currently is built to support annotation using a local (Docker-backed) instance of Argilla as well as a deployed instance of Argilla. There is an easy way to deploy Argilla as a Hugging Face Space, for instance, which is documented in the Argilla documentation.

How to deploy it?

The Argilla Annotator flavor is provided by the Argilla ZenML integration. You need to install it to be able to register it as an Annotator and add it to your stack:

shell
zenml integration install argilla

You can either pass the api_key directly into the zenml annotator register command or you can register it as a secret and pass the secret name into the command. We recommend the latter approach for security reasons. If you want to take the latter approach, be sure to register a secret for whichever artifact store you choose, and then you should make sure to pass the name of that secret into the annotator as the --authentication_secret. For example, you'd run:

shell
zenml secret create argilla_secrets --api_key="<your_argilla_api_key>"

(Visit the Argilla documentation and interface to obtain your API key.)

Then register your annotator with ZenML:

shell
zenml annotator register argilla --flavor argilla --authentication_secret=argilla_secrets --port=6900

When using a deployed instance of Argilla, the instance URL must be specified without any trailing / at the end. If you are using a Hugging Face Spaces instance and its visibility is set to private, you must also set theheaders parameter which would include a Hugging Face token. For example:

shell
zenml annotator register argilla --flavor argilla --authentication_secret=argilla_secrets --instance_url="https://[your-owner-name]-[your_space_name].hf.space" --headers='{"Authorization": "Bearer {[your_hugging_face_token]}"}'

Finally, add all these components to a stack and set it as your active stack. For example:

shell
zenml stack copy default annotation
# this must be done separately so that the other required stack components are first registered
zenml stack update annotation -an <YOUR_ARGILLA_ANNOTATOR>
zenml stack set annotation
# optionally also
zenml stack describe

Now if you run a simple CLI command like zenml annotator dataset list this should work without any errors. You're ready to use your annotator in your ML workflow!

How do you use it?

ZenML supports access to your data and annotations via the zenml annotator ... CLI command. We have also implemented an interface to some of the common Argilla functionality via the ZenML SDK.

You can access information about the datasets you're using with the zenml annotator dataset list. To work on annotation for a particular dataset, you can run zenml annotator dataset annotate <dataset_name>. This will open the Argilla web interface for you to start annotating the dataset.

Argilla Annotator Stack Component

Our Argilla annotator component inherits from the BaseAnnotator class. There are some methods that are core methods that must be defined, like being able to register or get a dataset. Most annotators handle things like the storage of state and have their own custom features, so there are quite a few extra methods specific to Argilla.

The core Argilla functionality that's currently enabled includes a way to register your datasets, export any annotations for use in separate steps as well as start the annotator daemon process. (Argilla requires a server to be running in order to use the web interface, and ZenML handles the connection to this server using the details you passed in when registering the component.)

Argilla Annotator SDK

Visit the SDK docs to learn more about the methods that ZenML exposes for the Argilla annotator. To access the SDK through Python, you would first get the client object and then call the methods you need. For example:

python
from zenml.client import Client

client = Client()
annotator = client.active_stack.annotator

# list dataset names
dataset_names = annotator.get_dataset_names()

# get a specific dataset
dataset = annotator.get_dataset("dataset_name")

# get the annotations for a dataset
annotations = annotator.get_labeled_data(dataset_name="dataset_name")

For more detailed information on how to use the Argilla annotator and the functionality it provides, visit the Argilla documentation.


Book Component Guide Annotators Custom (`docs/book/component-guide/annotators/custom.md`)



Develop a Custom Annotator

{% hint style="info" %}
Before diving into the specifics of this component type, it is beneficial to familiarize yourself with our general guide to writing custom component flavors in ZenML. This guide provides an essential understanding of ZenML's component flavor concepts.
{% endhint %}

Annotators are a stack component that enables the use of data annotation as part of your ZenML stack and pipelines. You can use the associated CLI command to launch annotation, configure your datasets and get stats on how many labeled tasks you have ready for use.

{% hint style="warning" %}
Base abstraction in progress!

We are actively working on the base abstraction for the annotators, which will be available soon. As a result, their extension is not possible at the moment. If you would like to use an annotator in your stack, please check the list of already available feature stores down below.
{% endhint %}


Book Component Guide Annotators Label Studio (`docs/book/component-guide/annotators/label-studio.md`)



Label Studio

Label Studio is one of the leading open-source annotation platforms available to data scientists and ML practitioners. It is used to create or edit datasets that you can then use as part of training or validation workflows. It supports a broad range of annotation types, including:

  • Computer Vision (image classification, object detection, semantic segmentation)
  • Audio & Speech (classification, speaker diarization, emotion recognition, audio transcription)
  • Text / NLP (classification, NER, question answering, sentiment analysis)
  • Time Series (classification, segmentation, event recognition)
  • Multi-Modal / Domain (dialogue processing, OCR, time series with reference)

When would you want to use it?

If you need to label data as part of your ML workflow, that is the point at which you could consider adding the optional annotator stack component as part of your ZenML stack.

We currently support the use of annotation at the various stages described in the main annotators docs page, and also offer custom utility functions to generate Label Studio label config files for image classification and object detection. (More will follow in due course.)

The Label Studio integration currently is built to support workflows using the following three cloud artifact stores: AWS S3, GCP/GCS, and Azure Blob Storage. Purely local stacks will currently not work if you want to do add the annotation stack component as part of your stack.

How to deploy it?

The Label Studio Annotator flavor is provided by the Label Studio ZenML integration, you need to install it, to be able to register it as an Annotator and add it to your stack:

shell
zenml integration install label_studio

You will then need to obtain your Label Studio API key. This will give you access to the web annotation interface. (The following steps apply to a local instance of Label Studio, but feel free to obtain your API key directly from your deployed instance if that's what you are using.)

shell
git clone https://github.com/HumanSignal/label-studio.git
cd label-studio
docker-compose up -d # starts label studio at http://localhost:8080

Then visit http://localhost:8080/ to log in, and then visit http://localhost:8080/user/account and get your Label Studio API key (from the upper right-hand corner). You will need it for the next step. Keep the Label Studio server running, because the ZenML Label Studio annotator will use it as the backend.

At this point you should register the API key under a custom secret name, making sure to replace the two parts in <> with whatever you choose:

shell
zenml secret create label_studio_secrets --api_key="<your_label_studio_api_key>"

Then register your annotator with ZenML:

shell
zenml annotator register label_studio --flavor label_studio --authentication_secret="label_studio_secrets" --port=8080

# for deployed instances of Label Studio, you can also pass in the URL as follows, for example:
# zenml annotator register label_studio --flavor label_studio --authentication_secret="<LABEL_STUDIO_SECRET_NAME>" --instance_url="<your_label_studio_url>" --port=80

When using a deployed instance of Label Studio, the instance URL must be specified without any trailing / at the end. You should specify the port, for example, port 80 for a standard HTTP connection. For a Hugging Face deployment (the easiest way to get going with Label Studio), please read the Hugging Face deployment documentation.

Finally, add all these components to a stack and set it as your active stack. For example:

shell
zenml stack copy default annotation
zenml stack update annotation -a <YOUR_CLOUD_ARTIFACT_STORE>
# this must be done separately so that the other required stack components are first registered
zenml stack update annotation -an <YOUR_LABEL_STUDIO_ANNOTATOR>
zenml stack set annotation
# optionally also
zenml stack describe

Now if you run a simple CLI command like zenml annotator dataset list this should work without any errors. You're ready to use your annotator in your ML workflow!

How do you use it?

ZenML assumes that users have registered a cloud artifact store and an annotator as described above. ZenML currently only supports this setup, but we will add in the fully local stack option in the future.

ZenML supports access to your data and annotations via the zenml annotator ... CLI command.

You can access information about the datasets you're using with the zenml annotator dataset list. To work on annotation for a particular dataset, you can run zenml annotator dataset annotate <dataset_name>.

Our computer vision end to end example is the best place to see how all the pieces of making this integration work fit together. What follows is an overview of some key components to the Label Studio integration and how it can be used.

Label Studio Annotator Stack Component

Our Label Studio annotator component inherits from the BaseAnnotator class. There are some methods that are core methods that must be defined, like being able to register or get a dataset. Most annotators handle things like the storage of state and have their own custom features, so there are quite a few extra methods specific to Label Studio.

The core Label Studio functionality that's currently enabled includes a way to register your datasets, export any annotations for use in separate steps as well as start the annotator daemon process. (Label Studio requires a server to be running in order to use the web interface, and ZenML handles the provisioning of this server locally using the details you passed in when registering the component unless you've specified that you want to use a deployed instance.)

Standard Steps

ZenML offers some standard steps (and their associated config objects) which will get you up and running with the Label Studio integration quickly. These include:

  • LabelStudioDatasetRegistrationConfig - a step config object to be used when registering a dataset with Label studio using the get_or_create_dataset step
  • LabelStudioDatasetSyncConfig - a step config object to be used when registering a dataset with Label studio using the sync_new_data_to_label_studio step. Note that this requires a ZenML secret to have been pre-registered with your artifact store as being the one that holds authentication secrets specific to your particular cloud provider. (Label Studio provides some documentation on what permissions these secrets require here.)
  • get_or_create_dataset step - This takes a LabelStudioDatasetRegistrationConfig config object which includes the name of the dataset. If it exists, this step will return the name, but if it doesn't exist then ZenML will register the dataset along with the appropriate label config with Label Studio.
  • get_labeled_data step - This step will get all labeled data available for a particular dataset. Note that these are output in a Label Studio annotation format, which will subsequently be converted into a format appropriate for your specific use case.
  • sync_new_data_to_label_studio step - This step is for ensuring that ZenML is handling the annotations and that the files being used are stored and synced with the ZenML cloud artifact store. This is an important step as part of a continuous annotation workflow since you want all the subsequent steps of your workflow to remain in sync with whatever new annotations are being made or have been created.

Helper Functions

Label Studio requires the use of what it calls 'label config' when you are creating/registering your dataset. These are strings containing HTML-like syntax that allow you to define a custom interface for your annotation. ZenML provides three helper functions that will construct these label config strings in the case of object detection, image classification, and OCR. See theintegrations.label_studio.label_config_generators module for those three functions.


Book Component Guide Annotators Pigeon (`docs/book/component-guide/annotators/pigeon.md`)



Pigeon

Pigeon is a lightweight, open-source annotation tool designed for quick and easy labeling of data directly within Jupyter notebooks. It provides a simple and intuitive interface for annotating various types of data, including:

  • Text Classification
  • Image Classification
  • Text Captioning

When would you want to use it?

If you need to label a small to medium-sized dataset as part of your ML workflow and prefer the convenience of doing it directly within your Jupyter notebook, Pigeon is a great choice. It is particularly useful for:

  • Quick labeling tasks that don't require a full-fledged annotation platform
  • Iterative labeling during the exploratory phase of your ML project
  • Collaborative labeling within a Jupyter notebook environment

How to deploy it?

To use the Pigeon annotator, you first need to install the ZenML Pigeon integration:

shell
zenml integration install pigeon

Next, register the Pigeon annotator with ZenML, specifying the output directory where the annotation files will be stored:

shell
zenml annotator register pigeon --flavor pigeon --output_dir="path/to/dir"

Note that the output_dir is relative to the repository or notebook root.

Finally, add the Pigeon annotator to your stack and set it as the active stack:

shell
zenml stack update <YOUR_STACK_NAME> --annotator pigeon

Now you're ready to use the Pigeon annotator in your ML workflow!

How do you use it?

With the Pigeon annotator registered and added to your active stack, you can easily access it using the ZenML client within your Jupyter notebook.

For text classification tasks, you can launch the Pigeon annotator as follows:

python
from zenml.client import Client

annotator = Client().active_stack.annotator

annotations = annotator.annotate(
    data=[
        'I love this movie',
        'I was really disappointed by the book'
    ],
    options=[
        'positive',
        'negative'
    ]
)

For image classification tasks, you can provide a custom display function to render the images:

python
from zenml.client import Client
from IPython.display import display, Image

annotator = Client().active_stack.annotator

annotations = annotator.annotate(
    data=[
        '/path/to/image1.png',
        '/path/to/image2.png'
    ],
    options=[
        'cat',
        'dog'
    ],
    display_fn=lambda filename: display(Image(filename))
)

The launch method returns the annotations as a list of tuples, where each tuple contains the data item and its corresponding label.

You can also use the zenml annotator dataset commands to manage your datasets:

  • zenml annotator dataset list - List all available datasets
  • zenml annotator dataset delete <dataset_name> - Delete a specific dataset
  • zenml annotator dataset stats <dataset_name> - Get statistics for a specific dataset

Annotation files are saved as JSON files in the specified output directory. Each
annotation file represents a dataset, with the filename serving as the dataset
name.

Acknowledgements

Pigeon was created by Anastasis Germanidis and
released as a Python package and
Github repository. It is licensed under
the Apache License. It has been updated to work with more recent ipywidgets
versions and some small UI improvements were added. We are grateful to Anastasis
for creating this tool and making it available to the community.


Book Component Guide Annotators Prodigy (`docs/book/component-guide/annotators/prodigy.md`)



Prodigy

Prodigy is a modern annotation tool for creating training
and evaluation data for machine learning models. You can also use Prodigy to
help you inspect and clean your data, do error analysis and develop rule-based
systems to use in combination with your statistical models.

{% hint style="info" %} Prodigy is a paid annotation tool. You will need a
Prodigy is a paid tool. A license is required to download and use it with ZenML.
{% endhint %}

The Prodigy Python library includes a range of pre-built workflows and
command-line commands for various tasks, and well-documented components for
implementing your own workflow scripts. Your scripts can specify how the data is
loaded and saved, change which questions are asked in the annotation interface,
and can even define custom HTML and JavaScript to change the behavior of the
front-end. The web application is optimized for fast, intuitive and efficient
annotation.

When would you want to use it?

If you need to label data as part of your ML workflow, that is the point at
which you could consider adding the optional annotator stack component as part
of your ZenML stack.

How to deploy it?

The Prodigy Annotator flavor is provided by the Prodigy ZenML integration. You
need to install it to be able to register it as an Annotator and add it to your
stack:

shell
zenml integration export-requirements --output-file prodigy-requirements.txt prodigy

Note that you'll need to install Prodigy separately since it requires a license.
Please visit the Prodigy docs for information
on how to install it. Currently Prodigy also requires the urllib3<2
dependency, so make sure to install that.

Then register your annotator with ZenML:

shell
zenml annotator register prodigy --flavor prodigy
# optionally also pass in --custom_config_path="<PATH_TO_CUSTOM_CONFIG_FILE>"

See https://prodi.gy/docs/install#config for more on custom Prodigy config
files. Passing a custom_config_path allows you to override the default Prodigy
config.

Finally, add all these components to a stack and set it as your active stack.
For example:

shell
zenml stack copy default annotation
zenml stack update annotation -an prodigy
zenml stack set annotation
# optionally also
zenml stack describe

Now if you run a simple CLI command like zenml annotator dataset list this
should work without any errors. You're ready to use your annotator in your ML
workflow!

How do you use it?

With Prodigy, there is no need to specially start the annotator ahead of time
like with Label Studio. Instead, just use Prodigy as per the
Prodigy docs and then you can use the ZenML wrapper / API to
get your labeled data etc using our Python methods.

ZenML supports access to your data and annotations via the zenml annotator ...
CLI command.

You can access information about the datasets you're using with the zenml annotator dataset list. To work on annotation for a particular dataset, you can
run zenml annotator dataset annotate <DATASET_NAME> <CUSTOM_COMMAND>. This is
the equivalent of running prodigy <CUSTOM_COMMAND> in the terminal. For
example, you might run:

shell
zenml annotator dataset annotate your_dataset --command="textcat.manual news_topics ./news_headlines.jsonl --label Technology,Politics,Economy,Entertainment"

This would launch the Prodigy interface for the textcat.manual recipe with the
news_topics dataset and the labels Technology, Politics, Economy, and
Entertainment. The data would be loaded from the news_headlines.jsonl file.

A common workflow for Prodigy is to annotate data as you would usually do, and
then use the connection into ZenML to import those annotations within a step in
your pipeline (if running locally). For example, within a ZenML step:

python
from typing import List, Dict, Any

from zenml import step
from zenml.client import Client

@step
def import_annotations() -> List[Dict[str, Any]:
    zenml_client = Client()
    annotations = zenml_client.active_stack.annotator.get_labeled_data(dataset_name="my_dataset")
    # Do something with the annotations
    return annotations

If you're running in a cloud environment, you can manually export the
annotations, store them somewhere in a cloud environment and then reference or
use those within ZenML. The precise way you do this will be very case-dependent,
however, so it's difficult to provide a one-size-fits-all solution.

Prodigy Annotator Stack Component

Our Prodigy annotator component inherits from the BaseAnnotator class. There
are some methods that are core methods that must be defined, like being able to
register or get a dataset. Most annotators handle things like the storage of
state and have their own custom features, so there are quite a few extra methods
specific to Prodigy.

The core Prodigy functionality that's currently enabled from within the
annotator stack component interface includes a way to register your datasets
and export any annotations for use in separate steps.


Book Component Guide Artifact Stores Alibaba Oss (`docs/book/component-guide/artifact-stores/alibaba-oss.md`)



Alibaba Cloud OSS

Alibaba Cloud Object Storage Service (OSS) is an S3-compatible object storage service. Since OSS provides an S3-compatible API, you can use ZenML's S3 Artifact Store integration to connect to Alibaba Cloud OSS.

{% hint style="warning" %}
Important: When using Alibaba Cloud OSS, you must set the following config_kwargs:

json
{"signature_version": "s3", "s3": {"addressing_style": "virtual"}}

This is required for proper compatibility with Alibaba Cloud OSS's S3 API implementation.
{% endhint %}

When would you want to use it?

You should use the Alibaba Cloud OSS Artifact Store when:

  • Your infrastructure is already deployed on Alibaba Cloud and you want to maintain data locality
  • You require artifact storage in specific geographic regions served by Alibaba Cloud (China, Asia-Pacific, Europe, Middle East)
  • You need S3-compatible object storage with Alibaba Cloud's pricing model and service level agreements
  • Compliance requirements mandate data residency in Alibaba Cloud regions

How do you deploy it?

Since Alibaba Cloud OSS is S3-compatible, you'll use the S3 integration. First, install it:

shell
zenml integration install s3 -y

You'll also need to create an OSS bucket and obtain your access credentials from the Alibaba Cloud console.

How do you configure it?

To use Alibaba Cloud OSS with ZenML, you need to configure the S3 Artifact Store with specific settings for OSS compatibility:

{% hint style="info" %}
Alibaba Cloud OSS does not support ZenML Service Connectors. Use ZenML Secrets to securely store and reference your Alibaba Cloud credentials.
{% endhint %}

{% tabs %}
{% tab title="Using a ZenML Secret (recommended)" %}

First, create a ZenML secret with your Alibaba Cloud credentials:

shell
zenml secret create alibaba_secret \
    --access_key_id='<YOUR_ALIBABA_ACCESS_KEY_ID>' \
    --secret_access_key='<YOUR_ALIBABA_SECRET_ACCESS_KEY>'

Then register the artifact store with the required OSS configuration:

shell
zenml artifact-store register alibaba_store -f s3 \
    --path='s3://your-bucket-name' \
    --authentication_secret=alibaba_secret \
    --client_kwargs='{"endpoint_url": "https://oss-<region>.aliyuncs.com"}' \
    --config_kwargs='{"signature_version": "s3", "s3": {"addressing_style": "virtual"}}'

{% endtab %}
{% endtabs %}

Replace <region> with your OSS region (e.g., eu-central-1, cn-hangzhou, ap-southeast-1). You can find the list of available regions and their endpoints in the Alibaba Cloud OSS documentation.

Finally, add the artifact store to your stack:

shell
zenml stack register custom_stack -a alibaba_store ... --set

How do you use it?

Using the Alibaba Cloud OSS Artifact Store is no different from using any other flavor of Artifact Store. ZenML handles the S3-compatible API translation automatically.

For more details on the S3 Artifact Store configuration options, refer to the S3 Artifact Store documentation.


Book Component Guide Artifact Stores Azure (`docs/book/component-guide/artifact-stores/azure.md`)



Azure Blob Storage

The Azure Artifact Store is an Artifact Store flavor provided with the Azure ZenML integration that uses the Azure Blob Storage managed object storage service to store ZenML artifacts in an Azure Blob Storage container.

When would you want to use it?

Running ZenML pipelines with the local Artifact Store is usually sufficient if you just want to evaluate ZenML or get started quickly without incurring the trouble and the cost of employing cloud storage services in your stack. However, the local Artifact Store becomes insufficient or unsuitable if you have more elaborate needs for your project:

  • if you want to share your pipeline run results with other team members or stakeholders inside or outside your organization
  • if you have other components in your stack that are running remotely (e.g. a Kubeflow or Kubernetes Orchestrator running in a public cloud).
  • if you outgrow what your local machine can offer in terms of storage space and need to use some form of private or public storage service that is shared with others
  • if you are running pipelines at scale and need an Artifact Store that can handle the demands of production-grade MLOps

In all these cases, you need an Artifact Store that is backed by a form of public cloud or self-hosted shared object storage service.

You should use the Azure Artifact Store when you decide to keep your ZenML artifacts in a shared object storage and if you have access to the Azure Blob Storage managed service. You should consider one of the other Artifact Store flavors if you don't have access to the Azure Blob Storage service.

How do you deploy it?

{% hint style="info" %}
Would you like to skip ahead and deploy a full ZenML cloud stack already, including an Azure Artifact Store? Check out thein-browser stack deployment wizard, the stack registration wizard, or the ZenML Azure Terraform module for a shortcut on how to deploy & register this stack component.
{% endhint %}

The Azure Artifact Store flavor is provided by the Azure ZenML integration, you need to install it on your local machine to be able to register an Azure Artifact Store and add it to your stack:

shell
zenml integration install azure -y

The only configuration parameter mandatory for registering an Azure Artifact Store is the root path URI, which needs to point to an Azure Blog Storage container and take the form az://container-name or abfs://container-name. Please read the Azure Blob Storage documentation on how to configure an Azure Blob Storage container.

With the URI to your Azure Blob Storage container known, registering an Azure Artifact Store can be done as follows:

shell
# Register the Azure artifact store
zenml artifact-store register az_store -f azure --path=az://container-name

# Register and set a stack with the new artifact store
zenml stack register custom_stack -a az_store ... --set

Depending on your use case, however, you may also need to provide additional configuration parameters pertaining to authentication to match your deployment scenario.

Authentication Methods

Integrating and using an Azure Artifact Store in your pipelines is not possible without employing some form of authentication. If you're looking for a quick way to get started locally, you can use the Implicit Authentication method. However, the recommended way to authenticate to the Azure cloud platform is through an Azure Service Connector. This is particularly useful if you are configuring ZenML stacks that combine the Azure Artifact Store with other remote stack components also running in Azure.

You will need the following information to configure Azure credentials for ZenML, depending on which type of Azure credentials you want to use:

  • an Azure connection string
  • an Azure account key
  • the client ID, client secret and tenant ID of the Azure service principal

For more information on how to retrieve information about your Azure Storage Account and Access Key or connection string, please refer to this Azure guide.

For information on how to configure an Azure service principal, please consult the Azure documentation.

{% tabs %}
{% tab title="Implicit Authentication" %}
This method uses the implicit Azure authentication available in the environment where the ZenML code is running. On your local machine, this is the quickest way to configure an Azure Artifact Store. You don't need to supply credentials explicitly when you register the Azure Artifact Store, instead, you have to set one of the following sets of environment variables:

{% hint style="warning" %}
Certain dashboard functionality, such as visualizing or deleting artifacts, is not available when using an implicitly authenticated artifact store together with a deployed ZenML server because the ZenML server will not have permission to access the filesystem.

The implicit authentication method also needs to be coordinated with other stack components that are highly dependent on the Artifact Store and need to interact with it directly to the function. If these components are not running on your machine, they do not have access to the local environment variables and will encounter authentication failures while trying to access the Azure Artifact Store:

  • Orchestrators need to access the Artifact Store to manage pipeline artifacts
  • Step Operators need to access the Artifact Store to manage step-level artifacts
  • Model Deployers need to access the Artifact Store to load served models

To enable these use cases, it is recommended to use an Azure Service Connector to link your Azure Artifact Store to the remote Azure Blob storage container.
{% endhint %}
{% endtab %}

{% tab title="Azure Service Connector (recommended)" %}
To set up the Azure Artifact Store to authenticate to Azure and access an Azure Blob storage container, it is recommended to leverage the many features provided by the Azure Service Connector such as auto-configuration, best security practices regarding long-lived credentials and reusing the same credentials across multiple stack components.

If you don't already have an Azure Service Connector configured in your ZenML deployment, you can register one using the interactive CLI command. You have the option to configure an Azure Service Connector that can be used to access more than one Azure blob storage container or even more than one type of Azure resource:

sh
zenml service-connector register --type azure -i

A non-interactive CLI example that uses Azure Service Principal credentials to configure an Azure Service Connector targeting a single Azure Blob storage container is:

sh
zenml service-connector register <CONNECTOR_NAME> --type azure --auth-method service-principal --tenant_id=<AZURE_TENANT_ID> --client_id=<AZURE_CLIENT_ID> --client_secret=<AZURE_CLIENT_SECRET> --resource-type blob-container --resource-id <BLOB_CONTAINER_NAME>

{% code title="Example Command Output" %}

text
$ zenml service-connector register azure-blob-demo --type azure --auth-method service-principal --tenant_id=a79f3633-8f45-4a74-a42e-68871c17b7fb --client_id=8926254a-8c3f-430a-a2fd-bdab234d491e --client_secret=AzureSuperSecret --resource-type blob-container --resource-id az://demo-zenmlartifactstore
Successfully registered service connector `azure-blob-demo` with access to the following resources:
┏━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃   RESOURCE TYPE   │ RESOURCE NAMES               ┃
┠───────────────────┼──────────────────────────────┨
┃ 📦 blob-container │ az://demo-zenmlartifactstore ┃
┗━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

{% endcode %}

Note: Please remember to grant the Azure service principal permissions to read and write to your Azure Blob storage container as well as to list accessible storage accounts and Blob containers. For a full list of permissions required to use an AWS Service Connector to access one or more S3 buckets, please refer to the Azure Service Connector Blob storage container resource type documentation or read the documentation available in the interactive CLI commands and dashboard. The Azure Service Connector supports many different authentication methods with different levels of security and convenience. You should pick the one that best fits your use-case.

If you already have one or more Azure Service Connectors configured in your ZenML deployment, you can check which of them can be used to access the Azure Blob storage container you want to use for your Azure Artifact Store by running e.g.:

sh
zenml service-connector list-resources --resource-type blob-container

{% code title="Example Command Output" %}

text
The following 'blob-container' resources can be accessed by service connectors:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃             CONNECTOR ID             │ CONNECTOR NAME          │ CONNECTOR TYPE │ RESOURCE TYPE     │ RESOURCE NAMES               ┃
┠──────────────────────────────────────┼─────────────────────────┼────────────────┼───────────────────┼──────────────────────────────┨
┃ 273d2812-2643-4446-82e6-6098b8ccdaa4 │ azure-service-principal │ 🇦  azure       │ 📦 blob-container │ az://demo-zenmlartifactstore ┃
┠──────────────────────────────────────┼─────────────────────────┼────────────────┼───────────────────┼──────────────────────────────┨
┃ f6b329e1-00f7-4392-94c9-264119e672d0 │ azure-blob-demo         │ 🇦  azure       │ 📦 blob-container │ az://demo-zenmlartifactstore ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

{% endcode %}

After having set up or decided on an Azure Service Connector to use to connect to the target Azure Blob storage container, you can register the Azure Artifact Store as follows:

sh
# Register the Azure artifact-store and reference the target blob storage container
zenml artifact-store register <AZURE_STORE_NAME> -f azure \
    --path='az://your-container'

# Connect the Azure artifact-store to the target container via an Azure Service Connector
zenml artifact-store connect <AZURE_STORE_NAME> -i

A non-interactive version that connects the Azure Artifact Store to a target blob storage container through an Azure Service Connector:

sh
zenml artifact-store connect <S3_STORE_NAME> --connector <CONNECTOR_ID>

{% code title="Example Command Output" %}

text
$ zenml artifact-store connect azure-blob-demo --connector azure-blob-demo
Successfully connected artifact store `azure-blob-demo` to the following resources:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃             CONNECTOR ID             │ CONNECTOR NAME  │ CONNECTOR TYPE │ RESOURCE TYPE     │ RESOURCE NAMES               ┃
┠──────────────────────────────────────┼─────────────────┼────────────────┼───────────────────┼──────────────────────────────┨
┃ f6b329e1-00f7-4392-94c9-264119e672d0 │ azure-blob-demo │ 🇦  azure       │ 📦 blob-container │ az://demo-zenmlartifactstore ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

{% endcode %}

As a final step, you can use the Azure Artifact Store in a ZenML Stack:

sh
# Register and set a stack with the new artifact store
zenml stack register <STACK_NAME> -a <AZURE_STORE_NAME> ... --set

{% endtab %}

{% tab title="ZenML Secret" %}
When you register the Azure Artifact Store, you can create a ZenML Secret to store a variety of Azure credentials and then reference it in the Artifact Store configuration:

This method has some advantages over the implicit authentication method:

  • you don't need to install and configure the Azure CLI on your host
  • you don't need to care about enabling your other stack components (orchestrators, step operators and model deployers) to have access to the artifact store through Azure Managed Identities
  • you can combine the Azure artifact store with other stack components that are not running in Azure

Configuring Azure credentials in a ZenML secret and then referencing them in the Artifact Store configuration could look like this:

shell
# Store the Azure storage account key in a ZenML secret
zenml secret create az_secret \
    --account_name='<YOUR_AZURE_ACCOUNT_NAME>' \
    --account_key='<YOUR_AZURE_ACCOUNT_KEY>'

# or if you want to use a connection string
zenml secret create az_secret \
    --connection_string='<YOUR_AZURE_CONNECTION_STRING>'

# or if you want to use Azure ServicePrincipal credentials
zenml secret create az_secret \
    --account_name='<YOUR_AZURE_ACCOUNT_NAME>' \
    --tenant_id='<YOUR_AZURE_TENANT_ID>' \
    --client_id='<YOUR_AZURE_CLIENT_ID>' \
    --client_secret='<YOUR_AZURE_CLIENT_SECRET>'

# Alternatively for providing key-value pairs, you can utilize the '--values' option by specifying a file path containing 
# key-value pairs in either JSON or YAML format.
# File content example: {"account_name":"<YOUR_AZURE_ACCOUNT_NAME>",...}
zenml secret create az_secret \
    --values=@path/to/file.txt

# Register the Azure artifact store and reference the ZenML secret
zenml artifact-store register az_store -f azure \
    --path='az://your-container' \
    --authentication_secret=az_secret

# Register and set a stack with the new artifact store
zenml stack register custom_stack -a az_store ... --set

{% endtab %}
{% endtabs %}

For more, up-to-date information on the Azure Artifact Store implementation and its configuration, you can have a look at the SDK docs .

How do you use it?

Aside from the fact that the artifacts are stored in Azure Blob Storage, using the Azure Artifact Store is no different from using any other flavor of Artifact Store.


Book Component Guide Artifact Stores B2 (`docs/book/component-guide/artifact-stores/b2.md`)



Backblaze B2

The Backblaze B2 Artifact Store is an Artifact Store flavor provided with the B2 ZenML integration that uses Backblaze B2 Cloud Storage to store ZenML artifacts. Backblaze B2 exposes an S3-compatible API, so this flavor reuses ZenML's S3 implementation under the hood while adding B2-friendly runtime fallbacks for the endpoint URL and credential environment variables.

When would you want to use it?

Running ZenML pipelines with the local Artifact Store is usually sufficient if you just want to evaluate ZenML or get started quickly without incurring the trouble and the cost of employing cloud storage services in your stack. However, the local Artifact Store becomes insufficient or unsuitable if you have more elaborate needs for your project:

  • if you want to share your pipeline run results with other team members or stakeholders inside or outside your organization
  • if you have other components in your stack that are running remotely (e.g. a Kubeflow or Kubernetes Orchestrator running in a public cloud).
  • if you outgrow what your local machine can offer in terms of storage space and need to use some form of private or public storage service that is shared with others
  • if you are running pipelines at scale and need an Artifact Store that can handle the demands of production-grade MLOps

You should use the Backblaze B2 Artifact Store when you want to keep your ZenML artifacts in shared object storage and you prefer Backblaze B2's pricing, egress terms, or geographic regions over the hyperscalers. Because the integration speaks B2's S3-compatible API, you get the same workflow as the S3 Artifact Store without having to manage any additional B2-native tooling. You should consider one of the other Artifact Store flavors if you don't have a Backblaze B2 account or if you require an S3 service that is co-located with other AWS resources in your stack.

How do you deploy it?

The Backblaze B2 Artifact Store flavor is provided by the B2 ZenML integration, you need to install it on your local machine to be able to register a B2 Artifact Store and add it to your stack:

shell
zenml integration install b2 -y

You will also need a Backblaze B2 account and a private bucket to hold your ZenML artifacts. The high-level setup steps in the Backblaze console are:

  1. Create a B2 bucket. From the Backblaze web console, navigate to B2 Cloud Storage > Buckets and click Create a Bucket. Pick a globally-unique bucket name (this becomes the s3:// path used by ZenML), choose Private, and select the region you want to store data in. The region segment of the bucket's S3 endpoint (e.g. us-west-004, eu-central-003) is needed in the next step.

  2. Generate a B2 application key. Navigate to Account > Application Keys and click Add a New Application Key. Scope the key to the bucket you just created and grant at minimum Read and Write access. Backblaze will display a keyID and an applicationKey exactly once — copy both values immediately.

  3. Export the credentials as environment variables. ZenML's B2 artifact store reads Backblaze's standard environment variable names at runtime if no key/secret is configured directly on the artifact store:

    shell
    export B2_APPLICATION_KEY_ID=<your-b2-key-id>
    export B2_APPLICATION_KEY=<your-b2-application-key>

    This convention matches the Backblaze CLI and SDKs, so the same environment that authenticates b2-cli will authenticate ZenML.

For full Backblaze documentation on bucket creation and application keys, see the B2 Cloud Storage docs.

How do you use it?

The only configuration parameter mandatory for registering a B2 Artifact Store is the root path URI, which needs to point to a B2 bucket using the s3:// scheme — this is intentional, because the B2 flavor talks to Backblaze through its S3-compatible API:

shell
# Register the B2 artifact store (uses the s3:// URI scheme since B2 speaks the S3 API)
zenml artifact-store register my_b2 --flavor=b2 --path=s3://my-bucket/zenml-artifacts

# Register and set a stack that uses the new artifact store
zenml stack register custom_stack -a my_b2 ... --set

If B2_APPLICATION_KEY_ID and B2_APPLICATION_KEY are exported in the shell that runs ZenML, no further authentication configuration is required. The artifact store client will pick them up when it is created without saving them as component configuration. To keep credentials out of the shell environment, store them in a ZenML Secret and reference them on registration:

shell
# Store the B2 application key in a ZenML secret
zenml secret create b2_secret \
    --access_key_id='<YOUR_B2_APPLICATION_KEY_ID>' \
    --secret_access_key='<YOUR_B2_APPLICATION_KEY>'

# Register the B2 artifact store and reference the secret
zenml artifact-store register my_b2 --flavor=b2 \
    --path=s3://my-bucket/zenml-artifacts \
    --authentication_secret=b2_secret

Endpoint defaults and regions

Configure the endpoint that matches your B2 bucket region at registration time:

shell
zenml artifact-store register my_b2 --flavor=b2 \
    --path=s3://my-bucket/zenml-artifacts \
    --client_kwargs='{"endpoint_url": "https://s3.eu-central-003.backblazeb2.com"}'

Use the S3 endpoint shown for your bucket in the Backblaze console. It always has the form https://s3.<region>.backblazeb2.com. If you omit client_kwargs.endpoint_url, the runtime client falls back to https://s3.us-west-004.backblazeb2.com without saving that fallback on the component configuration.

Advanced configuration

Because the B2 flavor subclasses the S3 flavor, every advanced option supported by the S3 Artifact Store — client_kwargs, config_kwargs, and s3_additional_kwargs — is available here too and is passed transparently to the underlying s3fs / botocore stack. Use these to configure things like server-side encryption, custom retry behavior, or alternative B2 endpoints.

Aside from the fact that the artifacts are stored in Backblaze B2, using the B2 Artifact Store is no different from using any other flavor of Artifact Store.


Book Component Guide Artifact Stores Custom (`docs/book/component-guide/artifact-stores/custom.md`)



Develop a custom artifact store

{% hint style="info" %}
Before diving into the specifics of this component type, it is beneficial to familiarize yourself with our general guide to writing custom component flavors in ZenML. This guide provides an essential understanding of ZenML's component flavor concepts.
{% endhint %}

ZenML comes equipped with Artifact Store implementations that you can use to store artifacts on a local filesystem or in the managed AWS, GCP, or Azure cloud object storage services. However, if you need to use a different type of object storage service as a backend for your ZenML Artifact Store, you can extend ZenML to provide your own custom Artifact Store implementation.

Base Abstraction

The Artifact Store establishes one of the main components in every ZenML stack. Now, let us take a deeper dive into the fundamentals behind its abstraction, namely the BaseArtifactStore class:

  1. As ZenML only supports filesystem-based artifact stores, it features a configuration parameter called path, which will indicate the root path of the artifact store. When registering an artifact store, users will have to define this parameter.
  2. Moreover, there is another variable in the config class called SUPPORTED_SCHEMES. This is a class variable that needs to be defined in every subclass of the base artifact store configuration. It indicates the supported file path schemes for the corresponding implementation. For instance, for the Azure artifact store, this set will be defined as {"abfs://", "az://"}.
  3. Lastly, the base class features a set of abstractmethods: open, copyfile,exists,glob,isdir,listdir ,makedirs,mkdir,remove, rename,rmtree,stat,walk. In the implementation of every ArtifactStore flavor, it is required to define these methods with respect to the flavor at hand.

Putting all these considerations together, we end up with the following implementation:

text
/* Detailed source-code truncated for AI context efficiency. */

{% hint style="info" %}
This is a slimmed-down version of the base implementation which aims to highlight the abstraction layer. In order to see the full implementation and get the complete docstrings, please check the SDK docs .
{% endhint %}

The effect on the zenml.io.fileio

If you created an instance of an artifact store, added it to your stack, and activated the stack, it will create a filesystem each time you run a ZenML pipeline and make it available to the zenml.io.fileio module.

This means that when you utilize a method such as fileio.open(...) with a file path that starts with one of the SUPPORTED_SCHEMES within your steps or materializers, it will be able to use the open(...) method that you defined within your artifact store.

Build your own custom artifact store

If you want to implement your own custom Artifact Store, you can follow the following steps:

  1. Create a class that inherits from the BaseArtifactStore class and implements the abstract methods.
  2. Create a class that inherits from the BaseArtifactStoreConfig class and fill in the SUPPORTED_SCHEMES based on your file system.
  3. Bring both of these classes together by inheriting from the BaseArtifactStoreFlavor class.

Once you are done with the implementation, you can register it through the CLI. Please ensure you point to the flavor class via dot notation:

shell
zenml artifact-store flavor register <path.to.MyArtifactStoreFlavor>

For example, if your flavor class MyArtifactStoreFlavor is defined in flavors/my_flavor.py, you'd register it by doing:

shell
zenml artifact-store flavor register flavors.my_flavor.MyArtifactStoreFlavor

{% hint style="warning" %}
ZenML resolves the flavor class by taking the path where you initialized zenml (via zenml init) as the starting point of resolution. Therefore, please ensure you follow the best practice of initializing zenml at the root of your repository.

If ZenML does not find an initialized ZenML repository in any parent directory, it will default to the current working directory, but usually, it's better to not have to rely on this mechanism and initialize zenml at the root.
{% endhint %}

Afterward, you should see the new custom artifact store flavor in the list of available artifact store flavors:

shell
zenml artifact-store flavor list

{% hint style="warning" %}
It is important to draw attention to when and how these base abstractions are coming into play in a ZenML workflow.

  • The CustomArtifactStoreFlavor class is imported and utilized upon the creation of the custom flavor through the CLI.
  • The CustomArtifactStoreConfig class is imported when someone tries to register/update a stack component with this custom flavor. Especially, during the registration process of the stack component, the config will be used to validate the values given by the user. As Config objects are inherently pydantic objects, you can also add your own custom validators here.
  • The CustomArtifactStore only comes into play when the component is ultimately in use.

The design behind this interaction lets us separate the configuration of the flavor from its implementation. This way we can register flavors and components even when the major dependencies behind their implementation are not installed in our local setting (assuming the CustomArtifactStoreFlavor and the CustomArtifactStoreConfig are implemented in a different module/path than the actual CustomArtifactStore).
{% endhint %}

Enabling Artifact Visualizations with Custom Artifact Stores

ZenML automatically saves visualizations for many common data types and allows you to view these visualizations in the ZenML dashboard. Under the hood, this works by saving the visualizations together with the artifacts in the artifact store.

In order to load and display these visualizations, ZenML needs to be able to load and access the corresponding artifact store. This means that your custom artifact store needs to be configured in a way that allows authenticating to the back-end without relying on the local environment, e.g., by embedding the authentication credentials in the stack component configuration or by referencing a secret.

Furthermore, for deployed ZenML instances, you need to install the package dependencies of your artifact store implementation in the environment where you have deployed ZenML. See the Documentation on deploying ZenML with custom Docker images for more information on how to do that.


Book Component Guide Artifact Stores Digitalocean (`docs/book/component-guide/artifact-stores/digitalocean.md`)



DigitalOcean Spaces

The DigitalOcean Spaces Artifact Store is an Artifact Store flavor provided with the DigitalOcean ZenML integration that uses DigitalOcean Spaces to store ZenML artifacts. Spaces exposes an S3-compatible API, so this flavor reuses ZenML's S3 implementation under the hood and only adds a region setting from which the Spaces endpoint URL is derived at runtime.

When would you want to use it?

Running ZenML pipelines with the local Artifact Store is usually sufficient if you just want to evaluate ZenML or get started quickly. However, the local Artifact Store becomes insufficient once you want to share pipeline results with teammates, run other stack components remotely (e.g. an orchestrator on DigitalOcean Kubernetes), or run production-grade pipelines at scale.

You should use the DigitalOcean Spaces Artifact Store when your infrastructure runs on DigitalOcean and you want your ZenML artifacts co-located with it — for example next to a DOKS cluster running the Kubernetes orchestrator. Because the integration speaks the S3-compatible Spaces API, you get the same workflow as the S3 Artifact Store without managing any additional tooling. Consider one of the other Artifact Store flavors if you don't use DigitalOcean.

How do you deploy it?

The DigitalOcean Spaces Artifact Store flavor is provided by the DigitalOcean ZenML integration. Install it on your local machine to be able to register the artifact store and add it to your stack:

shell
zenml integration install digitalocean -y

You will also need a Space (bucket) and a set of Spaces access keys:

  1. Create a Space. In the DigitalOcean control panel, go to Spaces Object Storage and create a bucket. Note the bucket name (this becomes the s3:// path used by ZenML) and the region slug shown in the bucket's endpoint (e.g. nyc3, ams3, fra1).
  2. Generate Spaces access keys. Go to Storage > Spaces Object Storage > Access Keys and generate a new key pair. Spaces keys are separate credentials from your DigitalOcean API token; copy both the access key and the secret when they are displayed.

How do you use it?

Register the artifact store with the bucket path (using the s3:// scheme, since Spaces speaks the S3 API) and the region slug:

shell
zenml artifact-store register do_spaces \
    --flavor=digitalocean \
    --path=s3://my-space \
    --region=fra1

# Register and set a stack that uses the new artifact store
zenml stack register do_stack -a do_spaces ... --set

The Spaces endpoint URL (https://<region>.digitaloceanspaces.com) is derived from the region at runtime and is not persisted in the component configuration. If you need to address a different endpoint (for example a custom domain), pass it explicitly instead — an explicit endpoint always takes precedence over the region-derived one:

shell
zenml artifact-store register do_spaces \
    --flavor=digitalocean \
    --path=s3://my-space \
    --client_kwargs='{"endpoint_url": "https://fra1.digitaloceanspaces.com"}'

To authenticate, store the Spaces access keys in a ZenML Secret and reference them on registration:

shell
zenml secret create spaces_secret \
    --access_key_id='<YOUR_SPACES_ACCESS_KEY>' \
    --secret_access_key='<YOUR_SPACES_SECRET_KEY>'

zenml artifact-store register do_spaces \
    --flavor=digitalocean \
    --path=s3://my-space \
    --region=fra1 \
    --authentication_secret=spaces_secret

All other configuration options of the S3 Artifact Store (client_kwargs, config_kwargs, s3_additional_kwargs) are available on this flavor as well and are passed through to the underlying S3-compatible filesystem.


Book Component Guide Artifact Stores Gcp (`docs/book/component-guide/artifact-stores/gcp.md`)



Google Cloud Storage (GCS)

The GCS Artifact Store is an Artifact Store flavor provided with the GCP ZenML integration that uses the Google Cloud Storage managed object storage service to store ZenML artifacts in a GCP Cloud Storage bucket.

When would you want to use it?

Running ZenML pipelines with the local Artifact Store is usually sufficient if you just want to evaluate ZenML or get started quickly without incurring the trouble and the cost of employing cloud storage services in your stack. However, the local Artifact Store becomes insufficient or unsuitable if you have more elaborate needs for your project:

  • if you want to share your pipeline run results with other team members or stakeholders inside or outside your organization
  • if you have other components in your stack that are running remotely (e.g. a Kubeflow or Kubernetes Orchestrator running in a public cloud).
  • if you outgrow what your local machine can offer in terms of storage space and need to use some form of private or public storage service that is shared with others
  • if you are running pipelines at scale and need an Artifact Store that can handle the demands of production-grade MLOps

In all these cases, you need an Artifact Store that is backed by a form of public cloud or self-hosted shared object storage service.

You should use the GCS Artifact Store when you decide to keep your ZenML artifacts in a shared object storage and if you have access to the Google Cloud Storage managed service. You should consider one of the other Artifact Store flavors if you don't have access to the GCP Cloud Storage service.

How do you deploy it?

{% hint style="info" %}
Would you like to skip ahead and deploy a full ZenML cloud stack already, including a GCS Artifact Store? Check out thein-browser stack deployment wizard, the stack registration wizard, or the ZenML GCP Terraform module for a shortcut on how to deploy & register this stack component.
{% endhint %}

The GCS Artifact Store flavor is provided by the GCP ZenML integration, you need to install it on your local machine to be able to register a GCS Artifact Store and add it to your stack:

shell
zenml integration install gcp -y

The only configuration parameter mandatory for registering a GCS Artifact Store is the root path URI, which needs to point to a GCS bucket and take the form gs://bucket-name. Please read the Google Cloud Storage documentation on how to configure a GCS bucket.

With the URI to your GCS bucket known, registering a GCS Artifact Store can be done as follows:

shell
# Register the GCS artifact store
zenml artifact-store register gs_store -f gcp --path=gs://bucket-name

# Register and set a stack with the new artifact store
zenml stack register custom_stack -a gs_store ... --set

Depending on your use case, however, you may also need to provide additional configuration parameters pertaining to authentication to match your deployment scenario.

Authentication Methods

Integrating and using a GCS Artifact Store in your pipelines is not possible without employing some form of authentication. If you're looking for a quick way to get started locally, you can use the Implicit Authentication method. However, the recommended way to authenticate to the GCP cloud platform is through a GCP Service Connector. This is particularly useful if you are configuring ZenML stacks that combine the GCS Artifact Store with other remote stack components also running in GCP.

{% tabs %}
{% tab title="Implicit Authentication" %}
This method uses the implicit GCP authentication available in the environment where the ZenML code is running. On your local machine, this is the quickest way to configure a GCS Artifact Store. You don't need to supply credentials explicitly when you register the GCS Artifact Store, as it leverages the local credentials and configuration that the Google Cloud CLI stores on your local machine. However, you will need to install and set up the Google Cloud CLI on your machine as a prerequisite, as covered in the Google Cloud documentation , before you register the GCS Artifact Store.

{% hint style="warning" %}
Certain dashboard functionality, such as visualizing or deleting artifacts, is not available when using an implicitly authenticated artifact store together with a deployed ZenML server because the ZenML server will not have permission to access the filesystem.

The implicit authentication method also needs to be coordinated with other stack components that are highly dependent on the Artifact Store and need to interact with it directly to the function. If these components are not running on your machine, they do not have access to the local Google Cloud CLI configuration and will encounter authentication failures while trying to access the GCS Artifact Store:

  • Orchestrators need to access the Artifact Store to manage pipeline artifacts
  • Step Operators need to access the Artifact Store to manage step-level artifacts
  • Model Deployers need to access the Artifact Store to load served models

To enable these use cases, it is recommended to use a GCP Service Connector to link your GCS Artifact Store to the remote GCS bucket.
{% endhint %}
{% endtab %}

{% tab title="GCP Service Connector (recommended)" %}
To set up the GCS Artifact Store to authenticate to GCP and access a GCS bucket, it is recommended to leverage the many features provided by the GCP Service Connector such as auto-configuration, best security practices regarding long-lived credentials and reusing the same credentials across multiple stack components.

If you don't already have a GCP Service Connector configured in your ZenML deployment, you can register one using the interactive CLI command. You have the option to configure a GCP Service Connector that can be used to access more than one GCS bucket or even more than one type of GCP resource:

sh
zenml service-connector register --type gcp -i

A non-interactive CLI example that leverages the Google Cloud CLI configuration on your local machine to auto-configure a GCP Service Connector targeting a single GCS bucket is:

sh
zenml service-connector register <CONNECTOR_NAME> --type gcp --resource-type gcs-bucket --resource-name <GCS_BUCKET_NAME> --auto-configure

{% code title="Example Command Output" %}

text
$ zenml service-connector register gcs-zenml-bucket-sl --type gcp --resource-type gcs-bucket --resource-id gs://zenml-bucket-sl --auto-configure
⠸ Registering service connector 'gcs-zenml-bucket-sl'...
Successfully registered service connector `gcs-zenml-bucket-sl` with access to the following resources:
┏━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━┓
┃ RESOURCE TYPE │ RESOURCE NAMES       ┃
┠───────────────┼──────────────────────┨
┃ 📦 gcs-bucket │ gs://zenml-bucket-sl ┃
┗━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━┛

{% endcode %}

Note: Please remember to grant the entity associated with your GCP credentials permissions to read and write to your GCS bucket as well as to list accessible GCS buckets. For a full list of permissions required to use a GCP Service Connector to access one or more GCS buckets, please refer to the GCP Service Connector GCS bucket resource type documentation or read the documentation available in the interactive CLI commands and dashboard. The GCP Service Connector supports many different authentication methods with different levels of security and convenience. You should pick the one that best fits your use case.

If you already have one or more GCP Service Connectors configured in your ZenML deployment, you can check which of them can be used to access the GCS bucket you want to use for your GCS Artifact Store by running e.g.:

sh
zenml service-connector list-resources --resource-type gcs-bucket

{% code title="Example Command Output" %}

text
/* Detailed source-code truncated for AI context efficiency. */

{% endcode %}

After having set up or decided on a GCP Service Connector to use to connect to the target GCS bucket, you can register the GCS Artifact Store as follows:

sh
# Register the GCS artifact-store and reference the target GCS bucket
zenml artifact-store register <GCS_STORE_NAME> -f gcp \
    --path='gs://your-bucket'

# Connect the GCS artifact-store to the target bucket via a GCP Service Connector
zenml artifact-store connect <GCS_STORE_NAME> -i

A non-interactive version that connects the GCS Artifact Store to a target GCP Service Connector:

sh
zenml artifact-store connect <GCS_STORE_NAME> --connector <CONNECTOR_ID>

{% code title="Example Command Output" %}

text
$ zenml artifact-store connect gcs-zenml-bucket-sl --connector gcs-zenml-bucket-sl
Successfully connected artifact store `gcs-zenml-bucket-sl` to the following resources:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━┓
┃             CONNECTOR ID             │ CONNECTOR NAME      │ CONNECTOR TYPE │ RESOURCE TYPE │ RESOURCE NAMES       ┃
┠──────────────────────────────────────┼─────────────────────┼────────────────┼───────────────┼──────────────────────┨
┃ 2a0bec1b-9787-4bd7-8d4a-9a47b6f61643 │ gcs-zenml-bucket-sl │ 🔵 gcp         │ 📦 gcs-bucket │ gs://zenml-bucket-sl ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━┛

{% endcode %}

As a final step, you can use the GCS Artifact Store in a ZenML Stack:

sh
# Register and set a stack with the new artifact store
zenml stack register <STACK_NAME> -a <GCS_STORE_NAME> ... --set

{% endtab %}

{% tab title="GCP Credentials" %}
When you register the GCS Artifact Store, you can generate a GCP Service Account Key, store it in a ZenML Secret and then reference it in the Artifact Store configuration.

This method has some advantages over the implicit authentication method:

  • you don't need to install and configure the GCP CLI on your host
  • you don't need to care about enabling your other stack components (orchestrators, step operators and model deployers) to have access to the artifact store through GCP Service Accounts and Workload Identity
  • you can combine the GCS artifact store with other stack components that are not running in GCP

For this method, you need to create a user-managed GCP service account, grant it minimal privileges to read and write to your GCS bucket, and then create a service account key.

{% hint style="info" %}
Security Best Practice: Instead of using the broad Storage Object Admin role, create a custom role with only the specific permissions needed:

  • storage.buckets.get
  • storage.buckets.list
  • storage.objects.create
  • storage.objects.delete
  • storage.objects.get
  • storage.objects.list
  • storage.objects.update

Alternatively, you can use the Storage Object Admin role scoped to specific buckets rather than project-wide access.
{% endhint %}

With the service account key downloaded to a local file, you can register a ZenML secret and reference it in the GCS Artifact Store configuration as follows:

shell
# Store the GCP credentials in a ZenML
zenml secret create gcp_secret \
    --token=@path/to/service_account_key.json

# Register the GCS artifact store and reference the ZenML secret
zenml artifact-store register gcs_store -f gcp \
    --path='gs://your-bucket' \
    --authentication_secret=gcp_secret

# Register and set a stack with the new artifact store
zenml stack register custom_stack -a gs_store ... --set

{% endtab %}
{% endtabs %}

For more, up-to-date information on the GCS Artifact Store implementation and its configuration, you can have a look at the SDK docs .

How do you use it?

Aside from the fact that the artifacts are stored in GCP Cloud Storage, using the GCS Artifact Store is no different from using any other flavor of Artifact Store.


Book Component Guide Artifact Stores Local (`docs/book/component-guide/artifact-stores/local.md`)



Local Artifact Store

The local