This is the fifth article in my series on Claude Code tools. The first four covered the interaction primitive trio—AskUserQuestion, EnterPlanMode, and ExitPlanMode—and the search duo, Grep + Glob. The former solve how the AI and the user align with each other; the latter solve how Claude locates relevant files inside a project.
Once Claude has a file path, it needs to perceive what that file looks like right now. That is the job of Read. It is the bridge in the execution-primitive chain: it consumes the coordinates found by Grep and Glob, then establishes the “perception commitment” on which Edit and Write depend.
This series begins with a prerequisite article explaining what tools are and how Claude uses them. Like the other articles, this one follows the four-layer framework introduced there.
Read
Of all the tools, Read is both the most fundamental and the easiest to underestimate. It appears to do nothing more than “read a file,” yet it plays a critical role: it is Claude’s only compliant channel for perceiving the external world.
Without Read, Claude can build its understanding of a project only from training-time memory, which may be outdated; fragments pasted into the chat, which are incomplete; or hallucination, which is dangerous. Read gives every subsequent change a grounding in reality.
What it does
Read is Claude Code’s built-in file-content reader. Its surface behavior is straightforward: provide an absolute path and receive the file contents. Its responsibilities, however, extend far beyond those four words:
- Expose the true state on disk instead of relying on training memory, pasted fragments, or guesses.
- Satisfy a prerequisite for Edit by establishing tracked state in the harness before a file can be modified safely.
- Provide one entry point for multimodal perception across text, images, PDFs, and Jupyter notebooks.
-
Read large files safely through pagination with
offsetandlimit, preventing a single call from consuming the context window.
A concrete example
Scenario: The user says, “Can you look at the token-validation bug in auth/middleware.ts? It should be around verifyToken.”
Claude calls Read directly:
-
file_path:/Users/xxx/project/src/auth/middleware.ts—an absolute path.
Runtime output:
1→import jwt from 'jsonwebtoken';
2→
3→export async function verifyToken(req, res, next) {
4→ const token = req.headers.authorization;
5→ if (!token) return res.status(401).send('unauthorized');
6→
7→ try {
8→ const decoded = jwt.verify(token, process.env.JWT_SECRET);
9→ req.user = decoded;
10→ next();
11→ } catch (err) {
12→ return res.status(401).send('invalid token');
13→ }
14→}
Every line is prefixed with a line number and a tab marker. Claude can therefore pinpoint the problem precisely. Line 4 exposes the bug immediately: the code passes the entire Authorization header without stripping the Bearer prefix.
This output demonstrates several important properties of Read:
- Absolute path in, current disk contents out. Claude receives the file’s state right now, not training memory, conversation history, or a hallucination.
-
Line-number prefixes establish a coordinate system. If the user says “the bug on line 4,” Claude can locate it instantly; if Claude refers to “the
jwt.verifycall on line 8,” the user can do the same. - The default limit is 2,000 lines. Large files do not automatically consume the entire context window.
Other input shapes:
-
Large files, such as a 5,000-line source file: Read returns the first 2,000 lines by default. Claude can request
offset: 2000, limit: 1000for the next section. - Screenshots and images: the runtime detects the extension and presents the file visually rather than returning text, allowing Claude to see error dialogs, stack traces, and field values.
-
PDFs: documents longer than 10 pages require a range such as
pages: "1-5"; each call can read at most 20 pages, preventing a large document from overwhelming the context window. - Jupyter notebooks: Read returns code cells, outputs, and Markdown together.
Core value: Read is Claude’s only compliant channel for perceiving the external world. It replaces “guessing, remembering, or hallucinating” with “knowing.” Every downstream use of Edit, Write, or Bash rests on that perception commitment.
When it is triggered
The official tool description is explicit: assume the tool can read any file on the machine. Claude should not waste time wondering whether it ought to read a path. If the file is relevant, it should read it.
Use Read when:
- Before modifying a known file. Reading is required preparation for Edit or Write.
-
Establishing a project baseline. Read
package.json,tsconfig.json, orCLAUDE.mdto understand the project. -
The user references
@filename. Claude should proactively read files cited in the user’s message. -
The system supplies a linked note. If
<linked_note>appears in the context, read it directly. - Inspecting an image, PDF, or notebook. Read is the multimodal perception entry point.
-
Encountering an embedded image in a wiki-link. When a document contains
![[image.png]], read the image as well to build the full context.
Do not use Read when:
- Re-reading a file immediately after Edit just to verify it. The harness tracks state, and a successful Edit already confirms that the change was applied. Another Read wastes tokens.
-
Listing a directory. Use Glob or
ls; Read does not read directories. - Searching for a keyword. Use Grep; Read retrieves a section rather than searching content.
- Second-guessing a successful Edit or Write. If the operation succeeded, Claude does not need to distrust its own previous action.
One especially interesting anti-waste rule appears in the official description: Do NOT re-read a file you just edited to verify. The harness already tracks the file state, so Claude does not need to repeat the confirmation loop familiar to human programmers.
Technical design
1. Naming
Read
The name is radically simple: one verb covers every responsibility. Files, images, PDFs, and Jupyter notebooks all pass through the same operation. It is not called ReadFile, LoadImage, or ParsePDF.
A unified name signals a unified entry point. Claude does not need to memorize several tools; the runtime dispatches behavior according to the file format.
The field names are equally intuitive: file_path, offset, limit, and pages. Anyone familiar with paginated APIs can understand them immediately.
2. Tool-level description
Read’s description revolves around four concerns: declaring capabilities, triggering pagination, explaining multimodal behavior, and preventing waste.
A declaration of broad access
Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid.
This trains Claude not to question a path supplied by the user and not to hesitate over whether the file is readable. Trust the user, trust the tool, and act. The instruction suppresses the model’s tendency toward excessive caution.
An absolute-path requirement
The file_path parameter must be an absolute path, not a relative path
The phrase must be makes this a hard constraint. Claude Code is an agent that operates across sessions and working directories. Relative paths become ambiguous when the current working directory changes: Claude may believe it is in ~/project while the runtime is actually in ~/project/src.
Requiring absolute paths removes that dependency. Every Read call becomes self-describing.
A pagination trigger
When you already know which part of the file you need, only read that part. This can be important for larger files.
This is not a hard rule but an optimization hint. It teaches Claude that it does not always need to begin at the top of a file. The intended behavior is “read on demand,” not “read everything.”
A declaration of multimodal capability
This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.
The key phrase is presented visually. An image is not reduced to an alt-text description; it enters Claude’s visual understanding directly. The prompt teaches Claude to interpret “Read an image” as “I can see the image.”
Mandatory PDF pagination
For large PDFs (more than 10 pages), you MUST provide the pages parameter to read specific page ranges (e.g., pages: "1-5"). Reading a large PDF without the pages parameter will fail. Maximum 20 pages per request.
The words MUST and will fail signal a hard barrier. This follows the same philosophy as requiring Read before Edit: an invalid or unsafe call is blocked rather than allowed to produce a poor result.
A social instruction for screenshots
You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths.
This trains social behavior. If the user provides a screenshot path, Claude should inspect it rather than hesitate over whether it is appropriate. Temporary paths are explicitly supported.
Defined behavior for empty files
If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.
Claude learns in advance that an empty file does not produce an empty string. Otherwise it might misinterpret the reminder as a tool failure. This is a considerate error message instead of a silent failure.
An anti-waste rule: do not verify by re-reading
Do NOT re-read a file you just edited to verify—Edit/Write would have errored if the change failed, and the harness tracks file state for you.
This instruction is particularly interesting because it overrides a learned programming instinct. Developers often verify a file immediately after changing it, and Claude may imitate that pattern. In Claude Code, however, the harness already tracks state, so the additional Read is redundant. The prompt explicitly turns off that behavior.
3. Field-level descriptions
Read exposes four fields:
-
file_path—the absolute path to the target file; relative paths are not accepted. -
offset—the line at which to begin, optional and defaulting to0. -
limit—the maximum number of lines to read, optional and defaulting to2000. -
pages—a PDF page range such as"1-5"; only relevant to PDFs.
Several design choices deserve closer examination.
The dual role of line numbers and tab prefixes
Read prefixes every line with its line number, a tab marker, and then the actual content. This does two things at once:
- It gives Claude a coordinate system. Claude can refer to “the bug on line 42,” and the user can find it.
- It creates a trap for Edit. The prefix is not part of the real file and must be stripped before constructing an edit. The next article will examine this in detail.
The same feature is both perception-friendly and operation-hostile. That is why Edit’s prompt spends an entire warning on the trap: the prefix is necessary output from Read and necessary input to filter out before Edit.
Pagination with offset + limit
Why does Read default to 2,000 lines?
- Claude has a finite context window, and a large file can crowd out everything else.
- Most tasks need only one relevant section, such as a particular function.
- Pagination trains Claude to read on demand rather than retrieve everything.
This mechanism also implies a broader philosophy: Claude does not need to see an entire file to modify one section safely. A human developer opening a 5,000-line source file also scrolls directly to the relevant function.
A unified multimodal entry point
Read is not limited to text. Images, PDFs, and notebooks all use the same tool call:
- Images—PNG, JPG, GIF, or WebP: the runtime detects the extension and supplies visual tokens rather than a textual description.
- PDFs: the runtime extracts text while preserving embedded images; documents longer than 10 pages require a page range to protect the context window.
- Jupyter notebooks: cell structure, code, outputs, and Markdown are all returned.
This is a unified perception layer. Claude does not learn a separate tool for every format. It always uses Read, and the runtime normalizes those formats into input the model can consume.
Collaboration with Edit through the harness
One of Read’s hidden responsibilities is to establish tracked state for Edit. The runtime records which files Claude has read during the session. When Claude invokes Edit, the runtime checks that record and returns an error if the file has not been read.
That makes Read more than “retrieve a file.” It becomes a perception commitment: Claude commits that “I know what this file looks like right now.” Edit consumes that commitment, creating a trust chain for modifications grounded in the current disk state.
4. Schema validation
Read’s schema contains almost no hard constraints beyond the essential ones:
| Field | Type | Constraint |
|---|---|---|
file_path |
string | required; must be an absolute path |
offset |
integer | optional; defaults to 0
|
limit |
integer | optional; defaults to 2000
|
pages |
string | optional; required for PDFs longer than 10 pages |
Defaults are central to Read’s design. A 2,000-line limit puts the default behavior in the “large enough to be useful, small enough not to explode” range. Mandatory pages for PDFs longer than 10 pages is the sole hard barrier protecting the context window from large documents.
Division of responsibility among neighboring tools
Read contrasts with the tools discussed in the first four articles:
| Dimension | Interaction trio | Grep + Glob | Read |
|---|---|---|---|
| Role | Collaborative alignment | Locate coordinates | Perceive the external world |
| Frequency | Key moments | High-frequency | High-frequency |
| Input | Structured for Ask; empty for the two PlanMode tools | Pattern; the path need not be known | File path + pagination; the path must be known |
| Output | User decision | Paths / matching lines / counts | File contents |
| Conservative bias | “When uncertain, plan” | “Search on demand before reading everything” | “When uncertain, read” |
The Grep + Glob → Read trust chain creates a smooth transition from search to perception:
- Grep and Glob return coordinates—file paths and optional line numbers—but only small matching fragments.
- Read consumes those coordinates, selects the files worth investigating, and retrieves their fuller context.
- Read establishes a perception commitment for the next use of Edit or Write.
Read and Edit form one of Claude Code’s tightest tool partnerships:
- Perception commitment: Read means “I know what this file looks like now.”
- Operational basis: Edit consumes that commitment and performs a precise replacement based on the content Claude observed.
- Shared trap: Read’s line-number prefix is useful output but must be removed from Edit’s input.
- State-machine collaboration: the harness records Read state, validates it during Edit, and errors when the prerequisite is missing.
If AskUserQuestion, EnterPlanMode, and ExitPlanMode form a collaborative alignment pipeline, then Grep + Glob → Read → Edit / Write form the full execution pipeline: locate, perceive, and act. They share tracked harness state and combine to create a safe closed loop for changing code.
Summary
Read’s elegance does not lie in the basic act of reading a file. It lies in how its behavioral signals are concentrated in the tool description and field design:
- Naming: one minimal verb covers text, images, PDFs, and notebooks.
- Tool-level description: a long set of constraints connects capability declarations, pagination triggers, multimodal guidance, and anti-waste rules.
- Field design: only four fields, each carrying a nontrivial decision—absolute paths, dual-purpose line numbers, pagination, and PDF page ranges.
- Schema validation: minimal, with the page-range requirement for PDFs longer than 10 pages as the key hard barrier.
Read’s defining role is that of a perception primitive. It replaces guessing, remembering, and hallucinating with knowing, then commits that knowledge to the harness as tracked state for Edit and Write. That commitment is the foundation of trust for the entire execution-primitive system.
The next article will examine Edit: how the perception commitment established by Read becomes a sequence of precise string replacements.
Top comments (0)