@trycedar/pi-mdiff

Markdown-aware edit tools for pi coding agent — normalized SEARCH matching and block-level anchored editing for .md files

Packages

Package details

extension

Install @trycedar/pi-mdiff from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@trycedar/pi-mdiff
Package
@trycedar/pi-mdiff
Version
0.3.0
Published
May 19, 2026
Downloads
not available
Author
jacobwang1992
License
MIT
Types
extension
Size
43.4 KB
Dependencies
6 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./src/index.ts"
  ],
  "image": "https://raw.githubusercontent.com/trycedar0x/pi-mdiff/main/banner.png"
}

Security note

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

README

pi-mdiff

Markdown-aware editing for pi coding agent. Fixes edit failures on .md files caused by line-wrap mismatches, and adds section-anchored editing so reformatting can never break your workflow.

npm version license pi-package

The problem

You ask pi to update a paragraph in your docs. It fails:

Error: cannot find matching context in docs/architecture.md
<<<<<<< SEARCH
The system uses PostgreSQL for all storage.
The schema is defined in schema.sql.
All queries go through the repository layer.

The file has the same content — just wrapped differently by a formatter. Pi read it as three lines, the file now has them joined into one. Exact text match fails.

pi-mdiff fixes this silently. The edit goes through without any retry, without any error, without the LLM ever knowing there was a problem.

Install

pi install npm:@trycedar/pi-mdiff

That is the only step. No config, no API keys.

Try this first

After installing, ask pi naturally:

Update the Architecture section of docs/README.md to mention that we moved to PostgreSQL.
Inspect docs/CONTRIBUTING.md and rewrite the Getting Started section.
Delete the "Legacy Notes" section from docs/api.md.
Add a new "Troubleshooting" paragraph after the Installation section in README.md.

pi will use md_inspect to find the right section and md_edit to apply the change — no fragile text matching involved.

What this adds

Transparent fix for edit on .md files

Every edit tool call on a markdown file is intercepted. The SEARCH block is normalized before matching — soft-wrapped lines are joined, extra blank lines collapsed, list bullets standardized.

Before pi-mdiff: formatter wraps paragraph differently → SEARCH fails → LLM retries → confusion.

After pi-mdiff: normalization runs silently → match found → edit applied → done.

If normalization still can't find a match, pi-mdiff applies its own fuzzy recovery and returns a success result. The LLM never sees the failure.

md_inspect — see section structure before editing

md_inspect path="docs/architecture.md"
## Overview
  [0] paragraph: "This project is a web application that helps…"
## Database Layer
  [0] paragraph: "We use PostgreSQL for all persistent storage…"
  [1] paragraph: "Migrations are managed via Alembic…"
## API Layer
  [0] paragraph: "The REST API is built with Express…"

Shows every section heading and the blocks inside it, with 0-based indices. Call this before md_edit so you know exactly what to target.

md_edit — section-anchored editing

md_edit path="docs/architecture.md"
        operation="replace"
        section="## Database Layer"
        block_index=0
        content="We use PostgreSQL for all persistent storage.
The schema is defined in schema.sql and managed via Alembic."

Anchors to a heading + block index. No text matching. Formatters can reflow the entire file — this still works.

Operation What it does
replace Replace the block at block_index with new content
insert_after Insert a new block after block_index
delete Remove the block at block_index

Common workflows

Task How to ask
Update a specific section "Rewrite the Deployment section of docs/README.md to mention Docker."
Add a new paragraph "Add a Troubleshooting section after Installation in README.md."
Delete stale content "Remove the 'Legacy API' section from docs/api.md."
Bulk doc update "Update all references to 'SQLite' to 'PostgreSQL' in docs/architecture.md."
Inspect before editing "Show me the structure of CONTRIBUTING.md before we edit it."

What the normalizer preserves

The normalizer only joins soft-wrapped prose lines. Everything else is left exactly as-is:

Element Example Touched?
Fenced code blocks `````` Never
YAML frontmatter ---\ntitle: …\n--- Never
Table rows | Col A | Col B | Never
Headings ## Section Name Never
List items - item, - nested Never
Blockquotes > quoted text Never
Horizontal rules ---, *** Never
Explicit line breaks line ending with Never
Inline code `code` Never

Tools

md_inspect

Parameter Description
path Path to the markdown file

Returns a formatted section map with block type and preview text for each block. Use this before md_edit to find the right section and block_index.

md_edit

Parameter Description
path Path to the markdown file
operation replace, insert_after, or delete
section Heading text to anchor to — case-insensitive, ## prefix optional
block_index 0-based index of the target block within the section
content New block content (required for replace and insert_after)

How it works

Normalization path (fixes existing edit calls transparently):

LLM calls edit() on .md file
  → pi-mdiff intercepts tool_call
  → normalizes SEARCH block: join soft-wrapped lines, collapse blank lines
  → built-in edit runs with normalized text
  → if still fails: pi-mdiff applies fuzzy findInMarkdown(), writes file, returns success

Block-anchor path (md_edit, most robust):

LLM calls md_edit()
  → parse file into mdast AST
  → find section by heading (case-insensitive)
  → locate nth block node
  → splice replacement at exact character offsets
  → write file

Eval coverage

npm run eval   # 64 cases, 100% pass rate
Category Cases Covers
normalize 20 Tables, frontmatter, fences, lists, blockquotes, headings, setext, unicode
find 10 2-line/3-line reflow, reverse reflow, flowmark vs 80-char, multi-paragraph, no-match
md_edit 15 replace / insert_after / delete, blast-radius, frontmatter, error cases
reflow 9 3×3 format matrix — all 6 off-diagonal mismatches recover correctly
edge 10 Empty files, preamble, duplicate headings, long paragraphs, inline code

Development

git clone https://github.com/trycedar0x/pi-mdiff
cd pi-mdiff && npm install
npm test          # 36 unit tests
npm run eval      # 64 scenario evals
npm run typecheck # strict TypeScript check
pi -e ./src/index.ts  # load in pi for manual testing