pi-edit-approval
Pi extension: confirm before write/edit with profiles, diff preview, and persistent allow/deny memory. Reads always allowed.
Package details
Install pi-edit-approval from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-edit-approval- Package
pi-edit-approval- Version
0.2.0- Published
- Aug 16, 2026
- Downloads
- 274/mo · 274/wk
- Author
- shawnma
- License
- GPL-3.0-only
- Types
- extension
- Size
- 69.2 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./extensions"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-edit-approval
Pi coding-agent extension that asks before the agent modifies files.
- Reads stay free —
read/grep/find/lsare never prompted - Writes need approval — built-in
write/edit, plus common mutator tool names (e.g. MCPreplace) - Profiles —
strict/workspace/review/offpresets - Diff preview — approval UI shows a compact unified-style diff for edits
- Persistent memory — always allow/deny a file or directory across sessions
- Protected paths — hard-deny for
.env, keys, etc. - Workspace-aware — separate policies inside vs outside the git root (or cwd)
Keywords: pi-package, pi, pi-extension, pi-coding-agent.
Pi has no built-in “confirm before edit” switch. This package adds that gate via the extension
tool_callhook.
Install
Requires Pi (@earendil-works/pi-coding-agent).
You can install from npm or GitHub.
From npm (recommended)
pi install npm:pi-edit-approval
Pin a version:
pi install npm:pi-edit-approval@0.2.0
From GitHub
pi install git:github.com/ShawnMa123/pi-edit-approval
pi install https://github.com/ShawnMa123/pi-edit-approval
pi install git:github.com/ShawnMa123/pi-edit-approval@v0.2.0
Try once without installing
pi -e npm:pi-edit-approval
pi -e git:github.com/ShawnMa123/pi-edit-approval
Local path (development)
pi install /path/to/pi-edit-approval
pi -e ./extensions/edit-approval.ts
Project-local install
pi install -l npm:pi-edit-approval
pi install -l git:github.com/ShawnMa123/pi-edit-approval
After install, start a new session or run /reload.
If you previously copied edit-approval.ts into ~/.pi/agent/extensions/, remove that copy to avoid loading the extension twice.
Profiles
| Profile | Inside workspace | Outside workspace | Notes |
|---|---|---|---|
strict (default) |
ask | ask | Safest everyday default |
workspace |
allow | ask | Codex-style workspace-write |
review |
ask | ask | Larger diff preview (diffMaxLines: 80) |
off |
allow | allow | Disables write gating |
Switch live (persists to config):
/edit-approval profile workspace
/edit-approval profile strict
Default behavior
| Tool / path | Default (strict) |
|---|---|
read, grep, find, ls |
Always allow |
write / edit inside workspace |
Ask (+ diff preview) |
write / edit outside workspace |
Ask (labeled OUTSIDE workspace) |
Paths matching protectedPaths |
Deny (no prompt) |
| Paths in persistent allow memory | Allow |
| Paths in persistent deny memory | Deny |
bash |
Not gated (see gateBash) |
Non-interactive (-p / no UI) when policy is ask |
Block |
Workspace root = git rev-parse --show-toplevel when available, otherwise the session cwd.
Prompt choices
- Yes — this call only
- Yes, this file this session
- Yes, all workspace writes this session (if enabled)
- Yes, all outside writes this session (if enabled)
- Yes, always allow this file — persists to memory
- Yes, always allow this directory — persists prefix allow
- No
- No, this file this session
- No, always deny this file — persists to memory
Configuration
Optional file:
~/.pi/agent/edit-approval.json
Copy the example from the package:
# from a clone / install tree
cp edit-approval.example.json ~/.pi/agent/edit-approval.json
Copy-Item edit-approval.example.json $env:USERPROFILE\.pi\agent\edit-approval.json
Example: strict (default)
{
"profile": "strict",
"persistentMemory": true,
"diffMaxLines": 40,
"protectedPaths": [".env", ".env.", "id_rsa", "id_ed25519", ".npmrc", "credentials"],
"gateBash": false,
"extraMutatingTools": []
}
Example: Codex-style workspace-write
{
"profile": "workspace"
}
Or:
{
"profile": "strict",
"workspaceWrites": "allow",
"outsideWrites": "ask"
}
Explicit workspaceWrites / outsideWrites override the profile baseline when set in the JSON file./edit-approval profile <name> rewrites those fields to match the preset.
Options
| Key | Type | Default | Meaning |
|---|---|---|---|
profile |
strict | workspace | review | off |
strict |
Named preset |
workspaceWrites |
allow | ask | deny |
from profile | Inside workspace |
outsideWrites |
allow | ask | deny |
from profile | Outside workspace |
allowSessionBypassInWorkspace |
boolean |
true |
Offer session-wide workspace allow |
allowSessionBypassOutside |
boolean |
false |
Offer session-wide outside allow |
persistentMemory |
boolean |
true |
Offer always-allow / always-deny |
diffMaxLines |
number |
40 |
Diff/preview size in the prompt |
protectedPaths |
string[] |
see example | Substring / *.ext hard-deny |
gateBash |
boolean |
false |
Confirm every bash (noisy) |
extraMutatingTools |
string[] |
[] |
Extra tool names to gate |
Reload without restarting Pi:
/edit-approval reload
Persistent memory
File:
~/.pi/agent/edit-approval-memory.json
{
"allowPaths": [],
"allowPrefixes": [],
"denyPaths": [],
"denyPrefixes": []
}
Managed from the approval UI or:
/edit-approval allow path/to/file
/edit-approval deny path/to/file
/edit-approval forget path/to/file
/edit-approval memory
Order of checks (first match wins where applicable):
- Session deny
- Protected paths → deny
- Memory deny → deny
- Memory allow → allow
- Session allow / session workspace|outside bypass → allow
- Policy
allow/ask/deny
Commands
| Command | Action |
|---|---|
/edit-approval |
Status (profile, policies, session, memory counts) |
/edit-approval reset |
Clear session allow/deny bypasses |
/edit-approval reload |
Re-read config + memory files |
/edit-approval profile <name> |
Set profile and persist |
/edit-approval allow <path> |
Persist allow path |
/edit-approval deny <path> |
Persist deny path |
/edit-approval forget <path> |
Remove path from memory |
/edit-approval memory |
Dump memory entries |
What gets gated
Always treated as mutators:
- Built-in
write,edit
Also matched by name (case-insensitive), including MCP-style names:
replace,create_file,delete_file,apply_patch,str_replace- Patterns like
fastctx_replace,mcp_foo_write, …
Path fields inspected:path, file_path, filePath, filepath, target, target_path, filename, paths[]
Edit preview also understands oldText / newText and old_string / new_string.
Limitations
bashcan bypass file gates unlessgateBashistrue. Redirects are not parsed by default.- Not an OS sandbox — only Pi tool calls this extension sees.
- Diff preview is a compact summary, not a full side-by-side reviewer (
pi-show-diffsis complementary). - In print / headless modes without UI,
askbecomes a hard block.
For stronger isolation, use containers or a sandbox package; see Pi security docs.
Package layout
pi-edit-approval/
├── package.json
├── extensions/edit-approval.ts
├── edit-approval.example.json
├── CHANGELOG.md
├── LICENSE
└── README.md
{
"keywords": ["pi-package", "pi", "pi-extension", "pi-coding-agent"],
"pi": { "extensions": ["./extensions"] }
}
The pi-package keyword is used by the Pi package gallery.
Development
git clone https://github.com/ShawnMa123/pi-edit-approval.git
cd pi-edit-approval
pi -e ./extensions/edit-approval.ts
# or
pi install .
No build step: Pi loads the TypeScript extension directly.
Uninstall
pi remove npm:pi-edit-approval
pi remove git:github.com/ShawnMa123/pi-edit-approval
Optional cleanup:
rm ~/.pi/agent/edit-approval.json
rm ~/.pi/agent/edit-approval-memory.json
License
Related
- Pi packages documentation
- Pi extensions documentation
- Upstream examples:
permission-gate.ts,protected-paths.ts - Complementary:
pi-show-diffs(full diff UI) - Heavier alternatives: various
pi-permission-*packages