[BUG] Session recap never auto-fires in Claude for Windows desktop GUI
Summary
Session recap (※ recap: / away-summary) never auto-fires in Claude for Windows desktop (the standalone GUI app), even after weeks of active use across many sessions. The same feature works as expected when claude runs in a real terminal (Linux SSH, Windows Terminal, etc.). Feature is enabled by default; no opt-out via env or /config was applied. Manual /recap not yet tested on the affected host.
Environment
- Host A (broken): Windows 11 + Claude for Windows desktop app v1.5354.0 (9a9e3d), which embeds Claude Code at
%APPDATA%\Claude\claude-code\2.1.121\claude.exe. Sessions logged withentrypoint: "claude-desktop". - Host B (working, control): Ubuntu 24.04 LTS,
claudev2.1.123, accessed via SSH from Windows Terminal on a separate workstation. Sessions logged withentrypoint: "cli". - Both hosts: telemetry on (API Usage Billing), no
CLAUDE_CODE_ENABLE_AWAY_SUMMARYset,awaySummaryEnablednot toggled tofalse,tengu_sedge_lantern: true.
Repro
- Install Claude for Windows desktop (the GUI app).
- Open the Code tab, start a chat, run any 5+ user turns over the course of normal work.
- Switch focus to another window for 5+ minutes, return.
- Observe: no
※ recap:line is rendered, nosystem / away_summaryevent is persisted to the session JSONL. - Repeat for any number of sessions/days. Recap never fires.
Run the same flow against claude in a real terminal (Windows Terminal, iTerm2, kitty, gnome-terminal, etc.) and recap does fire normally.
Expected vs actual
- Expected: after focus loss ≥ ~3 min and turn count ≥ 3, recap is generated and rendered on focus return.
- Actual on Host A: recap never fires. Verified across 125 JSONL session files, 0 entries with
type: "system"andsubtype: "away_summary", including in a single active session containing 74 user turns over 304 lines. - On Host B (control): recap fires routinely; 2 firings in one same-day interactive session.
Root cause (from claude.exe 2.1.121 string analysis)
The recap-eligibility gate mpH():
function mpH() {
let H = process.env.CLAUDE_CODE_ENABLE_AWAY_SUMMARY;
if (isFalsey(H)) return false;
if (isTruthy(H)) return true;
if (!growthBook("tengu_sedge_lantern", true)) return false;
if (Sq()) return false; // !isInteractive
return Cq()?.awaySummaryEnabled !== false;
}
returns true in this setup.
But the focus-tracking init in ensureInteractive:
ensureInteractive = () => {
if (this.unsubscribeTTYHandlers || !this.options.stdout.isTTY) return;
// … only here: this.options.stdout.write(qr) // qr contains \x1B[?1004h
…
};
bails immediately when process.stdout.isTTY === false.
When Claude for Windows desktop spawns the embedded claude.exe, stdout is wired as a pipe to the host React UI, not a PTY. So:
ensureInteractivereturns before sending\x1B[?1004h(DECSET 1004, focus reporting).- The host UI never echoes back
\x1B[I/\x1B[O(focus-in / focus-out). - Global
Ns6stays at its initial"unknown"and never transitions to"blurred". - The trigger inside
function v(R)/function N(R)never fires. - Recap is never generated.
Why it is not a config or feature-flag issue
CLAUDE_CODE_ENABLE_AWAY_SUMMARYis unset on both hosts.tengu_sedge_lantern: trueon both (from~/.claude.json/%USERPROFILE%/.claude.jsoncached GrowthBook features).awaySummaryEnablednot set tofalse.- Host B with identical user-side state fires recaps; Host A never does. The only structural difference is
claude-desktopentrypoint with piped stdout vsclientrypoint with PTY.
Suggested fix paths (non-prescriptive)
The desktop GUI host needs an alternate channel to feed focus state to the embedded process when stdout is a pipe — e.g.:
- Inject focus-in/focus-out escapes into the child stdin when the host window blur/focus changes.
- Or expose a programmatic
setFocusState(blurred|focused)IPC the embedded CLI listens for instead of DECSET 1004. - Or detect
claude-desktopentrypoint and switch focus detection to a non-terminal mechanism.
Workarounds for users
/recapslash command — manual force, bypasses focus check.- Run
claudedirectly in Windows Terminal (%USERPROFILE%\AppData\Roaming\Claude\claude-code\2.1.121\claude.exe) instead of the desktop GUI host.
Related issues (different but same MSIX/subprocess plumbing class)
- #36156 — Windows hooks receive stdin as TTY instead of pipe (mirror direction of the same kind of bug).
- #48362 — Claude Desktop MSIX session-persistence EXDEV bug.
- #48084 / #48863 — recap docs gap (not platform-specific but adjacent).
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗