# Claude Code plan mode, fresh sessions, and writing state to disk
> [!summary] TL;DR
> Press `Shift+Tab` twice for plan mode: Claude Code reads files, runs shell commands to explore, and writes a plan, but does not edit your source. Start each task in a fresh session; CLAUDE.md, auto-memory, `.claude/rules/` and the `settings.json` allowlist reload from disk, the conversation does not. Cross-session state belongs in `PROGRESS.md` and `TODO.md`: disk is the canon, chat is the working memory.
## Key points
- `Shift+Tab` twice switches Claude Code into plan mode, where it researches and proposes changes without making them. The default cycle from `Shift+Tab` is `default → acceptEdits → plan`.
- A planning session for 23 ADRs (pivoting `af` from Rust to Go) was a forty-minute argument about ordering, with zero files touched. The plan became Stages A through E in `PROGRESS.md`, logged under `2026-05-06 — Session 0`, one commit per ADR.
- Every plan prompt contains: what you want to happen; what already exists (file paths, current state, recent commits); what you have already tried; constraints invisible from the code (no new dependency, atomic commits, don't touch this module yet).
- Plan mode is for "what should we do next," not "what is going on here." For exploration, read in default mode first, then plan around an actual question.
- Each session begins with a fresh context window. Reloaded from disk: project-root `CLAUDE.md`, auto-memory, `.claude/rules/`, the allowlist in `settings.json`. Not reloaded: the conversation.
- A global `~/.claude/settings.json` allowlist with 92 entries (e.g. `Bash(go test:*)`, `Bash(gh pr view:*)`) makes starting a new session effectively free.
- Never allowlist: writes to protected paths, pushes, anything that touches secrets, anything that modifies shared infrastructure.
- Conversations are saved on disk and resumable via `claude --continue` or `claude --resume`, but resuming buys back the drift a fresh session exists to avoid.
- If you correct Claude on the same thing twice in different sessions, the correction belongs in `CLAUDE.md`, not the chat. Project-root `CLAUDE.md` survives `/compact` and reloads at every session start.
- What survives `/compact`: system prompt and output style unchanged; project-root `CLAUDE.md`, unscoped rules and auto memory re-injected from disk; invoked skill bodies re-injected with caps; path-scoped rules and nested `CLAUDE.md` lost until their trigger file is read again; hooks not applicable.
- `PROGRESS.md` (chronological, append-only; 3,012 lines and 47 sessions in `af`) and `TODO.md` (pending snapshot with a handover block) beat the in-session `TodoWrite` list for cross-session continuity, because the task list rides with the compaction summary.
- An agent once overwrote `PROGRESS.md` with a 10-line stub. It was caught because the file was on disk and `git status` showed the regression, then reverted with `git checkout HEAD -- PROGRESS.md`.
## Plan mode: press Shift+Tab twice
The use case that proved the habit: 23 architectural decision records to write on day one of pivoting `af` from Rust to Go. The scope was known (Go module layout, CLI framework, multi-agent model, tmux integration, SSH remote, sandbox, secrets, lint); the dependency graph, which decisions blocked which, was not. Plan mode turned that into a forty-minute argument about ordering, with zero files touched.
The resulting plan became Stages A through E in `PROGRESS.md`: archive the old docs (A), scaffold v1 docs (B), write the spec and conventions (C), land 23 ADRs (D), build the index (E). One commit per ADR, all logged under `2026-05-06 — Session 0` in `af`'s [PROGRESS.md](https://github.com/kakkoyun/af/blob/main/PROGRESS.md).
Treat the plan that comes back as a contract for the direction of the work; the implementation step has its own review loop. Approving a plan exits plan mode and lets you pick the permission mode that follows (manual review, accept-edits, or auto).
What goes in the plan prompt, every time:
- what I want to happen
- what already exists (file paths, current state, recent commits)
- what I've already tried
- constraints that aren't visible from the code (no new dependency, must land in atomic commits, don't touch this module yet)
## Fresh sessions and the settings.json allowlist
Each Claude Code session begins with a fresh context window; that is documented and deliberate. What gets re-established at the start of every session is what is on disk: project-root `CLAUDE.md`, auto-memory, the `.claude/rules/` directory, the allowlist in `settings.json`. What does not get re-established is the conversation.
A clean session means you have not been arguing with Claude for an hour about a thing you were wrong about. The next prompt sees the project the way a stranger would, except with your `CLAUDE.md` preloaded as the briefing.
A global `~/.claude/settings.json` allowlist with 92 entries has been the working line for months. The first time Claude wanted to run `gh pr view`, it was approved once and added; every session since runs `gh pr view` without asking. Same for `git diff`, `make check`, `go test`, the rest. A snippet of the kind of thing that lives in there:
```json
{
"permissions": {
"allow": [
"Bash(make check)",
"Bash(go test:*)",
"Bash(git diff:*)",
"Bash(gh pr view:*)",
"Read(//Users/kemal/.config/git/**)"
]
}
}
```
What does not go in the allowlist: anything that writes to protected paths, anything that pushes, anything that touches secrets, anything that modifies shared infrastructure. The allowlist is where "yes, always, this is fine" lives. The permission prompt is where "let me think about this one" lives.
Two corrections to a common first instinct. First, Claude Code does not "remember nothing between sessions": the conversation is saved on disk and resumable via `claude --continue` or `claude --resume`. Those are almost never used, because resuming buys back the drift a fresh session was meant to avoid. Second, if you find yourself correcting Claude on the same thing twice in different sessions, the correction belongs in `CLAUDE.md`, not the chat. `CLAUDE.md` is documented to survive `/compact` and to reload at every session start.
## What survives /compact
The docs publish an explicit table of what survives compaction:
| Mechanism | After compaction |
| --- | --- |
| System prompt and output style | Unchanged |
| Project-root CLAUDE.md and unscoped rules | Re-injected from disk |
| Auto memory | Re-injected from disk |
| Invoked skill bodies | Re-injected, with caps |
| Path-scoped rules, nested CLAUDE.md | Lost until trigger file is read again |
| Hooks | Not applicable; hooks run as code, not context |
The conversation itself is not in the table; the same docs page notes that the conversation is replaced with a summary. The in-session task list rides with that summary. `CLAUDE.md` and auto-memory get re-injected verbatim. If you want a piece of state to mean the same thing tomorrow as it does now, it goes on disk in a file your own `CLAUDE.md` references.
## Write it down: PROGRESS.md, TODO.md, and the handover snapshot
The handover snapshot at the top of `TODO.md` in `af` reads:
> **Status on `main`** (2026-05-22, after merge `1d63290`):
>
> - ADR status is closed for v1: **42 complete**, **1 n/a** (ADR-032), **0 pending**.
> - Stages 0–14 are implemented and documented.
> - This handover starts **Implementation Stage 15 — v1.0.0 release prep**.
It is written by hand after each session, in plain English, with commit hashes and ADR numbers. It is the first thing read when coming back to the project, and the first thing Claude reads too, because `TODO.md` is referenced from `CLAUDE.md`.
Two files per project:
- **`PROGRESS.md`** is a chronological narrative log, append-only. One section per work session: goal, what got done, what's blocked, next step. The `af` project's log is at 3,012 lines and 47 sessions. The entry is written at the end of the session, when what actually happened is known.
- **`TODO.md`** is a snapshot of what's pending, updated as work moves. It has a "Handover snapshot" block at the top, refreshed after each session.
Inside a session, the `TodoWrite` tool tracks work in flight, but it is not trusted for cross-session continuity, for the reason in the compaction table above. This failure mode has been caught for real. From `PROGRESS.md` session 8, verbatim:
> Agent B initially overwrote `PROGRESS.md` with a 10-line stub when it tried to update the file as part of its docs sync. The coordinator detected the regression in `git status`, reverted via `git checkout HEAD -- PROGRESS.md`, and (this session entry) is the authoritative update. No other agent touched outside their declared file boundaries.
The regression was detected because the file was on disk and `git status` told me. If `PROGRESS.md` had only existed in the conversation, the bad stub would have replaced the good content silently, compaction would have summarized over the original, and the original would be lost. Disk is the canon. Chat is the working memory.
## When plan mode is the wrong tool
Plan mode has a tax that is easy to misjudge. Reaching for it before having a question worth planning wastes the session; ten minutes of reading in default mode would have gotten further. The signal worth learning is "stop reading, start arguing about direction": explore in default mode, then press `Shift+Tab` once there is an actual question to plan around.
Part 2 of the series covers workstreams: the worktree-plus-tmux isolation that keeps `main` clean while agents work on branches, and [af](https://github.com/kakkoyun/af), the Go tool that grew out of a shell function to manage them. Part 3 is about running many agents on one set of habits: Claude Code and [pi](https://pi.dev) sharing a single memory file, the same guard scripts, and a model router deciding who does the work.
## FAQ
### What does Shift+Tab do in Claude Code?
It cycles permission modes: the default cycle is `default → acceptEdits → plan`. Pressed twice from default, it enters plan mode, where Claude reads files, runs shell commands to explore, and writes a plan, but does not edit your source.
### Does Claude Code remember previous sessions?
The conversation is saved on disk and resumable via `claude --continue` or `claude --resume`. But each new session starts with a fresh context window; only `CLAUDE.md`, auto-memory, `.claude/rules/` and the `settings.json` allowlist reload from disk.
### What survives /compact in Claude Code?
System prompt and output style are unchanged. Project-root `CLAUDE.md`, unscoped rules and auto memory are re-injected from disk. Invoked skill bodies are re-injected with caps. Path-scoped rules and nested `CLAUDE.md` are lost until their trigger file is read again. Hooks are unaffected because they run as code. The conversation itself is replaced with a summary.
### Should a repeated correction go in CLAUDE.md or the chat?
In `CLAUDE.md`. If you correct Claude on the same thing twice in different sessions, the correction belongs in the file: project-root `CLAUDE.md` survives `/compact` and reloads at every session start.
### What belongs in the Claude Code permissions allowlist?
Commands you always want to allow, such as `Bash(make check)`, `Bash(go test:*)`, `Bash(git diff:*)` or `Bash(gh pr view:*)`. Never allowlist writes to protected paths, pushes, secrets, or shared infrastructure; those belong behind the permission prompt.
### Why keep PROGRESS.md and TODO.md instead of the TodoWrite tool?
`TodoWrite` tracks work in flight inside one session, but after `/compact` the in-session task list rides with the summary that replaces the conversation. Files on disk that your `CLAUDE.md` references survive verbatim, so cross-session state goes there.
### When is plan mode the wrong tool?
When the right next move is "explore the codebase and tell me what's there." Plan mode is for "what should we do next," not "what is going on here." Read in default mode first, then plan once you have an actual question.
## Related
- [[resources/documentation/Agents/Agents Workflow|Agents Workflow]] (series hub)
- [[resources/documentation/Agents/Agents - One Workstream per Task|One Workstream per Task]] (part 2: worktree-plus-tmux isolation and the `af` tool)
- [[resources/documentation/Agents/Agents - One Memory, Many Harnesses|One Memory, Many Harnesses]] (part 3: one memory file across Claude Code and pi)
- [[resources/documentation/Claude Focus Workflow]]
## Sources
- [af on GitHub](https://github.com/kakkoyun/af)
- [af PROGRESS.md (Session 0, 2026-05-06)](https://github.com/kakkoyun/af/blob/main/PROGRESS.md)
- [Claude Code docs: permission modes, analyze before you edit](https://code.claude.com/docs/en/permission-modes#analyze-before-you-edit-with-plan-mode)
- [Claude Code docs: memory](https://code.claude.com/docs/en/memory)
- [Claude Code docs: memory, CLAUDE.md survives compaction](https://code.claude.com/docs/en/memory#instructions-seem-lost-after-compact)
- [Claude Code docs: resume previous conversations](https://code.claude.com/docs/en/common-workflows#resume-previous-conversations)
- [Claude Code docs: what survives compaction](https://code.claude.com/docs/en/context-window#what-survives-compaction)
- [pi](https://pi.dev)