Plan Mode vs Letting the Agent Edit Immediately
Derek Chen
September 30, 2026
The greenhouse controller at the community garden runs on an ESP32 I programmed three winters ago. It reads soil moisture and air temperature, opens a vent with a small linear actuator, and runs a drip line on a schedule. This spring the garden committee asked for humidity readings too, so they could stop guessing about mildew. A new sensor on the existing I2C bus, a few lines to read it, one more value in the status page. I asked a coding agent to add it and let it edit straight away.
The diff looked tidy. It added a driver for the sensor, a reading function, and a call to that function from the existing periodic update. The periodic update, it turned out, was a hardware timer interrupt. The agent had put a blocking I2C transaction, which waits on the bus for several milliseconds, inside an interrupt service routine. On the bench it worked for about forty minutes before the watchdog reset the board. In the greenhouse it would have meant a controller that rebooted at random, sometimes with the vent half-open.
I reverted, switched the agent to plan mode, and asked the same question. The plan’s second bullet said: “Call read_humidity() from on_sensor_timer() alongside the existing temperature read.” I stopped there. That single line would have saved me an hour of bench debugging, if I had seen it before any code existed.
Since then I have used both modes a lot, on firmware and on the ordinary Python and web code I write for maker workshops. Neither mode is always right. But the choice between them is more specific than “plan for big tasks, edit for small ones.”
What plan mode actually gives you
Most coding agents now have some version of it. Instead of editing files, the agent reads the code, works out an approach, and describes it: which files it will change, what it will add, in what order, and sometimes what it is assuming. You read the plan, correct it, and only then let it write code.
The value is not that the agent thinks harder in plan mode, though some tools do spend more effort there. The value is that you get to review the decisions before they are buried in a diff. A plan is maybe fifteen lines. A diff implementing it might be three hundred. The one decision that matters, “call this from the timer interrupt,” is a bullet point in the plan and a single line among hundreds in the diff.
Reviewing a plan is reviewing intent. Reviewing a diff is reviewing intent and implementation at once, and it is very easy to get absorbed in whether the implementation is clean and never ask whether the intent was right. The humidity driver in the first diff was well written. That is exactly why I did not question where it was called from.

When editing immediately is the right call
Plan mode has a cost: an extra round trip, and a document you have to actually read. For a lot of changes that cost buys nothing.
If I can predict the diff before the agent writes it, I skip the plan. Rename this variable across the module. Add a field to this dataclass and the two places it gets serialised. Fix this typo in the status page. Update the pin number constant. In these cases, the plan would say exactly what I already expect, and reading it is pure overhead. Better to let the agent edit and review the small diff directly.
I also skip planning when the change is easy to throw away and easy to test. On a scratch branch, where I can run the code in seconds and revert with one command, I would rather see the result than read about it. Sometimes the fastest way to find out whether an approach works is to let the agent try it.
And for pure exploration, like “show me how the actuator timing works,” there is nothing to plan. I am asking for an explanation, not a change.
When I always plan first
After the greenhouse incident and a few similar ones, I have a short list of situations where I will not let an agent edit before I have read its plan.
When the code has execution contexts that are not obvious from reading it. Interrupts, callbacks from a hardware driver, code that runs on a different core, anything triggered by a signal handler. On the web side, the equivalent is code that runs in a background worker versus a request handler, or on the server versus the client. The agent can read the code perfectly well and still miss that a function runs somewhere where blocking or allocation is forbidden. A plan that says “call X from Y” lets me check the context of Y.
When the change has to fit into a resource budget. The ESP32 in the greenhouse has limited RAM and a firmware image that is already close to the partition size. A plan that says “add the vendor’s full sensor library” is something I will reject in a second. After the fact, I would have to notice it by looking at build output.
When there is more than one reasonable place to put the change. Should humidity be read in the same task as temperature, in its own task, or on demand when the status page asks? Each is defensible. I want to choose, not discover which one the agent chose.
When the change touches something physical. Anything that moves the vent actuator, switches the pump relay, or changes timing that a physical system depends on. A bug in a status page is annoying. A bug that holds a drip valve open overnight floods a bed of seedlings. The planning step is cheap compared to that.
When I do not know the code well. Workshop participants sometimes bring projects they found online. When I help with one, I do not know its structure, and the plan doubles as a map: here are the files that matter, here is where the main loop lives, here is where it handles the sensor. Even if I accept the plan unchanged, I understand the diff much better afterwards.

How to read a plan so it is worth the round trip
The failure mode with plan mode is rubber-stamping. The agent writes a plausible plan, you skim it, you say “looks good,” and you have gained nothing except a delay. I did this for the first few weeks. What made plans useful was learning to read them for specific things.
Where does each new piece of code get called from? This is the question that would have caught the interrupt bug. For every new function in the plan, I find the caller and ask what context that caller runs in.
What does it plan to add as a dependency? New libraries, new modules, new global state. On a microcontroller this is about memory. On a web project it is about maintenance. Either way, I want to see it before it is installed.
What is it assuming? Good plans state assumptions: “assuming the sensor is at address 0x44,” “assuming the existing I2C bus is initialised before the timer starts.” Those are exactly the things to check against reality. If a plan states no assumptions for a non-trivial change, I ask it to list them. The list is often more revealing than the plan.
What will it not touch? I sometimes ask for this explicitly. “Which files will you leave alone?” If the answer does not include the actuator control code, and the task was about reading a sensor, something is off.
Is the order sensible? For anything that runs on hardware, I want the plan to add and test the read path before wiring the value into anything that acts on it. An agent will happily do both in one step unless the plan says otherwise.
The revised plan, and what I changed
For the humidity sensor, the corrected plan looked like this after my edits:
- Add a minimal driver for the sensor using the existing I2C helper, no vendor library.
- Create a separate low-priority task that reads humidity every thirty seconds and stores the value in a variable protected by the existing mutex.
- The timer interrupt does not touch I2C; it only sets a flag, as it already does for temperature.
- Status page reads the stored value; it never triggers a sensor read.
- Do not change vent or irrigation logic in this change.
That third line is the one I added. I also discovered while reading the plan that temperature was already being read in a task, not the interrupt; only the flag was set in the ISR. The agent had misread the existing pattern, and its plan made the misreading visible. Once I pointed that out, the implementation followed the existing pattern exactly. The controller has been running in the greenhouse since April without a single watchdog reset.
A simple rule that holds up
After a few months, my rule has settled into this: if I can predict the diff, let the agent edit. If I cannot predict where the new code will live or what it will be called from, ask for a plan first.
Plan mode is not a safety feature you turn on for important work. It is a way to review decisions while they are still cheap to change. On a board bolted to a post in a greenhouse, where a bad decision means a controller that reboots with the vent half-open, that is worth one extra round trip every time.