Skip to content

WSL support: Cannot import Claude Code sessions from WSL filesystem #28

@ShadiKhoury-nv

Description

@ShadiKhoury-nv

Problem

When running Harnss on Windows with Claude Code installed inside WSL, the "Resume CC Chat" feature shows "No Claude Code sessions found" because session JSONL files are stored in the WSL filesystem (~/.claude/projects/ inside WSL), not on the Windows filesystem.

Root cause

cc-import.ts:getCCProjectDir() constructs the session path using os.homedir() (Windows home) + project path hash. But when the project lives in WSL:

  1. Sessions are at \\wsl$\Ubuntu\home\user\.claude\projects\-home-user\
  2. Harnss looks at C:\Users\user\.claude\projects\... — wrong location
  3. The path hash also differs: WSL project /home/user hashes to -home-user, but Windows path \\wsl$\Ubuntu\home\user would hash differently

Additional issue: Claude binary resolution

claude-binary.ts uses where claude on Windows, which won't find Claude installed inside WSL (~/.local/bin/claude). A WSL fallback (wsl.exe -e which claude) would enable live sessions.

Environment

  • Windows 11 + WSL2 (Ubuntu 24.04)
  • Harnss v0.20.0
  • Claude Code installed in WSL only
  • 752 session JSONL files in ~/.claude/projects/-home-user/

Proposed fix

1. Session import (cc-import.ts)

Detect WSL project paths (\\wsl$\ or \\wsl.localhost\) and resolve the .claude directory from the WSL user's home:

function getCCProjectDir(projectPath: string): string {
  const normalized = projectPath.replace(/\\/g, "/");
  
  // Detect WSL paths: //wsl$/Distro/... or //wsl.localhost/Distro/...
  const wslMatch = normalized.match(/^\/\/wsl(?:\.localhost|\$)\/([^/]+)(\/.*)/i);
  if (wslMatch && process.platform === "win32") {
    const distro = wslMatch[1];
    const wslAbsPath = wslMatch[2];
    const hash = wslAbsPath.replace(/\//g, "-");
    const homeMatch = wslAbsPath.match(/^(\/home\/[^/]+)/);
    const wslHome = homeMatch ? homeMatch[1] : "/root";
    const wslPrefix = `\\\\wsl.localhost\\${distro}`;
    return path.join(wslPrefix, wslHome.replace(/\//g, "\\"), ".claude", "projects", hash);
  }

  const hash = projectPath.replace(/\//g, "-");
  return path.join(os.homedir(), ".claude", "projects", hash);
}

2. Binary resolution (claude-binary.ts)

Add WSL fallback to the resolution chain:

function resolveFromWsl(): ClaudeBinaryResolution | null {
  if (process.platform \!== "win32") return null;
  try {
    const output = execFileSync("wsl.exe", ["-e", "which", "claude"], {
      encoding: "utf-8", timeout: 10000, windowsHide: true,
    }).trim();
    if (output && output.startsWith("/")) {
      return { strategy: "wsl", path: `wsl:${output}` };
    }
    return null;
  } catch { return null; }
}

Then create a .cmd wrapper (wsl.exe -e /path/to/claude %*) that the SDK can spawn.

3. CWD translation

When spawning Claude for a WSL project, translate the CWD:
\\wsl.localhost\Ubuntu\home\user\project/home/user/project

Full patch

I have a working 168-line patch across 3 files. Happy to open a PR if there's interest.

Metadata

Metadata

Labels

area: sessionSession lifecycle, persistence, and revivalbugSomething isn't workingenhancementNew feature or requestgood first issueGood for newcomersplatform: windowsWindows specific

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions