Standalone pi policy gate extension package
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

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:

  • sudo and ssh are 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 / telnet are confirmed
  • env / printenv are 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 . -delete
  • sudo ... (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 ... or tee 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 confirmation
  • block.wav — lower, harsher alert for denied actions
  • refine.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:

  • paplay
  • pw-play
  • aplay
  • ffplay
  • play

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:

  1. built-in defaults
  2. ~/.pi/agent/policy-gate.json
  3. extra file passed with --policy-gate-config /path/to/file.json
  4. .pi/policy-gate.json in 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: false to disable all alert sounds.

  • soundConfirmEnabled, soundBlockEnabled, and soundRefineEnabled let you mute just one class of event.

  • soundDirectory is optional: by default the extension uses the package's bundled assets/ directory. If you set it, it should point to an existing directory containing confirm.wav, block.wav, and refine.wav.

  • workspaceRoots can be absolute paths, ~ paths, or paths relative to the current project cwd.

  • commandRegex is evaluated against the raw bash command string.

  • pathGlob is 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 nginx
  • ssh 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.