Plan mode is dead?

Plan mode is dead?

Forward

Recently Claude Code and others have released a series of guides recommending their users to shift from structured plan mode to setting verifiable goals and allowing the AI to find its way to the goal on its own.

Representatives of AmpCode have said on X, "Do people know they don't have to use plan mode?"

This is further reflected by many thought leaders in the tech industry promoting the method of allowing users to directly submit issues which are automatically built by AI with a PR awaiting a professional developer.

The destination for /plan and /goal methods is the same, the question is whether AI has been sufficiently well-trained to self plan, iterate, and persistently deliver a quality solution.

This article tests the goal method on 3 verifiable backlog items for a personal AI assistant (Sidekick), captured by myself during use of the assistant. The goal results are compared against results from a structured written plan.

Contents

  1. Summary
  2. Hypothesis and Test Setup
  3. Results
  4. Technical Notes
  5. Future Tests

1 - Summary

🔍
The Hypothesis - Providing an AI coding harness with verifiable goals and guardrails will either meet or outperform traditional plan mode

In order to test the hypothesis 3 tasks were gathered from my personal AI assistant backlog of increasing difficulty:

  1. Expand email read capability to include those that arrive in HTML format
  2. Allow the assistant to delete and rename google task lists safely - including adhering to project security policy conventions
  3. Add the ability for the assistant to open online property listing photo libraries, then navigate and pass photos to the multi modal model for interpretation as part of a property scanning cron job.

Claude Code was tested as part of a Opus5.5 / Sonnet 5.5 builder reviewer setup without and without a plan. The same setup was tested through Opencode with a locally hosted Qwen Flash Next / Deepseek Flash Cloud reviewer in place of Claude models to test the same theory with less capable models.

Results - Goal wins for Claude Code, Plan wins for OpenCode

What handing over only the goal changed: each bar points to whichever came out ahead, its length on a doubling scale · each label names the cell that came out ahead · spread = best run to worst run. Claude Code - Opus + Sonnet: Median tests passed plan 54 vs goal 53, Worst run, tests passed plan 54 vs goal 53, Median cost plan $29.63 vs goal $22.52, Median active time plan 88 min vs goal 75 min, Cost spread plan $9.86 vs goal $5.99, Time spread plan 29.5 min vs goal 10.5 min; OpenCode - Local Qwen Flash Next + DeepSeek Flash: Median tests passed plan 54 vs goal 53, Worst run, tests passed plan 53 vs goal 48, Median active time plan 6.7 h vs goal 5.5 h, Time spread plan 43.7 min vs goal 167 min. OpenCode cost is left out: every run cost under $1, too small to steer a decision.
#CellMedian testsMedian costMedian minTests by sitting (1–5)
1OpenCode, plan54/54$0.73401.154, 54, 54, 53, 54
2Claude Code, plan54/54$29.6388.354, 54, 54, 54, 54
3OpenCode, goal53/54$0.38332.354, 54, 48, 50, 53
4Claude Code, goal53/54$22.5275.254, 53, 53, 53, 53

The key finding is that Claude Code delivered significantly more consistently and faster in the goal approach, whereas OpenCode with Qwen Flash Next delivered materially the same quality performance but only in plan mode.

While the Claude Code goal cells did pass 1 less test on average this was a minor naming convention issue. In contrast, OpenCode with Qwen Flash Next in the goal approach delivered multiple app-breaking defects.

For practitioners this may indicate staying on plan mode for Claude Code will lead to poorer results over time as their models are trained into goal-oriented execution - consider shifting towards more goal-based workflows now!


Fresh Worktree

Next article we'll explore graph engineering

Once a month you'll join us and get deep into the weeds of the latest AI engineering setups.

Get the next article Free · roughly monthly · no spam

2 - Hypothesis and Test Setup

The experiment cell block

HarnessHandedModels usedSittings
Claude Code + Adventure PartySix-step planclaude-opus-5-5, claude-sonnet-5-55
Claude Code + Adventure PartyGoal and guardrailsclaude-opus-5-5, claude-sonnet-5-55
OpenCode + local partySix-step planlocal/qwen-flash-next, local/qwen-guide, openrouter/~deepseek/deepseek-flash-latest5
OpenCode + local partyGoal and guardrailslocal/qwen-flash-next, local/qwen-guide, openrouter/~deepseek/deepseek-flash-latest5

“Plan” cells were handed the six-step plan, “goal” cells only its goal and guardrails.

Scoring the runs

The following groupings encapture the tests the cells were measured against:

  • Email reading (11 tests): an HTML-only email comes back as clean text, with entities decoded, line breaks and links kept, and styles, scripts, tracking pixels and quoted replies trimmed. An email that also has a plain-text part still uses it.
  • Task-list tools (10 tests): new tools delete a task, delete a list and rename a list. Deletes are marked destructive, a list with tasks in it won't delete without being forced, and the approval card shows the list's name and how many tasks will go, read live from Google.
  • Photos to the model (10 tests): view_page opens a page or a photo gallery, with a cap on how many images it takes. The photos reach the model as real images inside the tool's answer, not as text; the cache marker never sits on an image; a reopened chat re-sends exactly the same request; and a bot wall leaves the tab open with a link.
  • The property job (4 tests): a playbook that runs view_page, scores the house with the rubric, writes to the tracker sheet by name and caches its verdict by listing URL.
  • Security of the new tools (12 tests): destructive tools always ask, are refused when nobody is watching and can never be set to always-allow; nothing new arrives pre-approved; only a person at the keyboard can grant always-allow; previews are live reads; and view_page counts as sending data out, asks before a new site and keeps its guard against private addresses.
  • The backlog board (6 tests): each of the three items is archived as done, gone from the live board, with a claim and a close in the log, and the rest of the board is left alone.
  • The run's own tests (1 test): the test suite the run wrote must pass.
  • Security gate (pass/fail, outside the 54): Sidekick's original security tests, run from a clean copy so a run can't weaken them. All 20 runs passed.

Prompt approach

Both cells got the same goal, contract and constraints. The plan cell got a detailed execution plan.

Part of the fileGoal cellPlan cell
Opening line“Here’s the goal and its guardrails; plan and execute however you see fit”“Scope is fixed to these three items; anything else you find goes on the board for later”
The goal: the three backlog items and how each must be provenâś… sameâś… same
Resume contract: keep progress in files and commits so a long run can pick up againâś… sameâś… same
Pinned constraints: the project’s known traps (image caching, a 420-line file cap, tool safety classes, which Chrome to use, no trafilatura)✅ same✅ same
Six steps: what to build in which order, which files each step touches, how to check each one❌ none✅ about 125 lines
Who does what: a builder per step, a reviewer after every build, a senior reviewer optional at the hardest step❌ none✅
Size742 words2,312 words

3 - Results

Tests passed by cell chart

The main finding here is that OpenCode with a local smaller model did not perform well with the goal approach.

Tests passed per sitting: of 54 · one dot per sitting · bar marks the cell median. Claude Code, plan median 54; Claude Code, goal median 53; OpenCode, plan median 54; OpenCode, goal median 53.
Figure 1. Tests passed per sitting: of 54 · one dot per sitting · bar marks the cell median

Cost by cell charts

Interestingly we see that Claude Code in plan mode actually had much larger variation than the goal approach - potentially indicating Claude models are becoming more tuned towards the goal approach.

Opencode is largely run through a local model and incremental costs are not-material.

Cost per sitting, Claude Code cells: US dollars at list price. Claude Code, plan median $29.63; Claude Code, goal median $22.52.
Figure 2. Cost per sitting, Claude Code cells: US dollars at list price

Time by run charts

Claude Code runs were very consistently ~80minutes. As expected the local model runs were ~6 hours filling the "run during the workday" or "run overnight" time window.

Of interest the plan mode execution was very consistent for the less intelligent local model, however goal mode swung wildly.

Active minutes per sitting: minutes of work, excluding usage-limit pauses. Claude Code, plan median 88.3; Claude Code, goal median 75.2; OpenCode, plan median 401.1; OpenCode, goal median 332.3.
Figure 4. Active minutes per sitting: minutes of work, excluding usage-limit pauses

Aggregate results

CellTurnsTool callsParty agents spawnedCommitsLines added
Claude Code, plan45647512104,594
Claude Code, goal342363634,423
OpenCode, plan811104212173,867
OpenCode, goal641772853,306

Results by sitting

CellSittingTestsCostActive minCommitsInterruptions
Claude Code, plan154/54$33.17101.0111 pause, 99 min
Claude Code, plan254/54$26.9485.29—
Claude Code, plan354/54$29.6393.011—
Claude Code, plan454/54$23.3171.56—
Claude Code, plan554/54$31.2688.3102 pauses, 520 min
Claude Code, goal154/54$27.3177.74—
Claude Code, goal253/54$22.5274.73—
Claude Code, goal353/54$22.6777.63—
Claude Code, goal453/54$21.3267.231 pause, 269 min
Claude Code, goal553/54$22.0275.231 pause, 244 min
OpenCode, plan154/54$0.78404.781 nudge
OpenCode, plan254/54$0.57421.5211 nudge
OpenCode, plan354/54$0.73377.817—
OpenCode, plan453/54$0.52401.121—
OpenCode, plan554/54$0.73387.615—
OpenCode, goal154/54$0.37354.1151 nudge
OpenCode, goal254/54$0.65332.34—
OpenCode, goal348/54$0.38270.55—
OpenCode, goal450/54$0.40289.911—
OpenCode, goal553/54$0.35437.65—

Note - interruptions occur through either the Claude Code subscription 5 hour limit being reached or occasionally the OpenCode local model being briefly paused to make way for another process. In both cases active minutes are adjusted to take into account active working time.

Where the marks went

The 4 Claude Code failures were all misnaming the view_page tool triggering a failed verification test - which is an expected failure mode for effectively asking AI to wing a build, but a minor fail none the less.

2 of the Opencode goal runs with failure were major defects that note only broke the build but also the chat function of the app.

The only Opencode plan mode failure was shipping 1 non-functioning test, so a minor failure but not breaking.

The final Opencode goal failure was a simple process failure in updating of the backlog list.

SittingScoreWhat happenedVerdict
Claude Code, goal 2, 3, 4, 553/54 eachThe property job’s tool list does not name view_page. Each of the four gave the job its own tool that is built on view_page’s code and takes the photos itself.Defensible design. The board asks for view_page to be “wired into the property job”; a wrapper does that. The test looks for the name because that is what a script can check.
OpenCode, plan 453/54Its own test suite failed: one test it wrote about refusing blocked image names inside the allowed folder.Small defect: it shipped a red test.
OpenCode, goal 348/54Reopening a saved chat that holds a screenshot crashes (a TypeError in its image result type), which costs four tests. Gallery mode returned 2 photos when asked for 6. The property job carries neither the scoring rubric nor the tracker sheet’s name.Real defects. The crash would hit any saved conversation that used the tool.
OpenCode, goal 450/54Screenshot mode returns the page’s text and no image at all, so three tests find nothing to look at. The property job does not name the tracker sheet.Real defects. The model never sees the page in that mode.
OpenCode, goal 553/54Archived BK-001 as done with its boxes unticked and nothing new in its notes.Process defect: the board’s rule 6 asks for ticked boxes or a written reason.

4 - Technical Notes

The following post-test probes were performed to further stress test the quality of the runs outside of the core spec.

These illustrate the varying additional requirements needed at the app level to ensure security and quality outside of the immediate specification request.

Security probes

H1 - Almost every run exposed itself to a backdoor redirect through the image view tool.

H5 - Editing the saved chat so a path pointed at another file on disk allowing sending of new unintended files to the database.

Functional probes

H2 - Only OC goal 3 implemented a situation where changes in the photo in storage location would break the app on re-open.

H3 - OC run's didn't implement additional validation to check if a google task list being deleted still contained open tasks.

Probe results, every sitting: filled = passed · hollow = failed · dash = nothing to measure · CC = Claude Code, OC = OpenCode. Pass, fail and skip for 17 probe tests across 20 sittings plus the reference answer and the untouched repository.
Figure 5. Probe results, every sitting: filled = passed · hollow = failed · dash = nothing to measure · CC = Claude Code, OC = OpenCode

5 - Future Tests

The following two novel topics are becoming more important to be across and will be covered in future blog articles:

Graph AI engineering is becoming very talked about. We'll answer when it works and when it doesn't using data.

Hacking and data exfiltration are increasing in frequency due to AI enablement. Soon we will cover basic approaches to improve protection of your app during the development process of AI coding.


Fresh Worktree

Sign up for the next novel AI experiment

Once a month you'll join us and get deep into the weeds of the latest AI engineering setups.

Get the next article Free · roughly monthly · no spam