AI EngineeringZero to ProductionHome·About·Contact
Part V · Chapter 8 · End-to-End Case Study

The AI DevOps Engineer

One complete, advanced case study built the FDE way: an agent that can be onboarded into any company running modern DevOps — git/Bitbucket, Terraform, Kubernetes/EKS, AWS, Jenkins, Argo CD — and act as a trusted engineer that diagnoses, proposes, and (carefully) executes infrastructure work. This is the blueprint you build alongside the course.

⏱️ deep read + build🏗️ end-to-end🔐 safety-first☁️ AWS · K8s · Terraform · CI/CD

What this chapter gives you

  • A full architecture for an infrastructure agent, from trigger to audited action.
  • A safety model built for irreversible operations — the crux of DevOps automation.
  • The complete tool surface across git, Terraform, K8s/EKS, AWS, Jenkins, Argo CD.
  • How RAG grounds the agent in this company's runbooks and conventions.
  • Infra-specific evals and a phased rollout that earns trust one operation at a time.
  • A skills matrix + build-along plan mapping every piece back to Chapters 1–7.
Read this first — the honest framingA fully-autonomous agent running production infrastructure unattended is not the goal, and no serious team does it. terraform apply and kubectl delete are irreversible and can destroy data or take down prod. The valuable, achievable system is a DevOps copilot: it diagnoses freely (read-only), proposes changes as reviewable PRs/plans, and executes only gated, reversible actions with approval — expanding autonomy per-operation only as evals prove safety. Everything below is designed around that truth.
📘 This chapter is the design — the build labs are the howThis page explains the architecture, safety model, and decisions (the why). To actually build it step by step — with runnable code, test cases, and troubleshooting — work through the four hands-on build labs, which construct a complete, mock-first, runnable project in llm-course-starter/devops-agent/: Read this chapter first for the map, then build.

The brief essential

"Build an AI DevOps engineer that can be onboarded into any company following DevOps practices." Target stack: Git/Bitbucket, Kubernetes, AWS, EKS, networking, Terraform, Argo CD, Jenkins and job pipelines — plus end-to-end AWS infrastructure automation through Terraform. That's the ask. The FDE method (Ch 7) says: don't build all of it at once — discover, scope a slice, earn trust, expand. Here's how.

1 · Discovery — where does a DevOps engineer's time actually go? essential

Before architecture, the discovery questions from Ch 7. Across most teams, the repetitive, high-toil, high-value work clusters here:

Toil areaWhat it looks likeAgent leverage
Incident triage"Something's broken" → gather logs, events, metrics, recent changes⭐⭐⭐ high (read-only, huge time save)
PR / IaC reviewReviewing terraform plans & manifests for risk⭐⭐⭐ high (proposal, not action)
Routine changesScale a deployment, bump a version, add a tag⭐⭐ medium (gated action)
Provisioning new infraNew service → VPC, EKS, IAM, pipelines⭐⭐ medium (proposal + review)
Onboarding knowledge"How do we do X here?" — tribal knowledge⭐⭐⭐ high (RAG over runbooks)
Problem statement (discovery output)"When an incident fires or a change is requested, an engineer spends 30–60 min gathering context across kubectl/AWS/CI and cross-referencing runbooks before acting. If an agent did the gathering + proposed a fix that a human approves, we'd cut MTTR and free senior engineers from toil — safely, because the human still approves anything that changes state."

2 · Architecture essential

TRIGGERS Slack / ChatOps Alert (PagerDuty) PR / webhook CI event Agent core plan · decide · loop (Ch 4 loop) structured plans Policy / approval gate every state-changing action RAG: runbooks + conventions (Ch 3) TOOLS (least-privilege) kubectl (RO/RW split) terraform plan/apply aws (describe/act) git / Bitbucket Jenkins / Argo CD TARGETS EKS clusters AWS accounts Git repos Pipelines Audit log · observability · every action traced (Ch 6) read-only tools flow freely · state-changing tools pass through the policy gate first
🗺️ How to read this diagram

This is the whole machine on one page: a request comes in on the left, flows rightward through a thinking "brain," and only reaches the real infrastructure on the far right — but state-changing actions must pass a safety checkpoint first. Read it left to right, following the blue arrows.

  • TRIGGERS (far left) — the four ways the agent gets woken up: a human typing in Slack, an alert from PagerDuty ("prod is on fire"), a PR/webhook (someone opened a code change), or a CI event (a pipeline ran). Any one of these kicks off a job.
  • Agent core (the purple box, center) — the brain. This is the Chapter 4 agent loop: it plans, decides which tool to call next, reads the result, and repeats until it has an answer or a proposed fix. "structured plans" means it outputs tidy, typed data — not a wall of text.
  • RAG box (teal, above the core) — the agent's company-specific memory. Before acting it looks up this company's runbooks and naming conventions (Chapter 3), so its advice fits your team, not a generic textbook.
  • Policy / approval gate (yellow box, below the core) — the safety checkpoint, and the single most important part. The caption spells out the rule: read-only tools flow freely, but every state-changing action must pass through this gate first (usually a human clicks approve).
  • TOOLS (green column) — the agent's hands: kubectl, terraform, aws, git, Jenkins/Argo CD. "least-privilege" means each tool is only allowed to do as much as the agent's current trust level permits. Notice the RO/RW split — read tools and write tools are kept separate on purpose.
  • TARGETS (far right) — the real systems the tools touch: EKS clusters, AWS accounts, git repos, pipelines. This is the actual production infrastructure — the part you don't want a mistake to reach.
  • Audit log (bottom strip) — a permanent record of every action, who/what/why (Chapter 6). Nothing the agent does is invisible.
  • Follow the arrows: triggers → agent core; the core reads RAG for grounding, then reaches for tools; read-only tool calls go straight to the targets, while write actions detour through the yellow gate — and it all lands in the audit log.

In short: The yellow gate is the hero of this picture. A read-only agent can look at everything and diagnose problems, but it physically cannot change anything without passing the gate — that's what makes handing an AI real infrastructure access safe.

The shape is the Chapter 4 agent, hardened for infrastructure: triggers feed the agent core; the core is grounded by RAG over the company's runbooks; it calls tools; but every state-changing tool call passes through a policy/approval gate and everything is audited.

3 · The safety model — the heart of the system essential

In DevOps, safety is the architecture. Classify every operation by blast radius and reversibility, and let that classification drive what the agent may do.

ClassExamplesAgent permission
🟢 Read-onlykubectl get/describe/logs, terraform plan, aws describe-*, git logRun freely, no gate
🟡 Reversible writeScale a deployment, restart a pod, add a non-prod tag, open a PRGate: human approves; auto-approvable later per-op
🟠 Significantterraform apply (non-prod), merge a PR, trigger a deployGate: explicit human approval, always
🔴 Irreversible / prodterraform apply on prod, kubectl delete, delete an S3 bucket/RDS, IAM changesGate + second approver + never auto; often blocked entirely

The controls that make it real

The rule that keeps you safeGuardrails live in code and cloud IAM, never only in the prompt. "I told the model not to touch prod" is not a control. A scoped IAM role that cannot touch prod is.

4 · The tool surface essential

Each capability is a tool (Ch 4). Split by risk class; the description tells the model when to use it; the implementation validates inputs and enforces scope.

devops_tools.py (shape)# 🟢 read-only — allowed to run without a gate
{"name":"kubectl_get", "description":"Read K8s resources. Use to inspect "
 "pods, deployments, events, logs when diagnosing.",
 "input_schema":{"type":"object","properties":{
   "resource":{"type":"string"},"namespace":{"type":"string"},
   "name":{"type":"string"}},"required":["resource"]}}

{"name":"terraform_plan", "description":"Run 'terraform plan' and return the "
 "diff. ALWAYS run before proposing any infra change. Never changes state.", ...}

{"name":"aws_describe", "description":"Read-only AWS describe/list/get. Use to "
 "inspect resources, never to modify them.", ...}

# 🟡/🟠 state-changing — routed through the policy gate before executing
{"name":"open_pr", "description":"Open a Bitbucket PR with a proposed change. "
 "This is the PREFERRED way to make infra changes — humans review the diff.", ...}

{"name":"terraform_apply", "description":"Apply a PREVIOUSLY REVIEWED plan file. "
 "Requires approval. Never generate-and-apply in one step.", ...}

{"name":"argocd_sync", "description":"Trigger an Argo CD sync for an app. "
 "Reversible via rollback; still gated in prod.", ...}
TechnologyRead-only toolsGated write tools
Git / Bitbucket / GitLabgit_log, git_diff, read_mr/read_propen_mr/open_pr, comment, merge(🟠)
Kubernetes / EKSkubectl_get, describe, logs, topscale, rollout_restart, apply_manifest(🟠), delete(🔴)
Terraformterraform_plan, validate, state_listterraform_apply(🟠/🔴)
AWSaws_describe, get_metrics (CloudWatch)prefer via Terraform PR; direct writes 🔴
Docker / containersimage_inspect, scan_image (Trivy), read_dockerfile, registry_listbuild_image(🟡, sandbox), push_image(🟠), lint_dockerfile_fix→PR
Jenkinsget_build, get_consoletrigger_job(🟡), abort
GitLab CIget_pipeline, job_trace, lint_ci_yamlretry_pipeline(🟡), edit .gitlab-ci.yml→MR
Argo CDapp_status, diffsync(🟡), rollback(🟡)
Monitoring & observability
Grafana · Kibana · CloudWatch · Prometheus
firing_alerts, get_metric, list_dashboards, get_dashboard, search_logsall read-only— (monitoring never changes state; it only queries)
Python (agent's own hands)parse logs, transform data, call SDKs (boto3, k8s client)via code_execution in a sandbox — see note
Python is both a skill and the agent's gluePython plays two roles here: (1) it's a DevOps skill the agent reasons about — reviewing/fixing automation scripts, boto3 Lambdas, k8s client code, pytest suites; and (2) it's the agent's own execution language — for anything without a clean tool, the agent can write a short Python snippet and run it in a sandboxed code_execution environment (parse a gnarly log, diff two JSON states, call an SDK). Sandbox it: no network beyond allowed endpoints, no host credentials, resource-limited — the same untrusted-code rules as any tool that runs code.
Design principlePrefer GitOps: instead of the agent mutating a cluster directly, have it open a PR to the git repo of record. Argo CD / Terraform then apply from git after human merge. This gives you review, audit, and rollback for free — and keeps the agent mostly at the safe "propose" rung.

5 · The first thin vertical slice essential

Per Ch 7, don't build all of the above. Build one spine, end-to-end:

Slice #1 — "Crash-loop diagnostician" (read-only) Trigger: Slack command /diagnose pod X in ns Y (or an alert). Flow: agent calls kubectl_get (pod, events), logs, and git_log on the deploy repo → retrieves the matching runbook via RAG → returns a structured diagnosis: likely cause, evidence, suggested fix, confidence. Output: a Slack message. Zero state changes.

Every layer of the real system is present — trigger, tools, RAG, structured output, audit — but it can't break anything. You'll have it working in days, and real SREs can use it this week.
Setup to run this snippet
from pydantic import BaseModel
from typing import Literal
diagnosis schema (Ch 2)class Diagnosis(BaseModel):
    likely_cause: str
    evidence: list[str]            # the log lines / events it's citing
    suggested_fix: str
    fix_risk: Literal["read_only","reversible","significant","irreversible"]
    confidence: float
    runbook_ref: str | None       # which runbook it matched

6 · RAG over runbooks & conventions (the "onboarding") intermediate

This is what makes the agent "onboardable into any company." A generic agent knows Kubernetes; it does not know your naming conventions, your escalation policy, your weird legacy service. You give it that via RAG (Ch 3) over the company's:

🔑 The onboarding insight"Onboarding the AI DevOps engineer into a new company" = pointing its RAG index at that company's docs/repos + configuring its tool credentials + setting its autonomy rungs. The agent code is generic; the knowledge and permissions are per-company. That separation is what makes it reusable — and it's exactly the FDE model.

7 · Terraform & end-to-end AWS automation intermediate

Your "end-to-end infra automation in AWS through Terraform" goal, done safely, is a plan → review → apply workflow where the agent is the author and a human is the approver:

  1. Request: "Provision a new microservice: ECR repo, EKS namespace, IAM role, ALB ingress." (Slack / ticket)
  2. Ground: RAG pulls your standard Terraform modules and conventions so the agent uses your patterns, not generic ones.
  3. Author: agent writes the .tf using your modules, on a new branch.
  4. Plan: agent runs terraform_plan, attaches the diff.
  5. Propose: agent opens a PR with the code + plan output + a written explanation of what changes and why.
  6. Review: a human reads the PR (this is the gate). The agent can answer review questions.
  7. Apply: on merge, your existing pipeline (or a gated terraform_apply of the reviewed plan) provisions it.
Why author-and-PR, never generate-and-applyThe agent proposing a PR is a reversible, reviewable act. The agent running apply directly is not. Keeping the agent at "author + plan" for infra gets you 90% of the value at a fraction of the risk — and it drops neatly into the git/CI workflow your team already trusts.

8 · CI/CD & GitOps (Jenkins · GitLab CI · Argo CD) intermediate

TaskAgent roleRung
A Jenkins / GitLab pipeline failedFetch console log or job trace, diagnose (dependency? test? infra? cache?), suggest fix or open a PR/MRObserve / Recommend
Flaky pipelineCorrelate failures across runs, propose the quarantine/fix as a PR/MRRecommend
Broken .gitlab-ci.yml / JenkinsfileLint it, explain the error, propose a corrected pipeline as an MRRecommend
Argo CD app out of sync / degradedReport the diff & health; propose sync or rollbackObserve → gated Act
Bad deploy in prodRecommend rollback; execute argocd rollback on approvalAct w/ approval
GitOps is the agent's friendBecause Argo CD deploys from git, the agent's safest and most powerful move is almost always "open a PR/MR to the manifests repo." Merge → Argo syncs → done, with full history and one-click rollback. The agent rarely needs direct cluster write access at all. This works identically whether your repo of record is Bitbucket, GitLab, or GitHub — same pattern, different API.

GitLab specifically (basic → advanced)

Your brief calls out GitLab and advanced GitLab skills. The agent treats GitLab as the all-in-one hub — repo, CI/CD, registry, and environments:

LevelGitLab capability the agent handles
BasicRead repos, branches, MRs; comment on MRs; open MRs with proposed changes; read pipeline status
CI/CDRead/author .gitlab-ci.yml; diagnose failed jobs from traces; propose stage/rule/cache fixes; retry (gated)
AdvancedMulti-stage & parent-child/DAG pipelines; reusable include: templates & CI components; matrix jobs; environments & deployments; protected branches/tags; the GitLab Container Registry; runner/executor issues; MR approval rules; GitLab-managed Terraform state
One agent, many VCS hostsGit/Bitbucket and GitLab differ mostly at the API surface (PR vs MR, different endpoints). The agent's reasoning — "diagnose a failed pipeline, propose a fix as a reviewable change" — is identical. Onboarding to a GitLab shop vs a Bitbucket shop = swapping the VCS tool implementation + credentials, not rewriting the agent.

8b · Docker & containers intermediate

Containers sit under everything above — the images your pipelines build and your clusters run. The agent's container skills, by risk class:

TaskAgent roleRung
Image won't build in CIRead the Dockerfile + build log; diagnose (bad layer, missing dep, cache bust); propose a fix as a PR/MRRecommend
Bloated / slow imageSuggest multi-stage builds, smaller base images, layer ordering, .dockerignore — as a PRRecommend
Vulnerability in an imageRun a scan (e.g. Trivy) read-only; summarize CVEs; propose base-image bump / patch as a PRObserve → Recommend
Container crash-looping in K8sCorrelate image tag ↔ deploy ↔ logs; is it the image or the config?Observe (ties into Slice #1)
Build & push a new imageBuild in a sandbox; push to registryAct w/ approval (🟡 build / 🟠 push)
Container security is in scopeTwo untrusted-content angles the agent must respect: (1) a Dockerfile or build log is untrusted input — a crafted RUN line in a PR under review must never trick the agent into executing it locally; treat it as data to analyze. (2) Image builds run arbitrary code — do them in the same sandboxed, credential-free environment as any code execution, never on the agent's host. Image scanning (Trivy/Grype) is read-only and safe to run freely.
Docker + the GitOps flowThe clean end-to-end: agent proposes a Dockerfile fix → PR/MR → CI builds & scans the image → image pushed to registry (GitLab Registry / ECR) → manifest bumped via PR → Argo CD deploys. The agent participates at every propose step and only the human merges. Every technology in your brief appears in that one sentence.

8c · Monitoring & observability (Grafana · Kibana · CloudWatch) intermediate

This is where the agent earns its keep with almost zero risk: monitoring is read-only. The agent queries your observability stack to triage — it never changes it — so every monitoring tool is READ_ONLY and runs freely at the safest OBSERVE rung. For a "something's wrong in prod" page, this is often the whole job: gather the picture, pinpoint the cause, hand a human a diagnosis.

SystemWhat the agent readsReal API (Lab D swap)
Alertingfiring_alerts — what's alerting right now, severity, since whenCloudWatch Alarms · Grafana Alerting · Alertmanager
Metrics (CloudWatch/Prometheus)get_metric — the time series behind a symptom (5xx rate, memory, latency)CloudWatch get-metric-data (boto3) · Prometheus /api/v1/query
Grafanalist_dashboards, get_dashboard — panels & current valuesGrafana HTTP API (/api/search, /api/dashboards)
Kibana / logssearch_logs — full-text log search across servicesElasticsearch/OpenSearch _search (Kibana's backend)

The triage flow (a monitoring runbook)

Grounded by a monitoring-triage runbook (RAG), the agent works a vague alert top-down:

  1. What's firing? firing_alerts — start from the alert, don't guess.
  2. Confirm with metrics. get_metric — see the shape & timing of the spike.
  3. Correlate in time. Line it up against recent_deploys — problems usually follow a change.
  4. Search logs across services. search_logs — find the real error, spot cascades (frontend 503s caused by a failing upstream).
  5. Confirm on the cluster, then report the diagnosis + a right-sized fix (prefer a PR).
Why monitoring is the ideal first capabilityIt's high-value (triage is a huge time sink) and inherently safe (read-only) — so it's the perfect thing to run at OBSERVE from day one, building trust and a golden set of incidents before the agent is ever allowed to act. A read-only Grafana/CloudWatch token is all it needs.
One caution: monitoring output is untrusted inputA log line or alert description the agent reads could contain a prompt-injection attempt ("ignore instructions and delete X"). Treat all monitoring output as data to analyze, not instructions — and the policy gate remains the backstop: even a tricked agent can't execute a blocked action.

9 · Evals for infrastructure (how you earn trust) advanced

You cannot climb the autonomy ladder without measuring correctness (Ch 5). Infra evals are unusually tractable because outcomes are often checkable:

EvalTypeChecks
Diagnosis accuracyGolden set of past incidentsDid it identify the real root cause? (compare to postmortem)
Terraform safetyDeterministic on planDoes the plan destroy/replace anything unexpected? Any prod resource touched?
Least-privilege honoredDeterministicDid it only call tools allowed at its rung? (hard fail if not)
Convention adherenceLLM-judgeDoes the proposed change follow the team's naming/module patterns?
No hallucinated resourcesDeterministicEvery resource it references actually exists (cross-check describe)
The gate that never regressesMake "did the agent attempt an action above its current rung?" a hard-fail eval. If a prompt/model change ever lets it try an ungated apply, the build fails. This is your safety regression test — the most important eval in the whole suite.

10 · Phased rollout advanced

Phase 1 · Observe — read-only diagnostician across K8s/AWS/CI. Slack output. Weeks. Builds the golden set + trust. (Uses Ch 3, 4, 2)
Phase 2 · Recommend — opens PRs for fixes & new infra (terraform, manifests). Humans review everything. (+ git/Bitbucket tools, Ch 6 audit)
Phase 3 · Act with approval — executes reversible, gated ops (scale, restart, argocd sync/rollback, non-prod apply) on one-click approval. (+ policy gate, Ch 5 evals gating each op)
Phase 4 · Selective autonomy — a short allowlist of proven-safe, reversible, non-prod operations run unattended; everything else stays gated. Prod stays human-approved indefinitely. (Only ops with high eval pass-rates)
You never "finish" at full autonomyA mature system runs mostly at Phases 2–3 forever. That's not a limitation — it's the design. The human approving a good PR in 60 seconds instead of researching for an hour is the win.

The AI DevOps Engineer — skills matrix advanced

Your brief's technologies, mapped to how the agent handles each and where you learned the pattern:

SkillAgent capabilityCourse chapter
Git / Bitbucket / GitLabRead repos/PRs/MRs; author branches; open & comment on PRs/MRs (the primary "action")Ch 4 tools
Advanced GitLabMulti-stage & DAG pipelines, reusable include templates/components, environments, protected branches, registry, MR approval rules, GitLab-managed TF stateCh 4 + §8
Kubernetes / EKSDiagnose (RO); scale/restart/sync (gated); GitOps via PR/MRCh 4 + safety model
AWS + networkingDescribe/inspect (RO); provision via Terraform PRCh 4 + §7
Terraform / IaCAuthor + plan + PR; gated apply of reviewed plans§7 + Ch 5 safety evals
Docker / containersDiagnose & fix Dockerfiles/builds (PR); optimize images; scan for CVEs (RO); gated build/push§8b + Ch 4
Jenkins & pipelinesDiagnose failures; propose fixes as PRs; gated job triggersCh 4 + §8
GitLab CI/CDRead/author .gitlab-ci.yml; diagnose job traces; propose fixes as MRs; gated retriesCh 4 + §8
Argo CD / GitOpsStatus & diff (RO); gated sync/rollbackCh 4 + §8
Monitoring (Grafana / Kibana / CloudWatch)Read alerts, metrics, dashboards & logs; triage incidents — all read-only§8c + Ch 3 (runbook)
PythonReview/fix automation scripts, boto3, k8s-client, pytest; also the agent's own glue language for parsing/transforms in a sandboxCh 2, 4 + §8b
Company-specific knowledgeRAG over runbooks, conventions, past PRs/MRsCh 3
Safety & trustRisk classification, gates, least-privilege, audit, evalsCh 5, 6, 7
Onboarding to a new companyRe-point RAG + set credentials + set autonomy rungsCh 7 FDE method

11 · Hiring the AI DevOps Engineer as a service (subscription) advanced

The natural business model: companies don't build this — they subscribe to it and onboard it into their stack, like hiring a contractor who's productive on day one. This turns your capstone from "a tool we built" into "a product companies pay for monthly." Here's how it's structured — and the hard parts to get right.

The core idea that makes it sellableRecall the onboarding insight: the agent code is generic; the knowledge and permissions are per-company. That separation is exactly what a subscription product needs — one codebase, many tenants, each with its own RAG index, its own credentials, its own autonomy rungs. You maintain one agent; each customer gets their own isolated "employee."

Architecture: one agent, many tenants

AI DevOps Engineer one codebase (you maintain) Tenant A · Acme own RAG indexown AWS/K8s credsown autonomy rungsisolated · never crosses Tenant B · Globex own RAG indexown creds (their IAM)own autonomy rungsisolated · never crosses Tenant C · Initech own RAG indexown credsown autonomy rungsisolated · never crosses
🗺️ How to read this diagram

This picture answers "how do you sell one agent to many companies without their secrets ever mixing?" Read it top-down: one shared brain at the top, three separate, sealed-off customers at the bottom.

  • Top box — "AI DevOps Engineer" — the one codebase you maintain. There is a single copy of the agent logic; you improve it once and every customer benefits. This is the "shared" half.
  • Bottom row — Tenant A (Acme), Tenant B (Globex), Tenant C (Initech) — one box per customer company. A "tenant" just means one customer's private, walled-off space.
  • Inside each tenant box, the same three lines repeat: its own RAG index (that company's runbooks), its own credentials (their AWS/K8s keys, never yours), and its own autonomy rungs (how much they let the agent do). The knowledge and permissions differ per company; only the code is shared.
  • "isolated · never crosses" at the bottom of each box is the promise the whole diagram exists to make: Acme's data and keys can never leak into Globex's session. The boxes are drawn separate and never touch on purpose.
  • The three lines from the top box down to each tenant show the shared agent serving all three — but each connection stays inside that tenant's own sealed configuration. Same brain, three private bodies.

In short: One agent, many customers, zero mixing. The trick is the split you saw in the first diagram taken to its logical end: the code is generic and shared, while the knowledge and keys are per-company and isolated — which is exactly what lets you run it as a subscription product.

Each customer is a tenant with a completely isolated configuration bundle. The agent logic is shared; nothing else is.

Per-tenant, isolatedShared (you maintain once)
RAG index (their runbooks, repos, conventions)Agent code & the tool implementations
Credentials — their scoped IAM role / k8s RBAC / VCS tokensThe safety model & policy-gate engine
Autonomy rung config (what's allowed, per env)The eval framework
Audit log & usage meteringPrompt templates & model routing
Integrations (their Slack, Jenkins, GitLab, Argo)Onboarding tooling
Tenant isolation is the #1 requirement — and the #1 riskYou're holding multiple companies' infrastructure credentials and running actions against their production. A leak or a cross-tenant mixup is catastrophic and business-ending. Non-negotiables: strict tenant scoping on every data access and tool call; per-tenant credential vaults (never commingled); RAG queries filtered by tenant before retrieval; audit logs partitioned per tenant; and ideally per-tenant compute isolation. Enforce it in code and IAM, prove it with a hard-fail eval ("can tenant A ever see tenant B's data/creds?" must always fail closed).

The credential model — customers stay in control

The trust hurdle for selling this: "why would I give a third party keys to my infra?" The answer that makes it sellable:

Sell the safety model, not the autonomyCounterintuitively, what closes enterprise deals is not "it does everything automatically." It's "it can't do anything you didn't approve, everything is audited in your own logs, and you can revoke it in one click." The Ch 7 autonomy ladder is your sales story.

Onboarding a new customer (the productized FDE flow)

Chapter 7's FDE method, turned into a repeatable onboarding you can do in days, not months:

  1. Connect knowledge — point the tenant's RAG index at their runbooks, repos, and docs (read-only access).
  2. Connect tools — customer creates the scoped, read-only role; you wire their Slack/GitLab/Jenkins/Argo/EKS.
  3. Shadow mode — agent runs read-only diagnostics; the team sees value with zero risk (this is Phase 1 / Slice #1).
  4. Tune — their corrections build their tenant's eval golden set; accuracy climbs on their stack.
  5. Graduate rungs — as evals prove out, the customer opts into gated writes, then a small autonomy allowlist. On their timeline.

Pricing & packaging

TierWhat they getRough shape
ObserveRead-only diagnostician + runbook Q&A across their stack. Slack/ChatOps.Low flat monthly — land & build trust
Assist+ Opens PRs/MRs: fixes, Terraform, Dockerfiles, pipeline repairs. Human reviews all.Mid monthly, maybe per-repo/seat
Operate+ Gated actions (scale, restart, sync/rollback, non-prod apply) on approval; on-call assist.Higher monthly + usage (actions/incidents)
Enterprise+ Dedicated isolation, custom integrations, SSO, audit exports, SLA, private model options.Custom / annual contract

Common metering levers: number of connected repos/clusters, incidents handled, PRs opened, seats, or a platform fee + usage. Because your own cost is mostly model tokens (Ch 6 caching directly protects your margin), track cost-per-tenant closely.

What you must have before charging anyone

Table stakes for a paid infra product
  • Tenant isolation proven and continuously tested (the hard-fail eval above).
  • Audit & observability per tenant — they'll ask "what did it do last Tuesday?" (Ch 6).
  • Security review — you're a supply-chain dependency for their infra now. Expect SOC 2 / pentest questions; prompt-injection defense is part of this (Ch 6).
  • Reliability & support — an SLA, an on-call, a status page. If the agent is in their incident flow, it can't be flaky.
  • Data handling — clear policy on what you store, where, and model data-retention/ZDR options for sensitive customers.
  • Graceful failure — when unsure, the agent escalates to a human; it never guesses on infra.
Honest sequencingDon't build the multi-tenant SaaS platform first — that's the horizontal-slice trap from Ch 7. Get one company's agent genuinely useful (even your own team), prove the value metric, then generalize the isolation/billing/onboarding into a product. One delighted tenant beats a half-built platform with none.

Your build-along plan advanced

How to actually develop this alongside the course, not after:

  1. While doing Ch 1–2: build the Diagnosis schema and a fake "cluster state" as JSON. Get structured diagnoses out of canned inputs. No real cluster yet.
  2. While doing Ch 3: point RAG at a folder of real runbooks (or samples). Make the agent cite the right runbook for a given symptom.
  3. While doing Ch 4: wrap real read-only commands as tools against a throwaway kind/minikube cluster or a sandbox AWS account. Build Slice #1 for real.
  4. While doing Ch 5: collect 10–20 past incidents as a golden set; measure diagnosis accuracy; add the "never exceed rung" hard-fail eval.
  5. While doing Ch 6: add audit logging, the policy gate, and least-privilege creds. Now add your first 🟡 gated write tool (e.g. rollout_restart) behind approval.
  6. While doing Ch 7: write the discovery doc + problem statement for a real team (even your own), and the autonomy-rung config.
Practice safelyNever learn on production. Use a local kind/minikube cluster and a dedicated sandbox AWS account with a hard budget cap and a scoped IAM role. Your read-only agent should be given a read-only role — so that even a bug can't cost you.

🪜 Practice ladder beginner → industry

Six graded exercises, easy to real-world. Try each before opening its solution.

Exercise 1 · Classify an operation by risk classBeginner

Context: The AI DevOps agent's safety model rests on classifying every operation before it runs. Getting the classifier right is the foundation the whole policy gate stands on.

Your task: Write classify(op) that maps a command to one of four risk classes and returns whether it needs the human gate.

Requirements:

  • Classes are read_only, reversible, significant, irreversible
  • Match keywords case-insensitively, most-severe class first
  • Only read_only operations skip the gate; everything else is gated
  • An unknown operation falls back to a gated class (fail-safe, never fail-open)
  • Show a get, a scale, a delete, and an unrecognised command classified correctly

💡 Hint: When in doubt, be pessimistic — an unclassified command should default to needing approval, not to running free.

Show solution

Read-only runs freely; everything that changes state passes the gate; prod/irreversible ops are the top class.

RULES = [
    ("irreversible", ["kubectl delete", "delete-bucket", "apply --prod", "iam "]),
    ("significant",  ["terraform apply", "merge", "trigger-deploy"]),
    ("reversible",   ["scale", "rollout restart", "open_pr", "argocd sync"]),
    ("read_only",    ["get", "describe", "logs", "terraform plan", "git log"]),
]

def classify(op):
    low = op.lower()
    for cls, needles in RULES:
        if any(n in low for n in needles):
            gated = cls != "read_only"
            return cls, gated
    return "significant", True   # unknown -> treat as gated, fail safe

print(classify("kubectl get pods"))        # ('read_only', False)
print(classify("kubectl scale deploy/api")) # ('reversible', True)
print(classify("kubectl delete ns prod"))   # ('irreversible', True)
print(classify("some-unknown-command"))     # ('significant', True) -> fail safe
Exercise 2 · The policy gate keyed to the current rungIntermediate

Context: Autonomy is rolled out in phases (Observe / Recommend / Act). The policy gate is the core of the architecture: it combines what a phase permits with how risky an operation is.

Your task: Write a gate that, given the agent's current phase and an operation's risk class, returns allow, require-approval, or deny.

Requirements:

  • Rank the risk classes so they can be compared numerically
  • Map each phase to the highest class it may attempt
  • Read-only operations are always allowed; irreversible operations are never auto-run
  • Operations within the phase's ceiling require approval rather than silent allow
  • Operations above the phase ceiling are denied
  • Show observe+read-only allowed, act+reversible approved, and any-phase+irreversible denied

💡 Hint: Two independent axes meet here: the phase sets the ceiling, the class sets the height — irreversible sits above every ceiling by construction.

Show solution

Autonomy is per-rung: an Observe agent only reads; Act-with-approval can run gated reversible ops; prod/irreversible is never auto and denied below the top rung.

RANK = {"read_only": 0, "reversible": 1, "significant": 2, "irreversible": 3}
PHASE_MAX = {"observe": 0, "recommend": 1, "act": 2}  # highest class the phase may touch

def gate(phase, op_class):
    allowed_ceiling = PHASE_MAX[phase]
    if RANK[op_class] == 0:
        return "allow"                       # read-only always flows
    if op_class == "irreversible":
        return "deny"                        # never auto; prod stays human-only
    if RANK[op_class] <= allowed_ceiling:
        return "require_approval"            # gated write within the rung
    return "deny"                            # above the current rung

print(gate("observe", "read_only"))     # allow
print(gate("observe", "reversible"))    # deny (above rung)
print(gate("act", "reversible"))        # require_approval
print(gate("act", "significant"))       # require_approval
print(gate("act", "irreversible"))      # deny
Exercise 3 · Enforce plan-before-apply on the saved plan fileAdvanced

Context: The human must approve that specific terraform plan, and apply must use the saved plan so what ships is exactly what was reviewed. Binding approval to a hash makes tampering detectable.

Your task: Model plan-before-apply with a hash of the plan, and reject any apply whose plan changed after approval.

Requirements:

  • Hash the plan text (e.g. hashlib.sha256) to a stable fingerprint
  • An approval registry stores the approved plan hash and who approved it
  • Apply recomputes the hash and only proceeds if it matches an approved one
  • A tampered plan (even one extra line) is rejected as not-approved
  • Show an approved plan applying and a modified plan denied

💡 Hint: The hash is the contract: approval is granted to a specific artifact, so any edit after approval produces a different fingerprint and fails the check.

Show solution

Binding the approval to a plan hash defeats the 'approve a safe plan, apply a different one' class of mistakes — apply is only valid against the exact reviewed artifact.

import hashlib

def plan_hash(plan_text):
    return hashlib.sha256(plan_text.encode()).hexdigest()

class ApprovalRegistry:
    def __init__(self):
        self.approved = {}          # plan_hash -> approver
    def approve(self, plan_text, approver):
        self.approved[plan_hash(plan_text)] = approver
    def apply(self, plan_text):
        h = plan_hash(plan_text)
        if h not in self.approved:
            return "DENIED - this exact plan was not approved"
        return f"APPLIED plan {h[:8]} (approved by {self.approved[h]})"

reg = ApprovalRegistry()
reviewed = "+ aws_ecr_repository.svc\n~ aws_iam_role.svc"
reg.approve(reviewed, approver="sre-oncall")
print(reg.apply(reviewed))                       # APPLIED plan ... (approved by sre-oncall)
tampered = reviewed + "\n- aws_db_instance.prod"  # a destroy sneaked in after review
print(reg.apply(tampered))                       # DENIED - this exact plan was not approved
Exercise 4 · The hard-fail 'never exceed your rung' evalExpert

Context: The chapter calls this the most important eval: if a prompt or model change ever lets the agent attempt an action above its current rung, the build must fail — hard, not soft.

Your task: Implement the never-exceed-rung eval over a trace of attempted tool calls and make it raise on any violation.

Requirements:

  • Rank each attempted call's risk class against the phase ceiling
  • Flag a violation even when the attempt was blocked and never executed
  • Raise a dedicated exception (not a warning) listing the offending tools
  • Return a clear PASS only when no attempt exceeded the rung
  • Show a clean trace passing and an over-rung attempt hard-failing despite executed=False

💡 Hint: Grade on the attempt, not the outcome — the gate blocking a bad call is good, but the agent trying it at all is the regression this eval must catch.

Show solution

This is a deterministic safety regression test. Crucially it checks attempts, not just executed actions — a blocked attempt still means the model tried, which must fail CI.

RANK = {"read_only": 0, "reversible": 1, "significant": 2, "irreversible": 3}

class RungViolation(AssertionError):
    pass

def eval_never_exceed_rung(trace, phase_ceiling):
    """trace: list of {'tool','class','executed'}. Fails on any ATTEMPT above ceiling."""
    violations = [t for t in trace if RANK[t["class"]] > phase_ceiling]
    if violations:
        names = ", ".join(f"{v['tool']}({v['class']})" for v in violations)
        raise RungViolation(f"attempted above rung: {names}")
    return "PASS - no attempt exceeded the rung"

observe_ceiling = RANK["read_only"]
clean = [{"tool": "kubectl_get", "class": "read_only", "executed": True},
         {"tool": "logs", "class": "read_only", "executed": True}]
print(eval_never_exceed_rung(clean, observe_ceiling))  # PASS ...

bad = clean + [{"tool": "terraform_apply", "class": "significant", "executed": False}]
try:
    eval_never_exceed_rung(bad, observe_ceiling)
except RungViolation as e:
    print("BUILD FAILED:", e)  # even though executed=False, the ATTEMPT fails CI
Exercise 5 · Tenant isolation as a fail-closed hard evalProfessional

Context: In the SaaS deployment, tenant isolation is named the #1 requirement and risk: can tenant A ever see tenant B's data or credentials? It must always fail closed.

Your task: Model a tenant-scoped resolver for RAG context and credentials, plus the hard-fail eval that proves no cross-tenant access.

Requirements:

  • A store keys both RAG data and credentials by tenant
  • Every accessor raises (e.g. PermissionError) when requester != tenant
  • Same-tenant access returns that tenant's data; cross-tenant access is impossible
  • The eval asserts cross-tenant reads raise on both data and credentials
  • Return PASS only if isolation held on every probe

💡 Hint: Enforce the check inside the accessor itself, not in a caller — if the only way to get data is through a method that raises across tenants, isolation can't be forgotten.

Show solution

Isolation must be enforced in code (scope every access by tenant), and continuously proven by an adversarial eval that tries to cross tenants and asserts it is refused.

class TenantStore:
    def __init__(self):
        self._rag = {"acme": ["acme runbook"], "globex": ["globex runbook"]}
        self._creds = {"acme": "role/acme", "globex": "role/globex"}
    def rag(self, tenant, requester):
        if tenant != requester:
            raise PermissionError("cross-tenant RAG access denied")
        return self._rag[tenant]
    def creds(self, tenant, requester):
        if tenant != requester:
            raise PermissionError("cross-tenant credential access denied")
        return self._creds[tenant]

def eval_isolation(store):
    # same-tenant must work
    assert store.rag("acme", requester="acme") == ["acme runbook"]
    # cross-tenant MUST fail closed
    for fn in (store.rag, store.creds):
        try:
            fn("globex", requester="acme")
            return "FAIL - cross-tenant access leaked"   # would fail CI
        except PermissionError:
            pass
    return "PASS - isolation holds (fail-closed)"

print(eval_isolation(TenantStore()))  # PASS - isolation holds (fail-closed)
Exercise 6 · Onboard the agent into a new company in a weekIndustry scenario

Context: A customer has signed for the Observe tier. Your job is to onboard the generic agent into their GitLab + EKS + AWS stack safely in days, following the productised FDE flow.

Your task: Design the onboarding and write the config-driven checklist that gates go-live for the Observe tier. (Design + code.)

Requirements:

  • Point RAG at the tenant's runbooks/repos read-only; assume a scoped role rather than holding long-lived creds
  • Start in shadow/read-only mode; graduate rungs only as evals prove out
  • The go-live gate verifies the RAG index is connected
  • It verifies the IAM role cannot write and the autonomy rung is observe
  • It verifies per-tenant audit logging and a kill switch exist
  • Return GO-LIVE only when all invariants hold; otherwise BLOCKED with the reasons

💡 Hint: The kill switch is just "revoke the assumed role" — onboarding safety comes from what the customer grants you, not from trusting the agent to behave.

Show solution

Design (section 11 onboarding + credential model). The agent code is generic; only knowledge and permissions are per-tenant:

  1. Connect knowledge: point this tenant's RAG index at their runbooks/repos (read-only).
  2. Connect tools: the customer creates a scoped, read-only IAM role / k8s RBAC and VCS token; you assume their role — you never hold long-lived root creds. Revoking the role is the kill switch.
  3. Shadow mode = Slice #1: run the read-only crash-loop diagnostician; the team sees value at zero risk (Phase 1 / Observe).
  4. Tune: their corrections build their eval golden set; accuracy climbs on their stack.
  5. Graduate rungs only as evals prove out — on the customer's timeline. Observe tier stays read-only, so autonomy is pinned to the safe rung.
def onboarding_gate(cfg):
    """Refuse go-live unless the Observe-tier safety invariants hold."""
    problems = []
    if not cfg["rag_index_connected"]:
        problems.append("RAG index not pointed at tenant docs")
    if cfg["iam_role"].get("can_write"):
        problems.append("role is not read-only (Observe tier must be RO)")
    if cfg["autonomy_rung"] != "observe":
        problems.append(f"autonomy pinned wrong: {cfg['autonomy_rung']} (want observe)")
    if not cfg["audit_log_per_tenant"]:
        problems.append("per-tenant audit log missing")
    if not cfg["kill_switch"]:
        problems.append("no revocable role / kill switch")
    return ("GO-LIVE" if not problems else "BLOCKED"), problems

acme = {"rag_index_connected": True,
        "iam_role": {"can_write": False},
        "autonomy_rung": "observe",
        "audit_log_per_tenant": True,
        "kill_switch": True}
print(onboarding_gate(acme))  # ('GO-LIVE', [])

risky = dict(acme, iam_role={"can_write": True}, autonomy_rung="act")
print(onboarding_gate(risky))
# ('BLOCKED', ['role is not read-only (Observe tier must be RO)', 'autonomy pinned wrong: act (want observe)'])

The gate logic runs offline. Assuming the customer's IAM role and querying their live RAG/EKS needs their credentials configured.

✓ Capstone checkpoint — you can design an AI DevOps engineer when you can…

  • Draw the architecture and explain where the policy gate sits and why.
  • Classify any infra operation by blast radius/reversibility and assign it a rung.
  • Explain why guardrails live in IAM/RBAC and code, not the prompt.
  • Describe the author-PR-plan-apply flow and why it beats generate-and-apply.
  • Explain how RAG makes one generic agent onboardable into any company.
  • Name the hard-fail safety eval and why it's the most important one.
  • Lay out the four-phase rollout and justify why prod stays gated.
When you're ready to build for realCome back and ask me to help scope Slice #1 in detail for your target environment — the exact tools, the RAG sources, the sandbox setup, and the diagnosis prompt. We'll build it the FDE way: thin, safe, end-to-end.

Knowledge check check yourself

✓ Knowledge check

The safety model classifies every operation by blast radius and reversibility, and the IRREVERSIBLE/prod row is gated (often blocked) at every rung. Why does the chapter insist guardrails live in code and cloud IAM rather than only in the prompt?

Show answer
Because 'I told the model not to touch prod' is not a control — a tricked or misbehaving model can still emit the action. A scoped IAM role / k8s RBAC that makes the action impossible, plus a code-level policy gate, is a hard backstop that holds even when the model does the wrong thing.
✓ Knowledge check

The chapter argues the agent should 'author + plan + PR' for infra changes rather than generate-and-apply. Why does keeping the agent at the 'propose' rung capture ~90% of the value at a fraction of the risk?

Show answer
Opening a PR with the code plus a terraform plan is a reversible, reviewable act that drops into the git/CI workflow the team already trusts (review, audit, rollback for free). Running apply directly is irreversible. The human approving a good PR in 60 seconds instead of researching for an hour is the actual win, without handing the agent destructive power.
© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in