[BUG] Edit tool breaks hard links — creates new inode instead of writing in-place
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?
When using the Edit tool on a file that is a hard link, the edit breaks the link — the source file gets a new inode. After editing, the source and linked copy are no longer connected. The linked copy retains the old content.
This affects any workflow using hard links for file deployment (e.g., agent definitions in a config repo hard-linked to ~/.claude/agents/).
What Should Happen?
The Edit tool should write to the existing file in-place (open → truncate → write → close), preserving hard links and inode identity. This is what most in-place editors do (vim with set nobackup, Python's open('w')).
Error Messages/Logs
No error. The edit succeeds silently, but the hard link is broken.
Steps to Reproduce
- Create a test file and hard link:
``bash``
echo "line 1" > /tmp/source.md
echo "line 2" >> /tmp/source.md
cp -l /tmp/source.md /tmp/deployed.md
# Verify same inode:
stat /tmp/source.md /tmp/deployed.md
- Open Claude Code in the directory containing source.md
- Ask Claude: "Edit /tmp/source.md — replace 'line 1' with 'modified line 1'"
- Claude uses the Edit tool. The edit succeeds.
- Check the hard link:
```bash
stat /tmp/source.md /tmp/deployed.md
# source.md has a NEW inode number
# deployed.md has the OLD inode number
# They are no longer linked
cat /tmp/deployed.md
# Still shows "line 1" — old content
```
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.69 (Claude Code)
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
Root cause (likely): The Edit tool uses a write-to-temp-file + rename pattern:
fs.writeFileSync(tempPath, newContent);
fs.renameSync(tempPath, originalPath);
This creates a new inode at originalPath, breaking any hard links.
Fix suggestion: Use in-place write:
// Option A: direct write (preserves inode)
fs.writeFileSync(originalPath, newContent);
// Option B: detect hard links and choose strategy
const stat = fs.statSync(originalPath);
if (stat.nlink > 1) {
// In-place write to preserve hard link
fs.writeFileSync(originalPath, newContent);
} else {
// Safe temp+rename for non-linked files
fs.writeFileSync(tempPath, newContent);
fs.renameSync(tempPath, originalPath);
}
My use case: I maintain 10 agent definitions in a config repo (claude-agents-config/agents/global/*.md) and deploy them via hard links to ~/.claude/agents/. Every time I use the Edit tool on an agent file, I have to manually cp -f source.md ~/.claude/agents/source.md to re-deploy. Symlinks require admin privileges on Windows, so hard links are the only practical option.
Note: This likely affects all platforms (Linux, macOS), not just Windows. The temp+rename pattern breaks hard links on any filesystem.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗