What you will be able to do
- Explain how Edit matches old_string exactly and why that string must be unique in the file
- Pick between a longer anchor, replace_all, and a full Read + Write rewrite when an Edit can't be applied
- Trace every use of a function through wrapper modules by listing exported names first, then searching for each one
1.Edit replaces exact text; Write replaces the whole file
The three file tools in Claude Code differ in how much of a file they touch. Read takes a file_path and, optionally, an offset and limit, and returns the file's contents. Write takes a file_path and content, and the tools reference says it "Creates or overwrites files". Whatever you pass as content becomes the whole file. Edit takes a file_path, an old_string, a new_string and an optional replace_all flag. It finds the old text and swaps in the new text, which is why the reference describes it as making "targeted edits to specific files".
So Edit works by matching text, not by line number. The Claude API's text editor tool is a separate, API-level tool, not Claude Code's Edit, but it uses the same idea in its str_replace command. Its documentation states the rule plainly: old_str is "The text to replace (must match exactly, including whitespace and indentation)". An anchor that is off by one space of indentation matches nothing.
| Tool | Parameters | What it does with them |
|---|---|---|
| Read | file_path, offset, limit | Returns the file's contents, optionally starting at a line and limited to a number of lines |
| Write | file_path, content | Writes content as the entire file, creating or overwriting it |
| Edit | file_path, old_string, new_string, replace_all | Finds old_string and replaces it with new_string; replace_all controls whether every occurrence is replaced |
Checkpoint 1 of 6· Fill the gap
In the API text editor tool, which command makes a precise in-place replacement like the one Claude Code's Edit performs?
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "str_replace_based_edit_tool",
"input": {
"command": " ? ",
"path": "primes.py",
"old_str": "for num in range(2, limit + 1)",
"new_str": "for num in range(2, limit + 1):"
}
}str_replace swaps an exact old_str for new_str. create writes a new file, insert adds text after a given line number, and view reads a file.
Source: platform.claude.com2.The uniqueness rule for old_string
Matching text has an obvious risk: the same text can appear in more than one place. The tools reference handles this directly. "Uniqueness: old_string must appear exactly once." Edit does not guess which occurrence you meant. When the string appears more than once, the reference describes two remedies. Claude "either supplies a longer string with enough surrounding context to pin down one occurrence, or sets replace_all: true to replace them all."
The two remedies fit different goals. A longer anchor is right when exactly one occurrence should change. Include the function signature above the line, or a nearby comment, so that the combined string appears only once. replace_all is right when every occurrence really should change, as in a rename within one file. Using replace_all to dodge a uniqueness problem when only one site should change would edit lines you never meant to touch.
Checkpoint 2 of 6· Check yourself
A file has three identical if not user: lines. Only the one inside delete_account() should change. What is the right Edit strategy?
Only one occurrence should change, so the documented fix is a longer anchor that pins down that occurrence. replace_all would change all three.
“Claude either supplies a longer string with enough surrounding context to pin down one occurrence, or sets replace_all: true to replace them all.”Source: code.claude.com
Sources1
3.When Edit can't anchor: Read, then Write
Sometimes neither remedy fits. The repeated text may have no surrounding context that makes it unique. Or the change may not be a single replacement at all. Gathering several scattered export statements into one block near the top of a file, for example, means deleting text in many places and adding it in another.
The exam expects a third approach for these cases: Read the full file, build the corrected version, and Write it back. The documentation doesn't name this as a fallback for Edit. It follows from how the tools work. Edit needs an exact, unique match. Write needs no anchor, because it "Creates or overwrites files" with whatever content you give it.
That same property is the danger. Write replaces the whole file, so the new content has to be built from a fresh Read of the current file. Anything left out of content is gone. Edit stays the default for targeted changes. Read + Write is for changes that can't be expressed as a unique find-and-replace.
Checkpoint 3 of 6· Check yourself
Claude needs to move five scattered export statements into a single grouped block at the top of a module. Edit can't anchor the move as one unique replacement. Which sequence is reliable?
Write overwrites the whole file, so the restructured version has to be built from the full contents returned by Read. Writing only the export block would erase everything else in the file.
“Creates or overwrites files”Source: code.claude.com
Checkpoint 4 of 6· Exam question
A developer wants Claude Code to update a deprecated log statement `logger.warn("legacy-path")` that appears twice in the same file, in two different functions, where only one of the two occurrences should change. Claude issues an Edit call with old_string set to exactly that log statement and the call fails. What is the correct next step?
Correct answer: B — Widen old_string to include enough surrounding context to uniquely identify the intended occurrence, then retry Edit with that string
- A. Incorrect. Write overwrites the entire file with exactly the content provided; passing only a single line would delete the rest of the file's contents rather than merging into it.
- B. Correct. Edit requires old_string to match exactly once; when a string occurs more than once, supplying additional surrounding context that appears only around the target occurrence restores uniqueness and lets Edit apply cleanly.
- C. Incorrect. replace_all rewrites every occurrence, which would also change the log statement the developer wants to keep, and reverting one afterward risks losing track of which change was intentional.
- D. Incorrect. Grep is read-only and searches file contents; it has no capability to write or modify files, so it cannot perform the edit.
4.Tracing a function through wrapper modules
Before changing a function's signature, you need every call site. The obvious step is to Grep for the function's name. That works until the function is re-exported under another name. A wrapper module might export formatDate as fmt, and code that imports the alias will never contain the string formatDate.
The sources don't describe this technique directly. It follows from how Grep works: its pattern is a "Regular expression pattern to search for", so it finds only the text you ask for. A reliable trace therefore has two stages. First, Read the wrapper module and list every name it exports for the function, the original and each alias. Then Grep the codebase for each of those names. Because the pattern is a regex, one search can cover several names, and setting output_mode to content shows the matching lines instead of just file names. Each hit then becomes an Edit at a known location.
This is the same search-before-reading habit the common-workflows guide encourages with prompts like "find deprecated API usage in our codebase". Search tells you where to look, and Read and Edit act only on those places.
Checkpoint 5 of 6· Check yourself
utils/index.ts re-exports parseConfig as loadConfig. Claude must update every call site after changing parseConfig's parameters. What is the most reliable search plan?
Grep matches the literal pattern you give it, so call sites that use the alias loadConfig won't appear in a search for parseConfig. Listing the exported names first makes sure every alias gets searched.
“Regular expression pattern to search for”Source: code.claude.com
Checkpoint 6 of 6· Exam question
An architect asks Claude Code to identify every React test file in a codebase where naming mixes `.test.tsx`, `.spec.tsx`, and older files simply ending in `Test.tsx`, spread across many nested feature directories. Only a list of matching file paths is needed, with no content inspection. Which tool is the most direct fit?
Correct answer: C — Glob, using patterns such as **/*.test.tsx, **/*.spec.tsx, and **/*Test.tsx to match the naming conventions directly
- A. Incorrect. A recursive Bash listing followed by manually reading every file to check its name is far less direct than a purpose-built path-pattern match, and unnecessarily consumes context reading files that were never needed.
- B. Incorrect. Grep searches file contents, not file names; searching for the word test inside file bodies would return unrelated files that mention testing and could miss test files that never use that literal word.
- C. Correct. Glob matches file paths by name pattern, including recursive ** matching, so running it with the three naming conventions directly returns exactly the matching file paths without needing to inspect any file contents.
- D. Incorrect. Read loads the contents of a single file at a given path and does not list directories at all, so pointing it at the project root would not produce a recursive file listing.
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.If old_string appears several times, Edit just replaces the first occurrence.Why is that wrong?
old_string must appear exactly once. Otherwise the anchor needs more surrounding context, or replace_all has to be set deliberately.
Covered in The uniqueness rule for old_string
2.When Edit can't anchor a change, Write just the changed section to the file.Why is that wrong?
Write overwrites the whole file, so the content must be the complete new file, built from a fresh Read.
Covered in When Edit can't anchor: Read, then Write
3.Grepping for a function's original name finds all of its call sites.Why is that wrong?
Grep matches only the pattern you give it, so callers that use a re-exported alias are missed unless each exported name is searched.
Covered in Tracing a function through wrapper modules
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.https://code.claude.com/docs/en/tools-referenceOfficial docs
“Makes targeted edits to specific files”
↩︎ Edit replaces exact text; Write replaces the whole file“Uniqueness: old_string must appear exactly once.”
↩︎ The uniqueness rule for old_string“Claude either supplies a longer string with enough surrounding context to pin down one occurrence, or sets replace_all: true to replace them all.”
↩︎ The uniqueness rule for old_string“Creates or overwrites files”
↩︎ When Edit can't anchor: Read, then Write“Uniqueness: old_string must appear exactly once.”
↩︎ Exam trap 1“Creates or overwrites files”
↩︎ Exam trap 2 - 2.
“old_str: The text to replace (must match exactly, including whitespace and indentation)”
↩︎ Edit replaces exact text; Write replaces the whole file - 3.https://code.claude.com/docs/en/hooksOfficial docs
“Whether to replace all occurrences”
↩︎ Edit replaces exact text; Write replaces the whole file“Content to write to the file”
↩︎ When Edit can't anchor: Read, then Write“Regular expression pattern to search for”
↩︎ Tracing a function through wrapper modules“Regular expression pattern to search for”
↩︎ Exam trap 3 - 4.https://code.claude.com/docs/en/common-workflowsOfficial docs
“find deprecated API usage in our codebase”
↩︎ Tracing a function through wrapper modules