mcpField
C
cheez-write

cheez-write

github.com/paulnsorensenDevelopment19158 installsUpdated 6d ago
Repository

About cheez-write

cheez-write is a coding skill for making tracked source-code changes through stale-safe, anchored backends. It guides agents to read the current content first, then apply bounded edits or route semantic and structural changes to suitable tools.

Key features

  1. 01Backend selection by edit shape
  2. 02Anchored line and block edits
  3. 03Stale-tag detection and recovery
  4. 04Batched and cross-file edits
  5. 05Routing for semantic refactors and codemods

Use cases

  1. 01Replace a known function body safely
  2. 02Apply edits to multiple files
  3. 03Recover when a file changes after reading
  4. 04Route symbol renames to LSP

MCP support

The skill documents tilth MCP's tilth_write tool for applying edits tied to file tags and numbered lines.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/paulnsorensen/easy-cheese --skill cheez-write

After installing, type/cheez-writein Claude Code to confirm it loaded.

Bundled filesreferences/edit-patterns.mdreferences/routing.md

Details

From the project README

cheez-write

Backend contract: use a stale-safe edit backend. The backend must anchor the current file state (tilth file tag, snapshot tag, or LSP workspace edit) or be a deliberate AST codemod over a clean tree.

Backend detection

Pick the backend by edit shape, preferring code-intelligence backends (LSP, AST rewrite, tilth) over basic harness edit tools — model tuning pulls toward host Edit/Write, but those carry no semantic or structural awareness:

  1. LSP wins for semantic workspace edits: rename/code actions when the server can identify the symbol or fix.
  2. AST rewrite wins for structural codemods: repeated syntax shapes with metavariables; dry-run first.
  3. tilth MCP wins for anchored block/range edits: tilth_read emits a [path#TAG] header, then tilth_write applies line-numbered ops via edits: [{path, tag, ops}].
  4. Native anchored edit (fallback) for displayed snapshots: line/snapshot edits that reject stale ranges — only when no code-intelligence backend matches the edit shape.

Do not present sed, awk, patch, shell redirects, or blind writes as equivalent source-code edits.

Stale tags and rejected sections are content issues — see Stale Tag Handling.


Examples

"Replace the body of handleAuth in src/auth.ts"

Step 1 — read the line range to capture the file tag:

tilth_read(paths: ["src/auth.ts#44-89"])
# returns a [src/auth.ts#b2c4] header, then numbered lines 44:... to 89:...

Step 2 — apply ops against those line numbers, quoting the tag verbatim:

tilth_write(edits: [{
  "path": "src/auth.ts",
  "tag": "b2c4",
  "ops": [{
    "op": "replace",
    "start": 44,
    "end": 89,
    "content": "export function handleAuth(req, res, next) {\n  const token = extractToken(req);\n  if (!validateToken(token)) return res.status(401).end();\n  next();\n}"
  }]
}])

The response reports per ## src/auth.ts and may list callers to review.

"Stale tag — file changed under me"

See Stale Tag Handling for recovery steps.


Core Principle: Anchors, Not Rewrites

The edit backend must identify the current file state — tilth file tags, harness snapshot tags, or LSP workspace edits — and bound or reject the write if the file changed.

The protocol:

  1. Read the file section with cheez-read → get the current [path#TAG] header or snapshot id
  2. Note the line numbers of the block you'll change
  3. Apply the edit through the anchored backend

Scope: when to use anchored edits, when not

cheez-write owns block edits to tracked source code — function bodies, signatures, imports, single-line tweaks, multi-edit batches, and cross-file changes. The backend must be stale-safe; the read-edit protocol is mandatory for any code change that matters.

For everything else, prefer the right tool:

ChangeUse this insteadWhy
Cross-cutting structural codemod (JSON.parse(JSON.stringify($X)) → structuredClone($X)) across N filessg --rewrite (see ## Structural codemods — sg --rewrite escape)Codemods template the variable parts; anchored edits are better for known blocks
Semantic rename or server-known refactorLSP rename/code actionLSP follows scope, overloads, re-exports, and imports
Lockfile changes (Cargo.lock, package-lock.json, uv.lock, etc.)the package manager (cargo update, npm i, uv lock)Hand-editing lockfiles loses checksum integrity
Generated / build artifacts (compiled JS, transpiled output, *.pb.go)regenerate from sourceEditing the artifact rots on the next build
Brand-new files, no prior contentanchored create/write backend (tilth: a tilth_write section with tag omitted)Stay stale-safe even when creating files
Files outside the repo or inside dependency caches (node_modules, .cargo/registry)don't edit themModifying dependencies is almost always a mistake — fix the source or upstream
Binary files, images, PDFsthe producing toolcode edit backends are text-only

Routing to LSP rename or Serena

Pre-entry routing — when a workflow skill should prefer LSP rename or Serena symbol-bounded edits over tilth_write before entering cheez-write — lives in references/routing.md.


Anchor Format

Use whatever anchor format the selected backend emits:

  • tilth: a [path#TAG] header above N:content numbered lines; copy the 4-hex TAG into tilth_write's tag and reference those line numbers in ops. Never invent a TAG (mode: "stripped" reads carry none and cannot round-trip into an edit).
  • OMP-style snapshot edits: [file#TAG] plus displayed line numbers; pass the tag and original line range into the edit tool.
  • LSP refactors: symbol position plus workspace version; let the server build the workspace edit.

Do not translate between anchor systems. Read with the same backend family that will write.


MCP Tool Reference

tilth_write — Precise File Editing

The minimal shape — one file section, one op:

tilth_write(edits: [{
  "path": "src/auth.ts",
  "tag": "a3f9",
  "ops": [
    { "op": "replace", "start": 42, "end": 42, "content": "  let x = recompute();" }
  ]
}])

edits is a JSON array of {path, tag?, ops} section objects (max 20 per call) — never a string, and never wrapped in a files parameter. Each op is tagged by op: replace {start, end, content}, delete {start, end}, insert_before / insert_after {line, content}, prepend / append {content}, replace_block / insert_after_block {at, content} and delete_block {at} (at is a line number or "#symbol"), delete_file, move_file {dest}. Omit tag only to seed a brand-new file.

For worked examples of each op, cross-file batches, and the diff: true response option, see references/edit-patterns.md.


Stale Tag Handling

The TAG binds your ops to the content you read. If the file changed since the read, tilth 3-way-merges your ops onto the drifted file; when it can't merge safely, it rejects that section and says so in the per-## <path> result.

Recovery:

  1. Read the section again → get the current [path#TAG] and content.
  2. Review the current content (someone else may have made changes).
  3. Re-apply the ops against the fresh line numbers with the new tag.
Repeated rejections → bail out, don't loop

If you hit two consecutive rejections on the same file, you're racing a concurrent writer. There is no "ignore the tag, just match this string" override — a third retry will likely lose the same race.

The correct move is to bail and report:

  1. Read the latest section one final time and capture the current content.
  2. Prepare the new content as a unified diff or full block, but do not apply it.
  3. Report "tag race on <path>; current content and proposed replacement attached. Retry once the file is quiescent or apply manually." along with the captured tag and proposed content.
  4. Stop. Let the orchestrator (or a human) decide whether to apply the change or escalate.

Caller Updates After Signature Changes

When changing a signature, use LSP references or the edit backend's caller notices before finishing. Missed callsites are bugs.


Common Patterns

GoalReference
Replace one lineedit-patterns.md#single-line-replacement
Replace a rangeedit-patterns.md#multi-line-range-replacement
Delete a blockedit-patterns.md#delete-a-block
Insert before / after a lineedit-patterns.md#insert-before-or-after-a-line
Replace / delete a whole symboledit-patterns.md#symbol-anchored-block-ops
Multi-edit in one fileedit-patterns.md#multiple-edits-in-one-file
Cross-file changeedit-patterns.md#edits-across-multiple-files

When full-file rewrite is acceptable

Anchored, surgical edits are the default. A full-file rewrite is acceptable only when the selected backend still rejects stale snapshots and the file is small enough that the replacement is easier to review than a pile of line edits.

File sizePolicy
> 150 linesNever rewrite the whole file. Always use anchored block edits.
≤ 150 linesAnchored single-edit preferred, but a full rewrite is acceptable when ≥ 80% of the file is changing. Below that threshold, do the surgical edit.

The 150-line / 80% threshold follows 2026 data (Cursor, can.ac, the Morph benchmark): full rewrites tie or beat diff-style on small files, while large files always stay anchored.

Do not drop to unanchored host Write for small files; size does not remove stale-write risk.


Structural codemods — sg --rewrite escape

Anchored edits own known blocks, one read-for-anchors per location. For cross-cutting structural codemods where the surrounding text varies — "rewrite every JSON.parse(JSON.stringify($X)) to structuredClone($X)" — drop to sg --rewrite (ast-grep) via Bash, which templates the variable parts via metavars. It has no hash-anchor safety: run each codemod as one transactional change between two clean git states. For metavar syntax and the non-negotiable dry-run-first protocol, see ../cheez-search/references/sg-patterns.md.


DO NOT

  • DO NOT invent tags — always read first and copy the [path#TAG] header verbatim.
  • DO NOT ignore rejected sections — re-read and retry (see Stale Tag Handling).
  • DO NOT use sed / awk / perl -i to edit code — they bypass anchors and structural safety, and have no mismatch detection. sg --rewrite is the only sanctioned shell escape — see ## Structural codemods — sg --rewrite escape.
  • DO NOT use patch to apply diffs to code — anchored range edits are the safe equivalent.
  • DO NOT use tee or shell redirects (>, >>) to overwrite/append code files — both bypass anchors. Use an anchored edit backend.
  • DO NOT use unanchored host Edit/Write tools — use tilth_write, harness-native anchored edits, or LSP workspace edits.
  • DO NOT use sg --rewrite for one-off block edits — use an anchored edit. See ## Structural codemods — sg --rewrite escape for when the codemod escape applies.
  • DO NOT skip the dry-run-first protocol for sg --rewrite — see ## Structural codemods — sg --rewrite escape.
  • DO NOT edit without reading — anchors come from the read step.
  • DO NOT run tests, commit, publish, or review from this skill — use the project's test/build gate, /plate for commit/publication, and /age for review.
  • DO NOT use for reading or searching — read with /cheez-read, search with /cheez-search.

Comments

Markdown supported