Hash-line edit format
Parent: Tools and workspace.
This page applies when the resolved edit format is hashline (the default for most providers under edit_tool = "auto", or when you pin edit_tool = "hashline").
edit changes existing UTF-8 files with line-anchored hunks. You pass one hashline document in input. Each section names a path and a snapshot tag from a prior read, then lists PUT and CUT ops against the original line numbers.
Use edit for targeted hunks when you already have a fresh [path#TAG]. Use write to create a path or replace a whole file. Do not use shell or Python to rewrite UTF-8 sources that edit can express.
Hashline snapshots
UTF-8 text and source files always read as a hashline view:
[src/app.py#A1B2]
1:import sys
2:print("hi")
3:| Piece | Meaning |
|---|---|
path | Display path for the file |
TAG | 4 uppercase hex digits. Full-file fingerprint with trailing whitespace ignored so a whitespace-only drift does not bust the tag |
N:line | 1-indexed original line body |
read_file still hashes the whole file when you pass offset / limit. Those args only choose which numbered rows appear. Rich documents and images are not hashline-editable; see documents and images.
Where tags come from
Copy TAG and line numbers from the latest snapshot for that path:
read_filehashline viewgrepcontent mode ([path#TAG]plus match line numbers)- a successful non-structural
editpreview - a successful
writechain snapshot - a failed
editlive snapshot
Never invent a tag. Grep match previews use N | text and may truncate. Copy TAG and line numbers only; do not paste preview bodies into PUT rows. Use read_file when you need exact line text.
Document shape
{
"input": "[src/app.py#A1B2]\nPUT 2:\n+print(\"Hello, world!\")\n"
}One or more sections, each starting with [path#TAG], then ops:
[path#TAG]
PUT N:
+replacement
PUT N.=M:
+range body
PUT <N:
+insert before N
PUT >N:
+insert after N
PUT >$:
+append at EOF
CUT N.=MOperations
| Op | Form | Effect |
|---|---|---|
| Replace one line | PUT N: | Replace original line N with the + body |
| Replace a range | PUT N.=M: | Replace inclusive lines N–M (also N-M / N..M) |
| Insert before | PUT <N: | Insert body rows before line N |
| Insert after | PUT >N: | Insert body rows after line N |
| Append | PUT >$: | Insert body rows at end of file |
| Delete | CUT N or CUT N.=M | Delete inclusive original lines (no colon) |
Locator rules:
- Digits then colon for single-line PUT:
PUT 12:— neverPUT 12.: - A trailing dot such as
PUT 12.=:is invalid and fails with an explicit error - Every body row under a
:header starts with+(use+alone for a blank line) PUTalways needs at least one+body row; useCUTto delete- Body matches the ranged span only: never restate neighbor lines; widen the range instead
- Line numbers name the original snapshot. They do not shift mid-document after earlier ops in the same input
Not supported yet: block ops (N*), registers, REM, and MV.
Rules
- Put every hunk for one path in a single
editdocument. Do not issue twoeditcalls on the same path in one batch; wait for the result first. Different paths may edit in parallel. - One
[path#TAG]section per path in that document. - Stale tags, overlapping destructive ranges, duplicate paths, out-of-range lines, mid-edit file changes, and inserts whose anchor sits inside another op's replace/delete range all fail closed with no write.
- Failures return a bounded live snapshot. Copy that header and lines to retry.
- Re-read only for lines outside the live snapshot or post-edit preview.
- After a large or structural edit, re-read before further ops on anchors outside the returned preview.
- Create or fully rewrite files with
write. Do not useeditto create paths.
Results and chaining
| Outcome | Model-facing content |
|---|---|
Successful normal edit | One-line ops summary (for example PUT 2.=5: (4 → 2 line(s))) plus a post-edit [path#NEW] numbered preview around the change |
Successful structural edit | New TAG and ops summary without numbered body lines. A structural edit is a single replace/delete span of 40 or more original lines. Re-read before the next op |
Successful write | Bounded head/tail hashline snapshot with the new TAG (about 28 head + 8 tail lines on large files) |
Failed edit | Error plus a bounded live snapshot focused on the op anchors |
Unified diffs are tool metadata for UI cards. They are not repeated in model-facing content. In the interactive TUI, added lines are green, removed lines red, and diff headers use the accent color.
Cards while the edit runs
- Streaming cards project the edit document alone (op summaries and PUT bodies).
- Approval and start cards dry-run against live files when readable so removals show as real
-rows. Missing or stale targets fall back to the document projection.
One read format for every caller
read_file returns the hashline view for every UTF-8 text file, whether or not the caller can use edit. Two read formats would make output depend on the agent's tool set, so the same file would read differently to a subagent, a workflow step, and the automation CLI. One format costs a small number of input tokens per line and keeps every reader on the same contract.
Related
- Documents and images - what
read_filedoes for non-text inputs - Search tools -
grepcontent mode tags and previews - Tools and workspace - when to prefer
editvswrite