[Feature] Edit tool: add dry-run preview and line-number targeting to prevent blind substitutions
Problem
The Edit tool has two related gaps that cause real bugs in large codebases:
1. replace_all performs blind substitution with no preview
When using replace_all=True, the tool replaces every match without showing where they are. In one incident, replacing self.company_frame.pack(...) with self._show_header() across a 32K-line file also replaced the pack() call inside _show_header() itself -- creating infinite recursion. The user had to manually rollback via git.
There is no way to see all match locations before committing the replacement.
2. Targeted edits require unique strings, with no line-targeting fallback
The Edit tool requires old_string to be unique in the file. In large files (10K+ lines), common patterns like cursor.execute("DROP TABLE IF EXISTS") or self.root.after(0, appear dozens of times. The only workaround is adding 5-10 lines of surrounding context to make the match unique -- which is error-prone and slow.
There is no way to say "replace the match at line 1793" or "replace the 3rd occurrence."
Impact
- replace_all caused infinite recursion in production code (required git rollback)
- "Found 2 matches" errors occur multiple times per session on large files, requiring repeated Read + re-craft of old_string with more context
- Estimated 10-15% of edit attempts on files over 5K lines fail on first try due to uniqueness issues
- Over 3 months of daily use on a 67K-line codebase, this is the single most frequent source of workflow friction
Suggested Solutions
dry_run=Trueparameter -- returns all match locations (file, line number, surrounding context) without applying changes. User/model can review before committing.line_numberparameter -- disambiguates whenold_stringhas multiple matches. "Replace the match nearest to line 1793."occurrenceparameter -- "Replace the Nth occurrence" as a simpler alternative.- For
replace_all: show a count + first/last match location in the response so the model knows what was changed and can verify.
Environment
- Claude Code VS Code extension, Opus model
- Python codebase with files ranging from 1K to 32K lines
- Encountered across 3 months of daily use
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗