{"_id":"@ctxnn/pi-permission-gate","name":"@ctxnn/pi-permission-gate","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ctxnn/pi-permission-gate","version":"0.1.0","description":"Fail-closed destructive-command approval gate and safe-operations skill for the Pi coding agent.","type":"module","keywords":["pi-package","pi","pi-coding-agent","extension","permissions","safety","destructive-commands"],"author":{"name":"ctxnn"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/ctxnn/pi-permission-gate.git"},"bugs":{"url":"https://github.com/ctxnn/pi-permission-gate/issues"},"homepage":"https://github.com/ctxnn/pi-permission-gate#readme","publishConfig":{"access":"public"},"pi":{"extensions":["./extensions"],"skills":["./skills"]},"scripts":{"check":"npm pack --dry-run","test":"node --experimental-strip-types tests/rules.test.ts && node --experimental-strip-types tests/dialog.test.ts && node --experimental-strip-types tests/extension.test.ts","typecheck":"tsc --noEmit","prepublishOnly":"npm test && npm run typecheck && npm pack --dry-run"},"peerDependencies":{"@earendil-works/pi-coding-agent":">=0.74.0","@earendil-works/pi-tui":">=0.74.0"},"devDependencies":{"@earendil-works/pi-coding-agent":">=0.74.0","@earendil-works/pi-tui":">=0.74.0","typescript":"^5.7.0"},"gitHead":"8f15b80281684fcf62e8c819762f2c953e39bfd6","_id":"@ctxnn/pi-permission-gate@0.1.0","_nodeVersion":"26.4.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-pR3wWFr+kXq3qwSbAXf3Wfxo0YddB0ouCxJ2tH3KDhd3rn1HWAngOGLyyYbIIvgRYRT/Rs7+sSu+zlhONWkIoQ==","shasum":"1a4387331bdfc982f7b7ae87f1a49c30ac243248","tarball":"https://registry.npmjs.org/@ctxnn/pi-permission-gate/-/pi-permission-gate-0.1.0.tgz","fileCount":8,"unpackedSize":33578,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCH1SqObM2ki0ukZRT6e2iAf6Oe3U+n6DiWQGQS09Rk2AIhAOmSQT4ZWXmTSGUUJndmdhByw7/ZMgwcCRjLPNt71yfJ"}]},"_npmUser":{"name":"ctxnn","email":"chiragtaneja.work@gmail.com"},"directories":{},"maintainers":[{"name":"ctxnn","email":"chiragtaneja.work@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-permission-gate_0.1.0_1786736323972_0.8535247443937544"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-14T19:38:43.818Z","0.1.0":"2026-08-14T19:38:44.111Z","modified":"2026-08-14T19:38:44.304Z"},"maintainers":[{"name":"ctxnn","email":"chiragtaneja.work@gmail.com"}],"description":"Fail-closed destructive-command approval gate and safe-operations skill for the Pi coding agent.","homepage":"https://github.com/ctxnn/pi-permission-gate#readme","keywords":["pi-package","pi","pi-coding-agent","extension","permissions","safety","destructive-commands"],"repository":{"type":"git","url":"git+https://github.com/ctxnn/pi-permission-gate.git"},"author":{"name":"ctxnn"},"bugs":{"url":"https://github.com/ctxnn/pi-permission-gate/issues"},"license":"MIT","readme":"# @ctxnn/pi-permission-gate\n\nFail-closed destructive-command approval for [Pi](https://github.com/earendil-works/pi).\n\nThis package ships two layers:\n\n- **Extension** — intercepts `bash` tool calls and `!` user-shell commands before they run\n- **Skill** — `safe-operations` tells the model not to evade the gate\n\nIt is a command-pattern gate, not an operating-system sandbox.\n\n## Install\n\n```bash\npi install npm:@ctxnn/pi-permission-gate\n```\n\nFrom git:\n\n```bash\npi install git:github.com/ctxnn/pi-permission-gate\n```\n\nLocal checkout:\n\n```bash\npi install /absolute/path/to/pi-permission-gate\npi -e .   # try for the current run only\n```\n\nThen start a new Pi session or run `/reload`.\n\n## Behavior\n\n| Situation | What happens |\n|---|---|\n| Interactive session, guarded command | Overlay card with why / directory / a paged command preview. **Block** is first. Allow is once, for that exact command |\n| Interactive session, `/permissions` (no args) | Overlay menu to guard everything or turn all protections off |\n| Interactive session, unguarded command | Runs immediately |\n| RPC / no overlay | Same content in a Block / Allow once selector |\n| Subagent / headless / no UI | Fail closed; the command is not run |\n| Command changes after approval | New approval required |\n| `/permissions off` | Session-only pause after interactive confirm |\n\nFor long commands, `PgUp` / `PgDn` page the command preview; `Home` / `End` jump to its beginning/end. The Block / Allow once choices remain visible.\n\nTurning all protections off resets to guarded after `/reload`, restart, `/new`, `/resume`, or `/fork`. It makes only the current interactive session behave like normal Pi; subagents and headless runs load their own gated instance and stay guarded.\n\nOnly the user may turn protections off. Agents must not request or invoke `/permissions off` to complete work.\n\n## Commands\n\n```text\n/permissions            # menu: guard everything or turn all protections off\n/permissions status\n/permissions on         # guard everything in this interactive session\n/permissions off        # turn all protections off in this interactive session\n```\n\n`/permissions` with no arguments opens an overlay menu. **Turn all protections off** still requires a second confirmation, makes the current interactive session behave like normal Pi, and resets after `/reload`, restart, `/new`, `/resume`, or `/fork`. Subagents and headless runs stay guarded. In RPC or on hosts without the overlay, it falls back to a selector.\n\nStatus line: `🛡 guarded` or `⚠ guard paused`.\n\n## How it works\n\n```mermaid\nflowchart TD\n    A[Command requested] --> B{Source}\n    B -->|Agent bash tool| C[tool_call hook]\n    B -->|User ! command| D[user_bash hook]\n    C --> E{Protections on?}\n    D --> E\n    E -->|Off in interactive session| F[Run like normal Pi]\n    E -->|On| G{Matches guarded family?}\n    G -->|No| F\n    G -->|Yes| H{Interactive approval UI?}\n    H -->|No: headless or subagent| I[Block: fail closed]\n    H -->|Yes| J[Approval overlay]\n    J -->|Block or Escape| I\n    J -->|Allow once| F\n```\n\n```text\n/permissions\n┌──────────────────────────────────────────────────────────────┐\n│ Permission gate                                              │\n│ Now: 🛡 guarded                                               │\n│                                                              │\n│ → Guard everything                                           │\n│   Turn all protections off                                   │\n│                                                              │\n│ Require approval for every guarded command in this           │\n│ interactive session.                                         │\n└──────────────────────────────────────────────────────────────┘\n```\n\n## Turn-all-off scope\n\n```mermaid\nflowchart LR\n    P[Interactive parent session] -->|Turn all protections off| N[Normal Pi behavior in this session]\n    N -->|Reload, restart, new, resume, or fork| G[Protections on again]\n    P --> S[Subagent or headless process]\n    S --> H[Always guarded and fail closed]\n```\n\nTurning all protections off never relaxes protection for subagents or headless runs.\n\n## Guarded families\n\n- recursive or forced deletion (`rm -r/-f`, `find -delete`, `shred`/`unlink`, scripted rmtree)\n- privilege escalation (`sudo`)\n- destructive Git (hard reset/clean, restore/checkout discard, force-push/amend/filter-branch, branch/tag/stash/file delete)\n- filesystem, partition, or raw-disk modification\n- recursive or world-writable `chmod`/`chown`\n- forced process kill and shutdown\n- destructive SQL (`DROP` / `TRUNCATE` / `DELETE FROM`)\n- destructive Docker, Kubernetes, Terraform, and cloud delete operations\n- `rsync --delete`\n\n## Conservative matches\n\nThe gate errs on the side of caution. A few commands are guarded even though a safe variant exists, because reliably distinguishing them by pattern is brittle and a miss is irreversible:\n\n- `git restore --staged <file>` — only unstages (keeps working-tree changes), but is guarded like a working-tree discard. Use `git reset <file>` semantics via a non-destructive path or approve once.\n- `git push --force-with-lease` — safer than `--force`, but guarded the same as a forced push.\n\nIf a guarded command is genuinely safe in your context, approve it once for that exact command. Do not rewrite it to evade the gate.\n\n## Limits\n\nTrusted third-party extensions can execute their own process APIs outside Pi's bash tool. Deliberately obfuscated programs cannot be perfectly classified. Review source before installing third-party Pi packages; they run with full system access.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-f2d502ef29653a9e8e04c8a595018352"}