Skip to content

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:

text
[src/app.py#A1B2]
1:import sys
2:print("hi")
3:
PieceMeaning
pathDisplay path for the file
TAG4 uppercase hex digits. Full-file fingerprint with trailing whitespace ignored so a whitespace-only drift does not bust the tag
N:line1-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_file hashline view
  • grep content mode ([path#TAG] plus match line numbers)
  • a successful non-structural edit preview
  • a successful write chain snapshot
  • a failed edit live 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

json
{
  "input": "[src/app.py#A1B2]\nPUT 2:\n+print(\"Hello, world!\")\n"
}

One or more sections, each starting with [path#TAG], then ops:

text
[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.=M

Operations

OpFormEffect
Replace one linePUT N:Replace original line N with the + body
Replace a rangePUT N.=M:Replace inclusive lines NM (also N-M / N..M)
Insert beforePUT <N:Insert body rows before line N
Insert afterPUT >N:Insert body rows after line N
AppendPUT >$:Insert body rows at end of file
DeleteCUT N or CUT N.=MDelete inclusive original lines (no colon)

Locator rules:

  • Digits then colon for single-line PUT: PUT 12: — never PUT 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)
  • PUT always needs at least one + body row; use CUT to 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

  1. Put every hunk for one path in a single edit document. Do not issue two edit calls on the same path in one batch; wait for the result first. Different paths may edit in parallel.
  2. One [path#TAG] section per path in that document.
  3. 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.
  4. Failures return a bounded live snapshot. Copy that header and lines to retry.
  5. Re-read only for lines outside the live snapshot or post-edit preview.
  6. After a large or structural edit, re-read before further ops on anchors outside the returned preview.
  7. Create or fully rewrite files with write. Do not use edit to create paths.

Results and chaining

OutcomeModel-facing content
Successful normal editOne-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 editNew 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 writeBounded head/tail hashline snapshot with the new TAG (about 28 head + 8 tail lines on large files)
Failed editError 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.