← Back to Blog

I Told the AI I Was Going to Bed. It Migrated 40 Sites While I Slept.

Paul Allington 19 June 2026 9 min read

At about half eleven one night I typed a sentence into Claude Code that, written down in cold daylight, looks completely unhinged: "I am now going to bed. keep going until you have completed the whole migration...do not ask questions until all sites have certs." Then I closed the laptop lid, brushed my teeth, and went to sleep while an AI deleted roughly forty production web apps one after another.

I'll be honest with you, when I describe it like that to other developers I get a particular face in return. The face says "you absolute lunatic". And I understand the face. Deleting a live app is about as destructive an operation as you can run in Azure short of dropping a database. Doing forty of them, unsupervised, overnight, sounds less like engineering and more like a dare. But it wasn't a dare. It was, if anything, almost boring. And the boringness is the whole point.

What I was actually doing

The job was unglamorous. I had around forty-two web apps sitting on an expensive dedicated App Service plan, a P3v3, that I'd long since outgrown the need for. They didn't need that much horsepower each, and I was paying dedicated-plan money for the privilege of over-provisioning. The plan was to shuffle the whole lot onto a cheaper, shared plan, a P2mv4, and stop bleeding money every month.

The annoying part is that you can't just drag a site from one plan to another and call it done when DNS and certificates are involved. The reliable path, the one I'd already proven worked, was destructive for every single site. Back the app up. Delete it. Recreate it with the exact same name on the new plan. Re-bind the custom DNS. Re-issue the managed TLS certificate. Repeat forty-two times.

Every one of those steps is a place a site can go dark and stay dark if you fluff it. And the bit that makes a human want to do it slowly, one careful site at a time, with a cup of tea and full attention, is exactly the bit that makes it perfect for an AI to grind through overnight. The risk in this job wasn't intelligence. It was repetition. The danger came from doing the same delicate thing forty-two times and getting bored on number nineteen.

The trust was earned by structure, not bravery

Here's the thing though. I did not type "keep going until it's done" because I'm a brave man. I'm not. I typed it because of a file.

Back in April I'd done a smaller version of this same migration by hand, and like a good little engineer I'd written down what went wrong as I went. By the time I came to do the big batch, that scribbled record had grown into a proper playbook, around 30KB of it, versioned in the repo, with numbered gotchas that read like the warning labels on a fireworks box. Not theory. Things that had actually bitten me.

Two of them tell you everything about why this kind of migration eats the unprepared. The first: when you delete an App Service, Azure doesn't immediately free the name. It holds it in a soft-delete state for thirty days. So if you delete an app and try to recreate it with the same name a moment later, Azure can refuse, because as far as it's concerned that name is still spoken for. The playbook knew that. It knew how to handle it instead of panicking.

The second is sneakier. When you recreate an app, Azure gives it a brand new default hostname with a fresh random hash in it, something like myapp-a1b2c3.azurewebsites.net. If any of your DNS sat as a CNAME pointing at the short *.azurewebsites.net address, it now points at a hostname that no longer exists. The site resolves to nothing. The playbook had that written down too, with the fix, because past-me had already walked into that exact wall and felt it.

That is what I was trusting overnight. Not the AI's cleverness in the moment, but a written record of every way this had already gone wrong. The AI wasn't improvising a migration at two in the morning. It was executing a checklist I'd paid for in earlier mistakes. I was the product manager who'd already learned the lessons. It was the very patient operator who never gets tired and never skips step four because it's late.

The save that justified the whole approach

Now for the bit that genuinely made my stomach drop when I read the logs the next morning, in a good way.

Before deleting one of the apps, the agent went to back it up as per the playbook, and while it was poking around it noticed something the playbook hadn't anticipated. Sitting inside an App_Data folder on that app were thousands of user-uploaded images. About 14,505 files. Around 3.43 GB of them. Real things real people had uploaded.

And here's the gut-punch: that folder was excluded by .gitignore. Which means those files existed in exactly one place on Earth, that running app, and nowhere in source control at all. If we'd followed the destructive playbook to the letter and deleted the app first, those 14,505 files would have been gone. Not "restore from a backup" gone. Gone gone. Soft-delete keeps the name, not your uploads.

The AI backed them up before it touched the delete button. It didn't do anything heroic. It just had the right reflex baked in: before you destroy something, make absolutely sure the irreplaceable thing is somewhere else first. A tired human doing site nineteen of forty-two at midnight is precisely the person who skips that check. "It's all in git, it'll be fine." It was not all in git. Ouch. Also fair.

When "HTTP 200" is a liar

The other moment I keep coming back to is duller and, to me, more important.

To back the sites up, the agent used Kudu, the deployment service that sits behind every App Service, and specifically its zip endpoint, /api/zip/, which is meant to hand you a tidy archive of a folder. It called it. It got back an HTTP 200. Success, allegedly.

Except the zip it received was truncated. The end-of-central-directory marker, the little bit at the end of every valid zip file that says "this is genuinely the end, nothing was cut off", simply wasn't there. The server said 200. The file said otherwise. A 200 status code only tells you the request didn't error; it does not promise the body is complete or correct.

The agent did not shrug and trust the 200. It fell back to downloading every file individually and then byte-matched the lot against Kudu's own file manifest, the list of what should be there. Only once the bytes lined up did it consider the backup real and move on to the destructive part.

Nobody writes about this part. Everyone wants to talk about the AI "doing the migration". The thing that actually let me sleep was that the AI did not believe a green tick. Real verification means checking the thing you care about, byte for byte, not checking that the request technically returned. If you only design your automation to look for 200s, you've built a machine that's very good at confidently telling you it succeeded while it quietly drops your data on the floor.

Oh, and the home internet dropped more than once during the night, because of course it did. The run picked itself back up and carried on each time. Which, again, isn't impressive bravery. It's just what happens when the work is idempotent enough and the playbook is good enough that an interruption is an inconvenience rather than a catastrophe.

The honest counter-point: breadth is not the same as judgement

I don't want to oversell this. Letting an AI run overnight worked here for a very specific reason, and the reason was not "AI is ready to be left alone now". It was that this particular job is mechanical breadth: the same safe-once-proven operation repeated dozens of times, plus a lot of patient monitoring. That is genuinely the sweet spot for autonomy. Repeating a known-good operation across many targets, sweeping up piles of small identical tasks, babysitting a long-running job and reporting back. AI is brilliant at the parts that bore humans into making mistakes.

What it is not ready for is judgement calls dressed up as mechanical ones. The whole reason that overnight run was safe is that I'd designed stop conditions. The instruction wasn't really "never ask questions". It was "don't ask me about the things we've already solved in the playbook, but escalate anything genuinely new". The discovery of 14,505 unbacked-up images is exactly the kind of thing that should, and did, change the plan rather than get bulldozed.

On other projects, ones with live customers actively using the thing, I've had to pull the tripwires much tighter. I've literally had to add "please check with me on any functional changes" to an agent's instructions, because the closer you get to real users, the less you want autonomy quietly reinterpreting what the software is supposed to do. Migrating my own infrastructure overnight is one thing. Letting an agent decide, unsupervised, how a feature should behave for paying customers is a completely different risk, and I treat it like one.

What actually makes "carry on while I sleep" reasonable

So no, I'm not going to tell you to go and leave an AI deleting your production apps tonight. If you take one thing from this, take the recipe rather than the stunt.

Unattended overnight AI is a function of guardrails, not courage. The three things that turned "you absolute lunatic" into "a sensible Tuesday" were boring and writeable-down. A versioned playbook of known failure modes, paid for in earlier mistakes, so the AI is executing experience rather than improvising. A hard reflex to back up the irreplaceable thing before destroying anything, even when it's "surely in git". And real verification, byte-for-byte against a manifest, instead of trusting a status code that only ever proves the request didn't fall over.

The actual skill, the thing I now think is the job, is designing what the AI must stop and escalate. Autonomy isn't a personality trait you hand the model; it's a set of edges you draw. Inside the edges, let it grind all night. At the edges, make it come and find me. Get those edges right and "I'm going to bed, keep going" stops being reckless and starts being, honestly, a bit of a relief.

I still wouldn't recommend doing it on a project with live customers without a lot more tripwires. But for forty-two of my own sites and a 30KB file full of hard-won warnings? I slept fine. The migration was done by morning. And the only thing I'd done heroically was write things down the first time they hurt.

Want to talk?

If you're on a similar AI journey or want to discuss what I've learned, get in touch.

Get In Touch

Ready To Get To Work?

I'm ready to get stuck in whenever you are...it all starts with an email

...oh, and tea!

paul@thecodeguy.co.uk