[BUG] `gitStatus` snapshot is captured at process launch, not at first-prompt-submit — goes stale when other workers commit before you type
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [ ] I am using the latest version of Claude Code — I'm on 2.1.140, held back due to an unrelated rendering regression in newer versions. I checked the
CHANGELOG.mdonmainfor fixes to the stale-gitStatussnapshot and found nothing relevant, so this bug should still apply to the latest version.
Related
#24487 reported the same root cause with a "session resumed days later" repro and was auto-closed NOT_PLANNED by stale-bot for inactivity, then auto-locked. The closing comment instructs filing a new issue if still relevant — this is that new issue, with a different (and much more common) repro path that doesn't require resuming an old session.
What's Wrong?
The gitStatus block in the system prompt is snapshotted at process launch, not at the moment the user submits their first prompt. Anything that lands in the working tree between launch and first message is invisible to the snapshot — so the agent's "initial" mental model of the repo is already wrong on turn one.
This is routine, not edge-case. The standard trigger is multiple Claude Code tabs: tab A is working on a refactor. User opens tab B, starts drafting a prompt in the input box. Tab A finishes and commits. User submits the prompt to tab B. Tab B's snapshot still shows tab A's pre-commit dirty state — even though by the time the model sees the user's first message, the tree is already clean.
Steps to Reproduce
git inita repo with a clean tree.- Launch Claude Code (do not submit a prompt yet).
- In another terminal:
echo x >> file.txt && git add file.txt && git commit -m "x". - Now submit any prompt to the Claude Code session from step 2 (e.g. "what does
git statussay?"). - Observe: the system-prompt
gitStatusblock shows the pre-step-3 state (file.txtuntracked or whatever it was at launch), but livegit statusreports a clean tree.
Expected Behavior
gitStatus reflects the state of the working tree at the moment the user actually submits a prompt — or carries a timestamp the model can use to invalidate it.
Actual Behavior
gitStatus reflects state captured at process launch. The model treats this as authoritative and:
- Reports modified files that aren't modified.
- Narrates a reconciliation story to explain the discrepancy when live
git statusdisagrees (e.g. "the file must have been committed outside this conversation"). This confuses the user, who knows nothing happened "outside this conversation" — the snapshot was simply wrong from turn one.
Concrete Evidence From a Real Session
Observed timeline:
- T+0 — Session A launched. System-prompt
gitStatussnapshot captured at this moment: HEAD = commit X, file F listed as modified. - T+5min — Session B (a different Claude Code tab in the same repo) committed file F. New HEAD = commit Y.
- T+~6min — First user message submitted to session A. Real HEAD is now Y; working tree is clean. Session A's system prompt still shows the T+0 snapshot (HEAD = X, F modified).
- Later in session A: model ran live
git status, got "working tree clean," noticed it contradicted the snapshot, and told the user "the file modification must have been committed outside this conversation" — narrating a reconciliation story instead of recognizing the snapshot was simply stale.
The gap between snapshot capture and first prompt was ~5 minutes — entirely normal for "open a tab, draft a prompt, hit enter."
Distinct From #24487
#24487 framed this as a problem for resumed sessions and large refactor commits. This report adds:
- Common trigger path: concurrent Claude Code tabs, which is the standard recommended workflow for parallel work — not an edge case.
- Model-behavior failure mode: when live state disagrees with the snapshot, the model fabricates a reconciliation narrative ("must have been committed outside this conversation") instead of recognizing the snapshot is stale. The system prompt frames
gitStatusas authoritative initial context, so the model defends it. Even users withCLAUDE.mdrules saying "ignore the snapshot, trust live state" still get this failure mode because the model only consults live state when the snapshot is contradicted, by which point it's already in defend-the-snapshot mode.
Proposed Fix
Any of these would resolve it:
- Snapshot at first-prompt-submit, not at process launch. The simplest and most correct fix.
- Re-snapshot whenever the input box has been idle for > N seconds before submit. Cheap upper-bound on staleness.
- Timestamp the snapshot so the model can compare against current time and decide to re-run
git statusif it's old. - Index-based invalidation: if
.git/indexmtime is newer than the snapshot, omit the block or flag it stale.
Additionally, the system prompt's framing of gitStatus as "this is the git status at the start of the conversation" trains the model to treat it as ground truth. Even a small wording change — "this may be stale; verify with git status before relying on it" — would help mitigate the model-behavior half of the bug.
Environment
- Claude Code version: 2.1.140
- Model: Opus 4.7
- OS: Windows 11
- Shell: PowerShell 7, running in the VS Code integrated terminal
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗