Engineering

Why Claude Code Sessions Break Past 400K Tokens — And the Self-Audit Pattern That Fixes It

2026-04-24 9

The 400K Wall

Anyone who has used Claude Code on a serious project for more than a day has met it: somewhere past roughly 400,000 tokens of conversation, the model starts to slip. Not catastrophically — Claude is too well-trained for that. But noticeably:

  • Fabricated file paths. It confidently references src/auth/middleware.ts when the file is actually src/middleware/auth.ts. You only catch it because the next Edit fails.
  • Skipped TODOs. A task you both explicitly agreed on 200 turns ago silently disappears. The model continues as if it was never raised.
  • Contradicted decisions. "We decided to use Postgres," it says, after the two of you spent an hour earlier choosing SQLite for a specific reason it can no longer recall.
  • Unwarranted confidence. The most dangerous one. It will assert "I already pushed the image" with the same tone as a verified fact, when in reality the push was attempted, failed, and got buried under 50 turns of unrelated work.

The model's claimed context window is 1M tokens. The window where it tells you the truth is much smaller. From repeated observation: quality holds up well under ~200K, degrades visibly between 200K-400K, and falls off a cliff after that.

This is not a Claude-specific failure mode. All transformer-based long-context models exhibit it. Recall quality is not uniform across the window — early information gets diluted, attention patterns thin out, and the model increasingly substitutes "what would plausibly fit here" for "what was actually said". For a coding agent that takes irreversible actions (git commits, deployments, file deletes), this matters.

The Naive Workaround Fails

The obvious response is: open a new window. Cold context, fresh attention, no degradation. Just transfer the state.

This works conceptually. In practice, the manual workflow has surprisingly painful friction:

  1. Ask the old window: "summarize what we were working on, write an opening message for a fresh window".
  2. Copy the summary, open a new window, paste it.
  3. Now the new Claude has the summary but no idea if it is accurate. So you ask: "does this match what is actually in the codebase?"
  4. Or you go back to the old window and ask it to verify itself, except the old window is the one whose memory you no longer trust.

Steps 3 and 4 are not optional. Step 3 exists because step 1 produces self-congratulatory summaries. When you ask a degraded model to summarize what it just did, it tells you a coherent story. The story is composed mostly of things that happened. But it includes things that almost happened, things it intended to do, and things it claimed to do without doing. The summary is wrong in exactly the ways the model itself can no longer detect.

This is a class of failure: a system cannot reliably audit its own output when the output and the auditor share the same degraded state. You need an external auditor.

The Self-Audit Pattern

The fix is structural. Instead of trusting the source session's summary, spawn a fresh-context auditor that has not seen the conversation and only sees:

  1. The handoff summary
  2. The codebase, read-only
  3. A strict checklist of what to verify

For every claim — "I pushed image X", "commit abc123 contains the fix", "file src/y.ts modified" — the auditor runs the corresponding real check (docker image inspect, git cat-file -e, ls). Results are appended to the handoff with verdicts:

  • ✅ verified — claim matches the filesystem
  • ⚠️ warning — partial match, worth noting
  • ❌ failed — verified fiction

Because the auditor is fresh, it catches exactly the failure mode that long-context self-summarization produces: the claim "I deployed it" when the deploy actually failed and was forgotten 50 turns ago.

This pattern has another property worth highlighting: it forces the source session to declare its own uncertainty. A handoff that claims confidence on every point is suspicious. A handoff with three explicit "I am not sure about X — verify by Y" entries is much more useful, because the new window can prioritize verification. Mandating that uncertainty section turns out to be most of the value.

How claude-next Implements It

We packaged this pattern as a Claude Code skill: claude-next. The full mechanism in concrete terms:

In the old window: /next

  1. Claude reviews the last ~20 turns and identifies the current task in one sentence. It announces this for confirmation: 3 seconds to correct, otherwise it proceeds.
  2. The script allocates the next free slot letter (A, B, C...).
  3. Claude fills a structured handoff template: task summary, context, progress, changed state (files / commits / images / containers), next step, and a mandatory minimum of 3 real uncertainties with how to verify each. If it can only think of fewer than 3, the template rejects the handoff.
  4. Claude spawns a fresh-context subagent as the auditor. The subagent has Read/Bash tools but zero conversation history. It works against a fixed rubric and appends a Pass A audit section to the handoff file.
  5. Output: a pass-phrase, like continue A.

In the new window: paste continue A

A UserPromptSubmit hook intercepts. Before the prompt reaches Claude, the hook:

  1. Looks up handoff slot A.
  2. Runs a Pass B drift check — has git HEAD moved since the handoff was written? Is the current working directory inside the handoff's project root? Is the handoff older than 24h? These are signals that the world changed between writing and reading.
  3. Injects the entire handoff (with both audit passes) as additional context.
  4. Deletes the source handoff file (consumed).

The new Claude opens by summarizing the task, listing the next step and uncertainties, and waits for your go-ahead.

The key UX property: the new window is otherwise zero-impact. No SessionStart hook. If you don't paste a pass-phrase, opening a new Claude Code window is exactly like opening one without claude-next installed. The hook only fires on the specific pass-phrase pattern.

What the Audit Actually Catches

The first time we dogfooded /next on its own development, the handoff included this claim:

All 4 original settings.json fields preserved (skipDangerousModePermissionPrompt, enabledPlugins, mcpServers, hooks).

The fresh-context auditor flagged it as ⚠️:

Wording is misleading: backup only had 3 top-level fields (skipDangerousModePermissionPrompt, enabledPlugins, mcpServers); hooks is the newly added one. Count is 3 original + 1 new = 4 total. Preservation itself verified.

It also volunteered an additional uncertainty the source session had not noticed:

AUD-1: install.sh mtime is Apr 24 03:33 but the backup file is dated Apr 24 04:06 — a ~33min gap suggests install was re-run or hook was added manually after initial install.

This is the kind of thing a careful human reviewer would catch. The source session would have shipped the misleading wording without noticing — and the new window would have inherited a slightly wrong mental model. The audit catches it with no human in the loop.

How It Compares to Memory Banks

There is an existing category of tools — claude-mem, memory-bank-mcp, agentmemory, and others — that do passive memory capture and auto-injection. They are good tools and solve a real problem.

They solve a different problem. Memory banks are for "I want continuity across many sessions about the same project." claude-next is for "I want a clean handoff right now because this session is degrading." Different optimization targets:

Memory banks claude-next
Captures everything passively Yes No (explicit /next only)
Auto-injects on new session Yes No (pass-phrase required)
Independent audit before handoff No Yes
Drift check before ingest No Yes
Forces uncertainty declaration No Yes
Zero ambient impact on unrelated windows Partial Yes

The two coexist trivially: claude-next only touches the UserPromptSubmit hook and only reacts to the specific pass-phrase. Use both if your workflow benefits from both.

Install

npx claude-next install

That is the entire installation. The script copies the skill files to ~/.claude/skills/next/, backs up your existing settings.json to a timestamped .bak, and adds only the UserPromptSubmit hook.

To use it:

  • In a long session: /next → get a pass-phrase like continue A
  • In a new window: paste continue A as the first message
  • Optional: /next list to see all pending handoffs, /next remove A to drop one

Pass-phrases work in both English (continue A / drop A) and Chinese (继续 A / 移除 A).

What This Is Not

A few things claude-next deliberately does not do:

  • It is not a memory system. Handoffs are consumed and deleted on use. If you want persistent cross-session memory, install claude-mem alongside it.
  • It is not multi-user. Handoffs are local files. Team-wide handoff sharing would need cryptographic signing on the audit verdict, which is on the roadmap but not built.
  • It is not a fix for hallucinations themselves. It is a way to detect and contain them at handoff boundaries. The model still slips inside any single session — claude-next just stops the slips from compounding into the next one.

Why This Matters

Software engineering with AI agents is becoming a multi-session activity. A real feature takes hours, sometimes days, sometimes spans multiple windows because of the 400K wall. The integrity of state transferred between sessions is becoming a load-bearing concern. Self-summarization without external audit is not sufficient. Every meaningful handoff between long-context AI sessions needs a fresh-context auditor in the loop.

We packaged claude-next because we hit this wall every day building LLM API. Now it is open source and on npm. If the pattern is useful to you, the install is one command. If you build a better one, please publish it — there is no good general solution yet.

claude-next on GitHub · claude-next on npm · Feedback issue

分享这篇文章

开始使用 LLM API

免费套餐可用。Claude Code 一行配置。

免费开始