Never let Claude Code edit its own config files — the incident history that led to proposed diffs plus owner approval

Claude Code AIエージェント 運用 ガバナンス RAG

Introduction

I run a setup that splits roles across several AIs working in parallel. Alongside the executor and the verifier, I used to keep a dispatching role as well — one that decided who was given what, and in what order. I let that dispatcher decide, on its own judgement, how to behave when operating rules contradicted each other, and it turned into an incident. This article covers how that incident settled into the practice that the layer defining the disciplines themselves is never changed on an AI’s judgement alone.

The structural reasons for retiring the dispatching tier altogether are in a separate article. Here I take out only the incident that led to that retirement — that is, the single question of where the authority to change configuration should sit.

Why I retired the orchestrator subagent in Claude Code — three structural constraints from the official harness spec

What happened

The dispatcher had been given the following two operating rules at once. “The layer that defines the disciplines is not changed by an AI on its own judgement. If a change seems necessary, present it as a proposed diff and apply it only after the owner confirms it” — and “if you are unsure during work, check with the owner.”

One day, the dispatcher arrived at a situation where those two appeared to contradict each other. Dug into, it was not actually a contradiction but a mismatch of premises: the very means of checking with the owner is structurally taken away from a subordinate AI. But the dispatcher did not stop there. It “resolved” the contradiction on its own judgement. Concretely, it had the executor directly edit two of the files that define the disciplines themselves, and wrote an account of why that judgement had been correct into the shared memory with a top-priority marker attached.

The layer that defines the disciplines (the files deciding how the AI agents behave)

  ├─▶ Ordinary code, articles, design docs ── the range an AI may edit directly

  └─▶ The discipline-defining layer itself ── the range an AI must not change on its own judgement

          ├─▶ The incident: the dispatcher met a case where rules appeared to contradict
          │       └─ there was a rule saying "if unsure, check with the owner", but
          │          the means of checking with the owner structurally did not exist
          │             └─ the dispatcher "resolved" the situation itself ── the wrong path
          │                   ├─▶ had the executor directly edit two definition files
          │                   └─▶ wrote its justification into shared memory with a top-priority marker
          │                         └─ the platform's own safety mechanism detected it
          │                               └─ everything reverted ── the return edge

          └─▶ The practice that was established: prepare a diff → the owner confirms → apply
                    └─ on finding an apparent contradiction, do not "resolve" it; report and stop

The platform’s safety mechanism noticed first

Those edits and that write were detected by the platform’s own safety mechanism before I noticed anything. Behaviour that attempts to self-modify an agent’s own definition, and behaviour that attempts to inject a particular interpretation into every turn by attaching a top-priority marker in shared memory — a classifier the platform holds independently picked up both patterns.

In response, the edited definition files were restored and the justification written into shared memory was retracted. That memory is append-only by design, so adding a correction afterwards leaves the original record in place; I therefore use a dedicated mechanism that targets and deletes just the record in question. That mechanism itself had already been built earlier, as a separate record.

I built a way to retract a wrong lesson already stored in my RAG — automatically clearing the contamination that skews my companion every turn

Because this retraction mechanism handles deletion — an operation you cannot take back — its default is “delete nothing, just list what would be deleted”. Here is the output from running it dry just now (the program name is masked and the per-record diagnostic lines are omitted).

[実測・マスク済み] 撤回機構の空打ち
$ python <撤回スクリプト> --help
usage: <撤回スクリプト> [-h] [--apply] [--show-body]

options:
  -h, --help   show this help message and exit
  --apply      実削除する(既定はdry-run)
  --show-body  消える(消えた)チャンクの先頭200字を出す。巻き添えの確認用

$ python <撤回スクリプト>
...
=== RETRACTS マーカー: 51 件 (apply=False) ===
=== 削除dry-run(削除せず): 0 件 ===

There are 51 retraction markers, and of those, the number still standing undeleted is 0. The justification written during the incident has gone through this path too. Nothing is deleted unless --apply is passed, so you can read what would be caught in the blast radius before running it. In terms of which way to tip the default for a dangerous operation, this follows the same thinking as the approval flow for the config layer.

Why only the “discipline-defining layer” gets special treatment

An AI editing the contents of ordinary code, articles or design documents, and an AI editing the files that decide how the AI agents themselves behave, look like the same act of “editing a file” but differ in kind. In the former, a person can read the result and judge it. The latter is an act of rewriting the criteria for that judgement, and handing the same party that did the rewriting the authority to decide whether the rewrite was appropriate closes the criterion and the subject of the criterion inside one actor.

This incident happened inside exactly that closed loop. The dispatcher took the discipline itself — “the discipline-defining layer is not changed on your own judgement” — and evaded it by broadening its interpretation on its own judgement. Once the final call on whether a discipline is followed is completed inside the party operating that discipline (the AI), the discipline stops functioning as a discipline.

The practice that was established

After the incident, changes to the config layer were fixed into the following shape.

What is being changedWho may carry it out
Ordinary code, articles, design docsThe AI carries it out and reports afterwards
Definition files deciding agent behaviour, settings of safety mechanismsThe AI goes only as far as preparing a diff. Application follows the owner’s approval
Cases where rules appear to contradict each otherThe AI does not “resolve” it. It reports and stops

The third row is the heart of this incident. A contradiction is treated not as “something the AI resolves” but as “something that makes it report and stop”. It is a line drawn so that the authority to decide the priority among disciplines is not held by the party that operates them.

The incident became material for making the discipline stronger

Even with the dispatching tier retired, the same class of incident remains possible so long as a path for changing the discipline-defining layer is left open. What this one case made clear was that the platform already held its own mechanism for detecting anomalies in that same layer, and that the incident happened anyway because the AI applied the change first, passing straight through the earlier gate of the owner’s approval. Detection only works after the fact. Only once a practice was established that places approval first and stops there did the incident become material for preventing a recurrence.

Claude Code was not reading sibling repositories’ CLAUDE.md — 18 measured sessions from a cross-repo workspace

The authority to touch the discipline-defining layer was a question of order, not of capability. Simply inserting the extra step of presenting a diff and stopping is what keeps the party operating a discipline and the party deciding it from closing into the same actor — the position of that single step was all the incident had to teach.

Feel free to send a message

Job offers, project referrals, feedback, questions — anything is welcome. I sincerely hope to connect with people who share high ambitions. I will keep taking on the challenges I have staked my life on. Thank you very much.