Skip to content

About

Universal, configurable Codex-style apply_patch extension for Pi — works seamlessly with Claude, Gemini, DeepSeek, and custom API relays.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

23 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pi-apply-patch-universal

English | 中文文档

Universal, configurable Codex-style apply_patch extension for Pi (pi-coding-agent).
Designed for Claude, Gemini, DeepSeek, GPT, and custom API relays supporting standard tool calls.

Features

  • Universal Model Support: Compatible with all models in ~/.pi/agent/models.json (Claude, Gemini, DeepSeek, GPT).
  • Compact-Patch Steering: prompt guidelines instruct the model to keep 2-3 lines of context per hunk, anchor with @@, and split large refactorings — reducing the risk of gateway timeouts during long generations.
  • Grammar-Constrained Sampling: the official Codex Lark grammar is attached to the tool; providers with OpenAI grammar-tool support decode structurally valid patches, while all other providers are unaffected.
  • Line-Numbered Colored Diff UI: The CLI shows completed diffs by default, just like Pi's native edit tool, using the same renderDiff for line colors and word-level highlighting. Each file retains its path and +X -Y counters; streaming progress stays compact.
  • WebUI Preview Contract: Completed results also include details.preview.files[] with per-file numbered diffs (filePath, operation, movePath, diff) for pi-web and other web clients. This is separate from the CLI renderer.
  • Live Streaming Progress: Real-time counter preview while the model streams patch arguments, memoized per tool call to stay cheap on long patches.
  • Preflight and Rollback: All files are matched and computed before any write. Commit failures or cancellation restore modified contents, permissions, and symlinks, and remove empty directories created by the patch.
  • Stream-Truncation Detection: a patch cut off before *** End Patch is reported distinctly (with guidance to split smaller) instead of failing with a confusing hunk error.
  • Per-Line Ending Preservation: untouched lines keep their exact CRLF/LF/CR terminators — including a missing final newline — including context inside a hunk and lines between hunks; changed lines adopt the file's preferred (first) ending, mirroring Codex's SourceFile semantics.
  • EOF Blank-Context Tolerance: a trailing blank context line standing in for the file's final newline is retried without it, so trailing additions land in the right place.
  • No Silent Relocation: when quoted context cannot be located, the patch fails with a diagnostic instead of quietly inserting the change somewhere else.
  • Self-Healing Diagnostics: hunk failures include the closest match with line numbers plus concrete advice, helping the model re-read and correct the patch.
  • Interactive TUI Configuration: Manage active providers and models with /apply-patch.
  • Native Edit Protection: Automatically hides and blocks native edit/write tools when active, and restores them when switching away.
  • Shell Detour Guidance: Recognizes command-position apply_patch, common aliases, and wrappers, while allowing searches, quoted text, and heredoc documentation containing the tool name.
  • Resilient Arguments: input/patch/diff/content argument keys — and raw strings — are normalized before validation, absorbing per-provider quirks.
  • Path Sandbox: Restricts patch operations to the current workspace by default (allowAbsolutePaths: false), including symlink-escape checks and rejection of dangling symlinks.
  • Forgiving Markers: Auto-corrects a mis-prefixed +*** End Patch so the marker is never written into your file.
  • Tolerant File Headers: *** Update File: and friends are recognized despite indentation, missing/extra spaces, extra asterisks, backticked paths, or a stray diff prefix — so a later file's hunks are never absorbed into the previous file.
  • Drift-Corrected Line Hints: @@ -L,N @@ hints from later hunks are rebased by the net size change of earlier hunks in the same file, then verified by content, so multi-hunk patches do not drift.
  • Comment-Tolerant Fallback: When every strict pass fails, a final pass anchors on real code and tolerates paraphrased or truncated doc comments — but only when the alignment is unique, and it reports any - line it could not find instead of skipping it.
  • Standard JSON Tool Calling: Usable with proxies and aggregators that support standard JSON tool calls, without requiring Lark grammar support.

Installation

pi install git:github.com/LyraAgent/pi-apply-patch-universal

Reload Pi after installation:

/reload

Configuration

1. Interactive Menu

Inside your Pi session, run:

/apply-patch

Use the arrow keys and spacebar to toggle active providers and individual models automatically discovered from ~/.pi/agent/models.json.

2. Configuration File (~/.pi/agent/pi-apply-patch.json)

Settings are persisted in ~/.pi/agent/pi-apply-patch.json. You can also create or edit it manually:

{
  "providers": ["cliproxy", "openai"],
  "models": ["anthropic/claude-3-7-sonnet"],
  "disableNativeEdit": true,
  "allowAbsolutePaths": false,
  "addFileOnExisting": "overwrite",
  "moveOnExisting": "error"
}

Field Details

Field Type Default Description
providers string[] [] Provider-level matching. All models under the specified provider IDs (e.g., "cliproxy", "openai", "aio") will automatically activate apply_patch.
models string[] [] Model-level granular matching. Enables apply_patch for specific models. Accepts full reference provider/model_id (e.g., "openai/gpt-4o"), bare model_id, or provider:model_id. Useful for enabling patch mode only on top-tier coding models while keeping others on standard tools.
disableNativeEdit boolean true Tool exclusivity policy. When true, hides and blocks built-in edit and write tools whenever apply_patch is active, compelling the LLM to use token-efficient diff patches and avoiding accidental full-file rewrites. Switching to non-target models automatically restores native tools. Set to false to keep all tools available concurrently.
allowAbsolutePaths boolean false Path traversal sandbox. When false (recommended), strictly restricts all patch operations within the current working directory (cwd) to prevent accidental edits outside your project root. Set to true only if you explicitly need cross-directory patch operations.
addFileOnExisting "overwrite" | "error" "overwrite" Add File collision policy. "overwrite" lets *** Add File: replace a file that already exists (common when a previous run left a half-written file behind); the resulting diff shows the replaced lines and rollback restores the original content if a later action in the same patch fails. "error" restores the strict Codex behavior and fails with guidance to use *** Update File: or *** Delete File: instead.
moveOnExisting "error" | "overwrite" "error" Move destination collision policy. "error" refuses a *** Move to: whose destination already exists. "overwrite" replaces the destination file, matching upstream Codex semantics; directories still fail rather than being recursively removed.

Activation Logic

  • A model is active if it matches any entry in models OR its provider is in providers.
  • If both providers and models are empty [], the extension remains completely inactive (safe default).

Patch Syntax

*** Begin Patch
*** Add File: src/hello.py
+def greet(name: str) -> str:
+    return f"Hello, {name}!"
*** Update File: src/main.py
@@ def main():
-    print("old")
+    print(greet("world"))
*** Delete File: obsolete.txt
*** End Patch

*** Begin Patch and *** End Patch must stand alone on their own lines. A stray diff prefix (+*** End Patch) is auto-corrected instead of being written into the target file, but only when no correctly formatted end marker is present — file bodies that legitimately contain the marker text are preserved.

Missing end markers are rejected before any write, including move-only and delete-only patches. Within file bodies, +++ and --- are ordinary addition/removal lines, not Git file headers.

Matching behavior

A semantic anchor @@ <existing complete line> must exist; subsequent matching cannot fall back before it. Hunks are located by content, not by trusting line numbers. @@ -L,N +L,N @@ is treated as a hint: it is rebased by the net line change of earlier hunks in the same file, searched outward from there, and then falls back to a full-file scan. A hunk that only matches after ignoring comment differences is applied only when that alignment is unique in the permitted search region; comment lines the patch omitted are preserved, and a - line that cannot be found is reported rather than silently skipped.

Line endings are preserved per line: untouched lines keep their exact terminators (including a missing final newline), while changed and inserted lines use the file's preferred (first) ending, and a changed final line always receives a terminator — matching Codex's behavior.

All file changes are prepared before any write. Inputs are checked again before committing each operation; failures or cancellation restore modified contents, permissions, and symlinks, and clean up newly created empty directories. Rollback failures are reported explicitly. This is in-process recovery, not crash recovery or transaction isolation against concurrent external writes.

Shell detour detection is model guidance, not a full shell interpreter or a security boundary.

Acknowledgements

Built upon and enhanced from WufeiHalf/pi-apply_patch and matsuzaka-yuki/pi-apply-patch-plus.
Special thanks to @WufeiHalf for the configurable architecture and interactive TUI settings design.

License

MIT License © 2026 LyraAgent, WufeiHalf

About

Universal, configurable Codex-style apply_patch extension for Pi — works seamlessly with Claude, Gemini, DeepSeek, and custom API relays.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages