OttoFlow · Open Source · Kubernetes-native

Deterministic AI workflows for Kubernetes

Collect. Analyze. Publish.

One explicit DAG. One bounded AI step — never the whole loop.

How OttoFlow works

collect

ResourceQuery, CEL expressions, PromQL — deterministic, no LLM involved.

analyze
llm judgement

The one Agent step. Sees a computed summary only — never a raw pod spec, never your kubeconfig.

publish/act

Report, mutation, or API call — gated by matchConditions, back to deterministic.

The Problem

Static runbooks, or a kubeconfig and a prayer

For a decade, automation meant a runbook: anticipate a failure, codify the response, run it on repeat. AI broke that ceiling — and the industry's answer swung to the opposite extreme.

Non-deterministic

Free-form prompts produce inconsistent results — hard to test, debug, or trust at scale.

Unpredictable costs

Stuffing whole tool catalogs into prompts inflates tokens, hallucinations, and bills.

Expanded attack surface

Open-ended agents with broad tool access widen blast radius and break governance.

The industry's response to these walls has swung between two extremes:

The old norm

The runbook shrugs

Deterministic and reviewable, but it handles only the failure its author anticipated. Twelve restarts, an OOM kill, this morning's rollout — a static pipeline can count them, not weigh them.

The overcorrection

The free agent

Hand an LLM a kubeconfig and let it explore. Every run differs — nothing to code-review, nothing to diff when it breaks — and it re-derives facts a single API call already knew.

OttoFlow's answer: judgement is one step in an explicit DAG — not the system itself.

How It Works

A workflow is a DAG. The model sees only what the graph hands it.

Independent steps resolve and run concurrently; the agent step receives a computed summary, never a raw pod spec — what it can see is declared in YAML, in code review, not decided by the model at runtime.

computed summary only verdict, 1 action RESOURCEQUERY collectPods CEL EXPRESSION failure signals AGENT STEP triagePods → 1 pod, 1 action OPENREPORT publishTriage gated: unhealthy>0
The pod-triage sample workflow: two deterministic collectors run in parallel, converge into a single bounded agent step, then publish — gated by matchConditions so a healthy cluster never invokes the LLM at all.
Controller

Reconciles Workflow/WorkflowRun CRDs, watches cluster events, spawns runner Jobs.

Workflow Runner

Resolves the DAG, runs independent steps concurrently, retries what fails, enforces expression cost budgets.

Agent Executor

Sandboxed service for LLM interpretation only — strict data boundaries, mTLS from the runner.

Highlights

Governed by construction, not by prompt

Declarative

A workflow is a Kubernetes CRD — reviewed, diffed, and versioned like any other YAML.

Deterministic

Explicit dependencies, parallel step batches, configurable retries, per-expression cost budgets.

Scoped data, not a kubeconfig

Agent steps see exactly the fields the workflow declares — never a raw pod spec, never live API access.

Sandboxed & least-privilege

Per-step RBAC, mTLS between controller/runner/agent-executor, scoped MCP tool access per step.

Multi-provider LLM

OpenAI, Anthropic, Gemini, Azure OpenAI, or a local llama.cpp-compatible server — swap with a flag.

Inherits Kyverno's DNA

Same architectural philosophy as the policy engine we created — declarative, reviewable, familiar CEL.

Samples

Five workflows you'll actually run

All under samples/workflows/production/ — 70+ more cover cost, security, and compliance automation.

WorkflowWhat it does
cluster-overviewPure-CEL cluster snapshot — pod phases, per-namespace CPU/memory. No LLM, runs anywhere.
pod-triageCEL extracts per-pod failure signals; the LLM picks the single highest-priority pod and next action.
resource-hygieneDetects 14 categories of unused or stale resources; LLM writes the cleanup report.
cost-analyzerRight-sizing from resource specs plus Prometheus P95 usage, per-workload $ savings.
workload-troubleshooterOne failing pod: events + logs → LLM root-cause. In-cluster only.

Browse all samples on GitHub →

terminal — zero prerequisites
# pure-CEL, no LLM, no cluster changes
ottoflow run https://raw.githubusercontent.com/nirmata/ottoflow/main/samples/workflows/production/cluster-overview.yaml

# adds one bounded agent step
GEMINI_API_KEY=AIza... \
  ottoflow run -f .../samples/workflows/production/pod-triage.yaml

Install

CLI first, cluster when you're ready

CLI (local mode)
brew install nirmata/tap/ottoflow

# runs in-process against your kubecontext
# read-only -- no controller, no CRDs, nothing to clean up
ottoflow run cluster-overview.yaml
Helm (in-cluster)
helm install ottoflow oci://ghcr.io/nirmata/ottoflow \
  --namespace ottoflow --create-namespace

kubectl apply -f samples/workflows/production/cluster-overview.yaml
ottoflow run cluster-overview -n ottoflow
Cosign-signed releases, SBOMs, and SLSA provenance — the supply chain is part of the product.

The Full Stack

Built on the architecture Kyverno proved

OttoFlow shares its governance primitives — per-step RBAC, admission-style webhooks, the same CEL — with the policy engine we created. Declarative and reviewable, all the way down.

Where It Fits

OttoFlow occupies a new seat

Argo runs deterministic jobs with no agent primitives. kagent runs agents with no deterministic DAG. OttoFlow is both at once.

Job Orchestration
Argo Workflows
Deterministic workflow DAG
Native AI / agent steps
Direct (non-LLM) tool calls

Excellent for CI and data pipelines. No agentic or LLM primitives — every step is a container.

Agent Runtime on K8s
kagent
Deterministic workflow DAG
Native AI / agent steps
Direct (non-LLM) tool calls

Strong multi-agent runtime from Solo.io. Agents are autonomous loops; tools are called through the LLM.

Give judgement a boundary.

Run a sample against your own kubecontext in under a minute — no controller, nothing to install, nothing to undo.