OttoFlow enables scalable and production-ready AI workflows on Kubernetes. You define a workflow as a Kubernetes CRD, and OttoFlow executes it as a DAG (directed acyclic graph) that mixes deterministic CEL, PromQL, K8s API queries, and LLM agents β with LLM calls constrained to the steps that actually need AI. Data collection, aggregation, and publication steps stay deterministic; the LLM is spent only on analysis, and it sees computed summaries rather than raw tool data that blow your context.
Kubernetes agentic applications generally follow a predictable pattern. They:
- Collect: query cluster and workload data.
- Analyze: process and synthesize that data, and
- Publish: execute an action, or publish data or an event.
Offloading this entire loop to high-level prompts or unconstrained agents with cluster access is an anti-pattern: it makes every run non-deterministic, widens the attack surface, and drives up token cost.
OttoFlow codifies the Collect β Analyze β Publish loop into a deterministic
execution pattern, bringing reviewable engineering practices to the AI
orchestration layer. OttoFlow is not a general-purpose agent framework β if you
want free-form agents, use one of those instead.
- β Declarative Kubernetes-native workflows β define workflows as CRDs in YAML.
- β Fast DAG execution β explicit dependency resolution with parallel step batches.
- β Multi-provider LLM support β use OpenAI, Anthropic, etc. or local models with vLLM.
- β Kubernetes and CNCF integrations β query API resources, PromQL, Kagent using A2A, otel, and more.
- β Compiled CEL expressions β sandboxed execution with full K8s and Kyverno CEL library support
- β Multiple step types β ResourceQuery, AgentRef, MCPToolCall, and more (full list).
- β Context optimization β agent steps receive agregated computed summaries, never raw data dumps.
- β
Retry & conditional execution β retry policies and
matchConditionsgating per step. - β CLI with local mode β execute workflows locally against your kubecontext.
- β
Extensive samples β ready-to-run workflows under
samples/.
brew install nirmata/tap/ottoflowSee installation guide for additional options.
The demo OttoFlow workflows used below are safe to execute on your clusters.
If you need a test cluster create one:
kind create cluster --name=ottoflowThe cluster-overview and pod-triage help identify issues. Seed a few deliberately-broken pods first:
kubectl apply -f https://raw.githubusercontent.com/nirmata/ottoflow/main/samples/fixtures/failing-pods.yamlThis creates a crash-looping (OOMKilled) pod, an ImagePullBackOff pod, and two healthy ones β real, differing failures for the workflows to prioritize.
Start with a pure-CEL workflow β no LLM, no API key, nothing to install:
ottoflow run https://raw.githubusercontent.com/nirmata/ottoflow/refs/heads/main/samples/workflows/production/cluster-overview.yamlThis runs in-process against your current kubecontext, read-only β no controller, no CRDs, nothing installed in your cluster, nothing to uninstall.
For details on the data collection, analysis, and reporting view the workflow source.
AI workflows include steps that call LLMs.
pod-triage adds an LLM step. The sample's Agent defaults to Gemini β
set an API key and run it by path, no cloning or --workflow-dir needed:
GEMINI_API_KEY=AIza... \
ottoflow run -f https://raw.githubusercontent.com/nirmata/ottoflow/main/samples/workflows/production/pod-triage.yamlUse https://aistudio.google.com/api-keys to get an API key.
Prefer OpenAI, Anthropic, or no cloud key at all? Override with --provider/--model
and the matching environment variable β no editing the workflow required. (-n ottoflow
is optional here: with -f the workflow loads under its own metadata.namespace, and
-n is only a hint to disambiguate when several same-named workflows are loaded at once.
Either way it never changes which namespace pod-triage scans β that's always default.)
# OpenAI -- OPENAI_API_KEY must be set; --model optional (defaults to gpt-4o)
OPENAI_API_KEY=sk-... \
ottoflow run -f https://raw.githubusercontent.com/nirmata/ottoflow/main/samples/workflows/production/pod-triage.yaml -n ottoflow --provider openai# Anthropic -- ANTHROPIC_API_KEY must be set; --model optional (defaults to a current Claude model)
ANTHROPIC_API_KEY=sk-ant-... \
ottoflow run -f https://raw.githubusercontent.com/nirmata/ottoflow/main/samples/workflows/production/pod-triage.yaml -n ottoflow --provider anthropic# Local -- no cloud key, no cluster data leaves your machine. --model is required
# here; there is no default local model.
LLAMACPP_HOST=http://127.0.0.1:11434/ \
ottoflow run -f https://raw.githubusercontent.com/nirmata/ottoflow/main/samples/workflows/production/pod-triage.yaml -n ottoflow \
--provider local --model gemma3:4bPoint LLAMACPP_HOST at any llama.cpp-compatible server β llama.cpp, ollama,
vLLM, or LM Studio. The local run above produces the transcript shown below.
Agent steps need an LLM: set modelProvider on the Agent CRD to openai,
anthropic, azure-openai, google/gemini, or local (any llama.cpp-compatible
server), or override it per run with --provider/--model as shown above. API
keys come from the process environment β OPENAI_API_KEY, ANTHROPIC_API_KEY,
GEMINI_API_KEY, AZURE_OPENAI_API_KEY β not from Agent.spec.config. In-cluster,
set them on the agent-executor pod via agentExecutor.env in the Helm chart; in
local mode they come from your shell.
collectPods β
Succeeded 24ms
triagePods β
Succeeded 1.13s
publishTriage β
Succeeded 414Β΅s
Outputs:
triageSummary:
4 pods scanned, 2 flagged unhealthy. Verdict: The crashy pod is the highest
priority due to its significantly higher restart count (4), indicating a
persistent issue requiring immediate attention.
**Next Action:** Investigate the crashy pod's underlying cause by checking
system logs for crash reasons and potential resource constraints.For details view the complete workflow source.
All paths are under samples/workflows/production/.
| Workflow | What it does | You get |
|---|---|---|
cluster-overview.yaml |
Pure-CEL cluster snapshot β pod phases, per-namespace CPU/memory requests and limits, health verdict. No LLM, runs anywhere. | Structured report, zero prerequisites. |
pod-triage.yaml |
Collect β Analyze β Publish; CEL extracts per-pod failure signals (restarts, OOMKilled, ImagePullBackOff), the LLM picks the single highest-priority pod and the concrete next action. | Prioritized verdict + next step. |
resource-hygiene.yaml |
Detects 14 categories of unused or stale resources; LLM writes the cleanup report, Prometheus gauges track it. | Prioritized markdown report + metrics. |
cost-analyzer.yaml |
Right-sizing from resource specs plus metrics-server/Prometheus P95 usage, per-workload savings. | Markdown report + estimated monthly $ savings. |
workload-troubleshooter.yaml |
One failing pod: events + logs β LLM root-cause. β in-cluster only (needs pod logs; not available in CLI local mode). | Root cause + remediation. |
There are 70+ more workflows in samples/ covering cost, security, and
compliance automation.
helm install ottoflow oci://ghcr.io/nirmata/ottoflow \
--version 0.1.0-rc1 --namespace ottoflow --create-namespace
kubectl apply -f samples/workflows/production/cluster-overview.yaml
ottoflow run cluster-overview -n ottoflowThe controller reconciles Workflows/WorkflowRuns and runs the leader-elected
scheduler; agent steps execute via the agent-executor pod (set LLM keys via
agentExecutor.env in the chart).
For an LLM-driven root cause of a single failing pod β events and logs in, cause
and remediation out β see
workload-troubleshooter.yaml.
It's in-cluster only (it needs pod logs, unavailable in local --workflow-dir
mode) and runs the agent on the agent-executor, so it uses the LLM you configured
there rather than the --provider/--model flags (which apply to local runs only).
- Getting started and installation
- Concepts β architecture and execution model
- API reference β Workflow, WorkflowRun, Agent, MCPServer, StepTemplate
- CEL reference β available functions, and the pitfalls worth reading first
- CLI reference and configuration reference β flags, environment variables, and
ottoflow validate - Sample workflows β production use cases, feature demos, and test fixtures
- Developer guide and design notes
- Security policy β supply-chain trust and vulnerability disclosure
- License and license FAQ
Questions? Open a GitHub Issue β Discussions are disabled.
Contributions are welcome β see CONTRIBUTING.md for setup, style and the PR process, and GOVERNANCE.md for how decisions get made.
Built with β€οΈ by the Nirmata team