How does the Edit tool apply a file change, from receiving the old/new patch to validating, diffing, and writing the new content to disk

en
100.0% sentence pass·21/21 cited·22/23 citations valid·95 fn·0 dec·872 sem
Tool FrameworkPermission & Security FrameworkFoundation Utilities

Edit tool: applying a file change

Overview

This flow runs when the main loop dispatches a tool_use for the FileEdit tool, ending with the patched content flushed to disk . The entry point is the tool's call method in tools/FileEditTool/FileEditTool.ts .

Steps

  1. The tool destructures file_path, old_string, new_string, and replace_all from the validated input and expands the path to an absolute path via expandPath .
  2. It fires off skill discovery for the path and activates conditional skills, not awaiting skill loading so the edit is not blocked .
  3. It notifies the diagnostics tracker that the file is about to change via diagnosticTracker.beforeFileEdited .
  4. It ensures the parent directory exists by calling fs.mkdir(dirname(absoluteFilePath)) before entering the atomic read-modify-write section .
  5. When file history is enabled, it snapshots pre-edit content via fileHistoryTrackEdit keyed on the parent message uuid .
  6. It reads current contents with readFileForEdit, capturing originalFileContents, fileExists, encoding, and line endings .
  7. It validates freshness: if the on-disk mtime is newer than the last tracked read, it compares content against the cached full read and throws FILE_UNEXPECTEDLY_MODIFIED_ERROR on divergence .
  8. It normalizes quote characters by calling findActualString to find the real old string in the file and preserveQuoteStyle to keep curly quotes in new_string matching the file's style .
  9. It generates the patch and updated file buffer via getPatchForEdit, honoring the replace_all flag .
  10. It writes the updated buffer to disk with writeTextContent, preserving the original encoding and line endings .
  11. It notifies the LSP manager of the change via changeFile and saveFile, and clears previously delivered diagnostics for that URI .
  12. It calls notifyVscodeFileUpdated with old and new content so the editor's diff view updates .
  13. It updates readFileState with the new content and fresh modification time so subsequent edits see a consistent snapshot and stale writes are invalidated .
  14. It emits telemetry: tengu_write_claudemd when editing CLAUDE.md, countLinesChanged(patch) for line deltas, and tengu_edit_string_lengths with byte sizes and the replaceAll flag .
  15. When CLAUDE_CODE_REMOTE is truthy and the GrowthBook tengu_quartz_lantern flag is enabled, it computes a single-file git diff via fetchSingleFileGitDiff and logs tengu_tool_use_diff_computed .
  16. Finally it returns a data object carrying filePath, oldString, newString, originalFile, structuredPatch, userModified, replaceAll, and the optional gitDiff .

State touched

  • — LSP failure paths log via logForDebugging

(The primary mutable state for the edit — readFileState — is a per-context map passed in as a parameter to call, not a module-level state token in the whitelist .)

Decisions

No [decision:...] tokens are available in the whitelist for this flow .