Capability · Read · updated 2026-09-02

Nine harnesses read files. What actually differs?

4
line-number formats across the implementations read
two harnesses emit no line numbers at all
6/9
will let you overwrite an edit made after the read
an invariant, not a preference
1/8
counts lines from zero
Qwen Code; everyone else starts at one
Getting file contents into the model's context. Nobody picks a read tool — it arrives with the harness — so this page is a reference for people building the harnesses and the tools around them, not a buying guide.

Nine harnesses were read from source. The thing worth knowing first is that almost none of the differences are the ones people argue about. Line caps and output formatting are visible, discussed, and mostly harmless. The differences that will actually cost you something are invisible until they bite.

The one that loses data

Six of the nine will let an agent overwrite a file that changed after it was read. The agent reads a file, thinks for a while, writes it back, and whatever happened in between is gone — silently, with no error and nothing in the transcript to suggest anything went wrong.

Three implementations guard against it, in three different places: Claude Code requires a prior read before an edit, Hermes compares mtime at write time, and MiMo Code tracks read state per file. That is three separate people arriving at the same problem independently, which is usually a sign the problem is real.

This is listed as an invariant rather than a design choice, which means the comparison table below shows it as pass/fail. That is a judgement, and it is the one place on this page where we are willing to make one: there is no coherent argument for silently discarding a concurrent edit.

The one that is nobody’s fault

Qwen Code’s read_file is 0-indexed. Every other implementation that answers the question starts at one. Neither is wrong — but a builder moving code between harnesses has no way to notice until every read is off by exactly one line, and nothing in either tool’s description mentions it.

This is a design choice, so the table records it and does not score it. Marking it as a failure would be the easy, wrong thing to do, and it is worth being explicit that we are not doing it.

Four ways to number a line

N + TAB, N: , N|, or nothing at all. Interesting, but it changes nobody’s decision, which is why it sits in the long tail rather than at the top.

There is one consequence worth noting. Two harnesses have written code specifically to stop the model writing the line-number prefix back into the source file — Claude Code instructs the model to strip it, Hermes runs a detector on the write path that rejects content matching N|. Same pothole, two patches, and neither team has any data on how often a model actually falls in. That is precisely the kind of question this site exists to answer, and it has not been answered yet.

Codex does not have a read tool

It reads files by running cat and sed through exec_command. That is a legitimate design — the shell is already there, and it composes — but it means raw bytes from a binary file land in the context window with nothing to mark them as binary, no truncation notice, and no line numbers to refer back to. It is the only implementation surveyed where reading a file can quietly spend the context window on bytes the model cannot use.

What is not here

Four harnesses register a read tool that could not be verified from source: OpenHands, OpenClaw, Grok Build and ZCode. They are named below the candidate table rather than shown as empty rows, because a blank cell reads as “does not do this” when the truth is “we have not checked”.

Candidates

13 tools · 9 read from source
OwnerToolOffset basechoiceAnnounces truncationinvariantBinary not silentinvariantStaleness checkinvariantSource
Claude CodeRead1-indexedsrcholdssrcholdssrcholdssrcrepo
Codexexec_commandfailssrcfailssrcrepo
dshread1-indexedsrc?holdssrcfailssrcrepo
Hermesread_file1-indexedsrcholdssrc?holdssrcrepo
Kimi Coderead1-indexedsrcholdssrc?failssrcrepo
MiMo Coderead1-indexedsrcholdssrcholdssrcholdssrcrepo
opencoderead1-indexedsrcholdssrcholdssrcfailssrcrepo
piread1-indexedsrcholdssrc?failssrcrepo
Qwen Coderead_file0-indexedsrcholdssrc?failssrcrepo

Present but not verified. 4 more harnesses register a read tool that has not been read from source: Grok Build read_file, OpenClaw read, OpenHands file_editor, ZCode Read. They are left out of the table below rather than shown as empty rows — a blank cell would claim the behaviour is absent, which is a different thing from not having checked.

Full comparison

every cell links to where it was read
DimensionClaude CodeReadCodexexec_commanddshreadHermesread_fileKimi CodereadMiMo CodereadopencodereadpireadQwen Coderead_file
Output shape
Dedicated read toolReadsrcnone — cat/sed via exec_commandsrcreadsrcread_filesrcreadsrcreadsrcreadsrcreadsrcread_filesrc
Line numberingN + TABsrcnonesrc?N|srcN + TABsrcN: srcN: srcnonesrc?
Output wrapperplainsrcraw stdoutsrcplainsrcplainsrcplainsrc<path>/<type>/<content>src<path>/<type>/<content>srcplainsrcplainsrc
Limits
Default line cap2000srcnonesrc2000src2000src1000src2000src2000src2000src?
Byte / char capnonesrc?100k chars (not lines)src100 KBsrc50 KBsrc50 KBsrc50 KBsrc?
Per-line cap2000 charssrcnonesrc?2000 charssrc2000 charssrc2000 charssrc?
Whichever hits firstlinessrc?charssrclines or bytessrclines or bytessrclines or bytessrclines or bytessrc?
Pagination
Offset base1-indexedsrc1-indexedsrc1-indexedsrc1-indexedsrc1-indexedsrc1-indexedsrc1-indexedsrc0-indexedsrc
Negative offset reads the tailyes (−1..−1000)src
Announces truncationinvariantholdssrc?holdssrcholdssrcholdssrcholdssrcholdssrcholdssrc
Continuation hinton truncationsrc?next_offsetsrcwasTruncated + truncatedLineNumberssrc(Showing X-Y of N. Use offset=Z)src(Showing X-Y of N. Use offset=Z)src[Showing X-Y of N. Use offset=Z]src(truncated)src
Reports total lines????yessrcyes (End of file - total N)srcyessrclinesShown[]src
Out-of-range offset????explicit error w/ line countsrcexplicit error w/ line countsrc??
Non-text
Binary content never enters context silentlyinvariantholdssrcfailssrcholdssrc??holdssrcholdssrc??
Binary filesrefusesrcraw bytes into contextsrcUTF-8 onlysrc??error: Cannot read binary filesrcerror: Cannot read binary filesrc??
Imagesinlinesrcseparate view_imagesrcseparate read_image (auto-downscale)srcseparate vision_analyzesrcseparate read-mediasrcattachment + mime sniffsrcattachment (jpeg/png/gif/webp)srcattachment, auto-resize 2000²srcvision bridgesrc
PDFspages param, max 20/reqsrc??read-mediasrcattachmentsrcattachmentsrc?page ranges + continuationsrc
Notebookscells + outputssrc???(notebook-edit tool)src???
Giant single lineper-line capsrcnonesrc?char budget absorbs itsrcper-line capsrcper-line capsrcper-line capsrcpoints at bash sed fallbacksrc?
Errors
Missing patherrorsrcshell errorsrc???Did you mean one of these?srcDid you mean one of these?src??
Path is a directoryerrorsrclistssrc???lists entriessrclists entriessrc??
Empty fileexplicit remindersrcempty stdoutsrc???????
Non-vision modelrequires image-capable modelsrc????explicit note in outputsrc?
Correctness
Mixed line endings?rawsrc??renders CR visiblysrc????
Re-read dedup(path,offset,limit)→mtime, 'File unchanged since last read'srcfile read cachesrc
Staleness check before writeinvariantholdssrcfailssrcfailssrcholdssrcfailssrcholdssrcfailssrcfailssrcfailssrc
Line-number contamination guardinstructs model to strip prefixsrcwrite-side detector rejects N| contentsrc
Multi-file readconcurrent batchessrcread_many_filessrc
Side effects
Warms LSP on readyessrcyessrc
Injects nearby instruction filesAGENTS.md as system-remindersrcAGENTS.md as system-remindersrccompact AGENTS.md/CLAUDE.mdsrc

Rows marked invariant are things every implementation should hold to, so they render as pass/fail. Everything else is a design choice: differing is recorded, never scored. ? means we could not verify it; means the question does not apply.