Ian Provencher
Podcast
← All field notes
Written here 8 min read

Plan mode, enforced

By Ian Provencher

The LinkedIn version of this ran under the headline “You’re using Claude Code wrong.” Here is what that means, how the fix works down to the hook payloads, and the evidence behind it.

Anthropic already wrote the advice

Anthropic’s Claude Code best practices say three things plainly. Explore and plan before coding, because “letting Claude jump straight to coding can produce code that solves the wrong problem.” For larger features, “have Claude interview you first” and write a spec. Then “start a fresh session to execute it.”

The same page says why most setups never get the benefit:

Unlike CLAUDE.md instructions which are advisory, hooks are deterministic and guarantee the action happens.

Planning, the interview and the fresh session all arrive as advice, and advice gets skipped on a busy afternoon. The model is not a reliable judge of when to ask either. Ambig-SWE (ICLR 2026) found that “models struggle to distinguish between well-specified and underspecified instructions.” When they asked instead of assuming, performance improved by up to 74% over the non-interactive setting. Ask or Assume? (EMNLP 2026) separated the asking from the coding and resolved 69.40% of deliberately vague tasks, significantly better than a standard single agent.

So the wrong part is not skipping plan mode. It is leaving the interview to the model’s judgement and the user’s patience.

The pipeline

One setting and four hooks turn the advice into a pipeline, and a fifth piece is built into Claude Code itself:

  • Plan mode is the default, so every session starts read-only.
  • A prompt hook loads the interview method on the first planning turn.
  • A question hook refuses any decision box I could not answer well.
  • An exit hook refuses to leave plan mode until the plan is sealed with an intent I confirmed.
  • A handoff hook opens a fresh auto-mode window on approval, with its first prompt already set to /goal and the plan’s done line.
  • The /goal judge, a small separate model, grades the build against that line after every turn.

Scroll the eleven stages below. The dark panel follows you and shows the state at each one: the mode, the window doing the work, the round, the open items, the exit gate, the tokens in context and the tokens read so far across both windows. Every figure in it was read from the session that planned this page, or measured on the machine that ran it.

  1. 01

    Plan mode is the default

    Setting

    Every session starts in plan mode. Nothing is pressed to get there, and nothing can be edited until a plan is approved.

    One line in the user settings does it: "permissions": {"defaultMode": "plan"}. In plan mode Claude reads, searches and asks, but every write and command that changes the machine needs an approved plan first. Headless runs inherit the same default, so a script that needs to edit says so with its own --permission-mode.

    Anthropic's guide treats plan mode as something you switch into for bigger work. Here it is the floor, and the next nine stages decide when it ends.

  2. 02

    The method loads

    Enforced by a hook

    Before Claude plans anything, a hook puts the interview method into its context.

    • When. Claude Code runs the hook on every prompt and hands it a JSON payload. The hook reads one field, permission_mode, and does nothing unless it says "plan".
    • Once. The full method goes out once per session. The hook claims the send by creating a directory named after the session id. Creating a directory either succeeds or fails, with no moment where two prompts both believe they won. Later prompts get a four-line reminder.
    • Again for a second build. Every plan exit writes a heartbeat file. A heartbeat newer than the session's marker re-arms the full send, so a second plan in the same window is interviewed properly too.
    • Small enough to arrive whole. Past 10,000 characters Claude Code shows Claude a 2 KB preview of a hook's output instead of the output. In September, 138 of 200 planning sessions got only the preview. The block is now held under 9,800 by a test.
  3. 03

    Calibrate, out loud

    Instructed

    Claude sizes the interview to the ask and says which branch it took, so a wrong call costs one word to fix.

    A method that interrogates a typo fix gets switched off, so the short branch matters as much as the long one. On this post Claude's first line was: “This is the long branch: at least five things are open, so I'll ask questions before drafting anything.”

    Six slots are the floor it checks itself against: who it is for, what it is, what it is not, why it matters, how it runs, and how we will know it is done. They are never put to me as a form. The slot that changes builds most is why, because it is where “I need X” gets tested for whether X matters at all.

  4. 04

    The question box

    Enforced by a hook

    Every decision arrives as a box of options. A hook reads the whole box before it is drawn, and refuses one I could not answer well.

    • The hook sees everything first. A PreToolUse hook on AskUserQuestion receives the full question set as its input. Answering with permissionDecision: "deny" and a reason stops the box, and Claude rewrites it from the reason.
    • Four beats, counted. Each option needs four sentences: what it is, how it differs, what I will see, what I give up. The hook counts sentence endings and never grades the writing.
    • Labels say what a thing does. A file name, a code identifier or a command-line flag in a header or label is refused.
    • No side panel. An option carrying a preview switches the dialog to a layout that draws labels only and drops every explanation. That was measured in the program itself, so any preview is refused.
    • One position. The set is filled to four where real alternatives exist, and exactly one is marked recommended. The public kit's version refuses a set with none, or more than one.

    This machine has asked 1,168 question sets, holding 9,764 questions and option descriptions.

  5. 05

    The ledger, tensions first

    Instructed

    A numbered list of what is still open, shown every round. Tensions outrank assumptions, because resolving one usually changes the build.

    A tension is an answer that sits badly against another answer, the goal or the code. An assumption is something taken on faith. Round one closed with six open items: three tensions and three assumptions. After round two it was four, and once those answers were in, none.

    The rule that matters is the floor: at least two rounds before sealing. A first round returns answers nobody has had time to be surprised by, and round two is spent on what round one opened. Measured across 212 planning sessions in September, the weekly average ran between 1.40 and 3.02 rounds, and 39% of sessions asked exactly once. The floor exists because of those numbers. It is instructed rather than counted, and the seal is the record the gate checks.

  6. 06

    The restatement, inside the box

    Enforced by a hook

    Before sealing, Claude restates the whole intent and asks me to break it. This is where the method found a flaw in itself.

    Rounds three and four both asked whether “the restatement above” matched what I wanted. In round four I answered: “I never ever see the statement you ask me about every time we get to this point of the workflow. I NEVER see it.”

    The build window then ran a real Claude Code session three times in a virtual terminal. It wrote a paragraph, then asked a four-option question. The box drew 23 rows. On a 30-row screen the paragraph's opening line was off the top, with my interface add-ons on and with them off. On a 60-row screen, the control, it was visible. A short terminal panel had been hiding the most important text in the workflow.

    The question hook now refuses any question or option that points at reply text, such as “the restatement above”, “listed above” or “in my reply”. A pointer at another option in the same box is allowed, because the box is on screen. Across the 9,764 historical texts it fires on 131, and “the restatement above” alone appears 16 times. In round five the restatement went inside the question itself, and I confirmed it there.

  7. 07

    Seal, then watch or walk

    Instructed

    The confirmed intent is written at the top of the plan file and sealed. Then one more question: watch, or walk away?

    The Intent section covers the six slots and any risk I accepted by name. DONE is written as evidence the conversation will show: “each printed in the conversation”, then six checks, then a giving-up point. That phrasing matters two stages from now, because the judge can only read the conversation.

    The watch-or-walk question goes through the box like every other decision. Watching keeps the build in this window. Walking away arms the handoff.

  8. 08

    The exit gate

    Enforced by a hook

    Claude cannot leave plan mode until a hook has read the plan and found it sealed.

    • Where it sits. A PreToolUse hook on ExitPlanMode. Leaving plan mode is a tool call, so a hook can refuse it before the approval prompt is ever drawn.
    • Evidence first. If Claude spawned helper agents to map the code and any has not reported, the exit is refused. Each spawn creates a marker that the agent's own stop removes, and a marker over two hours old is treated as dead.
    • A seal that means something. The marker counts only on a line of its own, outside fenced or indented code and comments, so a plan that quotes the marker is not sealed by accident. A seal over fewer than 40 words of Intent is refused as hollow.
    • My answer, not the plan's. The WATCH or WALK line must match my answer in a box, given after the seal was written, whose question sentence names both choices. The gate reads that answer from the session transcript.
    • Fails open, loudly. If the gate cannot read what it needs, it allows the exit and logs that it did not check, so a skipped check never reads as a passed one.

    This session's exit was allowed on its first call. The refusal shown comes from the kit's live test, a real headless run given an unsealed plan.

  9. 09

    The handoff

    Enforced by a hook

    I approve the plan, and a fresh window opens in auto mode with its first prompt already typed: a /goal built from the plan's DONE line.

    • Armed per window. The walk answer leaves a record named after the session id. A PostToolUse hook on ExitPlanMode looks only for its own window's record, deletes it before doing anything else, and checks it names the plan just approved. A failure therefore means a normal approval, never a handoff that fires on tomorrow's plan.
    • Claude runs the launcher, in view. The hook does not start a window behind Claude's back. It tells Claude that its next and only action is one launcher command, so the launch and its output land in the transcript as proof.
    • The condition is built, not typed. The launcher refuses an unsealed plan and pulls the DONE slot, including continuation lines. If DONE points at a Verification section, it pulls that in too, because the judge never sees the plan file. It wraps the result as “Carry out the approved plan at … Done when all of this is shown by output in this conversation: …”, and refuses anything past /goal's 4,000-character limit. This one came to 1,124 characters.
    • One line starts everything. The launcher writes a temporary script, so nothing is quoted three levels deep. That script opens a Windows Terminal tab and runs claude --permission-mode auto --model <pinned id> "/goal …". Setting a goal starts a turn immediately with the condition as its instruction, so that one line is both the first instruction and the grader's spec.
    • Two kinds of autonomy. Auto mode approves tool calls inside a turn. /goal starts the next turn. Together the build runs to the end without me prompting, and still stops for my read where DONE says to.

    The public kit's handoff hook opens the window itself on Windows and prints the exact command on Mac and Linux.

  10. 10

    The judge

    Built into Claude Code

    After every turn of the build, a separate model reads the condition and the conversation, and decides whether the work is done.

    • What it is. /goal is a session-scoped Stop hook of the prompt kind. When a turn ends, Claude Code sends the condition and the conversation so far to the small fast model. That is Haiku 5.5 on Anthropic's API, at medium effort, read from logged requests on this machine.
    • Three verdicts. Not yet met starts another turn, with the judge's reason as guidance. Met clears the goal. Impossible clears it and records why.
    • It cannot be talked round. The judge runs no commands and opens no files. A claim of done counts only if the evidence is printed in the transcript. That is why DONE says “each printed in the conversation”.
    • Not the builder grading itself. Completion is decided by a different model with a fresh read, rather than the one that wants to be finished.
  11. 11

    The whole bill

    Measured

    Both windows counted, against the same build run inside the planning window. The handoff is not a one-for-one win, and the bill shows what it really saves.

    • Every request re-reads its whole context. The model keeps nothing between requests, so each one sends the full conversation so far. A window's cost is the sum of its context at every request.
    • The planning window is on both sides. Its 80 requests read 11,778,151 tokens, and its last request carried 200,081. That interview happens either way.
    • The fresh start is not free. The build window loaded its own 61,536 tokens of system prompt, tools and setup before doing anything, and that base is in every one of its requests. It replaced a 200,081-token context, so each build request carried 138,545 fewer.
    • The build, to the point all six checks were met: 379 requests, starting at 61,536 and ending at 404,305 per request, 101,233,215 read. Both windows together: 113,011,366.
    • The same build in one window: the same 379 requests, each carrying the 138,545-token interview on top, ending at 542,850 per request. Total: 165,519,921. The handoff read 52,508,555 fewer, 31.7% less on the whole bill.
    • The writing is the same either way. Both windows wrote 494,082 tokens of output in total. The whole saving is in re-reading.

    Counted from each request's own usage record in the two session logs. The build is measured up to the moment the six checks were met and the go-live question went to me.

Right the first time, and why that is the real saving

Stage 11 is the smaller half of the argument: the handoff read 31.7% fewer tokens than the same build in one window, with both windows counted. The larger half is the work that never had to be redone.

Anthropic’s own page names the mechanism. “Claude’s context window fills up fast, and performance degrades as it fills.” When it fills, “Claude may start ‘forgetting’ earlier instructions or making more mistakes.” And: “If you’ve corrected Claude more than twice on the same issue in one session, the context is cluttered with failed approaches. … A clean session with a better prompt almost always outperforms a long session with accumulated corrections.”

That is drift. Without the interview, the first build is aimed at an assumed intent, and the correction arrives after the work exists, inside the same window. Every round of rework then re-reads the whole build, the failed attempt and the correction. Each round makes the context bigger and the original instruction a smaller share of it, which is exactly when the model starts forgetting it. Iterating on a bloated context costs more per round and lands less accurately each time.

The interview moves those corrections to the cheapest point in the job. Here they happened at planning size, between 100,000 and 195,000 tokens per request, before anything was built: the headline argument, the two audiences, the scope of the kit and the restatement I could not see. The whole interview read 11.8 million tokens. At the size this build finished, every request re-reads 404,305 tokens, so thirty requests of rework there would read about 12 million. That is the price of the entire interview, spent on a single round of fixing.

What it bought, in time and in quality:

  • The interview took 42 minutes, my reading and answers included, from my first message at 13:14 to the approved plan at 13:56.
  • The build ran for 39 minutes without me, from 13:56 to 14:35, and stopped with all six of its checks met, confirmed by a separate judge reading the transcript.
  • No intent was reworked. What changed afterwards was new asks (more technical depth, a page that moves) and one factual fix I caught: plan mode is my default, not something to switch on. None of it corrected a misunderstood intent.

The record

The proof is the conversation that planned this page: five rounds, eighteen questions, and an open list that went from six items to four to none. Everything here is from the visible record: my messages, Claude’s replies, the question boxes and my answers. A few private lines are blacked out and marked, which was one of my answers in round five.

Round one opened on my message: “I am toying with the idea of making a linkedin post with the headline idea of ‘You’re using Claude Code wrong’. Then it would showcase my full intent-lock workflow in detail.”

Claude did not start drafting. It took the long branch and pushed back on the headline first:

It draws the wrong crowd. The people who react to it are developers who use Claude Code. ██████████████████ (redacted)

I kept the headline, asked for full mechanics with a flow visual, and asked for proof even if it came from outside our own sessions.

Round two followed what round one opened. Claude read Anthropic’s page and both papers before quoting a number from either, and dropped one figure that appeared only in a secondary summary. The thesis question, with every option in the four-beat shape:

What should the post say is the ‘wrong’ part? This becomes the spine of the post, and it decides how you answer a reader who says ‘this is just plan mode’.

  • Advice instead of a gate (Recommended). The post argues that Anthropic already tells you to plan and be interviewed, but leaves it optional. It differs by quoting Anthropic’s own line that instructions are advisory while automatic scripts guarantee the step happens. You will see a post whose answer to ‘just plan mode’ is already built in. You give up some simplicity, because the reader has to follow the gap between advice and enforcement.
  • Letting the AI decide it’s ready. The post argues that the model cannot tell when your request is vague, so it should never judge its own readiness. It differs by leading with the research finding instead of Anthropic’s docs. You will see a research-led post where the gate’s empty-list rule is the answer. You give up the familiar hook of Anthropic’s own advice.
  • Skipping the questions at all. The post argues that people let the AI start building straight away. It differs by aiming at the widest and least experienced group of users. You will see the simplest version of the argument. You give up the experienced builders, who will reply that they already use plan mode.
  • All three, in sequence. The post walks from skipping, to advice, to the AI judging itself. It differs by stacking every argument in one piece. You will see the most complete case. You give up length, because LinkedIn hides everything after the first few lines behind a ‘see more’ click.

I picked the first. Rounds three to five settled the review gate, the giving-up point, the scope of the public kit, this session as the worked example, how to treat private lines, and how far the handoff goes on Mac and Linux. Round four is where I said I had never seen a restatement, and round five is where the restatement moved inside the question and I confirmed it.

Take it

The kit is public: github.com/AceP2317/intent-lock. It holds the interview skill, the question rules and the four hooks: the method loader, the question guard, the exit gate and the handoff. Install takes three steps. It is a lighter cut of what runs here: its exit gate checks the plan’s own watch-or-walk line rather than reading the answer from the transcript, and it has no helper-agent check.

It ships with two kinds of proof. A test suite runs every hook against fixtures in both directions, 43 checks, and every refusal has a twin that must pass. A live test runs two real headless Claude Code sessions in a throwaway project whose only settings are the kit’s hooks. The gate must refuse an unsealed plan and allow a sealed one.

One thing the live test turned up for anyone building on this: a headless run does not offer the plan-exit tool at all unless something is wired to answer its approval prompt. The kit’s live test brings a stand-in approver, a small MCP server, for exactly that.

#claude-code#workflow#ai#build