File picker doesn't follow symlinks in git repositories

Resolved 💬 6 comments Opened Dec 18, 2025 by hjtenklooster Closed Feb 27, 2026

Summary

The @ file picker fails to enumerate contents of symlinked directories when the current working directory is a git repository. The same symlink works correctly in non-git directories.

Environment

  • OS: macOS (Darwin 25.1.0)
  • Claude Code version: Latest (Opus 4.5)
  • Shell: zsh

Steps to Reproduce

  1. Create a symlink to an external directory:

```bash
mkdir ~/src/test-no-git
mkdir ~/src/test-with-git
mkdir ~/external-content
echo "hello" > ~/external-content/file.txt

ln -s ~/external-content ~/src/test-no-git/linked
ln -s ~/external-content ~/src/test-with-git/linked

cd ~/src/test-with-git && git init
```

  1. Open Claude Code in the non-git directory:

``bash
cd ~/src/test-no-git
claude
``

  1. Type @linked/ in the input - works correctly, shows file.txt
  1. Open Claude Code in the git directory:

``bash
cd ~/src/test-with-git
claude
``

  1. Type @linked/ in the input - fails, doesn't show contents

Expected Behavior

The file picker should enumerate the contents of symlinked directories regardless of whether the current directory is a git repository.

Actual Behavior

  • Without .git: Symlink contents are shown in the file picker
  • With .git: Symlink contents are NOT shown in the file picker

Additional Observations

  1. The "respect .gitignore in file picker" setting does NOT fix this.
  • Toggled via /config
  • Disabling it has no effect on this bug
  • The symlink is not in .gitignore (shows as ?? untracked in git status)
  1. The symlink itself appears in the picker - you can see linked/ as an option, but selecting it or typing @linked/ doesn't show its contents.
  1. Workarounds that DO work:
  • Using absolute paths: @/full/path/to/linked/file.txt
  • Using the symlink target directly: @/path/to/external-content/file.txt
  • Removing .git directory (not practical)

Root Cause Hypothesis

The file picker appears to use two different enumeration strategies:

if (isGitRepo) {
  // Git-based enumeration (git ls-files, git status, etc.)
  // Doesn't follow symlinks pointing outside the worktree
} else {
  // Filesystem-based enumeration (fs.readdir)
  // Naturally follows symlinks
}

Git intentionally doesn't recurse into symlinks pointing outside the repository. The file picker inherits this limitation when in git mode.

The "respect .gitignore" toggle likely only controls filtering behavior within the git enumeration path - it doesn't switch between git-based and filesystem-based enumeration.

Suggested Fix

When enumerating directory contents for the file picker:

  1. Use lstat() to detect symlinks
  2. If an entry is a symlink pointing to a directory, use filesystem-based enumeration for that subtree (even in git mode)
  3. This preserves git-aware behavior for regular files while properly handling symlinks

Alternatively, provide a separate toggle for "git-aware file picker" vs "filesystem file picker" independent of the gitignore setting.

Use Case

This affects developers who symlink external directories into their projects, such as:

  • Linking Obsidian vault folders for project documentation
  • Linking shared configuration directories
  • Linking monorepo packages during development
  • Any workflow where symlinks bridge repository boundaries

View original on GitHub ↗

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