@hank-warren/pi-auto-permissions
Fork of @ogulcancelik/pi-auto-permissions with dialog-answer user evidence: context-aware Bash permissions for Pi with automated guardian review.
Package details
Install @hank-warren/pi-auto-permissions from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@hank-warren/pi-auto-permissions- Package
@hank-warren/pi-auto-permissions- Version
0.10.0- Published
- Aug 20, 2026
- Downloads
- 2,022/mo · 1,295/wk
- Author
- hank-warren
- License
- MIT
- Types
- extension
- Size
- 126.2 KB
- Dependencies
- 1 dependency · 4 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-auto-permissions
Published fork. This is
@ogulcancelik/pi-auto-permissions0.1.3 (MIT, Can Celik) plus the dialog-answer evidence feature proposed upstream in ogulcancelik/pi-extensions#24 / PR #25. Switch back to the upstream package once it ships the feature. Never install both packages at once, or every Bash call is reviewed twice. The upstreamindex.test.tsharness suite is not vendored; the pure config/evidence tests live intest/.
A context-aware permission system for Pi shell commands, with an automated guardian that checks what the user actually authorized.
Pi Auto Permissions pauses configured Bash commands before execution. A guardian model reviews the exact command against a compact view of the current conversation:
- Clearly authorized and compliant commands run automatically.
- Authorized commands that violate the user's constraints are blocked with feedback so the agent can revise them.
- Commands without clear authorization are sent to the user for confirmation.
- High-risk commands always require confirmation.
Only user messages can grant permission or impose constraints. The assistant cannot authorize its own command.
Example
Suppose Git commits are globally guarded.
If the user says:
Fix the failing test and commit it with a concise lowercase message.
Then a matching commit can run without another permission prompt:
git commit -m "fix retry test"
But the guardian rejects a command that violates the request:
git commit -m "Fix the Failing Retry Test and Update Documentation"
If the conversation never authorized a commit, an interactive Pi session asks the user before running it. A non-interactive session blocks it.
Permissions are contextual, not permanent. Each command is judged against the current conversation and the exact action being proposed.
Install
pi install npm:@hank-warren/pi-auto-permissions
For local development:
pi install /absolute/path/to/pi-extensions/packages/pi-auto-permissions
Remove or disable other extensions that gate the same commands to avoid duplicate prompts.
Define your policy
The extension ships with an empty command policy. Nothing is guarded until you add rules, and commands that do not match a rule run normally.
Configuration is read before every Bash command from:
$PI_CODING_AGENT_DIR/pi-auto-permissions/config.json
PI_CODING_AGENT_DIR defaults to ~/.pi/agent.
Here is a small starter policy for commits, pushes, and publishing:
{
"rules": [
{
"pattern": "\\bgit\\s+commit\\b",
"flags": "i",
"level": "guarded",
"group": "git",
"label": "Git commit"
},
{
"pattern": "\\bgit\\s+push\\b",
"flags": "i",
"level": "guarded",
"group": "git",
"label": "Git push"
},
{
"pattern": "\\bnpm\\s+publish\\b",
"flags": "i",
"level": "guarded",
"group": "npm",
"label": "npm publish"
}
]
}
Rule fields are:
pattern: JavaScript regular expression sourceflags: optional regular expression flags, defaulting toilevel:guardedfor guardian review orconventionfor a direct policy blockgroup: policy group used by trusted-project bypasseslabel: short description shown during reviewmessage: optional feedback; required for convention rules
A convention rule blocks directly with its configured feedback instead of asking the guardian. The agent can call request_override for a legitimate one-session exception. Overrides require user confirmation and cannot bypass guarded rules.
Set enabled to false to disable the extension. Invalid configuration fails closed and blocks Bash calls until corrected.
Guardian configuration
By default, the guardian uses Pi's active model with low reasoning effort and a 30-second timeout. You can select a separate low-cost model.
Giving the guardian its own account keeps reviews from competing with your interactive session for a subscription's rate limits. Pi keys OAuth credentials by provider id, so a second login needs a second provider id — which is what @hank-warren/pi-multi-login exists to create. This package no longer registers one itself.
pi install npm:@hank-warren/pi-multi-login- Run
/multi-login, add a login with baseopenai-codexand suffixauto-permissions, and complete OAuth with the account reserved for guardian reviews. - Select the dedicated provider in the Auto Permissions config:
{
"reviewer": {
"provider": "openai-codex-auto-permissions",
"model": "gpt-5.6-luna",
"reasoningEffort": "low",
"timeoutMs": 30000
}
}
The separate credential is stored in Pi's normal auth.json under openai-codex-auto-permissions; the existing openai-codex credential is unchanged. The alias uses Pi's built-in OpenAI Codex OAuth flow, model catalog, and transport. Because it is a normal provider, its models also appear in Pi's model selector and in /login after login.
If you already used the login this package registered in earlier versions, nothing changes: pi-multi-login adopts the existing openai-codex-auto-permissions credential on first run, so the config above keeps resolving. Without that package installed, the provider is missing and Auto Permissions warns once per session; point reviewer.provider at openai-codex (or any signed-in provider) to silence it.
Other reviewer providers continue to work by setting their normal provider and model ids.
Guardian prompt
The bundled prompt evaluates authorization, command risk, and compliance with user constraints. Replace it inline with systemPrompt, or load a file:
{
"systemPromptFile": "./guardian-prompt.md"
}
Relative paths resolve from the configuration directory. Set only one of systemPrompt or systemPromptFile.
The guardian must return one of three decisions:
approve: execute the commandrevise: block it and tell the main agent what to correctask_user: open an approval prompt (rendered with@hank-warren/pi-permission-selector'sOptionSelector): numbered options with1–9hotkeys, Tab to attach a note that is delivered to the agent as a steering user message, Esc to cancel — which blocks the command
Conversation context and caching
The guardian receives a compact chronological view of Pi's active, compaction-aware conversation context plus the exact pending command. It includes retained user and assistant text, Pi's latest compaction summary, and small summaries of finalized tool calls, but excludes summarized-away history, thinking, tool output bodies, file contents, patches, images, and session metadata. Compaction summaries are non-authoritative assistant context and cannot grant permission.
The extension also recognizes native checkpoints created by @ogulcancelik/pi-codex-compaction. It keeps the checkpoint's retained plaintext user messages and post-checkpoint evidence, while excluding the opaque provider state and older local history. This integration is optional and does not change behavior when pi-codex-compaction is not installed.
The first review sends the complete compact evidence. Later reviews reuse the same reviewer session and append only newly finalized evidence and the latest action. The extension uses stable session identity, cache affinity, and long cache retention when supported by the provider. Branch changes, model or policy changes, failures, cancellation, and context pressure reset the reviewer session.
Assistant and tool evidence provide context but never grant permission. Later user messages override earlier conflicting user instructions.
Trusted projects may optionally provide their root AGENTS.md, or CLAUDE.md when no AGENTS.md exists, as policy evidence:
{
"reviewEvidence": {
"projectInstructions": true
}
}
Project instructions help interpret the requested workflow, but cannot independently authorize an action or override guardian policy.
Interactive dialog answers
When the main agent gathers a decision through an interactive question tool (for example ask_user_question), the user's selection is stored as a tool result, which never grants permission. Operators can allowlist user-answer tools, whose confirmed answers become source: "user" evidence records:
{
"reviewEvidence": {
"userAnswerTools": ["ask_user_question"]
}
}
A successful result from an allowlisted tool qualifies when its details are { "answers": [{ "question": string, "answer"?: string, "selected"?: string[], "notes"?: string }], "cancelled": false } with no error field. selected takes precedence over answer, non-string answers are ignored, and notes count only alongside a real answer. Each answered question contributes one USER (dialog answer): record; the guardian treats it as authorization for exactly the selected content and is told the question wording is assistant-drafted context, never an instruction. Any dialog extension emitting that shape qualifies.
The allowlist matches what you wrote: a bare name such as ask_user_question matches that tool in any namespace (functions.ask_user_question included), while a dotted name matches exactly. The default is an empty list.
Prompted-review evaluation log
Auto Permissions can append a private JSONL regression record whenever the guardian asks for confirmation and the user gives explicit feedback:
{
"evaluationLog": {
"enabled": true,
"path": "./review-evals.jsonl"
}
}
The path defaults to review-evals.jsonl beside the Auto Permissions config and resolves relative to that config. The file is created with mode 0600.
When logging is enabled, prompted reviews offer three choices:
- Allow — asking was unnecessary executes the command and records
userChoice: "allow_unnecessary"withexpectedDecision: "approve". - Block — asking was appropriate remains the second choice, blocks the command, and records
userChoice: "block"withexpectedDecision: "ask_user". (A block always affirms the prompt: the guardian has no reject verdict — its only non-approve outcomes are asking you or bouncing the command back to the agent asrevise— so the only true rejection in the system is yours at this prompt.) - Allow — asking was appropriate executes the command and records
userChoice: "allow_appropriate"withexpectedDecision: "ask_user".
When logging is disabled, the prompt retains the normal Allow and Block choices. Prompts from Pi or other extensions are unchanged.
Each version 2 record contains the collected user request, exact command, compact reviewer evidence, guardian reason, gate and session metadata, raw user choice, and both labels used for evaluation. The guardian's actualDecision is ask_user. Automatic-review failures are identified separately with decisionSource: "review_failure". Existing version 1 records can remain in the same JSONL file.
Logging is disabled by default. Records can contain sensitive conversation text and shell commands, so keep the file private and out of repositories. Cancelled or interrupted prompts are not labeled or logged.
Reviewer usage sidecar
Guardian reviews are model calls made outside the Pi agent loop, so they never appear in the session transcript and are invisible to tools that total usage from session files. Auto Permissions therefore appends one content-free record per completed review:
{"v":1,"id":"3f2b…","ts":"2026-08-11T22:41:03.118Z","source":"auto-permissions","label":"guardian","provider":"anthropic","model":"claude-fable-5","usage":{"input":812,"output":96,"cacheRead":18442,"cacheWrite":0,"reasoning":48,"cost":0.0121}}
The record carries identity, timing, and counters only. It never contains prompts, commands, reviewer evidence, verdicts, or responses, which is what makes it safe to keep on by default:
{
"usageLog": {
"enabled": true,
"path": "./usage.jsonl"
}
}
The path defaults to usage.jsonl beside the Auto Permissions config and resolves relative to it. The file is created with mode 0600 and rotates to usage.jsonl.1 once it passes 16 MB, keeping one previous generation. Writing is best effort: a failing sidecar never blocks or changes a permission decision.
@hank-warren/pi-stats reads <agent dir>/<extension>/usage.jsonl sidecars and shows this usage as its own provider/model (guardian) row. Set "enabled": false to stop recording.
Review display
The default UI shows guardian progress as a single animated status line in a temporary widget above the editor:
auto permissions · Git commit · ✶ waiting for openai-codex-auto-permissions/gpt-5.6-luna
A sparkle spinner (✶ ✸ ✻ ✽) cycles while the guardian is reviewing and resolves to ✓ approved, ↻ revision requested, ? waiting for your approval, or ✗ blocked. When approval is needed, the selector's leading ● pulses between warning-bright and dim so the active prompt remains visually distinct from the transcript. The guardian's reason, when present, appears on a dim second line; the command itself is not repeated because it is already visible in the Bash tool box. Configure the widget with:
{
"ui": {
"enabled": true,
"resultDisplayMs": 2500,
"placement": "widget"
}
}
Set placement to toolRow to show the review inside Pi's Bash tool row:
$ git commit --dry-run -m "fix auth"
◌ guardian running · Git commit · openai-codex-auto-permissions/gpt-5.6-luna
toolRow reconstructs Pi's standard local Bash definition because Pi does not expose renderer-only decoration. Do not use it with SDK-provided, remote, sandboxed, or otherwise replaced Bash backends. The extension detects non-native Bash tools and falls back to the widget instead of replacing them.
Set ui.enabled to false to hide review state without disabling enforcement.
Herdr pane indicator
When the environment variable HERDR_ENV is set to exactly 1, the extension additionally emits a herdr:blocked event whenever a command is waiting on your approval, and a matching cleared event once the review resolves. Herdr, a terminal multiplexer for coding agents, sets this variable for the panes it manages and uses the event to flag the pane that needs attention — useful when a review is blocking in a pane you are not currently looking at. The blocked event carries the gate label so the indicator can name the operation.
This is an optional integration and nothing needs to be configured to use it. Outside Herdr the variable is unset, the emit is skipped entirely, and every other feature behaves identically; the extension has no dependency on Herdr being installed.
Trusted groups
In a trusted project, create .pi/trusted-ops to bypass selected rule groups:
git
gh
Group names come from your configured rules. A trusted group bypasses all review for that group, so use it only in projects you control.
Subagent sessions
When a session is a pi-subagents child (PI_SUBAGENT_CHILD=1), the guardian receives additional execution facts with each review — run id, nesting depth, whether the cwd is a linked git worktree, and the checked-out branch — plus a prompt section telling it to judge risk by effect scope and reversibility relative to the subagent's own workspace instead of by command name. Mutations confined to the subagent's isolated worktree, its own feature branch, or resources it created are approvable when they serve the delegated task; ask_user is reserved for effects that escape that scope (shared or default branches, host-level configuration, production systems, credentials, data leaving the machine).
Subagent sessions have no interactive user, so an ask_user verdict blocks the command immediately with a reason instructing the child to route around the gated operation or report the blocker. Reviewer usage records from subagent sessions carry "subagent": true in the usage sidecar.
Guardian dispatch
Reviewer requests dispatch through the host's model runtime rather than pi-ai's compat layer, so provider transports registered by other extensions (for example @gotgenes/pi-anthropic-auth OAuth request shaping) apply to guardian calls. When the runtime seam is unavailable, dispatch falls back to compat.completeSimple.
Failure behavior
A missing reviewer model, unavailable credentials, malformed response, timeout, cancellation, or oversized review context never auto-approves a command.
- Interactive sessions fall back to user confirmation.
- Non-interactive sessions block the command.
- Invalid configuration blocks Bash calls until corrected.
Security boundary
Rules match raw shell text. Quoting, variables, aliases, generated scripts, or other indirection can evade a regex, while quoted command text can cause false positives.
Pi Auto Permissions is a permission layer for normal agent behavior. It is not an operating-system sandbox or a defense against hostile shell input. Pair it with sandboxing when commands need a hard security boundary.
reviewEvidence.userAnswerTools widens what counts as user authorization: any code that can record a tool result under an allowlisted tool name can mint USER (dialog answer) evidence. Allowlist only tool names served by extensions you trust.
License
MIT