Giving an agent write access to its own source, safely

Last week I gave the agent that works my backlog the ability to read and change its own source. It knows where its code lives, it can explain its own architecture when asked, and it can open a pull request against itself.
That is the headline. The useful part is the containment, because the capability without it is a stunt and with it is a tool. Here is the full design.
Why bother
Most of what I was changing about the agent was small and obvious. A skill missing a step. A message going to the wrong channel. A check running after the one that depends on it.
I was the bottleneck on improvements to the thing whose entire purpose was to stop me being a bottleneck. Letting it propose those changes removed a queue. It does not merge anything. It opens a pull request like anyone else and I read it like anyone else's.
The three brakes, and what each one is for
A kill switch with levels. Stopping one run, stopping all runs, and refusing to start anything new are three different needs. You want all three, and you do not want to be designing them in the moment when something is going wrong.
Every session registers itself. A kill switch is useless if the thing you want to kill never announced it existed. Anything that starts a model session registers it first, so there is always something to point at.
One at a time, globally. Exactly one job that touches a codebase runs at a time. Not one per repository. One in total. That is stricter than I expected to need and it has cost me almost nothing, because the slow part was never the parallelism.
The two failures that arrived immediately
It replied to itself. The agent posts to a channel, the channel event comes back, it reads its own message as a new request and answers it. That loop is obvious in hindsight and it is the first thing that happens the moment something can both write to and read from the same surface. If you are building anything that posts where it listens, write the self filter before the first deploy.
It wanted to restart after every change. Restarting is correct when the running code changed and pointless when a document changed, and a restart mid-job throws away work. The rule is now explicit: restart only for executable code, never for documentation.
The principle
Capability and containment belong in the same change. If you ship the clever part on Monday and the brakes on Friday, you have four days where the only safety mechanism is that nothing bad has happened yet.
That is not a rule about AI. It is the same rule as production access on someone's first day. The novelty is that this colleague works at four in the morning and does not get tired, so your Friday arrives much sooner than you think.
What I would add if I were starting again
A dry run mode for self modification, where it produces the diff and explicitly cannot write it, used for the first two weeks. I got to the same place by reading every pull request carefully, but a mode is cheaper than discipline and does not get tired either.