Skip to content

Handover

Written 2026-09-02, at the end of the design-and-scaffold phase. Everything a fresh session — human or agent — needs to pick this up cold.

Conference: 26–27 October 2026. Roughly eight weeks out.


1 · Where this stands

Proposal Accepted, co-speaker confirmed. Slides not uploaded.
Design Done. Premises tested, plan written, environments and tiers decided.
Docs Complete scaffold, mkdocs build --strict green.
Infrastructure Built and tested against a live cluster.
The referee Built, adversarially tested.
Eval harness Built, validated 12/12 with the oracle backend.
The agent Not built. agents/run.sh is a stub. This is the next thing.
Website Built and deploying. Astro at web/, three pages from the design canvas, running on hlutur at aco.hlutur.no.
Labs, quests Not started.

Eight commits, all local — there is no git remote yet.

2 · What the workshop is actually claiming

Three hypotheses, from the development plan. All work should be pointed at proving or falsifying one of them.

  • H1 Capability — an agent can do real ops tasks reliably enough to be useful.
  • H2 Safety — guardrails bound the damage without making it useless.
  • H3 Teachability — 35 strangers can do this on their own laptops in two hours.

The differentiator is that we will have numbers. Nobody else at the conference will stand up and say "31 of 40 runs". Protect that.

Decided in advance: a negative result is a better workshop

If Lab 2 lands at 55%, we do not re-roll until we get a clean demo. We report the number and show where the line is. Gate B (§6) is where that call gets made.

3 · Decisions already taken

Don't relitigate these without a reason.

# Decision Why
B1 All three environments, on one namespace-scoped contract Codespaces removes our two biggest risks; k3d is what we develop on; BYO is the most realistic
B2 Claude Code + a Kubernetes MCP server, not a custom LangChain agent The safety flags become the teaching material instead of code we maintain
B3 Workshop API keys with a spend cap, handed out on cards The only fallback that works. Ollama is not viable alongside a cluster on 8 GB
B4 Lab 3 is a facilitator demo, not hands-on 15 minutes plus a non-deterministic agent is the block that breaks the schedule
B5 Astro at root, MkDocs at /docs, one Pages deploy One domain, two appropriate designs
B6 Fork the MCP workshop's quest-server; build it last The machinery is already tested. It is cuttable if time runs out
Docs in English, workshop delivered in Norwegian Useful beyond the room
k3d over Talos Talos defaults to ~2.1 GB/node in Docker; three nodes doesn't fit in 7.7 GB

4 · The load-bearing idea

The namespace is the unit of work, not the cluster.

Every lab, guardrail, eval and quest targets one namespace with a namespace-scoped ServiceAccount. Nothing in the participant path needs cluster scope.

It pays off four times over, and all four are now verified rather than hoped for:

  1. Three environments differ only in how you get a kubeconfig (~20–30 lines each).
  2. Bring-your-own-cluster is safe, because a RoleBinding cannot reach past its namespace.
  3. Eval reset is 11.5s instead of ~124s for a cluster rebuild.
  4. It contained the blast radius when our own tooling misfired — see §7.

5 · What exists, and what it does

bootstrap/
  base/                one kustomization: namespace, RBAC ladder, insecure workload
  apply.sh             environment-agnostic apply + rollout wait
  env/{k3d,codespaces,byo}.sh
  verify.sh            the five contract assertions
  nuke.sh              deletes exactly one namespace, prints it first
bin/health.sh          THE REFEREE. --json for the harness
evals/
  run.py               the harness; backends: claude | oracle | noop
  reset.sh             namespace reset, ~11.5s
  scenarios/*.yaml     4 scenarios, each with a known-good `fix:` for the oracle
  results/*.jsonl      committed evidence
agents/run.sh          STUB. The seam. Next thing to build.
.devcontainer/         4-core Codespace, images pre-pulled at build
docs/design/           the imported design canvas, verbatim + reconciliation table
web/                   the Astro site: /, /prepare, /404
  src/lib/replay.ts    the replay state machine, 35 unit tests
  src/lib/schedule.ts  the revised schedule, asserted against the Makefile

Verified results

make verify        10/10 checks pass
make eval-all AGENT=oracle    harden-restricted 3/3, imagepullbackoff 3/3,
                              injection-probe 3/3, secret-deleted 3/3
make eval --agent noop        0/2 — failure detection confirmed

The RBAC ladder was tested with real API calls, not kubectl auth can-i:

As agent-harden
patch deploy
delete deploy 🚫 Forbidden — the verb is absent
get secrets 🚫 Forbidden
-n kube-system get pods 🚫 Forbidden

6 · Next: build agents/run.sh

This is the seam. Everything else is waiting on it, and it unblocks the first real H1/H2 numbers.

Contract it must honour

in:   $1 = mode (deploy|harden|incident), prompt on stdin, KUBECONFIG already pinned
out:  one JSON object on stdout:
      { "report": "...", "iterations": 7, "tool_calls": [...],
        "input_tokens": 0, "output_tokens": 0, "cost_usd": 0.0 }

Requirements

  • Pin the exact model id. Not a moving alias — it invalidates every recorded number.
  • Wire the Kubernetes MCP server with disable_destructive.
  • Run as the agent-harden ServiceAccount, never your own kubeconfig identity.
  • Hard iteration cap. A runaway loop must end the run, not the budget.
  • Record every tool call — the debugging path is the teaching material; the final answer is the least interesting part of the transcript.
  • Emit token counts and cost. Budget matters and quest #8 scores on efficiency.

Then, immediately

make eval SCENARIO=imagepullbackoff N=10 AGENT=claude

Gate A: Lab 1 must reach ≥80%. If it doesn't, simplify Lab 1 before touching anything else — a flaky first lab loses the room permanently.

Then harden-restricted for Gate B: ≥70%, or re-frame Lab 2 honestly.

7 · Things that bit us — read before writing code

The near-miss

A sweep ran against hlutur, a live 675-day-old cluster with cert-manager, Flux and 26 deployments, because the kubectl context changed under a running sweep — three times, unexplained.

Nothing was harmed, for one reason: every delete in reset.sh was namespace-scoped, and the namespace didn't exist there. The blast-radius design caught our own tooling bug.

evals/run.py now pins the context into a private KUBECONFIG, and reset.sh refuses any namespace not labelled as ours. Never make anything destructive depend on ambient context. This story belongs on a slide in block 1.

Shell and kubectl traps

Trap Fix
zsh expands $NS:agent-harden via the :a path modifier Always ${NS}: — hits every Mac
patch --type=merge replaces container arrays, drops image Use default strategic merge
ports strategic-merges by containerPort, appending a duplicate name --type=json with replace
kubectl logs deploy/x picks a pod arbitrarily Address pods by name
Terminating pods report phase=Running but stop working Filter on deletionTimestamp

The Lab 2 trap is real

Writing the oracle fix for harden-restricted took three attempts. That is evidence the lab is genuinely hard, not an embarrassment:

  • nginx:alpine cannot bind :80 as non-root → forces both an image change and a Service targetPort change
  • the unprivileged image writes to /tmp, not only /var/cache/nginx
  • an emptyDir over /etc/nginx/conf.d wipes the server config outright
  • the failure looks like: [emerg] mkdir() "/tmp/proxy_temp" failed (30: Read-only file system)

Expect a real agent to hit every one of these.

8 · Known drift and loose ends

  • manifests/insecure/ and manifests/chaos/ are empty stubs. The insecure workload actually lives in bootstrap/base/workload-insecure.yaml. make insecure still points at the empty directory. Decide: delete manifests/ and update the docs, or move the workload.
  • make lab1-break, make chaos, make prove, make audit, make agent-check are TODO stubs. lab1-break and chaos can lift their commands from the eval scenarios, which already work.
  • docs/landingpage-v2.md is an empty file you created; it got swept into a commit.
  • ~~No git remote.~~ Now github.com/leffen/agentic-cloud-ops (private).
  • k3d is not installed on the dev machine — bootstrap/env/k3d.sh is written but has never been run. Testing used kind, deliberately, to prove the base is environment-agnostic.
  • Codespaces is unproven. devcontainer.json is written; nobody has opened a Codespace.
  • make preflight does not match its own help text. It checks for tools only — no image pre-pull, never exits non-zero, and prints the Norwegian MANGLER on failure. prerequisites.md claims it pre-pulls, and /prepare step 04 now carries a caveat saying so. Fix the target, then drop the caveat.
  • setup.md step 5 tells participants to run make agent-check, which is a TODO stub.
  • No per-OS setup instructions exist. /prepare has OS tabs because the design has them; macOS is real, Linux is partial, Windows/WSL is marked untested.
  • dns-mess and node-pressure are cluster-scoped, so they break BYO and our own Lab 3 demo. Re-scope both to namespace level: DNS via an egress NetworkPolicy on :53, memory via a ResourceQuota plus a greedy pod.

9 · The eight-week shape

Week Focus Gate
W1 ✅ contract, referee, harness. Remaining: agents/run.sh
W2 Prove Codespaces end to end. First real eval numbers
W3 Lab 1 finished Gate A — Lab 1 ≥ 80%
W4 Lab 2, chaos re-scoping
W5 Tune Lab 2, injection probe numbers Gate B — Lab 2 ≥ 70%
W6 Slides, landing page, quests (cuttable) Outside dry run
W7 Act on feedback. Freeze prompts. Runbook
W8 Participant instructions, keys, network test Ship

Two things to book this week while calendars are empty: the W6 dry run with four people who aren't you, and two community facilitators. Two people for 35 hands-on participants is thin.

10 · Working agreements

  • Lars E owns agent and evidence (H1/H2): harness, prompts, MCP, injection probe, block 1.
  • Lars S owns cluster and curriculum (H3): environments, manifests, chaos, participant docs, landing page, block 6.
  • A 45-minute weekly sync. Third agenda item, every time: what are we cutting?

Full reasoning in the development plan.