6.3 KiB
@enne2/pi-policy-gate
A standalone pi extension package that applies a practical policy layer to risky tool calls.
It classifies operations into four outcomes:
- allow — execute immediately
- confirm — require human approval
- deny — block outright
- refine — block and tell the model how to reformulate the command safely
The default policy is opinionated but usable, and it is now baked into the code even if you provide no config file.
Built-in defaults:
sudoandsshare not denied by default- risky commands are generally confirmed
- only objectively dangerous or ambiguous forms are denied/refined
- destructive deletes should use an explicit absolute path
curl/wget/nc/socat/telnetare confirmedenv/printenvare confirmed- bash-based writes to sensitive files such as
AGENTS.md,.env, shell dotfiles, SSH config, and local policy files are confirmed - programmatically generated local alert sounds play on confirmation requests and blocks/refinements by default
What it protects against
Examples of behavior it catches by default:
rm -rf *rm -rf .rm -rf ..rm -rf /find . -deletesudo ...(confirmation)ssh .../scp/rsync/sftp(confirmation)curl ...,wget ...,nc ...,socat ...(confirmation)env,printenv(confirmation)git reset --hard,git clean -fdx,git push(confirmation)sed -i ~/.bashrc ...ortee AGENTS.md(confirmation)- writes outside the workspace (confirmation)
- reads/writes to sensitive paths such as
~/.ssh,AGENTS.md, or.env(confirmation)
Install
Directly in pi from git
Private Gitea/GitHub style install:
pi install 'ssh://git@git.enne2.net:222/enne2/pi-policy-gate.git'
Or with HTTPS:
pi install https://git.enne2.net/enne2/pi-policy-gate.git
With npm from the git repository
npm install git+ssh://git@git.enne2.net:222/enne2/pi-policy-gate.git
Then load it from local node_modules or publish it to your npm registry later.
Sound alerts
The package ships with three pre-generated WAV files and the extension only plays them at runtime:
confirm.wav— soft ascending alert for human confirmationblock.wav— lower, harsher alert for denied actionsrefine.wav— distinct mid-tone alert for “blocked, but reformulate safely” cases
By default it plays the bundled files from the package assets/ directory, so it does not write audio files into your agent home at startup.
It automatically uses the first available local player among:
paplaypw-playaplayffplayplay
You can also test them manually inside pi:
/policy-gate-sound/policy-gate-sound block/policy-gate-sound refine
Config files
The extension looks for config files in this order:
- built-in defaults
~/.pi/agent/policy-gate.json- extra file passed with
--policy-gate-config /path/to/file.json .pi/policy-gate.jsonin the current project
Project config overrides global config.
Example config
Copy and adjust:
cp policy-gate.example.json ~/.pi/agent/policy-gate.json
Example:
{
"workspaceRoots": ["."],
"requireAbsolutePathForRecursiveDelete": true,
"soundEnabled": true,
"soundConfirmEnabled": true,
"soundBlockEnabled": true,
"soundRefineEnabled": true,
"soundPlayer": "auto",
"overrides": [
{
"tool": "bash",
"commandRegex": "^sudo systemctl restart my-safe-service$",
"action": "allow"
}
]
}
Config reference
{
"workspaceRoots": ["."],
"requireAbsolutePathForRecursiveDelete": true,
"requireAbsolutePathForFindDelete": true,
"confirmSensitiveReads": true,
"confirmSensitiveWrites": true,
"confirmWritesOutsideWorkspace": true,
"soundEnabled": true,
"soundConfirmEnabled": true,
"soundBlockEnabled": true,
"soundRefineEnabled": true,
"soundPlayer": "auto",
"soundDirectory": "/absolute/path/to/custom/policy-gate-sounds",
"sensitivePathGlobs": ["~/.ssh/**", "**/.env"],
"overrides": [
{
"id": "optional label",
"tool": "bash",
"commandRegex": "^ssh deploy@staging\\b",
"pathGlob": "~/.ssh/**",
"action": "allow | confirm | deny | refine",
"reason": "Shown to the user / model",
"suggest": "Only used with refine/deny to explain the safer alternative"
}
]
}
Notes
-
soundPlayer: "auto"picks the first available local player. -
Set
soundEnabled: falseto disable all alert sounds. -
soundConfirmEnabled,soundBlockEnabled, andsoundRefineEnabledlet you mute just one class of event. -
soundDirectoryis optional: by default the extension uses the package's bundledassets/directory. If you set it, it should point to an existing directory containingconfirm.wav,block.wav, andrefine.wav. -
workspaceRootscan be absolute paths,~paths, or paths relative to the current project cwd. -
commandRegexis evaluated against the raw bash command string. -
pathGlobis matched against both the absolute path and the path relative to the current cwd. -
last matching override wins.
Behavior model
Allow
Low-risk reads and normal project-local writes are allowed.
Confirm
Potentially dangerous but legitimate actions prompt the human.
Examples:
sudo systemctl restart nginxssh deploy@staging 'systemctl status api'rm -rf /full/path/to/some/build-cache
Deny / Refine
Only clearly unsafe or ambiguous forms are blocked.
Examples:
rm -rf *rm -rf .find . -delete
The extension tells the model to switch to a safer form such as using an explicit absolute path.
Useful commands
Inside pi:
/policy-gate— show current policy summary/policy-gate-sound— play the confirmation sound/policy-gate-sound block— play the deny sound/policy-gate-sound refine— play the refine sound
Development
Install deps, regenerate the packaged WAV assets if needed, and verify the tarball:
npm install
npm run generate:sounds
npm run pack:check
Try it without installing globally:
pi -e /absolute/path/to/pi-policy-gate --list-models
Packaging notes
This package is intentionally TypeScript-only and relies on pi's built-in runtime loader. No build step is required.