Chapter 16 of 18

Shipping and running

Getting code to users safely and knowing what it does there: deploys, flags, rollbacks, logs and incidents.

Code nobody runs has done nothing. Tests, types and review are all predictions about what the code will do. Production, the place where real people use it, is where you find out which of those predictions were true.

Agents raise the rate of change. Chen and Stratton, in a working paper using data from 655 firms (version of 1 November 2026), found that pull requests opened rose 35.7% after teams adopted agents. Google's SRE book, describing its own systems before coding agents existed, says "roughly 70% of outages are due to changes in a live system". Put those two together and you have a reason to care about how a change gets out, and about what you can see once it has.

DORA's 2025 report calls AI an amplifier, and finds that AI adoption now goes with higher delivery throughput and still with more instability. It is a survey of nearly 5,000 people, self-reported and correlational, so it shows a pattern and not a cause. We looked for a primary study measuring incidents caused by AI-written code and found none, so this chapter won't imply one. If someone quotes you a rate, ask where it came from.

So the chapter runs in the order the work does: make something that can run, get it out so you can take it back, see what it is doing, agree how much failure is acceptable, respond when it breaks, and measure whether all of this is working.

Production

Also called Prod, Live

Where your software runs for real, with real users, real data and real money. Every other copy of it exists to prepare for this one.

It is the one place where a mistake reaches people, and the only place that can tell you what was true. An agent should have no way in unless you gave it one on purpose.

Say it to your agent

“Use the staging database URL, and read-only production logs if you need them. Production credentials don't go in .env on this machine. If a job has to touch production, give me the exact command and I'll run it.”

Environment

Also called Deployment environment

One complete place your software can run, with its own address, its own data and its own settings. Development on your machine, staging and production are the usual three.

The more two environments differ, the less a pass in one tells you about the other. And an agent that can't tell which one it is in will sooner or later run the right command in the wrong place.

Say it to your agent

“Add a dev:fresh script so you can boot your own copy of this app on a free port, with a throwaway SQLite database and seed data. Test against that. Print which environment you are in on the first log line.”

Staging

Also called Pre-production, Preprod

An environment that copies production as closely as you can afford, where a release runs before real users get it.

It catches what shows up only when the pieces run together: a bad setting, a missing variable, a migration that won't run. It can't show what only real traffic and real data reveal, and a pass there can feel like more proof than it is.

Say it to your agent

“Deploy to staging and run the smoke tests against its URL. Then tell me what staging can't show us: it has 200 rows and one user. List anything that needs real traffic to prove, and we'll watch for that in the canary.”

Before anything can run anywhere, it has to be made into something that runs, out of your code and a lot of other people's.

Build

The step that turns source code into the thing that actually runs: compiling, bundling, and copying everything into one output.

It is the first time all of the code has to fit together. A build also pulls things in from outside, such as dependencies, so it is where a change nobody made can arrive.

Say it to your agent

“Run bun run build from a clean checkout, in CI and not on your machine, and show me the output. If it needs anything that isn't in the repo or the lockfile, tell me what, because that means it builds only here.”

Semantic versioning

Also called Semver, Version range, Caret range

A three-part version number, like 2.4.1, that makes a promise. The last number means a bug fix, the middle one a new feature that breaks nothing, and the first means something may break.

It lets tools take safe updates on their own. But it is a promise made by a person, and nothing enforces it, so a patch can still break you.

Say it to your agent

“Bump zod from 4.1 to 4.6. It is a minor, so it should be safe, and you will check that and not assume it: run the full tests, read the changelog, and tell me anything we use whose behaviour changed.”

Pinning

Also called Version pinning, Frozen lockfile

Fixing the exact version of something you depend on, by number or by hash, so that it changes only when you decide. A range is a rule. A pin is this one and no other.

Without a pin, a build can change or break on a day nobody touched the code. But a pin holds still in both directions: a security fix doesn't arrive until someone moves it. So pin, and have something move the pins for you, with tests in front.

Say it to your agent

“Use bun install --frozen-lockfile in CI, so that a mismatch fails the build. Pin each GitHub Action to a full commit SHA with the version in a comment. Add Dependabot to open weekly PRs that move them, so the pins don't go stale, and let CI judge each one.”

SBOM

Also called Software bill of materials

A list of every component in your software, including what your dependencies depend on, with exact versions. An ingredients label, generated from what you really built.

When an advisory lands, the first question is "do we have this?", and the answer is often in a package nobody here chose. With a list it takes seconds. An agent can add a dependency in one line of a diff, so the list is worth more than anyone's memory.

Say it to your agent

“Add a CI step that generates a CycloneDX SBOM with syft from the build output, and saves it next to the release. Then answer from it, and not from package.json: do we ship any version of zod below 4?”

Artefact

Also called Artifact, Build artifact, Release artifact

The finished output of a build, stored with a version so that you can move exactly that thing between environments. A bundle, a zip, a container image.

If you build again for production, what you tested isn't what you ship. Build once and move the same artefact along, and a pass in staging says something real about production.

Say it to your agent

“Have CI build once on merge and label the output with the commit SHA. Staging and production both deploy that same artifact, with no second build in the deploy job. Show me that the hash matches on both sides.”

An artefact needs somewhere to run. A container brings its surroundings with it. Serverless hands the surroundings to someone else.

Container

Also called Docker container, Container image

A way to package a program with all the files it needs and run it as an isolated process, so that it behaves the same on your laptop and on a server.

It makes "works on my machine" a smaller problem, because the machine's contents travel with the program. It also gives an agent a place to run commands where a mistake is more likely to stay inside.

Say it to your agent

“Write a Dockerfile: pin the base image by digest, copy only what the app needs, and run as a non-root user. Build it in CI, and run it here with docker run before you tell me it works.”

Serverless

Also called Functions as a service, FaaS

You hand a provider your code, and they run it on their machines when requests arrive. There are still servers. They just aren't yours to manage.

There is nothing of your own to patch or keep running. The price is limits you don't choose, code that can't count on anything staying in memory between requests, and a dependence on one provider.

Say it to your agent

“This runs on Cloudflare Workers, so don't keep state in a module-level variable and expect it on the next request, which may not reach the same instance. Put it in the database, and show me every place you read it.”

Infrastructure as code

Also called IaC, Terraform

Describing your servers, databases and networks in files kept in the repo, and letting a tool make the real world match them, in place of clicking around a console.

Changes become reviewable and repeatable. It also means one wrong command can change everything at once. Agents are good at writing these files. The danger is in letting them run the result.

Say it to your agent

“Write the Terraform and run terraform plan -out=tfplan. Show me every line that says destroy or replace. Never run apply and never use auto-approve: I'll apply that saved plan myself. If you can't read the remote state, stop and say so.”

Config and secrets

Also called Environment config, Deploy secrets

Whatever changes between deploys belongs outside the code: addresses, keys, passwords. The same artefact can then run anywhere, reading its settings from wherever it is running.

Hardcoded config means rebuilding to move, and a key in the repo is a key in every clone, every log and every agent's context. Deleting it later doesn't help, because the history remembers: rotate it.

Say it to your agent

“Move the API key and database URL out of the code and read them from the environment. Fail at boot with a clear message if one is missing. List the names in .env.example with no values. Then check the git history, and tell me if the old key was ever committed, because then it needs rotating.”

Now it has to get out, and the way out decides how much risk each change carries.

Deployment

Also called Deploy

Putting a new version where it can run. The aim is to make it automatic, small and boring, so that it can happen often.

A manual step is one that a tired person or an eager agent will skip. So deploying should be a script, the same every time, and what matters most is what stands in front of that script.

Say it to your agent

“Add a deploy job to ci.yml with needs: check, so that it can't start unless check passed. Give it a GitHub environment called production with a required reviewer, and put CLOUDFLARE_API_TOKEN in that environment's secrets. Then tell me every way someone could still deploy around it.”

Continuous delivery

Also called CD

Keeping your software in a state where it could go to production at any moment, so that releasing is a decision and not a project.

Small changes are easier to check, and easier to take back. This matters more with agents, because they produce changes faster, and saving those up into one big release piles up risk that nobody can review.

Say it to your agent

“Split this into four PRs that can each go to production alone: the migration, the reader, the writer, and the UI behind a flag. Main has to be deployable after each one. If it can't be, tell me which and why.”

Trunk-based development

Also called TBD

Everyone merges small changes into one main branch, at least daily, and nobody keeps a branch going for long. Unfinished work stays hidden behind flags.

The longer a branch lives, the more it and main both change, and conflicts grow faster than the time does. Parallel agents sharpen this, because each one is a branch.

Say it to your agent

“Rebase on main before you start, keep this branch under a day, and merge behind the new-search flag even though it isn't finished. If you can't split it that small, stop and tell me why before you write more.”

Deploying and releasing can be two different moments. That is the main idea of the next four words.

Feature flag

Also called Feature toggle, Kill switch, Percentage rollout

A condition in your code that turns something on or off, for some or all users, without a deploy. The code ships switched off, and you switch it on when you are ready.

If a release goes wrong, turning it off takes seconds and not a rollback. A percentage lets you try it on a few people first. The cost is real: each flag is a second version of your code, which has to be tested and later removed.

Say it to your agent

“Put the new checkout behind a flag called new-checkout, off by default, with a hash of the user id picking the percentage, so nobody flips between versions. Test it both on and off. Add a ticket, with an owner, to delete the flag within two weeks of reaching 100%.”

Canary

Also called Canary release, Canary deployment, Gradual rollout

Sending a small share of real traffic to the new version, comparing it with the old one, and only then sending everyone. If it is bad, few people met it.

Some problems appear only under real traffic, and a canary limits how many people find them. It only helps if you can tell in time, which takes enough requests and a real comparison. A tiny canary on a quiet site tells you nothing.

Say it to your agent

“Deploy with wrangler versions deploy at 10%, and compare its 5xx rate with the old version's for 15 minutes. At 1,000 requests a minute, 10% is enough to judge. If it is worse, go back to 0% and tell me. If not, go to 50%, then 100%. "No alerts fired" doesn't count as a pass.”

Blue-green deployment

Also called Blue-green

Two identical production environments. One serves users while you deploy to the other and check it. Then you switch the traffic across, and the old one stays ready to switch back to.

Going back becomes flipping a switch, and nobody meets a half-finished deploy. You pay for two environments while you keep both, and there is usually one database, which both versions have to work with.

Say it to your agent

“Deploy to the idle environment and run the smoke tests on its private URL. Only then switch the load balancer, and keep the old one running for an hour. Any database change has to work with both versions, so do that first, separately.”

Rollback

Also called Roll back, Roll forward, Fix forward

Going back to the previous version after a bad release. Rolling forward is the other choice: shipping a new version with the fix. Rolling back is usually faster, so you stop the harm first and fix it calmly.

How quickly you can undo decides how much risk each change carries. The trap is data. Code goes back and data doesn't, so one migration can quietly remove your way back, and you find out on the worst possible day.

Say it to your agent

“Before we deploy, tell me the rollback: the exact command, how long it takes, and what happens to rows written by the new version. If this migration makes that impossible, split it with expand and contract, so that going back works at every step. Then rehearse it on staging.”

Once it is out, can you tell what it is doing? If you can't, you shipped it blind.

Observability

Also called o11y, Monitoring

How well you can work out what a running system is doing from the outside, using what it emits, including for problems you didn't predict.

It decides whether you find out from your signals or from your users. It also changes what an agent can do: if it can read logs and traces, it can check its own work, and you aren't the one relaying symptoms.

Say it to your agent

“Before you ship this, give me a way to see it in production: log one JSON line per request with route, status, duration and release, and tell me the exact query that would show the new code failing. Run that query on staging and show me its output.”

Logs, metrics and traces

Also called Telemetry, Spans, The three pillars

Three kinds of signal. A log is a timestamped event. A metric is a number over time, such as requests a second. A trace follows one request through every call it makes.

They answer different questions: a metric says something is wrong, a trace says where, and a log says what happened there. Give an agent only one of them, and it will guess at the rest.

Say it to your agent

“Checkout p95 went from 300 ms to 900 ms on Tuesday. Pull one slow trace and one normal trace, and compare them span by span. Tell me which span grew, then find the log lines for that trace id. Don't guess from the code until you have the trace.”

Structured logging

Also called Structured logs, JSON logs, Canonical log line

Writing each log entry as named fields, usually JSON, and not as a sentence. A query can then ask for exact values, without guessing at the wording.

In an incident the question is "which users, which release?". Against free text, every answer is a guess at how someone phrased it, and it is wrong without saying so. An agent reading the logs does far better with fields it can query than with prose it has to interpret.

Say it to your agent

“Log one JSON line at the end of each request, with route, status, duration_ms, user_id, order_id and release. No names, emails, card numbers or tokens. Then give me the query for which users got a 502 on release v2, and run it on staging.”

Seeing isn't enough. You also have to decide how much failure is acceptable, and the time to decide is before anything fails.

SLI and SLO

Also called Service level indicator, Service level objective, SLA

An SLI is a measure of how your service is doing, like the share of requests that succeed in time. An SLO is the target you set for that measure, like 99.9% over 30 days.

Without an agreed number, "is it reliable enough?" is an argument about feelings, and perfect isn't on offer. With one, you know when to keep building and when to stop and fix things. Choose what counts as good with care, because that choice can hide a real problem.

Say it to your agent

“Propose one SLI and one SLO for checkout: the share of POST /checkout requests that return under 500 ms and aren't 5xx, measured at the load balancer, over 30 days. Compute the last 30 days from real logs and tell me where we are before you suggest a target.”

Error budget

The failure your SLO allows. At 99.9% over 30 days, that is 43.2 minutes of total outage. While there is budget left you ship, and when it is gone you stop and work on reliability.

It turns an argument into arithmetic, and it applies directly to agents. If they let you ship faster than your budget can absorb, the budget says slow down, whatever the velocity chart says.

Say it to your agent

“We run at 99.9% over 30 days, so we have 43.2 minutes. Tuesday's incident was 18 minutes at 30% failing, about 5.4 budget minutes. Work out what is left from the real logs. If we have spent over half in the first week, hold the risky migration and work on the cause.”

Alert

Also called Page, Burn-rate alert, Alert fatigue

A signal that tells a person to act now. A good one fires when users are being hurt and someone can do something about it. A burn-rate alert does this by asking how fast the error budget is going.

An alert that cries wolf gets ignored, including on the day it is right, and one set too high misses the slow leak. Asking an agent to "add monitoring" can produce alerts by the dozen, so ask for few, and ask what each would have caught.

Say it to your agent

“Replace these 14 threshold alerts with a burn-rate alert on the checkout SLO: page at 14.4x over 1 hour and 5 minutes, page at 6x over 6 hours and 30 minutes, ticket at 1x over 3 days and 6 hours. Replay last month, and show me how many pages we would have had and what each one caught.”

An alert needs someone to answer it.

On-call

Also called Pager, Rotation

The rota that decides who answers when something breaks, at any hour. That person has to respond quickly, and needs the access and the knowledge to act.

An agent can write the code and it can't be accountable at 3am. Whoever is on call has to understand what shipped, and a codebase nobody has read is a bad thing to be woken up by.

Say it to your agent

“Write the on-call note for this change: what it touches, how we would know it is broken, the exact command to turn it off, and what you aren't sure about. Assume the reader was just woken up, has never seen this code and can't ask you.”

Incident

Also called Outage, Incident commander, Mitigation

An unplanned event that is hurting users, or about to, and needs people to coordinate. The work has an order: stop the harm first, then understand why.

The instinct is to hunt for the root cause while users keep failing, and an agent's instinct is to start changing things. Someone has to hold the whole picture and decide what gets tried, because a change made during an incident needs the most care of all.

Say it to your agent

“We have an incident and I am running it. You are read-only: pull the error rate by release for the last hour, and the last three deploys. Change nothing, even things you are sure about. Give me two options for stopping the harm, each with what it could make worse.”

Runbook

Also called Playbook

Written steps for a known situation, which someone tired can follow: what you see, what to check, the exact commands, and when to call for help.

Thinking it through while calm beats thinking it through in an emergency. A runbook in the repo is also something an agent can read and follow, and that gives you a cheap way to find out whether it has gone stale.

Say it to your agent

“Write docs/runbooks/checkout-5xx.md: how to confirm it, how to tell a bad deploy from a gateway outage, the exact rollback command, and who to call. Then have a fresh session follow it on staging with no other context, and fix every step where it got stuck.”

Time to restore

Also called MTTR, Mean time to recover, Failed deployment recovery time

How long it takes to get back to healthy after something breaks. DORA's current version, failed deployment recovery time, counts only failures caused by a change.

You can't stop every failure, and you can decide how fast you recover. It is why rollbacks and flags pay for themselves. Take care with the mean, because one bad day can dominate it, so report the median as well.

Say it to your agent

“Compute our recovery time from this quarter's incident log, both the median and the worst, and leave out the two provider outages. Then split each incident into time to notice, time to decide and time to fix, and tell me which part is largest.”

Postmortem

Also called Blameless postmortem, Incident review

A written record of an incident: what happened, what it cost, why, and what changes so that it doesn't happen again. Blameless means it asks how the system allowed this, and doesn't stop at who.

People who fear blame hide what they did, and then nobody learns. With agents there is a new version of this: "the agent did it" is blame with a new target. Who gave it that access, and which check let it through?

Say it to your agent

“Draft the postmortem from the timeline, the logs and the diff. No names, and never "the agent decided". Say what the agent was able to do and what the checks allowed. Mark each cause as evidenced or guessed. Each follow-up gets an owner and a date, and at least one has to be a check that would have failed.”

Last question: is all of this working? These are the most widely used numbers for answering it, which is also why they are so often misquoted.

DORA metrics

Also called DORA, Four keys

Five measures of software delivery from Google's DORA research: change lead time, deployment frequency, failed deployment recovery time, change fail rate and deployment rework rate. Speed and stability, side by side.

They stop you fooling yourself with lines written or pull requests merged. Speed with no stability number beside it hides what it cost, and that is the case you need to catch when agents raise the rate.

Say it to your agent

“From the deployment history and incident log, compute all five DORA metrics for this service over the last 90 days. Give me the definition you used for each, including what counts as failed. Compare us with our own previous 90 days and not with other teams.”

Change fail rate

Also called Change failure rate, CFR

The share of deployments that need fixing straight away, by a rollback or a hotfix. Five bad deploys out of fifty is 10%.

It is the number that shows whether going faster is costing you. It is also easy to fool: the definition of failed moves it a lot, and adding harmless deploys lowers it with the same number of bad ones.

Say it to your agent

“Count change fail rate over the last 90 days. Failed means rolled back, hotfixed within a day, or a flag turned off because of harm. Leave out no-change deploys and say how many there were. Show me the list, so I can argue with the definition before I see the number.”

The amplifier

Also called AI as an amplifier

DORA's description of what AI does to a software team: it makes strong teams stronger, and makes the problems of struggling ones worse. What decides which is what was already around the tool.

So buying the tool doesn't settle what you get. This chapter is the surrounding part: small changes, a way back, real signals and an agreed budget. Without them, a faster rate of change can reach your users as more failures.

Say it to your agent

“Before we double the agents on this repo, pull our change fail rate, recovery time and budget spend for the last 90 days. Tell me which of those gets worse at twice the deploys, and what would have to change first. Use numbers from our logs, and not from a report about other companies.”

Do it for real

Reading gets you the words. This gets you the experience behind them, and something to show.

Ship one small thing, then undo it

You don't have a way back until you have used it. An hour of this tells you more about your deploy than any diagram of it.

  1. Pick a small real project you have, or make one, and deploy it somewhere free. A Cloudflare Worker or similar is plenty.
  2. Ask your agent to add a CI job that runs your checks, and a deploy job that can't start unless they pass. Read the workflow yourself, then try to break the check and confirm that the deploy doesn't run.
  3. Ask your agent to put one visible change behind a flag, using a hash of a user id. Turn it on for 10%, and check that the same id gets the same answer every time.
  4. Ship a deliberately bad version, on purpose, where you can see it fail. Then roll it back, timing how long that takes from the moment you notice.
  5. Write down the exact rollback command and the time it took, and keep them in the repo.

Done when: A workflow that refuses to deploy after a failing check, a screenshot or log of that refusal, and your rollback command with a measured time next to it.

Put a number on one service

Everyone has a feeling about how reliable their software is. A number you can defend changes the conversation, and calculating one shows you what your logs can't yet answer.

  1. Choose one user-facing action on something you run. If you have no real traffic, generate some with a script and say so.
  2. Ask your agent to log one JSON line per request, with the route, status, duration and release. Then write the query for "how many of the last 1,000 requests were good?" yourself.
  3. Decide what good means, including how fast, and pick an SLO. Work out the budget in minutes for 30 days by hand, then check it on the error budget bench.
  4. Ask your agent for a burn-rate alert from the Workbook's table, and for how many times it would have fired on the last week of logs.

Done when: One page saying: this SLI, this SLO, this much budget, what we have spent, and what would page someone, with the query that produced each number.

Break it on purpose, and write it up

An incident is the worst time to find out that your signals don't work. This drill lets you find out on a day you chose, and it finishes with the step teams most often skip, which is turning what you learned into a check.

  1. On staging or a throwaway copy, introduce a fault without telling yourself exactly when: ask an agent to pick one from a list you wrote, such as a wrong config value, a slow call or a bad migration.
  2. Time how long it takes you to notice, using only your signals, and how long it takes to stop the harm. Keep the agent read-only while you do this.
  3. Write a blameless postmortem from the evidence: impact, timeline, causes and follow-ups. Run it through the check on the postmortem bench, and mark each cause as evidenced or guessed.
  4. Pick one follow-up and turn it into a test or a CI step that would have caught this. Show it failing on the broken version.
  5. Ask a fresh agent session to find the same fault using your runbook alone. Fix whatever stopped it.

Done when: A written postmortem with no names in it, a new check that fails on the broken version and passes on the fixed one, and your measured times to notice and to recover.

The build, stage 16 of 18

Live, broken, and back

The app on Cloudflare, an incident you caused on purpose, a timed rollback, a blameless postmortem, and a new check that fails on the broken version.

About 180 to 300 minutes, on the same app as every other stage. We ran it first and show what went wrong.

Open stage 16 of the build

Gate 16: Shipping and running

0 of 6 right

  1. 1You get 1,000 requests a minute. A colleague wants the canary at 1%, "so that hardly anyone gets hurt". The release might have a bug that fails 3% of requests, where normal is 0.5%. What is the best answer?

  2. 2A release dropped the users.name column and shipped new code to match. Forty minutes later, checkout errors appear. The agent proposes wrangler rollback. What do you check first?

  3. 3An alert fires when the error rate is over 0.3% for 5 minutes. It paged 40 times last month, and nobody needed to act on 38 of them. The SLO is 99.9%. What do you change?

  4. 4A slide says: "DORA proved AI causes more incidents, and only 3% of developers highly trust it." Which correction is right?

  5. 5An agent deleted a staging cluster and then a production one. The draft postmortem says: "Root cause: the agent decided to delete the cluster. Asked why, it said it misread the config. Follow-up: use a better model." What is wrong?

  6. 6CI built fine last week. This week it fails, and nobody changed the code. package.json has "typescript": "5.9", and CI runs an install that is free to update the lockfile. What do you do?

Get every answer right to install it, and to put 4 files in your repo. Wrong answers cost nothing.

Next chapterMany agents

The workshop

Name a word, or describe what you mean in everyday language.