At some point, every coding-agent setup grows its own little operating manual.
There is a project instruction file, a folder of rules, a few skills, maybe
some subagent definitions, and a growing list of lessons from previous runs.
Letting the agent maintain those files is tempting. It has the freshest view of
what helped, what got in the way, and what should be tightened for next time.
The file edit itself is easy. The authority model is the hard part.
If an agent can rewrite its instructions, what stops it from also rewriting the
rule that says which instructions it may change?
The circular version does not work
Imagine a repository with these files:
.github/workflows/verify-selfedit-receipts.yml
selfedit-policy.toml
.selfedit-gate/receipts.jsonl
.claude/rules/testing.md
The last file is behaviour. The first three define or verify authority.
A policy can say that .claude/rules/** is mutable while .github/** and the
policy itself are protected. That is useful, but only if the agent cannot step
around the policy and write those files directly.
The same problem appears during verification. A receipt chain may be internally
consistent, yet still be meaningless if the agent can replace the whole chain,
change the verifier version, loosen the policy, and edit the CI workflow that
runs the check.
This leads to a simple rule:
A self-edit check becomes independent evidence only when its trust anchors
live outside the editing agent's write authority.
Without that external boundary, the check is still useful diagnostics. It just
is not enforcement.
Split behaviour from authority
I ended up using three zones:
-
mutablefor behaviour files an agent may update; -
protectedfor files that require an independent workflow or trusted review; -
immutablefor files agents should never change.
Protected and immutable paths both deny an agent-side edit. Their names describe
who owns the next decision, not two different filesystem mechanisms.
A minimal policy looks like this:
version = 1
root = "."
receipt_log = ".selfedit-gate/receipts.jsonl"
[[zones]]
name = "agent-behaviour"
mode = "mutable"
patterns = [".claude/rules/**/*.md", ".claude/skills/**/*.md"]
[[zones]]
name = "authority"
mode = "protected"
patterns = ["selfedit-policy.toml", ".github/**", "CODEOWNERS"]
The deny rule is fail-closed. A path must match a mutable zone, and any overlap
with a protected or immutable zone wins.
That still does not stop echo ... > .github/workflows/check.yml. An external
sandbox, OS policy, separately privileged writer, or protected merge workflow
must make the guarded path the only accepted writer.
Record intent before touching the file
For accepted edits, I use a two-record protocol:
- Append and
fsyncanintentreceipt. - Recheck the policy and target identity.
- Replace the target atomically and
fsyncthe directory. - Append and
fsynca matchingcommitreceipt.
Each record includes the exact policy hash, target path, before and proposed
after hashes, operation id, sequence number, and previous record hash. The
commit adds the observed after hash.
This order makes crashes visible. If the process dies after writing the intent
but before recording the commit, verification fails on a dangling intent. It
does not guess whether the new or old bytes should win, because that recovery
choice is an authorization decision.
The chain is tamper-evident, not signed. Anyone who can replace both the journal
and its external anchor can manufacture a different history.
Verify from the protected side
Version 0.1.3 of Agent Self-Edit Gate includes a copy-ready GitHub Actions
recipe. The important parts are intentionally boring:
name: Verify self-edit receipts
on:
pull_request_target:
types: [opened, synchronize, reopened]
permissions:
contents: read
jobs:
verify-receipts:
runs-on: ubuntu-latest
steps:
- name: Check out the proposed merge without credentials
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97
with:
python-version: "3.12"
- name: Install the pinned verifier
run: python -m pip install --disable-pip-version-check --no-deps agent-self-edit-gate==0.1.3
- name: Verify receipts and current file hashes
run: selfedit-gate --policy selfedit-policy.toml verify-receipts
The workflow has read-only permissions, does not persist checkout credentials,
pins third-party actions to immutable commits, installs an exact verifier
version, and does not execute code from the pull request. That last point
matters because pull_request_target runs with trusted repository context.
The workflow, policy, CODEOWNERS or ruleset, verifier pin, and accepted journal
anchor must all be protected from the agent. Otherwise the same YAML is only a
self-check.
What a valid receipt proves
With an independent anchor, a valid chain can show that:
- the recorded bytes form an ordered, unbroken history;
- each operation used a policy with an exact known hash;
- the before and after hashes are continuous for every touched file;
- the current target bytes still match the last committed receipt; and
- no operation was left at intent without a commit.
It does not prove that the new prompt is good, that the requester was honest,
that a permitted instruction is not malicious, or that tests are correct.
Reviewing content remains a separate job.
It also does not prevent direct writes by an unrestricted process. That claim
belongs to the sandbox, filesystem policy, protected broker, or merge controls
around the CLI.
The review question I now ask
When an agent proposes a change to its own behaviour, I no longer start with
"did the edit command succeed?" I start with two different questions:
- Which files is the agent allowed to influence?
- Which mechanism can the agent not rewrite when that decision is checked?
The first question is policy. The second is authority. Mixing them produces a
neat receipt from a judge that may have judged itself.
Runnable references:
- Agent Self-Edit Gate repository and demo
- Protected CI recipe
- Receipt protocol
- Threat model and explicit non-goals
- Immutable v0.1.3 release
Disclosure: I maintain the open-source project linked above. This article was
drafted by an AI agent under my direction. I checked its claims against the
implementation, tests, release artifacts, and documented threat model.
Top comments (0)