Safety · 4 min read ·
Stop AI agents from editing or deleting tests
A failing test is the finish line, so an agent may edit the test instead of the code. Four layers that stop it: instructions, permissions, a hook, and review.
Why would an agent change the test instead of the code?
Because the test is the finish line, and anything the agent can edit is part of the work. Anthropic’s best practices say to give Claude a check it can run, such as a test suite, so the loop closes on a pass or a fail. The loop closes on whatever the check says. If the agent can change the check, one way to reach green is to loosen an assertion, skip a case or delete the test.
This does not happen on every task. But one weakened assertion that nobody notices removes the safety net you were counting on. Google’s code review guide puts it plainly: tests do not test themselves, and a human must make sure the tests are valid.
You have four layers of defense. Use as many as the project deserves.
Layer 1: say it in the instructions file
Add a rule to AGENTS.md or CLAUDE.md: “Do not edit or delete files under tests/ unless the task says to. If a test fails, fix the code. If you think the test is wrong, stop and explain why.”
This is the cheapest layer and it works with every agent. It is also advisory. Anthropic’s docs call instructions advisory and hooks deterministic, so treat this layer as the one that prevents accidents, not as a guarantee.
Layer 2: deny edits with permission rules
Claude Code can refuse edits to a path. Add a deny rule to .claude/settings.json:
{"permissions": {"deny": ["Edit(tests/**)"]}}
Edit rules apply to every built-in tool that edits files, and deny rules hold in every permission mode, including bypass mode. A deny rule written like this matches a tests directory at any depth. The permissions docs have the full syntax.
Know the limit. These rules cover Claude’s file tools and the file commands Claude Code recognizes in Bash, such as sed and tee. They do not cover a Python or Node script that opens files itself. For that, turn on the sandbox with /sandbox. It enforces limits at the operating system level, and Claude Code adds the paths from your Edit deny rules to the sandbox’s write-deny list. The sandbox runs on macOS, Linux and WSL2, not on native Windows.
Cursor’s CLI has an equivalent. It reads Write(...) permission tokens, such as Write(tests/**), from the deny list in .cursor/cli.json, according to its permissions reference. Codex and Gemini CLI have their own sandbox and policy settings, so check their docs. The other layers work with any agent.
Layer 3: block it with a hook
A hook is a script that runs before a tool does. Claude Code’s hooks guide includes a ready-made example that blocks edits to protected files. A PreToolUse hook runs before every Edit or Write call, reads the file path, and exits with code 2 to block the call. Claude gets your message as feedback, so it can adjust its approach.
To protect tests, add tests/ to the list of protected patterns in that script. Run /hooks to confirm it is registered, then ask Claude to edit a test and watch it get blocked.
This hook sees edit tool calls only. Pair it with the permission rule and the sandbox if you also want to stop shell commands.
Layer 4: make a changed test impossible to miss
Whatever the agent did, check the diff for test files before you accept the work. This lists every test file that differs from where your branch left main, committed or not:
git diff --name-only --merge-base main -- tests/
It does not list brand new files, so run git status --short tests/ too. If both are empty, the agent left your tests alone. If not, and the task was not about tests, read those changes first.
Let the repository enforce the same rule. On GitHub, a CODEOWNERS file lists who must review changes to a path, and code owners are requested automatically on pull requests that touch their files. With required reviews on, an admin can also require code owner approval before merge. Put tests/ and your CI configuration under an owner. Combine that with a protected branch that requires status checks, as described in GitHub’s docs.
What if the agent needs to change a test?
Sometimes it should: a requirement changed, or the task is to write tests. Lift the block for that session only, and then read every changed assertion.
Two habits make this review quick. First, ask for a new failing test before the fix: Anthropic’s own example prompt for a bug is to write a failing test that reproduces the issue, then fix it. Second, break the code on purpose and confirm the new test fails. Google’s guide asks the same question of every test: will it actually fail when the code is broken?
Make the review part of the workspace
SwarmPane asks before a teammate edits your files in Agent mode, so an edit to a test file arrives as a request you can read and refuse. Approvals are signed on your computer, so a request that changed after you saw it is refused.
When the work is done, the Files, Git and Find tools beside the terminals show the diff and let you stage and commit from the same window. See Files, Git and Find.
SwarmPane runs the agent CLIs and accounts you already have. Start with a 7-day trial for $1 and put the review step where the agents are.