Back to blog

AI in DevOps: using Jev as a decision layer for pipelines, incidents and Kubernetes

Introduction

Adopting Artificial Intelligence in DevOps usually starts with Large Language Models (LLMs) analyzing logs, explaining pipeline errors, generating commands, writing documentation, or suggesting fixes.

That approach is useful, but there's a category of problem where reaching for a full generative LLM can be overkill.

Consider a few common decisions a platform has to make:

  • is this pipeline failure caused by code, infrastructure, or an external dependency?
  • should the pipeline run again?
  • does an incident need to be escalated?
  • which team should receive a given alert?
  • does this deploy carry enough risk to require manual approval?
  • does this log look like an application error or infrastructure downtime?
  • should we call in a more powerful AI agent to investigate the problem?

These questions don't necessarily need a long text answer.

They need a decision.

That's exactly the space Jev occupies — a model introduced by TypeSafe AI in September 2026. Unlike a traditional LLM, Jev was designed to take in a state, run bounded questions against it, and return structured decisions with probabilities and confidence scores. TypeSafe classifies this architecture as a System One model, built for fast decisions inside software.

For DevOps, SRE and Platform Engineering, this opens up an interesting architecture:

Pipeline / Kubernetes / Observability
                 ↓
          context collection
                 ↓
                Jev
                 ↓
      structured decision
                 ↓
      ┌──────────┼──────────┐
      ↓          ↓          ↓
    retry     escalate     ignore
                            ↓
                          action

The key point is that Jev doesn't replace Kubernetes, Azure DevOps, Prometheus, or an LLM.

It can work as a decision layer between technical events and automations.


What is Jev?

Jev is TypeSafe AI's first public model built around the concept of System One Models.

Instead of receiving a question and producing text token by token, the way a generative LLM normally does, the model works with a limited set of possible answers.

The conceptual contract is:

STATE + QUESTIONS
        ↓
       JEV
        ↓
DECISIONS + PROBABILITIES

A state could be:

Pipeline: payments-api
Stage: Build
ExitCode: 137

Logs:
Killed
npm ERR! process terminated
Node worker exited unexpectedly

And the application could ask:

What is the most likely failure category?

- application
- infrastructure
- dependency
- timeout
- resource
- unknown

Instead of producing:

It looks like your process was probably killed due to running out of memory...

the application receives something conceptually similar to:

{
  "category": "resource",
  "probability": 0.94
}

The software can then decide:

if probability >= 0.90 and category == "resource":
    retry_pipeline()

This model is particularly well suited for automation because it reduces reliance on free-text parsing and constrains the possible answers to the decision space defined by the application. TypeSafe itself describes Jev as a kind of intelligent function call: unstructured state goes in, typed probabilistic decisions come out.


System One versus a traditional LLM

A simple way to visualize the difference:

CharacteristicJevGenerative LLM
ClassificationVery well suitedSuited
RoutingVery well suitedSuited
ScoringVery well suitedSuited
Binary decisionVery well suitedSuited
Long-form textNot the goalVery well suited
Technical explanationLimitedVery well suited
Code generationNot the goalVery well suited
Open-ended analysisLimitedVery well suited
Structured outputNative to the modelUsually requires a schema/structured output
Frequent decisionsCompellingCan be more costly

So an efficient architecture can combine both.

Event
  ↓
Jev
  ↓
classification
  ↓
simple problem?
 ├─ yes → automation
 │
 └─ no
      ↓
     LLM
      ↓
 detailed investigation

This creates a kind of AI Cascade.

The cheaper, specialized model handles simple decisions.

Larger models are reserved for situations that really need complex analysis.


Key concepts

State

The state represents the context to be analyzed.

In DevOps it can include:

pipeline name
stage
exit code
logs
duration
commit
environment
deployment status
pod status
Kubernetes events
metrics

Example:

{
  "pipeline": "checkout-api",
  "stage": "deploy",
  "exitCode": 1,
  "environment": "production",
  "logs": "ImagePullBackOff..."
}

The quality of the state directly drives the quality of the decision.

There's no benefit in sending thousands of irrelevant lines.

An earlier layer should ideally normalize the data first.


Choice

Choice represents a selection among known options.

Example:

What's the likely cause?

application
infrastructure
dependency
security
resource
unknown

It's particularly useful for classification.


Score

Score lets you rate something on a scale.

For example:

Deployment risk:

1 - very low
2 - low
3 - medium
4 - high
5 - critical

This can feed a deployment gate.


Noul

Another type of question is a decision roughly equivalent to yes/no together with a probability.

For example:

Will this failure likely be resolved by a retry?

Conceptual result:

true: 0.91
false: 0.09

Choice, Score and Noul are among the core question types documented in Jev's ecosystem.


AI architecture in DevOps using Jev

A real environment could use an architecture like:

Azure DevOps
     │
     │ logs / status
     ▼
Classifier Service
     │
     ▼
Jev API
     │
     ▼
Decision Engine
     │
 ┌───┼────────────┐
 │   │            │
 ▼   ▼            ▼
Retry Escalate   Ignore
 │   │
 │   └───────────────► Teams / PagerDuty / Jira
 │
 ▼
Azure DevOps API

In Kubernetes:

EKS
 │
 ├── API
 ├── Workers
 ├── RabbitMQ
 └── PostgreSQL
       │
       ▼
Prometheus / Loki
       │
       ▼
Incident Collector
       │
       ▼
Jev
       │
       ▼
Decision Engine
       │
       ├── retry
       ├── restart
       ├── alert
       └── LLM Investigator

Jev doesn't necessarily execute the action.

It helps answer:

What should the system do?

The action stays the application's responsibility.

That separation matters for security.


A day-to-day example: classifying build failures

Imagine an organization with dozens of microservices.

Roughly 600 pipelines run on Azure DevOps every day.

A pipeline fails with:

##[error]The process '/usr/bin/docker' failed with exit code 1
error pulling image configuration:
download failed after attempts=6
TLS handshake timeout

Normally a developer opens the log and tries to figure out:

Code?
Docker?
Registry?
Network?
Agent?

A service could collect:

{
  "pipeline": "customer-api",
  "stage": "docker-build",
  "exit_code": 1,
  "message": "TLS handshake timeout pulling base image"
}

And ask:

Classify the most likely cause:

application
network
registry
dependency
agent
unknown

Hypothetical result:

registry: 0.72
network: 0.23
unknown: 0.05

The pipeline could apply:

confidence >= 0.90 → automatic retry

0.70 to 0.89 → log the classification

< 0.70 → manual investigation

This detail is fundamental.

Probability should not be confused with certainty.

The ecosystem's own documentation stresses that confidence should guide the workflow, not be interpreted as a guarantee of correctness.


HTTP integration example

A basic integration can call the API directly.

A simplified structure would be:

curl -X POST \
  "https://api.typesafe.ai/v1/systemone" \
  -H "Authorization: Bearer ${TYPESAFE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "jev-latest",
    "state": {
      "pipeline": "payments-api",
      "stage": "build",
      "exitCode": 137,
      "logs": "Process terminated unexpectedly after memory usage increased."
    },
    "questions": {
      "failure_type": {
        "type": "choice",
        "instructions": "Classify the most likely cause of this pipeline failure.",
        "options": [
          "application",
          "dependency",
          "infrastructure",
          "resource",
          "timeout",
          "unknown"
        ]
      }
    }
  }'

The POST /v1/systemone endpoint, along with sending state together with typed questions, is part of the documented contract for the model.

The category names don't come from Jev.

The application defines the decision space.

This detail lets you model taxonomies specific to your company.


Classifier for Azure DevOps

We can build a small service dedicated to classification.

Flow:

Azure DevOps
     ↓
pipeline log
     ↓
failure-classifier
     ↓
Jev
     ↓
classification
     ↓
pipeline decision

A Python application could follow this logic:

import os
import requests

API_URL = "https://api.typesafe.ai/v1/systemone"
API_KEY = os.environ["TYPESAFE_API_KEY"]


def classify_failure(log: str) -> dict:
    payload = {
        "model": "jev-latest",
        "state": {
            "log": log
        },
        "questions": {
            "failure_type": {
                "type": "choice",
                "instructions": (
                    "Classify the primary cause of this CI/CD failure."
                ),
                "options": [
                    "application",
                    "dependency",
                    "network",
                    "infrastructure",
                    "resource",
                    "timeout",
                    "unknown"
                ]
            }
        }
    }

    response = requests.post(
        API_URL,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        json=payload,
        timeout=10,
    )

    response.raise_for_status()

    return response.json()

Production would still require:

  • retry with backoff;
  • timeout handling;
  • circuit breaker;
  • telemetry;
  • secret redaction;
  • rate limiting;
  • controlling the size of the state.

Azure DevOps Pipeline

A pipeline could run the classification only after a failure.

Conceptual example:

trigger:
  branches:
    include:
      - main

pool:
  vmImage: ubuntu-latest

stages:
  - stage: Build
    jobs:
      - job: BuildApplication

        steps:
          - script: |
              npm ci
              npm run build
            displayName: Build application

          - script: |
              python scripts/classify_failure.py \
                "$(System.DefaultWorkingDirectory)/pipeline.log"
            condition: failed()
            displayName: Classify failure with Jev
            env:
              TYPESAFE_API_KEY: $(TYPESAFE_API_KEY)

The secret should be stored as a secret variable, a protected variable group, or another secret management solution.

Never:

TYPESAFE_API_KEY: abc123

directly in the repository.


Using Jev with Kubernetes

Another interesting application is classifying Kubernetes incidents.

Consider:

Pod → CrashLoopBackOff

The system collects:

kubectl describe pod
kubectl logs
kubectl get events

Then builds the context:

{
  "pod": "checkout-api-76d88f",
  "namespace": "production",
  "status": "CrashLoopBackOff",
  "restartCount": 14,
  "logs": "connection refused postgres:5432"
}

Jev can classify it as:

application
database
network
configuration
resource
unknown

In this example, probably:

database

The automation can then decide which runbook to run.


Kubernetes YAML

A service responsible for classifying events could be deployed to the cluster.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jev-incident-classifier
  namespace: platform
spec:
  replicas: 2

  selector:
    matchLabels:
      app: jev-incident-classifier

  template:
    metadata:
      labels:
        app: jev-incident-classifier

    spec:
      serviceAccountName: jev-classifier

      containers:
        - name: classifier
          image: registry.example.com/platform/jev-classifier:1.0.0

          ports:
            - containerPort: 8080

          env:
            - name: TYPESAFE_API_KEY
              valueFrom:
                secretKeyRef:
                  name: jev-api
                  key: api-key

          resources:
            requests:
              cpu: 100m
              memory: 128Mi

            limits:
              cpu: 500m
              memory: 512Mi

          readinessProbe:
            httpGet:
              path: /ready
              port: 8080

            initialDelaySeconds: 5
            periodSeconds: 10

          livenessProbe:
            httpGet:
              path: /health
              port: 8080

            initialDelaySeconds: 15
            periodSeconds: 20

---
apiVersion: v1
kind: Service
metadata:
  name: jev-incident-classifier
  namespace: platform
spec:
  selector:
    app: jev-incident-classifier

  ports:
    - port: 80
      targetPort: 8080

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jev-classifier
  namespace: platform

What this configuration does

It creates two replicas of the classification service.

The service receives events, prepares the context, and calls Jev.

replicas: 2 avoids depending on a single instance.

The requests guarantee minimum resources:

cpu: 100m
memory: 128Mi

while the limits prevent uncontrolled growth.

The probes let Kubernetes pull unhealthy containers out of traffic.

In production it would be advisable to add:

  • PodDisruptionBudget;
  • NetworkPolicy;
  • HorizontalPodAutoscaler;
  • observability;
  • External Secrets;
  • specific IAM;
  • egress policies.

Security

Integrating AI with infrastructure requires care.

The biggest mistake would be turning:

Jev → direct execution

into:

Jev decided restart → kubectl delete pod

without intermediate controls.

A safer architecture would be:

Jev
 ↓
Decision Engine
 ↓
Policy Engine
 ↓
Risk Check
 ↓
Action

For example:

if (
    decision == "restart"
    and confidence >= 0.95
    and environment != "production"
):
    restart()

For production:

recommended restart
       ↓
policy
       ↓
approval / runbook

Principle of least privilege

The classifier doesn't need to have:

cluster-admin

In most cases it doesn't even need to change resources.

Its RBAC can be read-only:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: incident-reader
  namespace: production
rules:
  - apiGroups:
      - ""

    resources:
      - pods
      - events

    verbs:
      - get
      - list

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: incident-reader-binding
  namespace: production
subjects:
  - kind: ServiceAccount
    name: jev-classifier
    namespace: platform

roleRef:
  kind: Role
  name: incident-reader
  apiGroup: rbac.authorization.k8s.io

If decisions result in actions, a separate service can hold specific permissions.


Redaction and secret leakage

Logs can contain:

Authorization: Bearer ...
password=
AWS_SECRET_ACCESS_KEY=
connectionString=

Never send logs directly to any external service without sanitizing them first.

Before:

raw logs
   ↓
secret redaction
   ↓
normalization
   ↓
Jev

A simple pattern-based expression could strip known patterns.

But in production, sanitization should account for:

  • JWT tokens;
  • AWS credentials;
  • HTTP headers;
  • connection strings;
  • cookies;
  • personal information;
  • regulated data.

Production example

Consider an EKS with:

120 microservices
600 pipelines/day
4,000 pods
Prometheus
Grafana
Loki
Tempo
Alertmanager
RabbitMQ
PostgreSQL
Redis

Hundreds of alerts can come in every day.

Instead of sending all of them straight to PagerDuty:

Prometheus
   ↓
Alertmanager
   ↓
PagerDuty

we could add a layer:

Prometheus
   ↓
Alertmanager
   ↓
Incident Processor
   ↓
Jev
   ↓
severity / team / action
   ↓
Routing Engine
   ↓
PagerDuty / Slack / Jira

For example:

CPU 95%
pod restarts = 0
latency normal
duration = 2 min

Classification:

severity=low

Another event:

HTTP 5xx = 72%
checkout unavailable
3 replicas down
database latency 8s

Classification:

severity=critical
team=platform
requires_human=true

The system then creates the incident.


Jev + LLM

One of the most interesting architectures is combining both.

Incident
   ↓
Jev
   ↓
simple?
 │
 ├─ YES
 │    ↓
 │ runbook
 │
 └─ NO
      ↓
   GPT / Claude / another LLM
      ↓
 investigation

Jev works as an intelligent router.

The LLM stays responsible for complex reasoning.

This combination avoids using more expensive models for tasks that are essentially classification.

Community projects are already experimenting with Jev in exactly this intermediate position, classifying before routing context to larger agents.


Observability

A solution like this needs to be observable.

It's not enough to know that:

Jev answered resource

You need to log:

request_id
pipeline
decision
confidence
duration
action
model_version
timestamp

Example Prometheus metric:

jev_requests_total
jev_request_duration_seconds
jev_decision_total
jev_low_confidence_total
jev_errors_total

Example:

jev_decision_total{
  decision="resource",
  pipeline="payments"
} 143

In Grafana you could have:

Decisions/minute

Average confidence

Top categories

Low confidence %

API errors

p95 latency

Automated actions

Manual escalations

Logs

A well-structured log would look like:

{
  "timestamp": "2026-09-27T10:00:00Z",
  "pipeline": "payments-api",
  "classification": "resource",
  "confidence": 0.94,
  "action": "retry",
  "duration_ms": 182
}

In Loki:

{app="jev-classifier"}
| json
| classification="resource"

Tracing

OpenTelemetry can track:

pipeline-event
     ↓
classifier
     ↓
Jev API
     ↓
decision-engine
     ↓
Azure DevOps API

This lets you figure out whether a problem is:

in the collector
in the network
in the API
in the decision
in the automation

Troubleshooting

API returning a timeout

Check connectivity:

curl -I https://api.typesafe.ai

Inside Kubernetes:

kubectl exec -n platform \
  deploy/jev-incident-classifier \
  -- curl -I https://api.typesafe.ai

Possible causes:

DNS
NetworkPolicy
proxy
firewall
blocked egress
external outage

Classifier pod restarting

kubectl get pods -n platform

kubectl describe pod \
  -n platform \
  <pod>

kubectl logs \
  -n platform \
  <pod>

Events:

kubectl get events \
  -n platform \
  --sort-by=.metadata.creationTimestamp

Check for:

OOMKilled
CrashLoopBackOff
ImagePullBackOff
probes
missing secret

Secret not found

kubectl get secret jev-api \
  -n platform

Never print the secret's value in pipelines or logs.


Bad classifications

Not every problem is infrastructure.

The first thing to investigate should be the state.

For example:

BAD STATE

"pipeline failed"

versus:

BETTER STATE

pipeline=payments-api
stage=deploy
exit_code=137
pod_status=OOMKilled
memory_limit=512Mi
memory_peak=510Mi

AI doesn't make up for poor context quality.


Development versus production

Development

Might be acceptable:

one replica
full logs
lower threshold
simulated actions
no autoscaling

Example:

confidence > 0.70 → show a recommendation

Production

Should have:

redundancy
timeouts
retry
circuit breaker
rate limiting
redaction
observability
versioning
audit trail
higher thresholds
action controls

For example:

confidence >= 0.95 → safe automatic action

0.80-0.94 → suggestion

<0.80 → manual investigation

Thresholds need to be calibrated with real data.


Best practices

Start with small decisions

Don't start by asking:

Fix any incident in my infrastructure.

Start with:

Classify this failure.

Then:

Determine whether a retry will likely fix it.

Then:

Determine which runbook to use.

Mature automation is built progressively.


Keep the decision space limited

Prefer:

resource
application
network
dependency
unknown

over dozens of nearly identical categories.


Have an unknown option

Forcing a decision can produce bad automations.

Whenever possible:

unknown

should be a valid result.


Use confidence gates

Never treat:

0.51

as equivalent to:

0.99

Log every decision

For auditing:

input
model
decision
confidence
action
outcome

What to avoid

Avoid architectures like:

Alert
 ↓
AI
 ↓
kubectl delete

Also avoid:

AI with cluster-admin

or:

unfiltered logs containing secrets

Another common mistake is using AI where a simple rule would do.

For example:

if exit_code == 0:
    return "success"

doesn't need AI.


Costs and FinOps

The real cost of an AI-based architecture doesn't come only from the model call.

Consider:

tokens
API requests
intermediate service
observability
storage
network
secondary LLMs

TypeSafe currently publishes a price of US$42 per billion input tokens, roughly US$0.042 per million tokens, positioning Jev as a low-cost decision layer compared to several generative models.

This can matter when there are thousands or millions of small decisions.

Consider:

100,000 events/day

If all of them went to a large LLM:

100,000
   ↓
LLM

the architecture could instead be:

100,000
   ↓
simple rules
   ↓
Jev
   ↓
only 2,000 complex cases
   ↓
LLM

This strategy reduces:

tokens
latency
cost
dependency on larger models

Kubernetes and cost

The classification service itself tends to be lightweight.

For example:

requests:
  cpu: 100m
  memory: 128Mi

So it can run on Spot nodes when appropriate.

But the classification service shouldn't be put on Spot without considering availability.

One approach could be:

2 replicas

spread across nodes.

The local compute cost will likely be small compared to pipelines, observability and core workloads.


When to use Jev

Jev makes sense when there are frequent, well-bounded decisions.

Examples:

pipeline classification

incident triage

alert routing

ticket routing

deployment risk scoring

agent routing

tool selection

prioritization

log classification

confidence gates

retry decisions

When not to use it

Don't use Jev for problems like:

"Explain why my Kubernetes cluster is slow."

"Write my Terraform."

"Design a complete architecture."

"Summarize these 500 logs."

"Fix my code."

These problems need generation or open-ended reasoning.

A traditional LLM is a better fit.

Also don't use AI when a deterministic rule solves the problem.

if pod.status == "Succeeded":
    return

is better than any model.


Recommended architecture

A mature AI-in-DevOps strategy could have four layers:

                 EVENTS

                   ↓

          DETERMINISTIC RULES

                   ↓

                  JEV

                   ↓

            COMPLEX CASE?

            ┌──────┴──────┐
            │             │
           NO            YES
            │             │
            ▼             ▼

         RUNBOOK          LLM
                            │
                            ▼
                       HUMAN REVIEW

This architecture avoids two extremes.

The first:

never use AI for anything

The second:

use an LLM for absolutely everything

The best design tends to combine:

deterministic code
+
fast decision models
+
LLMs
+
automation
+
human-in-the-loop

Practical summary

Jev shouldn't be understood as a drop-in replacement for ChatGPT, Claude or other generative models.

Its role is different.

LLM
→ generates

Jev
→ decides

In DevOps, this lets you build an intelligent layer between events and automations.

A pipeline can use Jev to determine:

failure type
risk
whether a retry is needed
whether escalation is needed

A Kubernetes cluster can use it for:

incident classification
alert routing
runbook selection
prioritization

And agent systems can use it to decide:

which tool to call
which model to use
when to escalate
when to stop

All of this should be paired with:

confidence thresholds
RBAC
audit trail
observability
sanitization
policy engines
human-in-the-loop

Conclusion

For many years, the connection between Artificial Intelligence and DevOps was focused on tools that generate text: explaining logs, writing YAML, creating scripts, or helping during incidents.

The rise of decision-oriented models opens up a different layer.

Not every problem needs a model that writes five paragraphs.

Sometimes the system just needs to answer:

Which category?

Which priority?

Which action?

Retry or not?

Escalate or not?

Which tool?

Which agent?

This is exactly where a technology like Jev becomes particularly interesting.

In a modern platform, we can picture:

Azure DevOps
Kubernetes
Prometheus
Loki
OpenTelemetry
Alertmanager
       │
       ▼
   Event Layer
       │
       ▼
     Jev
       │
       ▼
 Decision Engine
       │
       ├── automation
       ├── runbook
       ├── LLM
       └── human

The outcome isn't simply "putting AI in the pipeline."

It's building an intelligent decision layer inside the platform.

For DevOps, SRE and Platform Engineering, that difference matters.

The goal stops being just "use AI to answer questions" and becomes "use AI to help systems make small operational decisions with speed, structure, observability and clear limits."

Combined with deterministic code, policies, telemetry, runbooks, LLMs and human controls, Jev can occupy exactly that spot: the fast decision layer between what happened in the infrastructure and what the platform should do next.

Want to apply this to your environment?

Book a free 30-minute call. I will look at your setup and tell you where to start.

Book a call

Get new articles by email

One email when a new article on infrastructure, backend and AI is published. No spam, unsubscribe anytime.