edit-o-matic

Whitespace-tolerant edit fallback for Pi — fail-closed relative-indent matching, match-failure diagnostics, dry-run preview, correct indent-unit detection, Myers line diffs, multi-edit hardening, backups, atomic writes, and remapped Python syntax errors.

Packages

Package details

extension

Install edit-o-matic from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:edit-o-matic
Package
edit-o-matic
Version
1.1.0
Published
Aug 8, 2026
Downloads
110/mo · 25/wk
Author
bighornwoods
License
MIT
Types
extension
Size
106.9 KB
Dependencies
0 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/index.js"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

editomatic

Whitespace-tolerant edit fallback for Pi — for local/quantized LLM users who also use gentle-pi.

Upgrade to 1.1.0+ (diagnostics + dry-run)

Versions before 1.0.5 could silently corrupt indent-sensitive files (especially Python) when aggressive fallback matching flattened indentation and rewrote the wrong region.

1.0.5+ fail-closed matching · 1.0.6+ backups + atomic write · 1.0.7 multi-edit hardening · 1.0.8 Myers line diffs · 1.1.0 match-failure diagnostics, dry-run preview, correct indent-unit detection, remapped Python syntax errors.

Full details: CHANGELOG.md · lockdown: EDITOMATIC_STRICT=1

editomatic is not a replacement for Pi's built-in edit tool. It is a fallback for models that struggle with exact text matching due to indentation drift, trailing whitespace, or Unicode normalization differences — common failure modes of local and quantized language models.

The problem

Pi's built-in edit tool uses exact string matching. When a model's output contains different indentation levels, trailing spaces, or Unicode smart quotes, the edit fails. Quantized models (4-bit, 8-bit) are especially prone to these drift patterns.

# What the model sends:
{ "oldText": "function hello() {}" }

# What the file actually has:
"    function hello() {\n      // does nothing\n    }"

# Result: edit fails, model has to guess again

editomatic handles this with progressive fallback matching and fail-closed safety so it never silently destroys structure.

How it works

Matching strategies (first success wins):

Strategy What it does Speed
Exact Byte-perfect indexOf match Fastest
Fuzzy Strips trailing whitespace, normalizes Unicode; always replaces at line level Fast
Relative-indent Same content after fuzzy normalization, with matching relative indentation between lines (absolute indent may differ) Medium

Pure “strip all leading whitespace and hope” is not used. Two blocks that only look identical after flattening structure are rejected or treated as ambiguous.

Replacement preserves:

  • Original BOM and line endings (CRLF vs LF)
  • Unchanged lines outside the match
  • Tab/space convention and relative indent structure
  • Trailing newlines when intentional in newText

Write safety

Every successful write:

  1. Saves previous content to yourfile.ext.editomatic-bak
  2. Writes new content to a temp file, then renames (atomic on the same filesystem)
  3. For Python paths, runs best-effort python -m py_compile before overwrite when an interpreter is available (errors cite the real path and proposed-file line numbers, not a temp path)

Dry-run preview

{ "path": "app.py", "dryRun": true, "edits": [{ "oldText": "...", "newText": "..." }] }

Matches and builds the same Myers diff (and Python syntax gate) but does not write or create a backup. Use when verifying a large newText before committing the change.

Match-failure diagnostics

When oldText is not found, the error includes the closest candidate region, the first differing line (expected vs actual), and whether the drift is whitespace-only. That saves a full re-read when a successive edit used stale text.

Emergency lockdown

export EDITOMATIC_STRICT=1   # exact + fuzzy only

Install

pi install npm:edit-o-matic

Project-local:

pi install npm:edit-o-matic -l

Confirm 1.1.0 or later. See CHANGELOG.md.

Recovery from backup

cp path/to/file.py.editomatic-bak path/to/file.py
Variable Effect
EDITOMATIC_STRICT=1 Exact + fuzzy matching only
EDITOMATIC_NO_BACKUP=1 Skip sidecar backup
EDITOMATIC_SKIP_PYTHON_CHECK=1 Skip py_compile for .py files

Usage

The tool registers as editomatic in Pi's tool registry.

Parameters

{
  path: string;          // Path to file (relative or absolute)
  edits: Array<{
    oldText: string;     // Text to find (whitespace-tolerant)
    newText: string;     // Replacement text ("" = delete)
  }>;
  dryRun?: boolean;      // Preview diff + syntax check; no write
}

Tips

  • Keep oldText small and unique — ambiguous matches are rejected; not-found errors include first-diff diagnostics
  • One call, multiple edits — searched against original content; applied bottom-up safely
  • After a successful edit, re-read or use updated text for further edits to the same region
  • Preserve relative indentation in multi-line blocks (critical for Python)
  • dryRun: true — verify large replacements before writing
  • Deletion — empty newText deletes matched lines; "\n" inserts a blank line

When to use editomatic vs built-in edit

Situation Use
Standard edit on well-formatted files Built-in edit
Models that produce indentation drift editomatic
Mixed tab/space files editomatic
Unicode drift (smart quotes, special dashes) editomatic
Quantized or local models editomatic

Indentation context injection

On before_agent_start, editomatic injects per-file indent style, short indent examples, and a Python-specific reminder that indentation is syntax. That reduces how often fallback matching is needed.

Package contents

Path Purpose
index.ts Extension entry point
smart-edit.ts Matching engine + reindent
write-safety.ts Backup, atomic write, Python syntax gate
test/ Unit tests (matching, corruption regressions, write-safety)
CHANGELOG.md Version history and integrity notices

Changelog

See CHANGELOG.md.

Building

npm install
npm run build
npm run check
npm test

License

MIT — LICENSE