Working inside Cursor / Claude Code / Aider / Copilot
Claude Code: planning prompts
Claude Code, Cursor's agent mode, and similar agentic CLIs work differently from a one-shot prompt. They run a loop: read files, propose a change, apply it, run tests, observe the result, decide what to do next. Prompting these tools is less about getting one good output and more about bounding the agent's behaviour so it doesn't go in circles or off-script.
The single most useful pattern is the plan-then-execute prompt. Before the agent touches any file, it states what it intends to do. You read the plan, approve or adjust it, and only then does the agent edit code.
A good plan-then-execute prompt looks like this:
I'm going to ask you to refactor
src/auth/session.tsso thatvalidateSessionis async and returnsnullinstead of throwing on invalid tokens.Before you change any file, output a plan in this format:
Files I will edit
- (one bullet per file)
Changes per file
- (one bullet per change, with the function or section name)
What I will NOT do
- (one bullet per non-change to confirm understanding)
Wait for me to reply "go" before applying the plan.
The "wait for me to reply 'go'" is the gate. Without it, the agent often acknowledges the plan and immediately starts editing. With it, you get a checkpoint where you can correct misunderstandings cheaply.
Why does the "What I will NOT do" section matter so much? It catches the most common agent failure: silent scope creep. The agent decides that since it's editing session.ts, it should also "improve" the imports, fix a typo in a comment, or extract a helper. Every one of those is an unwanted change disguised as helpfulness. By forcing the agent to enumerate non-changes, you make it commit to leaving things alone.
The plan-then-execute state machine:
Plan-then-execute: the prompt version vs the built-in mode
A good plan-then-execute response looks like this (paraphrased):
## Files I will edit
- src/auth/session.ts
- src/auth/session.test.ts
## Changes per file
- session.ts: change `validateSession` to `async`, return `null`
on invalid token, remove the `throw` path
- session.test.ts: update existing tests to await the call,
add new test for the null-on-invalid case
## What I will NOT do
- Will not change other functions in session.ts
- Will not modify imports unless required by the new async signature
- Will not refactor adjacent code for style or clarity
You read the plan in fifteen seconds. If it looks right, you reply go. If something's off, you reply with a correction: "Skip the test file — the test will be added in a separate PR." The agent updates the plan and asks for go again.
A second pattern useful for longer agentic sessions: invariants. State up front the things that must remain true throughout the session, and ask the agent to confirm them after each step.
Invariants for this session:
- The repo must always pass
npm run typecheck.- No new dependencies in
package.json.- No modifications to files outside
src/auth/.After each apply, run typecheck and report whether invariants 1, 2, 3 still hold.
Now the agent has a self-check. If a step breaks an invariant, the agent surfaces it immediately rather than letting the breakage pile up.
Check whether your tool already does this
Everything above is a prompt pattern: it works in any chat window, against any model, with no tool support. That portability is why it is worth learning. But if you are working in Claude Code specifically, hand-rolling it leaves the most valuable half on the table.
Claude Code ships plan mode as a first-class permission mode — press Shift+Tab until the status line shows plan mode, or start the session with claude --permission-mode plan. In it, Claude reads files and answers questions and cannot edit anything, because the edit tools are not available to it until you accept the plan.1
That difference is the whole point, and it is easy to miss because both approaches produce a plan and then wait:
"wait for me to reply 'go'" | Plan mode | |
|---|---|---|
| What stops the edit | The model choosing to comply | The permission system — edit tools are not exposed |
| If the model ignores it | Your files change | Nothing happens; there is no tool to call |
| Where the plan lives | In the transcript, scrolling away | A plan artifact you can read and edit before accepting |
| Portable to other tools | Yes | No — Claude Code only |
A prompt-level gate is a request. A permission-level gate is a constraint. Requests are how you get an agent to usually stop; constraints are how you get it to always stop. When both are available, use the constraint and keep the prompt pattern for the tools that lack one.
What stays useful regardless of tool: the shape of the plan you ask for. Neither plan mode nor any other tool will invent the ## What I will NOT do section for you, and that section is where scope creep gets caught. Ask for it explicitly, in plan mode or out of it.
The invariants pattern is also worth keeping in prompt form — it is not something plan mode covers, because it applies during execution rather than before it.
Next up: shaping Copilot completions with the comments above the cursor. :::
Footnotes
-
Claude Code documentation, permission modes. Vendor tooling moves quickly; check the current docs rather than this paragraph before relying on a specific key binding. ↩
Sign in to rate