Deployments
Version and share durable flow entrypoints for remote invocation.
A deployment is a reusable, versioned entrypoint for a Kitaru flow. Think of it like pinning a recipe card to the wall: the flow source is the recipe, a deployment version is one saved copy of that recipe, and an invocation starts a fresh execution from that saved copy.
You can create deployments from three surfaces:
CLI:
kitaru deploy path/to/file.py:flow_namePython SDK:
flow_name.deploy(...)MCP:
kitaru_deployments_deploy(target="path/to/file.py:flow_name", ...)
The CLI also has kitaru build path/to/file.py:flow_name for the narrower case where you want to create an immutable deployment version without attaching a route yet. Think of it as putting a sealed build artifact on the shelf. It exists, it has a version, but nobody reaches it through default, stable, or canary until you attach a tag later with kitaru flow tag.
You can then invoke the deployed flow without the original target path:
CLI:
kitaru invoke flow_namePython SDK:
flow_name.invoke(...)ordeployment.invoke(...)MCP:
kitaru_deployments_invoke(flow="flow_name", ...)
If you want a step-by-step producer/consumer walkthrough, see the Deploy and invoke flows guide.
When you deploy from source targets (path.py:flow_name) via CLI, run kitaru init in the repository first so build/deploy-from-source metadata can be resolved correctly.
What gets saved
Deploying a flow creates a Kitaru-managed saved snapshot that Kitaru treats as an immutable deployment version. Kitaru records the public flow name, an integer version, representative deployment-time input values, deploy-time image config (when provided), the stack context, and any public routing tags.
Deployment-time inputs should be representative values. They let Kitaru prepare the saved deployment snapshot, especially for flows whose shape depends on concrete parameters. Later invocations can override those values by passing new inputs.
Deploy-time image config follows the same shape across CLI, SDK, and MCP: a base image string or an object matching kitaru.ImageSettings.
Image config is part of the saved deployment snapshot. Later kitaru invoke or .invoke(...) calls can override flow inputs for each execution, but they do not rewrite the deployment image.
Each kitaru deploy call attaches exactly one routing tag at deploy time. If you want to add another tag later, or move an existing route after testing, use kitaru flow tag against the deployed version instead of redeploying.
Auto-versioning
Kitaru assigns deployment versions automatically per flow:
The first deployment of
research_agentbecomes version1.The next deployment of
research_agentbecomes version2.Another flow gets its own independent version sequence.
Internally, Kitaru injects the version into the backend snapshot name using this shape:
For example, research_agent version 3 is stored as:
That name is an implementation detail, but it explains the behavior: Kitaru can scan the existing deployment snapshots for a flow, find the highest v<N>, and allocate the next version. If two deploys race and both try the same next name, Kitaru retries with the next available version.
Tags and routing
Tags are human-readable selectors that point at deployment versions. They are how producers publish a route and consumers invoke it without memorizing version numbers.
There are two tag modes:
Exclusive
The tag can point to only one version at a time. Adding it to a new version moves it away from older versions.
default, stable, prod
Shared
The tag can point to multiple versions. Invoking by that tag is only valid when it resolves to one version.
experiment, team-a, benchmark
The default tag is special:
defaultis reserved by Kitaru.defaultis always exclusive, even if you passexclusive=False.The first deployment of a flow gets
defaultautomatically.defaultcannot be removed.A deployment that still has any exclusive tag cannot be deleted. Move or remove the exclusive tag first. Because
defaultcannot be removed, move it to another version before deleting the old default version.
Concrete routing story:
You deploy
research_agentfor the first time. Kitaru createsv1and tags itdefault.You deploy a new candidate with
--tag canary --exclusive. Kitaru createsv2and tags itcanary.You invoke
kitaru invoke research_agent --tag canaryto testv2.When you are happy, you move the stable route:
That split keeps deploy-time routing simple: create the version with one route, then use kitaru flow tag to mix in later routing changes. For example, you might deploy version 2 with an exclusive canary route, then add a shared benchmark label afterward:
Remote-executable stack requirement
Deployment creation is only supported for stacks that the Kitaru server can execute remotely from a saved snapshot. If the selected stack is local or otherwise not remotely executable by the Kitaru server, deployment creation is rejected (CLI, SDK, and MCP).
This guard keeps deploy-time behavior aligned with invoke/curl behavior.
Invocation model
kitaru invoke is the primary CLI command for deployed flows:
If you omit both --version and --tag, Kitaru tries the implicit default route:
If the flow has no deployments, Kitaru tells you that directly. If deployments exist but none is currently routed as default, invoke with an explicit tag or version, or move default with kitaru flow tag ... --exclusive.
You can pin an exact version when you need reproducibility:
In Python, .invoke() is the remote invocation verb for deployed flows:
A Deployment object invokes its pinned version:
At the client level, use the deployment API when the producer flow object is not imported in the consumer process:
Serverless routing
Deployment invocation starts a new Kitaru execution from a saved deployment version. It does not call a long-lived Python process owned by the producer, and it does not create a separate always-on service for each version.
The route is just: flow name + tag/version selector.
The consumer invokes one flow route, for example
research_agent+stable.Kitaru resolves that route to the saved snapshot for the selected deployment version.
Kitaru starts a normal execution from that saved snapshot and returns a normal execution handle.
That gives a clean producer/consumer split:
The producer owns source code, deploys versions, and moves tags.
The consumer only needs a flow name plus a selector (
default, another tag, or an exact version).There is no long-lived per-version service and no per-deployment token.
Inputs passed at invocation time override the deployment-time defaults for that new execution.
Authentication and Kitaru server access
Deployments do not have per-deployment tokens. Access is controlled by the same active Kitaru server connection that the CLI, SDK, and MCP server already use.
For a remote Kitaru server, authenticate once and choose the project you want to work in:
For headless environments, configure the same connection with environment variables:
For automation, KITARU_AUTH_TOKEN should normally be a service-account API key created with kitaru auth service-accounts create and kitaru auth api-keys create. Those three values are the whole connection puzzle: where the Kitaru server is, how to authenticate to it, and which project to use once you are there. If any piece is missing, commands that need the server fail with a short error telling you what to set. kitaru info shows which connection values Kitaru currently sees.
After that, kitaru invoke, KitaruClient().deployments.invoke(...), and MCP kitaru_deployments_invoke(...) all use the active Kitaru server connection. The invocation request does not carry a separate deployment-specific token.
For shell scripts or CI jobs, kitaru flow deployments curl FLOW generates a copy-pasteable curl command for the active Kitaru server. Kitaru resolves the requested tag or version first, then prints a command that starts a new execution for that resolved deployment version. The generated snippet calls kitaru auth token to get a short-lived server bearer token from your active connection, but the curl generator itself does not inline real token values. That bearer token is temporary; create or rotate long-lived automation credentials with kitaru auth api-keys.
When you generate curl from a tag such as default or stable, the printed command is pinned to the deployment version that tag resolved to at generation time. Regenerate the command if the producer moves the tag later.
Snapshot-backed invocation (kitaru invoke, KitaruClient().deployments.invoke(...), and kitaru flow deployments curl) depends on server workload-manager support. The official zenmldocker/kitaru image already enables this. If you run a custom image or plain ZenML server setup, preserve or configure workload-manager support explicitly (for example via ZENML_SERVER_WORKLOAD_MANAGER_IMPLEMENTATION_SOURCE).
Runtime secrets for the flow itself should live in Kitaru secrets or stack configuration, not in deployment tags or invocation examples.
Worked example: producer deploys and shares
A producer has a flow in flows/research.py:
They deploy the first default version:
They deploy a canary candidate:
They inspect versions and promote the canary to the stable route:
They can now tell consumers: "Invoke research_agent with tag stable."
Worked example: consumer invokes
A CLI consumer invokes the shared route:
A Python consumer invokes the same route without importing the producer's source module:
An MCP-capable assistant can do the same with structured tool input:
Use kitaru_deployments_list(flow="research_agent") or kitaru_deployments_get(flow="research_agent", tag="stable") when the assistant needs to inspect the available routes before invoking.
Last updated
Was this helpful?