Kitaru: turn agent failures into regression tests — replay real traces against your real code.Read the docs →

The unified layer for ML and AI

Reproducible ML pipelines with ZenML. Replayable agent evals with Kitaru. One platform, on the infrastructure you already use.

Integrate your MLOps stackFor compute-intense, distributed ML pipelines.
simple_pipeline · run #7
quickstart.pyZENML
from typing import Annotatedfrom zenml import pipeline, step @stepdef simple_step(name: str = "World") -> Annotated[str, "greeting"]:    return f"Hello, {name}! Welcome to ZenML!" @pipelinedef simple_pipeline(name: str = "World"):    return simple_step(name=name)
name
namestr
defaultWorld
simple_step
2s
greetingstr · v7
local · default stackhealthy
Integrate your MLOps stackFor compute-intense, distributed ML pipelines.
training · run #32
pipelines/training.pyZENML
from zenml import pipeline, step @stepdef data_loader(random_state: int) -> pd.DataFrame:    return load_breast_cancer(as_frame=True).frame @stepdef model_trainer(dataset_trn: pd.DataFrame) -> ClassifierMixin:    return SGDClassifier().fit(dataset_trn.drop("target", axis=1), dataset_trn.target) @pipelinedef training(model_type: str = "sgd"):    model_trainer(dataset_trn=data_loader(random_state=17))
data_loader
7s
dataset_trnDataFrame
dataset_tstDataFrame
model_trainer
4m 5s
sklearn_classifiersklearn · v32
kubernetes-prod · 12 podshealthy
Integrate your MLOps stackFor compute-intense, distributed ML pipelines.
llm_peft_full_finetune · run #18
pipelines/train.pyZENML
from zenml import pipelinefrom steps import prepare_data, finetune, evaluate_model, promote @pipelinedef llm_peft_full_finetune(    base_model_name: str = "microsoft/phi-2",    dataset_name: str = "gem/viggo",):    datasets_dir = prepare_data(base_model_name, dataset_name)    ft_model_dir = finetune(base_model_name, datasets_dir)    evaluate_model(base_model_name, ft_model_dir, datasets_dir)    promote(ft_model_dir)
prepare_data
3m 41s
datasets_dirPath
tokenizerPreTrainedTokenizer
finetune
58m 22s
ft_model_dirphi-2 · v18
vertex-gcp · 1× A100 80GBhealthy
Integrate your MLOps stackFor compute-intense, distributed ML pipelines.
churn_inference_pipeline · run #44
pipelines/inference_pipeline.pyZENML
from zenml import pipelinefrom zenml.config import DeploymentSettingsfrom steps.inference import predict_churn @pipeline(    on_init=init_model,    settings={"deployment": DeploymentSettings(        app_title="Churn Prediction API",        dashboard_files_path="ui",    )},)def churn_inference_pipeline(customer_features: Dict) -> Dict:    return predict_churn(customer_features=customer_features)
init_model
warm
modelRandomForest
customerDict
predict_churn
87ms
predictionDict · v44
sagemaker-aws · 2 replicaslive
Integrate your MLOps stackFor compute-intense, distributed ML pipelines.
object_detection_training · run #12
pipelines/training_pipeline.pyZENML
from zenml import pipelinefrom steps import load_coco_dataset, train_yolo, fiftyone_analysis @pipelinedef object_detection_training_pipeline(    max_samples: int = 50,    epochs: int = 1,    model_name: str = "yolov8n.pt",):    dataset = load_coco_dataset(max_samples=max_samples)    model = train_yolo(dataset=dataset, epochs=epochs, model_name=model_name)    fiftyone_analysis(dataset=dataset, model=model)
load_coco_dataset
1m 02s
datasetFiftyOneDataset
labelsCOCO80
train_yolo
17m 14s
yolo-modelultralytics · v12
airflow · 4× T4 GPUhealthy
Stack composerSwap orchestrator, store, tracker — same pipeline code.
5 components
StackOrchestratorArtifact storeContainer regTracker
local-dev
locallocaldefaultmlflow
kubernetes-prod
kubeflows3://prodecrmlflow
vertex-gcp
vertexgcs://prodgcrneptune
sagemaker-aws
sagemakers3://eu-westecrw&b
airflow-staging
airflowgcs://staginggcrmlflow
azureml-eu
azuremlazure://euacrcomet
Register the stack1 command
$zenml stack register local-dev -o default -a default --set
Register the stack3 commands
$zenml service-connector register aws-prod --type aws -i
$zenml orchestrator register kubeflow-orch --flavor kubeflow --connector aws-prod
$zenml stack register kubernetes-prod -o kubeflow-orch -a s3-prod --set
Register the stack3 commands
$zenml service-connector register gcp-prod --type gcp -i
$zenml orchestrator register vertex-orch --flavor vertex --connector gcp-prod
$zenml stack register vertex-gcp -o vertex-orch -a gcs-prod --set
Register the stack3 commands
$zenml service-connector register aws-eu --type aws -i
$zenml orchestrator register sagemaker-orch --flavor sagemaker --connector aws-eu
$zenml stack register sagemaker-aws -o sagemaker-orch -a s3-eu --set
Register the stack3 commands
$zenml service-connector register gcp-staging --type gcp -i
$zenml orchestrator register airflow-orch --flavor airflow --connector gcp-staging
$zenml stack register airflow-staging -o airflow-orch -a gcs-staging --set
Register the stack3 commands
$zenml service-connector register azure-eu --type azure -i
$zenml orchestrator register azureml-orch --flavor azureml --connector azure-eu
$zenml stack register azureml-eu -o azureml-orch -a blob-eu --set
churn_predictorv18 of 18
6c5e0a14 · sklearn 1.4 · 2.4 MB
Version Evolution18 versions · +4.2pt since v1
v1v8 · DEVv12 · STAGEv18 · PROD
Metadata4 fields
accuracy0.926
f1 score0.911
train rows47,392
promotedv18 → PROD
LineageProduced by step predict_on_endpoint · used by model churn_predictor·v18 · deployed to kubernetes-prod
Where it runs3 envs · 4 endpoints
PROD
v18vertex · 2 endpoints
99.97% uptime
STAGE
SHADOW
v18k8s · shadow traffic
promoted 3h ago
CANARY
v18·rc2vertex · 5% rollout
accuracy +0.4pt vs v18
Registry42 models · 248 artifacts
last promoted 3h ago
INSIDE THE @STEPUse PyTorch in any @step.Bring your own. ZenML wraps it — you don't change your training loop.
torch 2.4.1 · CUDA 12.1
training_pipeline.py
@step · zenml
import torchfrom zenml import step @step(enable_cache=False)def train_model(    X: torch.Tensor, y: torch.Tensor) -> torch.nn.Module:    model = torch.nn.Sequential(        torch.nn.Linear(784, 256), torch.nn.ReLU(),        torch.nn.Linear(256, 10),    )    return model  # auto-versioned by ZenML
What ZenML gives youautomatic versioningGPU pinningany torch version
Good fitCustom training loops and research code that changes often.
Trade-offLarge CUDA images mean slower cold starts on remote stacks.
INSIDE THE @STEPTrain Keras models in any @step.ZenML snapshots your SavedModel automatically — no boilerplate.
tensorflow 2.16.1 · Keras 3
train_classifier.py
@step · zenml
import tensorflow as tffrom zenml import step @step(enable_cache=False)def train_classifier(    X_train: tf.Tensor, y_train: tf.Tensor) -> tf.keras.Model:    model = tf.keras.Sequential([        tf.keras.layers.Dense(128, activation='relu'),        tf.keras.layers.Dense(10, activation='softmax'),    ])    return model  # saved as SavedModel artifact
What ZenML gives youSavedModel artifactKeras 3 supportauto caching
Good fitProduction Keras models with a stable SavedModel format.
Trade-offHeavier dependency — version pinning matters across environments.
INSIDE THE @STEPFit any sklearn estimator in a @step.ZenML auto-pickles your model and registers it in the model registry.
scikit-learn 1.5.2
pipelines/training.py
@step · zenml
import pandas as pdfrom sklearn.ensemble import RandomForestClassifierfrom typing_extensions import Annotatedfrom zenml import ArtifactConfig, step @stepdef model_trainer(    dataset_trn: pd.DataFrame,) -> Annotated[RandomForestClassifier,               ArtifactConfig(is_model_artifact=True)]:    model = RandomForestClassifier()    model.fit(dataset_trn.drop('target', axis=1), dataset_trn['target'])    return model
What ZenML gives youpickle materializermodel registryArtifactConfig
Good fitTabular models where fast iteration beats raw scale.
Trade-offPickled estimators are Python-version sensitive across envs.
INSIDE THE @STEPReturn DataFrames from any @step.ZenML materializes your DataFrame as a versioned artifact — no manual saving.
pandas 2.2.2
steps/data_loader.py
@step · zenml
import pandas as pdfrom sklearn.datasets import load_breast_cancerfrom typing_extensions import Annotatedfrom zenml import step @stepdef data_loader(    random_state: int,) -> Annotated[pd.DataFrame, 'dataset']:    df = load_breast_cancer(as_frame=True).frame    df.reset_index(drop=True, inplace=True)    return df  # versioned DataFrame artifact
What ZenML gives youDataFrame artifactversioned by runlazy loading
Good fitFeature prep and ETL when the dataset fits in memory.
Trade-offIn-memory DataFrames strain on very large datasets.
INSIDE THE @STEPFine-tune any HF model in a @step.ZenML saves your model checkpoint as a versioned artifact on any cloud.
transformers 4.44.2 · PEFT 0.12
steps/finetune.py
@step · zenml
from transformers import AutoModelForCausalLMfrom peft import get_peft_model, LoraConfigfrom zenml import step @step(enable_cache=False)def finetune_step(    base_model_name: str, datasets_dir: str) -> str:    model = AutoModelForCausalLM.from_pretrained(base_model_name)    model = get_peft_model(model, LoraConfig(r=16, lora_alpha=32))    # trainer.train() — ZenML tracks the checkpoint    return datasets_dir
What ZenML gives youLoRA / PEFTcheckpoint artifactremote GPU stack
Good fitFine-tuning transformers and LLMs with PEFT or LoRA.
Trade-offCheckpoints are large — budget artifact-store space and transfer.
INSIDE THE @STEPTrain XGBoost models in a @step.ZenML registers your Booster as a model artifact with full lineage.
xgboost 2.1.1
steps/train_xgb.py
@step · zenml
import pandas as pdimport xgboost as xgbfrom zenml import step @stepdef train_xgb_model(    df_train: pd.DataFrame, label_col: str = 'target') -> xgb.Booster:    dtrain = xgb.DMatrix(        df_train.drop(columns=[label_col]), df_train[label_col]    )    return xgb.train({'max_depth': 6}, dtrain, num_boost_round=100)
What ZenML gives youBooster artifactfull lineagecache-aware
Good fitStrong tabular baselines with minimal tuning.
Trade-offBooster objects need the matching XGBoost version to reload.
INSIDE THE @STEPRun LightGBM training in a @step.ZenML saves your LGBMModel as an artifact and links it to the run.
lightgbm 4.5.0
steps/train_lgbm.py
@step · zenml
import lightgbm as lgbimport pandas as pdfrom zenml import step @stepdef train_lgbm(    df_train: pd.DataFrame, label: str = 'target') -> lgb.LGBMClassifier:    clf = lgb.LGBMClassifier(n_estimators=300, learning_rate=0.05)    clf.fit(df_train.drop(columns=[label]), df_train[label])    return clf
What ZenML gives yousklearn APIGPU treesversioned model
Good fitFast gradient boosting on wide tabular data.
Trade-offGPU builds need extra setup in the orchestrator image.
INSIDE THE @STEPPass ndarrays between @steps.ZenML serializes NumPy arrays automatically — share them across steps.
numpy 2.1.0
steps/preprocess.py
@step · zenml
import numpy as npfrom typing_extensions import Annotatedfrom zenml import step @stepdef normalize_features(    X_raw: np.ndarray,) -> tuple[    Annotated[np.ndarray, 'X_norm'],    Annotated[np.ndarray, 'mean'],]:    mean = X_raw.mean(axis=0)    return (X_raw - mean) / X_raw.std(axis=0), mean
What ZenML gives youndarray artifacttuple outputscontent-hashed
Good fitPassing numerical arrays cleanly between steps.
Trade-offRaw ndarrays carry no schema — annotate outputs for clarity.
INSIDE THE @STEPUse Polars DataFrames in a @step.ZenML materializes Polars DataFrames — fast ETL without Spark overhead.
polars 1.9.0
steps/feature_eng.py
@step · zenml
import polars as plfrom typing_extensions import Annotatedfrom zenml import step @stepdef build_features(    raw_path: str,) -> Annotated[pl.DataFrame, 'features']:    return (        pl.scan_parquet(raw_path)        .filter(pl.col('value') > 0)        .collect()    )
What ZenML gives youParquet artifactlazy executionfast ETL
Good fitLarge ETL that's too big for pandas, too small for Spark.
Trade-offNewer ecosystem — fewer integrations than pandas.
INSIDE THE @STEPLog experiments to W&B from a @step.ZenML connects your stack's experiment tracker — one decorator, full lineage.
wandb 0.18.3
steps/train_with_tracking.py
@step · zenml
import wandbfrom zenml import stepfrom zenml.integrations.wandb.flavors import WandbExperimentTrackerSettings @step(    experiment_tracker='wandb_tracker',    settings={'experiment_tracker.wandb':        WandbExperimentTrackerSettings(tags=['training', 'v2'])})def train_and_log(X_train, y_train) -> float:    wandb.log({'loss': 0.42, 'accuracy': 0.91})    return 0.91
What ZenML gives youexperiment trackersweep supportrun linking
Good fitRich experiment tracking and sweep visualization.
Trade-offAdds an external service and API key to manage.
1f42d62dproduction-gpu-poolHIGH LOAD
GPUs75%
6/ 8
CPU (Cores)75%
18/ 24
Memory (GB)75%
48/ 64
Parallel Pipelines100%
21/ 21
Parallel Steps68%
68/ 100
A10050%
4/ 8
Active Jobs
step_0321f42d62d
pipeline_032 #0045
2 GPUs · 4 CPU · +1
19s
CRITICAL
step_0334e7a34bc
pipeline_032
4 GPUs · 8 CPU · +1
45s
HIGH
step_0348c5e1abc
pipeline_032
1 GPU · 16 GB · +1
59s
MEDIUM
CONNECTEDkubernetesdockeraws_ec2google_cloudazure
5 active
RECORDED VS REPLAYReplay the fix against the 23 recorded failures.
23 executions · repeats ×3
RECORDEDv2.2 — production recordings
EXECUTIONS23
ESCALATED CORRECTLY0 / 23
COST / RUN$0.14
PROTECTIONS TRIPPED
REPLAYv2.3 — fix: escalate on 5xx
EXECUTIONS
23same
ESCALATED CORRECTLY
21 / 23+21
COST / RUN
$0.12−11%
PROTECTIONS TRIPPED
0held
PASS — merge the fix.21 / 23 escalate correctly · 0 forbidden regressions · the experiment now guards every PR.
RECORDED VS REPLAYFork at the failing tool call — is it the tool or the agent?
1 execution · repeats ×10
RECORDEDtr-8f3a91c2 — recorded failure
RESOLVED0 / 10
“TRY AGAIN LATER”10
TOOL RETRIES6
DURATION78s
REPLAYfork — refund tool stubbed healthy
RESOLVED
10 / 10+10
“TRY AGAIN LATER”
0−10
TOOL RETRIES
0−6
DURATION
12s−85%
Fault isolated.With a healthy tool the agent resolves every time · the bug is the 5xx handling, not the tool.
RECORDED VS REPLAYSame 200 executions, replayed on a cheaper model.
200 executions · 12m total
RECORDEDproduction — gpt-5.4
EXECUTIONS200
OUTPUTS IDENTICAL
COST$210
LATENCY P951.9s
REPLAYreplay — gemini-flash
EXECUTIONS
200same
OUTPUTS IDENTICAL
192 / 2008
COST
$34−84%
LATENCY P95
1.1s−42%
Ship the swap.192 / 200 identical answers at a sixth of the cost · review the 8 diverging runs first.
RECORDED VS REPLAYThe recorded execution — the world every replay runs against.
recorded Jul 13 · 8 checkpoints
RECORDEDtr-8f3a91c2 — production recording
CHECKPOINTS8
TOOL CALLS4
COST$0.14
STATUSfailed
REPLAYselect a replay to compare
CHECKPOINTS
8same
TOOL CALLS
4same
COST
$0.14same
STATUS
failedsame
Immutable recording.Every model and tool call captured · replay forks from any checkpoint · pick a replay above.
Wrap your harness with one lineEvery model and tool call becomes a replayable recording.
research_agent · run #4127llm_writer · run #8341audit_company · run #2014wait_for_approval · run #1198news_scout · run #6720
first_working_flow.pyKITARU
from kitaru import checkpoint, flow

@checkpoint
def gather_sources(topic: str) -> str:
    return f"Source notes on {topic}."

@checkpoint
def summarize(notes: str) -> str:
    return f"Summary: {notes.split(':')[0].lower()}."

@flow
def research_agent(topic: str) -> str:
    notes = gather_sources(topic)
    return summarize(notes)
Execution timeline
flowllmtoolcheckpoint
Span
0s30s1m1m30s2m
research_agent
gather_sources
chkpt.notes
summarize
runtime: kubernetes · 1 checkpoint persisted · resumableLIVE · 1m 47s
flow_with_llm.pyKITARU
import kitaru
from kitaru import checkpoint, flow

@checkpoint
def write_draft(topic, outline):
    return kitaru.llm(
        f"Write a paragraph about {topic} from {outline}.",
        model="fast", name="draft_call",
    )

@flow
def llm_writer(topic: str) -> str:
    outline = kitaru.llm(
        f"Create a 3-bullet outline about {topic}.",
        model="fast", name="outline_call",
    )
    return write_draft(topic, outline)
Execution timeline
flowllmtoolcheckpoint
Span
0s3s6s9s12s
llm_writer
outline_call
chkpt.outline
draft_call
chkpt.draft
runtime: kubernetes · 2 checkpoints persisted · resumableCOMPLETED · 11s
stage_2_multi_domain.pyKITARU
from kitaru import checkpoint, flow

@checkpoint
def check_hr_compliance(prompt=HR_PROMPT):
    return _run_domain_turn(prompt, domain="hr")

@checkpoint
def check_it_security(prompt=IT_PROMPT):
    return _run_domain_turn(prompt, domain="it_security")

@checkpoint
def synthesize_report(hr, it, vendors, ins):
    return _run_agent(SYNTHESIS_PROMPT.format(...))

@flow
def audit_company():
    hr, it, v, ins = run_domain_checks()
    return synthesize_report(hr, it, v, ins)
Execution timeline
flowllmtoolcheckpoint
Span
0s2m4m6m8m
audit_company
check_hr_compliance
check_it_security
check_vendor_contracts
check_insurance
chkpt.findings
synthesize_report
runtime: kubernetes · 4 checkpoints persisted · resumableLIVE · 6m 18s
wait_and_resume.pyKITARU
import kitaru
from kitaru import checkpoint, flow

@checkpoint
def draft_release_note(topic: str) -> str:
    return f"Draft about {topic}."

@flow
def wait_for_approval_flow(topic: str) -> str:
    draft = draft_release_note(topic)
    approved = kitaru.wait(
        name="approve_release",
        schema=bool,
        question=f"Approve {topic}?",
        timeout=3600,
    )
    if approved is False:
        return f"REJECTED: {topic}"
    return publish_release_note(draft, details)
Execution timeline
flowllmtoolcheckpoint
Span
0s30s1m1m30s2m
wait_for_approval_flow
draft_release_note
chkpt.draft
wait.approve_release
publish_release_note
runtime: kubernetes · compute released · resumable via CLIPAUSED · awaiting input
scout.pyKITARU
from kitaru import checkpoint, flow
from kitaru.adapters.pydantic_ai import KitaruAgent
from pydantic_ai import Agent

scout_agent = KitaruAgent(
    Agent(MODEL, name="news_scout",
          tools=[search_news, search_twitter,
                 investigate, fetch_url]),
    granular_checkpoints=True,
)

@checkpoint
def publish_report(text: str) -> str:
    return text

@flow
def news_scout(interests: list[str]) -> str:
    result = scout_agent.run_sync(
        build_user_prompt(interests),
    )
    return publish_report(result.output)
Execution timeline
flowllmtoolcheckpoint
Span
0s1m2m3m3m30s
news_scout
agent.plan
search_news
search_twitter
investigate
fetch_url
agent.summarize
publish_report
runtime: kubernetes · 12 checkpoints persisted · replayableCOMPLETED · 3m 22s
EXECUTION CHECKPOINTSResume from any checkpoint after a crash, rate-limit, or eviction.
report_agent · ex_8a2f
EXECUTION TIMELINE
checkpointfailureresume
gather12s
llm.outline33s
chkpt.notes0.4s
llm.write1m 14s
resumed+11s
draft42s
chkpt.draft0.3s
persistqueued
429 RATE-LIMIT↗ at 1m 14s
openai api · llm.write
RESUMED FROM CHECKPOINT 314:02:59
$kitaru flow resume ex_8a2f --from chkpt.notes
Saved47s·2 LLM callsnot re-issued
ex_8a2f·6 checkpoints·38m 12s
resumed
HARNESStyped agent logic
Harness stays.Kitaru wraps around it.
KITARU ADDSdurable run layer
KitaruAgent(agent)
Kitaru runtimeouter layer
flowone durable run
checkpointsaved between steps
waitpause & resume
replayfrom a boundary
PydanticAI
typed depstoolsoutput
Model + tools
OpenAIMCPdb
Good fitTyped agents where you want schema validation on every step.
Trade-offAdds a Pydantic dependency and some per-call overhead.
KITARU ADDSdurable run layer
KitaruAgent(runner)
Kitaru runtimeouter layer
flowone durable run
checkpointsaved between steps
waitpause & resume
replayfrom a boundary
OpenAI Agents
toolshandoffsoutput
Model + tools
OpenAIMCPdb
Good fitMulti-agent runs with handoffs via the Agents SDK Runner.
Trade-offTied to OpenAI-hosted models and their rate limits.
KITARU ADDSdurable run layer
KitaruAgent(graph)
Kitaru runtimeouter layer
flowone durable run
checkpointsaved between steps
waitpause & resume
replayfrom a boundary
LangGraph
statetoolsedges
Model + tools
OpenAIMCPdb
Good fitBranching multi-step graphs that need explicit state.
Trade-offGraph state must stay JSON-serializable to checkpoint cleanly.
KITARU ADDSdurable run layer
KitaruAgent(session)
Kitaru runtimeouter layer
flowone durable run
checkpointsaved between steps
waitpause & resume
replayfrom a boundary
Anthropic
messagestoolsstream
Model + tools
OpenAIMCPdb
Good fitLong Claude tool-use sessions with expensive context to rebuild.
Trade-offCheckpoints land between turns — mid-stream tokens aren't saved.
KITARU ADDSdurable run layer
KitaruAgent(fn)
Kitaru runtimeouter layer
flowone durable run
checkpointsaved between steps
waitpause & resume
replayfrom a boundary
Custom loop
any callablesync / async
Model + tools
OpenAIMCPdb
Good fitAny Python callable — no framework lock-in at all.
Trade-offYou define the checkpoint boundaries; Kitaru can't infer them.
AFTER A CRASHrun #4127 · resumed
resumed
SPAN
0s15s30s45s60s
classify13s
checkpointsaved
tool.lookupcrashed
resumed+8s
tool.lookup35s
artifactsaved
with kitaruresumed in 8s · classify & model call preserved
withoutrestart from zero · repeat the model call · ~2m lost
AFTER A CRASHrun #7834 · resumed
resumed
SPAN
0s12s24s36s48s
triage9s
checkpointsaved
web_searchcrashed
resumed+6s
web_search29s
responsesaved
with kitaruresumed in 6s · triage & first tool call preserved
withoutrestart from zero · repeat the model call · ~2m lost
AFTER A CRASHrun #2291 · resumed
resumed
SPAN
0s18s36s54s72s
route_intent17s
checkpointsaved
tool_nodecrashed
resumed+11s
tool_node40s
statesaved
with kitaruresumed in 11s · graph state & routing preserved
withoutrestart from zero · re-invoke full graph · ~2m lost
AFTER A CRASHrun #3019 · resumed
resumed
SPAN
0s13s26s39s52s
classify_intent10s
checkpointsaved
tool_use_blockcrashed
resumed+6s
tool_use_block31s
messagesaved
with kitaruresumed in 6s · context window & tool call preserved
withoutrestart from zero · rebuild context · ~2m lost
AFTER A CRASHrun #1102 · resumed
resumed
SPAN
0s16s32s48s64s
step_one16s
checkpointsaved
tool_callcrashed
resumed+9s
tool_call34s
outputsaved
with kitaruresumed in 9s · step progress & tool call preserved
withoutrestart from zero · repeat all steps · ~2m lost
DURABLE BY DEFAULTVersioned deployments. Promote, shadow, or roll back.
support_agent · v3.2.1
checkpointreplaywait / resumefan-out
VERSION HISTORY
v1
v2
v3rolled back
v4
PROD
100% traffic
v3.2.1Hamza · deployed 3h ago
HISTORY
v3.2.0· 2d
v3.1.5· 5d
CANARY
5% shadow
v3.2.2-rcPriya · deployed 32m ago
HISTORY
v3.2.1-rc· 6h
v3.2.0-rc· 3d
DEV
dev only
v3.3.0-devAdam · deployed 8m ago
HISTORY
v3.2.9-dev· 1h
v3.2.8-dev· 5h
5 deployments · 3 envs · last promotion 3h agohealthy

Trusted by teams shipping ML pipelines and AI agents

AXA
JetBrains
ADEO
Leroy Merlin
Brevo
Safran
AECOM
Airbus Defence & Space
Rohlik
Knuspr
Maven Robotics
CrossScreen Media
GEMA
Homa Games
Koble
IKEA
Sciemo
Vodafone
Stepstone
Neara
Rivian
Happening XYZ
Veridas
AXA
JetBrains
ADEO
Leroy Merlin
Brevo
Safran
AECOM
Airbus Defence & Space
Rohlik
Knuspr
Maven Robotics
CrossScreen Media
GEMA
Homa Games
Koble
IKEA
Sciemo
Vodafone
Stepstone
Neara
Rivian
Happening XYZ
Veridas
Two products · one team

ML systems today. Agent systems tomorrow. One engineering team underneath both.

ZenML — ML/AI Orchestration

The open-source platform for production ML systems.

Orchestrate workflows across your existing tools, clouds, and environments. Modular, agnostic, no lock-in.

  • Pipelines and stacks across any cloud
  • Model registry, lineage, and reproducibility built in
  • Open source — your stack, your data, your governance
Explore ZenML

Kitaru — Agent Evals

Turn agent failures into regression tests.

Your agent’s real traces become frozen, replayable worlds. Score what happened, replay your real code against it, and keep every fix as a regression test. Self-hosted, framework-agnostic, no lock-in.

  • Score thousands of traces — the agent never runs
  • Replay with one thing changed — model, tool, or prompt
  • Every fix becomes a regression test that guards CI
Explore Kitaru

The platform advantage

One foundation. ML pipelines and AI agents.

78%

faster time‑to‑market

65%

reduced engineering overhead

3x

more workflows in production

5x

faster time to production

Unified workflow orchestration dashboard showing ML and agent runs
Artifact and checkpoint versioning view
Infrastructure abstraction across clouds
Smart caching and deduplication across runs
Governance and security dashboard

Your stack, not ours

Run in your VPC, point at your object store, train on your clusters. The platform is a metadata layer — your artifacts, prompts, and code stay inside your infrastructure end to end. No lock-in on either side.

From local prototype to production

Stop rewriting code to move between environments. The same pipeline step or agent flow runs locally for debugging and on Kubernetes for production — without changing your logic. The platform handles the wiring.

Lineage and replay across both workspaces

Every execution is recorded and every artifact version is tracked in the same metadata store. When something breaks, replay the exact recorded run to reproduce it — and the fix becomes a regression test that guards against it coming back.

Open source, enterprise ready

Apache 2.0 from day one, with thousands of teams running it in production. Self-host forever, or adopt the managed control plane when you need governance, SSO, and an SLA. SOC2 and ISO 27001 certified.

Pick your workspace and start shipping.

Open source at the core. ML pipelines, agent flows, or both — same plans, same control plane.

Works with the tools you already use

60+ integrations across the AI ecosystem — from scikit-learn to LangGraph, PyTorch to OpenAI Agents SDK.

Apache AirflowAmazon S3ArgillaAutoGenAWSAWS StrandsMicrosoft AzureAzure Blob StorageAzure Container RegistryAzureML PipelinesBentoMLCometCrewAIDatabricksDatabricks DeploymentDeepchecksDiscordDockerElastic Container RegistryEvidentlyFacetsFeastGoogle Cloud Vertex AI PipelinesGithub ActionsGitHub Container RegistryGoogle ADK AgentGoogle Artifact RegistryGoogle CloudGoogle Cloud Storage (GCS)Great ExpectationsHaystackHugging FaceHugging Face (Inference Endpoints)HyperAIKanikoKubeflowKubernetesLabel StudioLangChainLangGraphLightGBMLightning AILlamaIndexMLflowModalNeptuneNeuralProphetOpenAI Agents SDKPigeonPillowProdigyPydanticAIPyTorchPyTorch LightningSagemaker PipelinesSeldonSemantic Kernelscikit-learn (sklearn)Skypilot VMSlackTektonTensorBoardTensorFlowWeights & BiasesWhyLabs whylogsXGBoost

Whitepaper

ZenML as your Enterprise-Grade AI Platform

We have put down our expertise around building production-ready, scalable AI platforms, building on insights from our top customers.

Customer Stories

How engineering teams cut time-to-production and simplify their AI infrastructure.

Track production ML and AI deployments across the industry

See the LLMOps database →

HashiCorp
ZenML offers the capability to build end-to-end ML workflows that seamlessly integrate with various components of the ML stack. This enables teams to accelerate their time to market by bridging the gap between data scientists and engineers.
Harold Gimenez

Harold Gimenez

SVP R&D at HashiCorp

Salesforce
ZenML allows orchestrating ML pipelines independent of any infrastructure or tooling choices. ML teams can free their minds of tooling FOMO from the fast-moving MLOps space, with the simple and extensible ZenML interface.
Richard Socher

Richard Socher

Former Chief Scientist Salesforce and Founder of You.com

ADEO
ZenML allowed us a fast transition between dev to prod. It's no longer the big fish eating the small fish – it's the fast fish eating the slow fish.
François Serra

François Serra

ML Engineer / ML Ops / ML Solution architect at ADEO Services

Stanford University
Many teams still struggle with managing models, datasets, code, and monitoring as they deploy ML models into production. ZenML provides a solid toolkit for making that easy in the Python ML world.
Chris Manning

Chris Manning

Professor of Linguistics and CS at Stanford

WiseTech Global
Thanks to ZenML we've set up a pipeline where before we had only Jupyter notebooks. It helped us tremendously with data and model versioning.
Francesco Pudda

Francesco Pudda

Machine Learning Engineer at WiseTech Global

MadeWithML
ZenML allows you to quickly and responsibly go from POC to production ML systems while enabling reproducibility, flexibility, and above all, sanity.
Goku Mohandas

Goku Mohandas

Founder of MadeWithML

No compliance headaches

Your VPC, your data

ZenML is a metadata layer on top of your existing infrastructure, meaning all data and compute stays on your side.

ZenML architecture — metadata layer on top of your infrastructure
SOC2 Type II certifiedISO 27001 certified

ZenML is SOC2 and ISO 27001 Compliant

We Take Security Seriously

ZenML is SOC2 and ISO 27001 compliant, validating our adherence to industry-leading standards for data security, availability, and confidentiality in our ongoing commitment to protecting your ML workflows and data.

Getting Ahead in Pipelines, Agents & Evals?

Subscribe to the ZenML newsletter and receive regular product updates, tutorials, examples, and more.

We care about your data in our privacy policy.

Support

Frequently asked questions

Everything you need to know about the product.

What is the difference between ZenML and other machine learning orchestrators?
ZenML doesn't take an opinion on the orchestration layer. Start writing locally, deploy on any orchestrator. We support many orchestrators natively and can be extended to work with custom orchestrators. Read more about how ZenML compares to orchestrators.
Does ZenML integrate with my MLOps stack?
Yes! ZenML supports Kubernetes, AWS, GCP Vertex AI, Kubeflow, Apache Airflow, and many more. Artifact, secrets, and container storage for all major cloud providers.
Does ZenML help in GenAI / LLMOps use-cases?
Yes, ZenML is fully compatible and intended for productionalizing LLM applications, and Kitaru extends this to evaluating and regression-testing live agents. We have examples with LlamaIndex, OpenAI, LangChain, and more. Check out our projects for real-world examples.
What is Kitaru?
Kitaru is ZenML's agent experimentation platform. It records your agents' real production runs as replayable executions. You can score a recording without ever running the agent again, or replay your real code against the recorded world — with one thing changed, like a model, tool, or prompt — to see what would have happened. Re-run a replay in CI and it becomes a regression test. Read more in the Kitaru docs.
How can I build my MLOps/LLMOps platform using ZenML?
Start simple with our user guides, then extend with experiment trackers, model deployers, model registries and more from the stack components library.
What is the difference between the open source and Pro product?
The core framework is Apache 2.0 on GitHub. Pro offers a managed version plus Pro-only features for scaling teams. Learn more on the comparison page.

Ship agents you can prove, and pipelines you can trust.

  • Open-source foundation, no vendor lock-in
  • Works with any infrastructure
  • Upgrade to managed Pro features
Dashboard displaying machine learning models with version tracking