Skip to content

Fix Claude restore cwd after subagent metadata#4979

Open
lawrencecchen wants to merge 2 commits into
mainfrom
issue-claude-restore-wrong-folder-after-subagent
Open

Fix Claude restore cwd after subagent metadata#4979
lawrencecchen wants to merge 2 commits into
mainfrom
issue-claude-restore-wrong-folder-after-subagent

Conversation

@lawrencecchen
Copy link
Copy Markdown
Contributor

@lawrencecchen lawrencecchen commented May 29, 2026

Summary

  • Preserve the first cwd parsed from a Claude transcript so later subagent metadata cannot move the parent session into another directory.
  • Add a regression test that seeds a Claude transcript with a parent cwd, then a subagent cwd, and verifies the directory snapshot plus claude --resume command still use the parent folder.

Red failure

At commit 2ed6ac65f, the focused AWS cmux-unit run failed for the intended reason:

SessionIndexViewTests.testClaudeDirectorySnapshotKeepsProjectCwdWhenSubagentCwdAppears
XCTUnwrap failed: expected non-nil value of type "SessionEntry"

The session disappeared from the parent directory snapshot because the later subagent cwd overwrote the parent cwd.

Green pass

At commit 4b235c269, the same focused AWS cmux-unit run passed with exit code 0:

xcodebuild -project cmux.xcodeproj -scheme cmux-unit ... -only-testing:cmuxTests/SessionIndexViewTests/testClaudeDirectorySnapshotKeepsProjectCwdWhenSubagentCwdAppears test

Tagged build

./scripts/reload.sh --tag claude-cwd succeeded and built cmux DEV claude-cwd.app.

Proof notes

Cloud bootstrap artifacts are under /Users/lawrence/fun/cmuxterm-hq/cmux-assets/issue-claude-restore-wrong-folder-after-subagent/auto-issue/20260528-232909. The accepted proof for this fix is the red/green behavior test because it exercises the restore command source directly. The initial cloud recording was only a CUA bootstrap smoke check and did not reproduce the Claude restore path.


Note

Low Risk
Small, targeted change to Claude metadata parsing plus a unit test; no auth, persistence, or broad indexing refactors.

Overview
Claude session indexing now keeps only the first cwd found while scanning a transcript’s head, so later lines (including subagent isMeta bookkeeping with a different folder) no longer replace the parent session’s working directory.

That fixes wrong directory snapshots and claude --resume commands that previously cd’d into a subagent scratch path and could hide the session from the parent repo’s index. A regression test builds a transcript with parent then subagent cwd and asserts snapshot cwd and resume command stay on the parent folder.

Reviewed by Cursor Bugbot for commit 4b235c2. Bugbot is set up for automated code reviews on this repo. Configure here.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.


Summary by cubic

Fixes Claude restore picking the wrong folder when subagent metadata includes a different cwd. We now lock to the first cwd in the transcript so directory snapshots and claude --resume stay in the project root.

  • Bug Fixes
    • Parse the first non-empty cwd only; ignore later cwd values from meta/subagent lines.
    • Add a regression test that seeds parent and subagent cwds and asserts the snapshot and resume command use the parent folder.

Written for commit 4b235c2. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where project directory context could be overwritten when processing transcripts containing multiple directory references. The correct project directory is now preserved throughout session operations.

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 29, 2026 7:15am
cmux-staging Building Building Preview, Comment May 29, 2026 7:15am

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3524b1ad-c6f3-4e8a-af8d-41fe18f9e7d4

📥 Commits

Reviewing files that changed from the base of the PR and between d7b5b14 and 4b235c2.

📒 Files selected for processing (2)
  • Sources/SessionIndexStore.swift
  • cmuxTests/SessionIndexViewTests.swift

📝 Walkthrough

Walkthrough

extractClaudeMetadata now guards the Claude cwd field assignment with a one-time read flag to prevent overwriting from subsequent JSONL lines. A unit test validates that the parent session cwd is preserved when the transcript contains additional subagent cwd fields.

Changes

Claude Transcript cwd Capture

Layer / File(s) Summary
One-time cwd capture in metadata extraction
Sources/SessionIndexStore.swift
extractClaudeMetadata introduces didReadTranscriptCwd flag to capture the transcript cwd field only during head parsing, preventing later JSONL lines from overwriting out.cwd.
Test validation for single cwd capture
cmuxTests/SessionIndexViewTests.swift
New async test testClaudeDirectorySnapshotKeepsProjectCwdWhenSubagentCwdAppears constructs a temporary snapshot with a mixed-cwd transcript, verifies the parent cwd is preserved in the loaded entry, and asserts the resume command uses the correct parent directory path.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly Related Issues

  • #4938: The fix to prevent transcript cwd overwriting in extractClaudeMetadata directly addresses the transcript-parsing and resume-binding drift mentioned in this issue.

Poem

🐰 A wayward transcript once confused the path,
Each cwd that came would overwrite the last,
But now with flags we read it once and true,
The parent stays, the subagent's overdue! 🌟

🚥 Pre-merge checks | ✅ 17 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (17 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix: preserving Claude's working directory when subagent metadata appears later in the transcript.
Description check ✅ Passed The description includes comprehensive summary, test results with red/green commits, tagged build proof, and notes on risk level, exceeding template requirements despite some sections being informal.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed Changes confined to nonisolated static function with only local variable additions. No implicit MainActor models or shared mutable Sendables introduced. Tests properly @MainActor scoped.
Cmux Swift Blocking Runtime ✅ Passed Changes introduce only a simple boolean flag for control flow in production code; no blocking primitives (semaphores, locks, sleeps) are added. Test code uses proper async/await without blocking.
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift file changes; the check applies to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts. Per rule, Swift sleeps covered by separate check.
Cmux Algorithmic Complexity ✅ Passed Production code adds boolean flag to guard cwd assignment, maintaining O(n) linear complexity with no nested scans, rescans, or sorting. Test code is appropriately designed for regression testing.
Cmux Swift Concurrency ✅ Passed PR introduces no legacy async patterns. Changes to extractClaudeMetadata are purely logic improvements (boolean flag), and the new test uses proper async/await within XCTest boundary.
Cmux Swift @Concurrent ✅ Passed Only synchronous helper function modified and test case added for MainActor-isolated work. No @concurrent violations: proper actor isolation maintained.
Cmux Swift File And Package Boundaries ✅ Passed Focused bugfix adding 3 lines to existing oversized file (1800 lines, under 250-line addition threshold) with regression test. Qualifies as allowed case.
Cmux Swift Logging ✅ Passed PR introduces a simple boolean flag and guard logic to preserve initial Claude cwd; test additions are allowed per the rules; no print/NSLog/Logger/dump statements or problematic logging detected.
Cmux User-Facing Error Privacy ✅ Passed PR modifies only a private function and adds test code; neither contains user-facing error messages, alerts, or sensitive information that would violate privacy rules.
Cmux Full Internationalization ✅ Passed PR adds only internal logic and test code with no user-facing strings or localization requirements. New boolean flag is internal, test changes are exempt from i18n rules per the guidelines.
Cmux Swiftui State Layout ✅ Passed PR adds only a local flag variable to preserve cwd logic and a regression test. No new SwiftUI state, GeometryReader, list rows, or render-time mutations introduced.
Cmux Architecture Rethink ✅ Passed Local parsing flag controlling first-write-wins semantics within extractClaudeMetadata function; no timing constructs, duplicate state ownership, or split lifecycle patterns present.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds no new NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGroup code. Changes are to SessionIndexStore metadata parsing and unit tests only, not UI windows.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-claude-restore-wrong-folder-after-subagent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 29, 2026

Greptile Summary

This PR fixes a bug in extractClaudeMetadata where a later subagent metadata record (with isMeta: true and its own cwd) would overwrite the parent session's working directory, causing claude --resume to target the wrong folder. It adds a didReadTranscriptCwd guard so the first non-empty cwd found in the transcript head wins, and adds a focused regression test to protect against recurrence.

  • Sources/SessionIndexStore.swift: Adds didReadTranscriptCwd boolean flag to make cwd parsing "first wins" instead of "last wins" in the head-scanning loop.
  • cmuxTests/SessionIndexViewTests.swift: Adds testClaudeDirectorySnapshotKeepsProjectCwdWhenSubagentCwdAppears — seeds a transcript with a parent cwd followed by a subagent cwd, then asserts the snapshot entry and resumeCommand still reference the parent folder.

Confidence Score: 5/5

Safe to merge — the change is a small, well-contained guard in one parsing loop backed by a direct regression test.

The production change is three lines in a private static parsing helper: a local boolean flag prevents subsequent cwd fields from overwriting the first one found in the transcript head. The tail loop never touched cwd and is unchanged. The test seeds a realistic transcript, exercises the full loadDirectorySnapshot path, and asserts both the stored cwd and the generated resumeCommand. No actor isolation, blocking, logging, or i18n concerns are introduced.

No files require special attention.

Important Files Changed

Filename Overview
Sources/SessionIndexStore.swift Adds didReadTranscriptCwd flag in the head-parsing loop so the first non-empty cwd in the transcript wins; tail loop is unaffected and does not parse cwd. Fix is scoped, correct, and does not introduce blocking, isolation, or logging concerns.
cmuxTests/SessionIndexViewTests.swift New regression test creates a synthetic JSONL transcript with parent then subagent cwd, mutates CLAUDE_CONFIG_DIR via setenv/unsetenv within a @MainActor class (safe for serial test execution), and verifies both entry.cwd and resumeCommand use the parent path.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[extractClaudeMetadata called\nwith head, tail, projectDir] --> B[out.cwd = decodeClaudeProjectDir\ndidReadTranscriptCwd = false]
    B --> C{Iterate head lines}
    C --> D[Parse JSON line]
    D --> E{didReadTranscriptCwd?\nor cwd empty?}
    E -- "No / has cwd" --> F[out.cwd = cwdField\ndidReadTranscriptCwd = true]
    E -- "Yes (already read)" --> G[Skip cwd update]
    F --> H[Continue parsing\ngitBranch, model, title…]
    G --> H
    H --> C
    C -- done --> I{Iterate tail lines}
    I --> J[Parse pr-link, gitBranch,\npermissionMode, model]
    J --> I
    I -- done --> K[Return ClaudeParsed\nwith parent cwd preserved]

    style F fill:#d4edda,stroke:#28a745
    style G fill:#fff3cd,stroke:#ffc107
Loading

Reviews (1): Last reviewed commit: "fix: preserve Claude restore cwd after s..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant