CLI resolves symlinks in working directory instead of preserving $PWD logical path

Resolved 💬 4 comments Opened Mar 26, 2026 by in4mer Closed Mar 30, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Claude Code resolves the working directory to its physical path at startup,
discarding the logical path the user navigated through. When the user reaches
their project via symlinks, every path displayed in output, tool results, and
file references uses the fully dereferenced physical path instead of the
symlink-based path the user actually works with.

For example, my shell's $PWD is:

/home/user/txt/duetto/c/duetto2

But Claude Code resolves this to:

/home/user/Documents/Dropbox/txt/duetto/code/duetto2

All tool output (Read, Glob, Grep, Edit, etc.) then references the long
physical path. The symlink-based path, which is the one present in my shell
history, aliases, scripts, and muscle memory, is never used.

This also degrades relative path computation. The physical path sits 7+
directories below /, so cross-module references produce chains like
../../../../../../.. that are unreadable and unusable. The symlink exists
specifically to provide a short anchor point close to /; if Claude
respected it, those same references would be 2-3 levels of ../ at most.
Even when a relative path is technically correct, a short absolute path
through the symlink (e.g., /home/user/txt/duetto/c/duetto2/some/file)
will almost always be preferable to an ungainly string of ../../../..
derived from the deep physical hierarchy. Resolving the symlink away
throws out both benefits: short absolute paths and shallow relative ones.

What Should Happen?

Claude Code should use $PWD (the logical path from the shell environment)
as the working directory rather than resolving it via realpath() or
fs.realpathSync(). This is what the user's shell shows, what their prompt
displays, and what all their other tools use.

Most shells maintain $PWD as the logical path (preserving symlinks) by
default (set -o logical). Node.js process.cwd() returns the physical
path on Linux, but process.env.PWD contains the logical path. The fix
would be to prefer process.env.PWD (after validating it points to the
same inode as process.cwd()) for display and tool path construction.

Steps to Reproduce

  1. Create a symlink to a project directory:

``bash
ln -s /long/physical/path/to/project ~/short/project
``

  1. cd ~/short/project
  1. Confirm the shell preserves the logical path:

``bash
echo $PWD # /home/user/short/project
pwd # /home/user/short/project
pwd -P # /long/physical/path/to/project
``

  1. Launch claude
  1. Ask Claude to read or reference any file. All paths in tool output use

the physical path, not the symlink path.

Environment

  • Platform: Linux (Ubuntu 22.04)
  • Terminal: CLI
  • Version: 2.1.39

Related Issues

  • #28201 — Same root cause on Windows (junction points resolved instead of

using workspace path). Currently Windows/VS Code scoped.

  • #764 — Symlink resolution failure for ~/.claude directory.
  • #16507 — Glob tool does not follow symbolic links.
  • #34125, #36610, #33140 — fs.realpath() resolving mapped drives to UNC

paths on Windows, breaking session matching. Same underlying pattern.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗