Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fix Claude session cwd resume drift - #2292

Merged
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76
Apr 23, 2026
Merged

Fix Claude session cwd resume drift#2292
juliusmarminge merged 9 commits into
mainfrom
cursor/fix-claude-cwd-resume-0c76

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Apr 22, 2026

Copy link
Copy Markdown
Member

Aims to fix#2256

What Changed

  • restart provider sessions when a thread's effective workspace cwd changes, so Claude does not keep running in a stale repo root or prior worktree
  • backfill the persisted cwd when ProviderService.startSession() resumes an existing Claude session without an explicit cwd
  • annotate provider/session start spans with the effective cwd and resume-source decision, and add a dedicated Claude adapter start-session span with the exact launch inputs passed to the Claude SDK
  • add regression tests for both workspace-switch restarts and trace-file visibility of Claude cwd/resume inputs
  • fix a ProviderService test isolation issue by using a unique thread id for the runtime-persistence assertion, avoiding cross-test reuse of persisted cwd
  • stabilize the Claude trace test by switching it from the real file/batch trace sink to an in-memory sink, avoiding CI timeout/flushing variance while still asserting the emitted span attributes

Why

Claude resume state currently reuses persisted session identity independently of workspace selection. That can leave an active Claude session bound to an outdated working directory, or replay a persisted resume cursor without the matching persisted cwd, which makes resume behavior unreliable for worktrees and subdirectory clones. The added span attributes make future regressions diagnosable from local trace files and exported OTEL spans.

Testing

  • bun run test src/provider/Layers/ClaudeAdapter.test.ts
  • bun run test src/provider/Layers/ProviderService.test.ts
  • bun run test src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderService.test.ts -t "captures claude start-session span annotations for resume and cwd inputs|passes Claude resume ids without pinning a stale assistant checkpoint|uses an app-generated Claude session id for fresh sessions|reuses persisted cwd when startSession resumes a claude session without cwd input"
  • bun fmt
  • bun lint
  • bun typecheck

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in WebOpen in Cursor

Note

Fix Claude session cwd drift by restarting sessions on workspace change and preserving cwd across resumes

  • Provider sessions are now restarted when the effective working directory changes between turns; previously the session was reused even if the workspace had changed.
  • ProviderService.startSession now falls back to the persisted cwd from an existing session binding when no cwd is provided as input, ensuring resumed sessions use the correct working directory.
  • ClaudeAdapter no longer treats transient hook_started, hook_progress, or hook_response session IDs as durable thread identifiers; thread.started events and resume cursor updates are now gated on a durable session ID (e.g. from init).
  • Behavioral Change: sessions that previously survived a workspace path change will now be restarted, and the resume cursor is preserved across the restart.

Macroscope summarized 11d6b00.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Apr 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0830e957-3a5b-46d7-b4cf-e4ab6fed91b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-claude-cwd-resume-0c76

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 22, 2026
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Apr 22, 2026
cursoragentand others added 2 commits April 22, 2026 14:09
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@juliusmarminge
juliusmarminge marked this pull request as ready for review April 23, 2026 04:30

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Potential infinite restart loop when effectiveCwd is undefined
    • Added an effectiveCwd !== undefined guard to the cwdChanged check so that an unresolved workspace (undefined) no longer triggers a spurious restart that would loop indefinitely due to the persisted cwd backfill in ProviderService.

Create PR

Or push these changes by commenting:

@cursor push 9974bfe8fa
Preview (9974bfe8fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -334,7 +334,7 @@
thread.session && thread.session.status !== "stopped" && activeSession ? thread.id : null;
if (existingSessionThreadId) {
const runtimeModeChanged = thread.runtimeMode !== thread.session?.runtimeMode;
- const cwdChanged = effectiveCwd !== activeSession?.cwd;+ const cwdChanged = effectiveCwd !== undefined && effectiveCwd !== activeSession?.cwd;
const sessionModelSwitch =
currentProvider === undefined
? "in-session"

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit fcb4421. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

A prior Macroscope approval was dismissed. Re-evaluating 4c5917b…

No code changes detected at 11d6b00. Prior analysis still applies.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:10

Dismissing prior approval to re-evaluate 94af290

@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 94af290 to fd7f5ceCompareApril 23, 2026 16:12
macroscopeapp[bot]
macroscopeappBot previously approved these changes Apr 23, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewApril 23, 2026 16:43

Dismissing prior approval to re-evaluate 4c5917b

- Ignore transient hook session IDs when updating resume state
- Add regression coverage for Claude resume hooks
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarmingeforce-pushed the cursor/fix-claude-cwd-resume-0c76 branch from 4c5917b to 11d6b00CompareApril 23, 2026 16:43
@juliusmarminge
juliusmarminge merged commit 188df6d into mainApr 23, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the cursor/fix-claude-cwd-resume-0c76 branch April 23, 2026 17:29
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added cwd/resume-drift regression tests that wired
AnalyticsService.layerTest. MarCode removed PostHog/analytics per
FEATURES.md §"Telemetry Removal" and exposes only AnalyticsServiceNoopLive
(already imported in this file at line 45 and used at line 369). Switch
the two resume-drift test layers to the noop so typecheck passes.
tyulyukov added a commit to tyulyukov/marcode that referenced this pull request Apr 24, 2026
Upstream pingdotgg#2292 added the "restarts the provider session when the thread
workspace changes" test using the hardcoded path "/tmp/provider-project-worktree".
MarCode's ProviderCommandReactor (line 302) auto-archives threads whose
worktree directory is missing on disk — so the non-existent path short-circuits
the session restart and the test times out waiting for startSession call #2.
Use mkdtempSync for a real dir that exists during the test, clean up in finally.
This preserves MarCode's missing-worktree auto-archive behavior (MEMORY.md:
"Handle missing worktree directories gracefully #54e6ddc2") while still
exercising the workspace-change restart path.
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Session context get's lost/forgotten if i leave it for a while

2 participants

@juliusmarminge@cursoragent