pi-auto-approve 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/index.ts +992 -0
- package/package.json +16 -0
- package/policy/LICENSE +201 -0
- package/policy/NOTICE +7 -0
- package/policy/policy.md +65 -0
- package/policy/policy_template.md +78 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Erik Staab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# pi-auto-approve
|
|
2
|
+
|
|
3
|
+
LLM auto-approval of risky tool calls for the [pi coding agent](https://pi.dev), ported from
|
|
4
|
+
OpenAI Codex's "guardian" auto-review system
|
|
5
|
+
([`codex-rs/core/src/guardian/`](https://github.com/openai/codex/tree/main/codex-rs/core/src/guardian),
|
|
6
|
+
[`codex-rs/guardian-context/`](https://github.com/openai/codex/tree/main/codex-rs/guardian-context),
|
|
7
|
+
[`codex-rs/ext/guardian-reviewer/`](https://github.com/openai/codex/tree/main/codex-rs/ext/guardian-reviewer),
|
|
8
|
+
Apache-2.0). Instead of prompting you for every risky tool call - or running with no
|
|
9
|
+
gate at all (pi ships without a permission system) - a reviewer model judges each
|
|
10
|
+
risky action against a written policy and allows or denies it automatically.
|
|
11
|
+
|
|
12
|
+
`pi-auto-approve` is pre-1.0: the command, config file names, and policy paths may
|
|
13
|
+
still change between minor versions.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pi install npm:pi-auto-approve
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install straight from git (clones under `~/.pi/agent/git/` and registers the
|
|
22
|
+
extension in your settings):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pi install git:github.com/erikus/pi-auto-approve
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Requires pi >= 0.84 (the reviewer runs through `ctx.modelRegistry.complete`, added in
|
|
29
|
+
0.84; on older pi the extension fails closed and blocks every gated action).
|
|
30
|
+
|
|
31
|
+
To try it once without installing: `pi -e git:github.com/erikus/pi-auto-approve`.
|
|
32
|
+
For local development, clone the repo and run `pi -e ./index.ts` from the checkout
|
|
33
|
+
(or symlink the checkout into `~/.pi/agent/extensions/`).
|
|
34
|
+
|
|
35
|
+
- `/auto-approve` - show state and stats (reviews / allowed / denied / overridden / failures)
|
|
36
|
+
- `/auto-approve off`, `/auto-approve on` - disable / re-enable (`on` also resets the circuit breaker)
|
|
37
|
+
|
|
38
|
+
Set `PI_AUTO_APPROVE_LOG=/path/to/file` to append one JSON line per review.
|
|
39
|
+
|
|
40
|
+
## How a tool call is decided
|
|
41
|
+
|
|
42
|
+
1. **Static gates** (no model call):
|
|
43
|
+
- read-only tools (`read`, `grep`, `find`, `ls`) run freely;
|
|
44
|
+
- `write`/`edit` inside the working directory run freely (stands in for Codex's
|
|
45
|
+
workspace-write sandbox - pi has no sandbox);
|
|
46
|
+
- `bash` commands made only of allowlisted read-only segments (`ls`, `cat`, `git status`,
|
|
47
|
+
`grep`, …, no redirection/substitution) run freely.
|
|
48
|
+
2. **Auto-approve review** for everything else: the extension builds a compact transcript
|
|
49
|
+
(every user message, plus recent assistant/tool evidence that is capped,
|
|
50
|
+
truncation-tagged, and treated according to the policy's trust rules), renders the
|
|
51
|
+
complete planned action, fits the request into the reviewer model's context window
|
|
52
|
+
(optional evidence is evicted first, user messages are shortened only as a last
|
|
53
|
+
resort, and an omission notice tells the reviewer not to infer authorization from
|
|
54
|
+
missing evidence), and asks for a strict-JSON verdict
|
|
55
|
+
`{risk_level, user_authorization, outcome, rationale}` per the policy prompt.
|
|
56
|
+
3. **Deny** blocks the tool call with instructions to the agent not to work around the
|
|
57
|
+
denial (mirroring Codex). In the TUI you get an "Allow anyway?" override prompt - a manual approval is final, like Codex's post-denial user approval.
|
|
58
|
+
4. **Fail closed**: timeout (one 90s deadline shared by all attempts), unparseable
|
|
59
|
+
verdict, oversized action, malformed reviewer config, or no authenticated model never
|
|
60
|
+
silently allows - with a UI you're prompted; headless, the action is blocked. Parse
|
|
61
|
+
errors and transient service/network failures retry up to three total attempts with
|
|
62
|
+
backoff; permanent failures do not retry. The planned action is never shortened for
|
|
63
|
+
model review and then run in full: if it cannot fit the reviewer's window beside the
|
|
64
|
+
policy and the minimum evidence, the review fails.
|
|
65
|
+
5. **Circuit breaker**: 3 consecutive denials in a turn or 10 denials in the last 50
|
|
66
|
+
reviews pauses auto-review; gated actions fall back to manual prompts
|
|
67
|
+
(the same shape as Claude Code's auto-mode breaker).
|
|
68
|
+
|
|
69
|
+
## Model
|
|
70
|
+
|
|
71
|
+
By default the reviewer is the session's current model (`ctx.model`), always run at
|
|
72
|
+
low effort regardless of the session's effort setting. To review with a different
|
|
73
|
+
model, create the first of:
|
|
74
|
+
|
|
75
|
+
1. `<project>/.pi/auto-approve.json`
|
|
76
|
+
2. `~/.pi/agent/auto-approve.json`
|
|
77
|
+
|
|
78
|
+
containing exactly:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{ "model": "<provider>/<model-id>" }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
for example `{ "model": "anthropic/claude-opus-5" }`. The provider is everything before
|
|
85
|
+
the first `/`, so OpenRouter-style ids like `openrouter/anthropic/claude-opus-5` work. The model must exist in pi's
|
|
86
|
+
model registry and have configured auth. A malformed file, an unknown model, or a
|
|
87
|
+
model without auth is a configuration error: gated actions fail closed with a message
|
|
88
|
+
naming the file, rather than silently falling back to the session model. A missing
|
|
89
|
+
file simply means no override.
|
|
90
|
+
|
|
91
|
+
## Policy
|
|
92
|
+
|
|
93
|
+
The judging prompt is `policy/policy_template.md` with `{{ tenant_policy_config }}`
|
|
94
|
+
replaced by the first of:
|
|
95
|
+
|
|
96
|
+
1. `<project>/.pi/auto-approve-policy.md`
|
|
97
|
+
2. `~/.pi/agent/auto-approve-policy.md`
|
|
98
|
+
3. bundled `policy/policy.md` (Codex's default tenant policy)
|
|
99
|
+
|
|
100
|
+
The template's `{{ extra_policy }}` slot (Codex's `[auto_review] extra_policy`) is filled
|
|
101
|
+
from the first of `<project>/.pi/auto-approve-extra-policy.md` or
|
|
102
|
+
`~/.pi/agent/auto-approve-extra-policy.md`, and left empty when neither exists. Use it to
|
|
103
|
+
add rules on top of the default policy without replacing it.
|
|
104
|
+
|
|
105
|
+
Both prompt files are copied verbatim from openai/codex (Apache-2.0); see the license
|
|
106
|
+
note below. The extension appends a pi-specific environment override because pi has no
|
|
107
|
+
operating-system sandbox and the reviewer has no investigation tools. Notable defaults:
|
|
108
|
+
sensitive egress must be authorized for the specific payload and destination; critical
|
|
109
|
+
actions are denied; and high-risk actions need at least `medium` user authorization.
|
|
110
|
+
|
|
111
|
+
## Differences from Codex's guardian (prototype limitations)
|
|
112
|
+
|
|
113
|
+
- **No investigation tools.** Codex's guardian can run read-only commands (e.g. inspect
|
|
114
|
+
an `rm -rf` target) before deciding; this extension judges from the transcript alone
|
|
115
|
+
and the output contract tells it to lean conservative when facts are unverifiable.
|
|
116
|
+
- **Single-completion review**, no prewarmed review session.
|
|
117
|
+
- **Char-based caps** (~4 chars/token) instead of Codex's tokenizer-based transcript and
|
|
118
|
+
request budgets; like Codex, message and tool evidence have separate budgets, all user
|
|
119
|
+
messages are retained before recent non-user evidence, and the whole request is fitted
|
|
120
|
+
to the reviewer model's context window. Codex additionally scales that window by a
|
|
121
|
+
per-model percentage that pi does not expose.
|
|
122
|
+
- **Reviewer model.** Codex reviews with a dedicated `codex-auto-review` model and falls
|
|
123
|
+
back to the session model when it is missing from the account's catalog; this
|
|
124
|
+
extension reviews with the session model unless an override is configured (see
|
|
125
|
+
Model above), and an unusable override fails closed instead of falling back.
|
|
126
|
+
- The static safe-command check is a much smaller allowlist than Codex's
|
|
127
|
+
`is_safe_command` parser - anything it can't prove safe just goes to review, so
|
|
128
|
+
being conservative here only costs latency, not safety.
|
|
129
|
+
- Verdicts are not persisted or cached (Claude Code caches e.g. network-host
|
|
130
|
+
verdicts; a nice future addition).
|
|
131
|
+
|
|
132
|
+
## Testing
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
./node_modules/.bin/tsc -p tsconfig.json # typecheck (node_modules symlinks to ../pi)
|
|
136
|
+
node --experimental-strip-types smoke-test.ts # static-gate, parser, and budget tests
|
|
137
|
+
node --experimental-strip-types harness-test.ts # tool_call handler against a mocked registry
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## License / attribution
|
|
141
|
+
|
|
142
|
+
The extension code is MIT licensed (see `LICENSE`).
|
|
143
|
+
|
|
144
|
+
`policy/policy_template.md` and `policy/policy.md` are copied from
|
|
145
|
+
[openai/codex](https://github.com/openai/codex) (`codex-rs/prompts/templates/guardian/`),
|
|
146
|
+
licensed under Apache-2.0 (see `policy/LICENSE`; `policy/NOTICE` reproduces the
|
|
147
|
+
upstream attribution notice as Apache-2.0 requires). The extension code is a re-implementation of that design
|
|
148
|
+
for pi's extension API; constants (timeout, retry count, breaker thresholds, transcript
|
|
149
|
+
caps) mirror `codex-rs/ext/guardian-reviewer/` and `codex-rs/guardian-context/`.
|