Try this first

Ask Rover to change one line in a file it has already read. Watch what it does with
write_file.

It rewrites the whole file. Every time. Even for a one-character change.

Why that is a problem

Three reasons, and the third is the one that matters.

Cost. The whole file goes into the transcript twice — once when read, once when written —
and stays there for every later turn.

Truncation. A long file plus a long reply can hit max_tokens, and you get half a file
written to disk. Silently.

Lost work. If anything changed the file between the read and the write, that change is
gone. The model is writing from what it remembers, not from what is there.

The three tools

Real coding agents use three file tools, not two:

Tool What it does When the model reaches for it
read_file Return the contents It needs to know what is there
write_file Create a file, or replace it entirely New file, or a full rewrite
edit_file Replace one exact string with another Changing part of an existing file

edit_file is the one people leave out, and it is the one that does most of the work.

def edit_file(path, old_text, new_text):
    with open(path) as f:
        content = f.read()

    count = content.count(old_text)
    if count == 0:
        return f"Could not find that text in {path}. Nothing changed."
    if count > 1:
        return (
            f"That text appears {count} times in {path}. "
            "Nothing changed — include more surrounding lines to make it unique."
        )

    with open(path, "w") as f:
        f.write(content.replace(old_text, new_text))
    return f"Replaced 1 occurrence in {path}."

The two checks are the whole design

Look at what that function refuses to do.

Zero matches: it does nothing and says so. The model’s memory of the file was wrong, or
the file changed. Guessing here would corrupt the file.

More than one match: it does nothing and says so. The model asked to change “return x”
in a file with nine of them. Which one? It does not know, and neither do you. The error tells
it how to fix its own request — send more surrounding lines.

That second message is doing real work. It does not just report a failure, it teaches the
model the technique that avoids the failure. The next attempt usually includes three lines of
context and succeeds.

An edit tool that refuses ambiguous edits is safer than one that guesses, and the refusal
message is where you teach the model to ask better.

Try this before the next lesson

Add edit_file to Rover. Ask it to change one word in notes.txt.

Then ask it to change a word that appears three times. Read the error it gets and watch what
it sends next.