@erichll/pi-auto-review 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 - 2026-08-20
4
+
5
+ - **Safer evidence selection.** Review only request-linked tool calls, paired
6
+ results, current-task user intent, and bounded security evidence. Compaction
7
+ summaries cannot restore authorization, raw revocations override model
8
+ allows, and missing mandatory evidence fails closed before a model call.
9
+ - **Independent, smaller reviewer requests.** Use one compact canonical request
10
+ envelope and a byte-stable policy prefix, reducing fixed input from 2,011 to
11
+ 1,396 characters. Independent SSE calls prevent prior review state from
12
+ carrying into later approvals while preserving cache/routing identity.
13
+ - **Explicit token limits.** Add tighten-only `maxReviewerInputTokens` with an
14
+ 8,192 default and conservative UTF-8 accounting across the complete prompt.
15
+ Lower the default `maxTokens` from 1,600 to 256 after sequential real-model
16
+ validation at 384 and 256; the legal range remains 256–4,096.
17
+ - **Typed, bounded retries.** Share one deadline across each review, disable
18
+ provider-internal retries, and allow at most two actual model calls. Only
19
+ format errors, recognized connection/5xx failures, and bounded 429 responses
20
+ retry; deterministic and unknown failures remain terminal and fail closed.
21
+ - **Privacy-bounded telemetry.** Record per-attempt usage and per-review
22
+ summaries for both reviewer entry points using stable status/error codes and
23
+ prompt-part counts, without logging evidence text, provider errors,
24
+ credentials, headers, or URL query values.
25
+
3
26
  ## 0.4.0 - 2026-08-19
4
27
 
5
28
  - **Credential-exfiltration hardening.** Expand deterministic terminal denies to cover
package/README.md CHANGED
@@ -1,139 +1,138 @@
1
1
  # @erichll/pi-auto-review
2
2
 
3
- A model-backed boundary approval broker for the Pi coding agent.
3
+ A fail-closed, model-backed boundary reviewer for the Pi coding agent.
4
4
 
5
- `pi-auto-review` currently integrates with
6
- `@gotgenes/pi-permission-system` as an authorizer-chain link. It also publishes
7
- a small cross-extension broker service so an OS sandbox adapter can submit
8
- filesystem and network boundary requests without creating a second approval
9
- system.
5
+ The extension participates in `@gotgenes/pi-permission-system` as the
6
+ `pi-auto-review` authorizer and exposes a process-local broker for OS sandbox
7
+ adapters. The npm package and reviewer model have separate names:
10
8
 
11
- The package name and model name are intentionally separate:
9
+ - package: `@erichll/pi-auto-review`
10
+ - authorizer: `pi-auto-review`
11
+ - default reviewer model: `codex-auto-review`
12
12
 
13
- - npm package: `@erichll/pi-auto-review`
14
- - Authorizer: `pi-auto-review`
15
- - Default reviewer model: `codex-auto-review`
13
+ ## Install and enable
14
+
15
+ Install the package outside the agent-writable workspace:
16
+
17
+ ```bash
18
+ pi install npm:@erichll/pi-auto-review
19
+ ```
20
+
21
+ Add it to the permission-system authorizer chain:
22
+
23
+ ```json
24
+ {
25
+ "authorizerChain": ["pi-auto-review"]
26
+ }
27
+ ```
28
+
29
+ The configured reviewer provider and model must also be registered in Pi.
16
30
 
17
31
  ## Security model
18
32
 
19
- The broker applies the following order:
20
-
21
- 1. Deterministic hard denies
22
- 2. Model review
23
- 3. Local terminal when the authorizer chain requires one
24
- 4. Exact, expiring, one-use grants for external sandbox adapters
25
-
26
- Model approval cannot override `pi-permission-system`'s bounded-delegation
27
- checkpoint. In version 24, an authorizer's `allow` on `path` or
28
- `external_directory` is still downgraded to `defer`. In an interactive v24 TUI,
29
- `autoConfirmBoundedAllows` can bind that exact model allow to the immediately
30
- following local permission dialog and complete it as `auto_approved`. The
31
- default enables this bridge only for `external_directory`; `path`, non-TUI
32
- modes, UI mismatches, and reviewer defers still reach the human terminal.
33
- Sandbox adapters should use concrete surfaces such as `filesystem-read`,
34
- `filesystem-write`, and `network`.
35
-
36
- The TUI bridge is request-ID-bound, expires after ten seconds, is consumed
37
- once, and recognizes the v24 inline permission component before completing it.
38
- Any event ordering, request, mode, component, or shared-UI wrapper mismatch
39
- fails closed to the original dialog. This is a compatibility bridge around the
40
- v24 delegation envelope, not permission-system authority-chain API.
41
-
42
- The broker stops automatic review for a turn after three consecutive denials
43
- or ten denials in the rolling last fifty reviews. An explicit denial is
44
- returned to the agent with an instruction not to pursue the same outcome
45
- through a workaround.
46
-
47
- ## User-facing feedback
48
-
49
- In interactive UI sessions, the extension shows short operator feedback that is
50
- separate from agent denial reasons:
51
-
52
- 1. Footer status while review is in flight:
53
- `auto-review: reviewing <surface> · <target>`
54
- 2. A toast when the decision lands:
55
- - allowed
56
- - allowed + auto-confirming the local dialog
57
- - allowed but local confirmation still required
58
- - deferred to you
59
- - denied
60
- - circuit-breaker stopped after repeated denials
61
-
62
- These notices are best-effort UX only; missing or broken UI delivery never
63
- changes the security decision.
64
-
65
- ## Exact human retry override
66
-
67
- In interactive TUI mode, `/approve` shows up to ten recent model denials from
68
- the current session. Selecting one authorizes exactly one unchanged retry and
69
- automatically asks the agent to perform it. The authorization:
70
-
71
- - is bound to the complete request hash, including cwd, command, requested and
72
- resolved paths, destination, tool input, and agent;
73
- - expires after 60 seconds and is consumed once;
74
- - is passed to the reviewer as a separate host-generated
75
- `trusted-user-override` evidence block;
76
- - does not directly allow anything—the reviewer can still deny or defer; and
77
- - is checked only after deterministic hard denies, so critical tenant and
78
- security-control policy cannot be overridden.
33
+ Requests pass through these controls in order:
34
+
35
+ 1. deterministic hard denies;
36
+ 2. bounded model review;
37
+ 3. the local permission terminal when required; and
38
+ 4. an exact, expiring, one-use grant for an external sandbox adapter.
79
39
 
80
- Changing any request field misses the override. An override that was consumed
81
- cannot be issued again for the same request semantics in that session.
40
+ The model cannot override hard denies or grant authority directly. External
41
+ adapters must consume the exact grant before retrying an operation. Changing
42
+ the command, path, resolved path, destination, cwd, agent, or tool input
43
+ invalidates that grant.
82
44
 
83
- ## Configure
45
+ Permission-system v24 downgrades authorizer allows on `path` and
46
+ `external_directory` to `defer`. In an interactive TUI,
47
+ `autoConfirmBoundedAllows` can bind the exact model allow to the immediately
48
+ following recognized permission dialog. The bridge is request-ID-bound,
49
+ expires after ten seconds, and is consumed once. Mode, component, request, or
50
+ event-order mismatches leave the original human dialog in place.
84
51
 
85
- Trusted configuration is resolved in this order:
52
+ Automatic review stops for the current turn after three consecutive denials or
53
+ ten denials in the last fifty reviews. An explicit denial tells the agent not
54
+ to pursue the same outcome through a workaround.
86
55
 
87
- 1. Package defaults from the installed `src/config.json`
88
- 2. Optional user-global overlay at
89
- `~/.pi/agent/extensions/pi-auto-review/config.json`
90
- 3. Optional project tighten-only file at `.pi/pi-auto-review.json`
56
+ ## Configuration
91
57
 
92
- Prefer the user-global file for day-to-day overrides (same location style as
93
- `pi-permission-system`). It may set any legal key, including `model` and
94
- `autoConfirmBoundedAllows`. A partial file overlays the package defaults.
58
+ Configuration is resolved in this order:
59
+
60
+ 1. package defaults in `src/config.json`;
61
+ 2. optional trusted user overlay at
62
+ `~/.pi/agent/extensions/pi-auto-review/config.json`; and
63
+ 3. optional project tighten-only settings at `.pi/pi-auto-review.json`.
64
+
65
+ Use the user-global file for normal customization. It may set any legal key:
95
66
 
96
67
  ```json
97
- // ~/.pi/agent/extensions/pi-auto-review/config.json
98
68
  {
69
+ "model": "provider/reviewer-model",
99
70
  "autoConfirmBoundedAllows": ["external_directory", "path"]
100
71
  }
101
72
  ```
102
73
 
103
- Package-shipped defaults live in `src/config.json`:
74
+ Package defaults:
104
75
 
105
76
  ```json
106
77
  {
107
78
  "model": "codex-auto-review",
108
79
  "reasoning": "low",
109
80
  "timeoutMs": 90000,
110
- "maxTokens": 1600,
81
+ "maxTokens": 256,
111
82
  "retries": 2,
112
83
  "maxUserTranscriptTokens": 1200,
113
84
  "maxToolTranscriptTokens": 1200,
114
85
  "maxRelevantResultTokens": 800,
86
+ "maxReviewerInputTokens": 8192,
115
87
  "failureMode": "deny",
116
88
  "grantTtlMs": 60000,
117
89
  "autoConfirmBoundedAllows": ["external_directory", "path"]
118
90
  }
119
91
  ```
120
92
 
121
- The configured provider must be registered in Pi and must support the
122
- configured model. `failureMode: "deny"` is the fail-closed default;
123
- `failureMode: "defer"` falls through to the normal human terminal.
124
- Set `autoConfirmBoundedAllows` to `[]` to keep every bounded allow manual, or
125
- include `"path"` as well to opt into the same TUI bridge for the cross-cutting
126
- path surface.
93
+ `failureMode: "deny"` is the default. `"defer"` falls through to the human
94
+ terminal. Set `autoConfirmBoundedAllows` to `[]` to keep every bounded allow
95
+ manual.
127
96
 
128
- Add the link to the permission-system configuration:
97
+ Project configuration may only lower timeouts, token/evidence limits, retries,
98
+ and grant TTL, set `failureMode` to `"deny"`, or remove auto-confirmed
99
+ surfaces. It cannot select a model, raise a trusted limit, or weaken fail-closed
100
+ behavior. Invalid configuration disables the reviewer for that session.
129
101
 
130
- ```json
131
- {
132
- "authorizerChain": ["pi-auto-review"]
133
- }
134
- ```
102
+ ### Deadlines and retries
103
+
104
+ `timeoutMs` is one deadline shared by model resolution, authentication, model
105
+ attempts, and retry delays. Each attempt receives only the remaining time.
106
+ Provider-internal retries are disabled, and a review makes at most two actual
107
+ model calls even when the public `retries` value is higher.
135
108
 
136
- ## Boundary broker service
109
+ Valid decisions, output-length stops, timeouts, aborts, authentication/model/
110
+ request errors, and unknown failures do not retry. Empty, non-JSON, or
111
+ schema-invalid output and recognized connection, temporary 5xx, or 429
112
+ failures may retry once when the retry budget and deadline allow it. A
113
+ `Retry-After` above five seconds or beyond the remaining deadline fails closed.
114
+ Format retries preserve the canonical request and selected evidence and append
115
+ only a fixed, budget-checked schema correction.
116
+
117
+ ## Operator feedback and exact retry
118
+
119
+ Interactive sessions show a best-effort footer while review is running and a
120
+ short result toast for allow, local confirmation, defer, deny, or circuit
121
+ breaker outcomes. UI delivery never changes the authorization result.
122
+
123
+ In an interactive TUI, `/approve` lists up to ten recent model denials from the
124
+ current session. Selecting one asks the agent to retry exactly that request.
125
+ The host-generated override:
126
+
127
+ - binds the complete request hash;
128
+ - expires after 60 seconds and is consumed once;
129
+ - remains separate from untrusted user/tool evidence;
130
+ - still goes through deterministic hard denies and model review; and
131
+ - cannot be reissued for the same request semantics in that session.
132
+
133
+ It is authorization evidence, not a direct allow.
134
+
135
+ ## Boundary broker API
137
136
 
138
137
  The extension publishes a process-local service at:
139
138
 
@@ -141,7 +140,7 @@ The extension publishes a process-local service at:
141
140
  Symbol.for("pi-auto-review:boundary-approval-broker")
142
141
  ```
143
142
 
144
- Adapters should normally use the exported helper:
143
+ Adapters should use the exported helper:
145
144
 
146
145
  ```ts
147
146
  import {
@@ -156,118 +155,124 @@ const request: BoundaryRequest = {
156
155
  operation: "connect",
157
156
  cwd: "/workspace/project",
158
157
  command: "npm install",
159
- destination: "registry.npmjs.org:443"
158
+ destination: "registry.npmjs.org:443",
160
159
  };
161
160
 
162
- const service = getBoundaryBroker();
163
- const decision = await service?.review(request, {
161
+ const broker = getBoundaryBroker();
162
+ const decision = await broker?.review(request, {
164
163
  sessionId: "pi-session-id",
165
164
  scopeKey: "pi-session-id:turn-id",
166
- issueGrant: true
165
+ issueGrant: true,
167
166
  });
168
- ```
169
-
170
- When `decision.kind` is `allow`, an external sandbox adapter must consume the
171
- returned grant before retrying:
172
167
 
173
- ```ts
174
168
  if (
175
169
  decision?.kind === "allow" &&
176
170
  decision.grant &&
177
- service?.consumeGrant(request, "pi-session-id", decision.grant.token)
171
+ broker?.consumeGrant(request, "pi-session-id", decision.grant.token)
178
172
  ) {
179
173
  // Retry this exact operation once inside the OS sandbox.
180
174
  }
181
175
  ```
182
176
 
183
- Changing the command, path, destination, working directory, agent, or tool
184
- call/input invalidates the grant. Grants expire after `grantTtlMs` and cannot
185
- be reused.
186
-
187
- ## Relevant reviewer evidence
188
-
189
- The reviewer always receives bounded user intent and assistant tool calls. It
190
- may additionally receive only these bounded result classes:
191
-
192
- - The exact result correlated by `toolCallId`.
193
- - A read-only `stat`, `ls`, `find`, `test`, `readlink`, or `realpath` result for
194
- a pending deletion target.
195
- - `git remote`, branch, status, revision, and remote configuration results for
196
- a pending Git push.
197
- - The current structured Sandbox Runtime trap.
198
-
199
- Unrelated tool results and assistant prose remain excluded. Selected results
200
- have a separate `maxRelevantResultTokens` budget, common secret/token forms are
201
- redacted, and markup characters are escaped before the evidence is sent to the
202
- reviewer. Results remain explicitly labeled as untrusted and possibly
203
- incomplete.
204
-
205
- ## Sandbox adapter status
206
-
207
- The broker-facing contract is implemented, but this package does not intercept
208
- OS sandbox events by itself. Adapters translate a concrete boundary into a
209
- `BoundaryRequest` and must consume the exact grant before allowing the
210
- operation.
211
-
212
- This monorepo's `pi-sandbox` uses Anthropic Sandbox Runtime. Filesystem policy
213
- is static and fails closed; unmatched public network destinations use the
214
- broker for per-connection approval. Each Bash command or built-in subagent
215
- session owns an independent Sandbox Runtime broker process. Adapters should use
216
- the `./sandbox` export.
217
-
218
- Do not implement the adapter by writing broad permanent rules to
219
- `.pi/sandbox.json`.
177
+ Grants expire after `grantTtlMs` and cannot be reused.
178
+
179
+ ## Reviewer context and token budgets
180
+
181
+ The reviewer receives one compact canonical request plus bounded, explicitly
182
+ untrusted evidence. Selection is deterministic rather than semantic:
183
+
184
+ - the latest raw user message is the authorization anchor;
185
+ - older user messages require an exact request/tool/requester association, an
186
+ exact trusted retry, or a bounded narrowing/revocation rule;
187
+ - tool calls require an exact tool-call ID, exact structured request fields, a
188
+ surface profile, or a security-combination classification; and
189
+ - selected results stay paired with their producer and are limited to exact
190
+ results, deletion prechecks, Git push context, matching branch protection,
191
+ and Sandbox Runtime process evidence.
192
+
193
+ Unrelated reads, directory listings, builds, tests, assistant prose, and old
194
+ task history are excluded. Vague continuation text cannot restore older
195
+ authorization. Raw revocations override model allows. Compaction and branch
196
+ summaries are risk context only; they never count as user authorization.
197
+
198
+ The current operation appears once as stable, key-sorted JSON. Duplicate exact
199
+ tool-call arguments collapse to an ID/name/reason linkage shell, while fields
200
+ not represented by the request remain available as evidence. This compact
201
+ reviewer representation does not affect request hashes, grants, overrides, or
202
+ audit evidence.
203
+
204
+ `maxReviewerInputTokens` covers the fixed policy, canonical request, override,
205
+ evidence, omissions, JSON framing, and a 64-token provider-framing reserve. Its
206
+ legal range is 2,048–32,768. Because no matching tokenizer is bundled, the
207
+ `conservative:utf8` estimator counts every UTF-8 byte as one token.
208
+
209
+ When over budget, the host removes secondary reasons, older structured tool
210
+ matches, then optional producer/result units, re-estimating after each step. It
211
+ never silently removes the canonical request, exact override, latest user
212
+ evidence, security-combination evidence, exact tool linkage, or a required
213
+ surface profile. If mandatory evidence does not fit, review fails closed before
214
+ calling the model. More than four security-combination candidates also fails
215
+ closed locally.
216
+
217
+ ## Sandbox integration
218
+
219
+ This package exposes the broker contract but does not intercept OS sandbox
220
+ events itself. Adapters translate a concrete boundary into a `BoundaryRequest`
221
+ and consume the exact grant before allowing it.
222
+
223
+ This monorepo's `pi-sandbox` adapter uses Anthropic Sandbox Runtime. Filesystem
224
+ policy is static and fail-closed; unmatched public network destinations use the
225
+ broker for one connection. Each Bash command or built-in subagent session owns
226
+ an independent Sandbox Runtime broker process. Adapter implementations should
227
+ use the package's `./sandbox` export and must not create broad permanent rules
228
+ in `.pi/sandbox.json`.
220
229
 
221
230
  ## Trust boundary
222
231
 
223
- The extension refuses to activate when its package directory is inside the
224
- agent-writable workspace. Install production copies as a user-level npm
225
- package, or as a Git package pinned to a reviewed tag or commit:
226
-
227
- ```bash
228
- pi install npm:@erichll/pi-auto-review
229
- ```
230
-
231
- Pi places user npm packages under `~/.pi/agent/npm/` and Git packages under
232
- `~/.pi/agent/git/`, outside the project workspace. For local development only:
232
+ Production copies must live outside the agent-writable workspace. Pi installs
233
+ user npm and Git packages under `~/.pi/agent/npm/` and `~/.pi/agent/git/`.
234
+ Workspace-loaded copies are rejected unless local development explicitly opts
235
+ in:
233
236
 
234
237
  ```bash
235
238
  PI_AUTO_REVIEW_ALLOW_UNTRUSTED_DEV=1 pi --approve
236
239
  ```
237
240
 
238
- The trusted configuration (package defaults plus optional user-global overlay)
239
- is copied and frozen at `session_start`. An optional workspace file at
240
- `.pi/pi-auto-review.json` may only lower timeouts, token/evidence limits,
241
- retries, and grant TTL, or set `failureMode` to `deny`. It may remove entries
242
- from `autoConfirmBoundedAllows`, but cannot add a surface not enabled by the
243
- trusted configuration. It cannot select a model, weaken fail-closed behavior,
244
- or raise a trusted limit. Invalid user-global or project configuration disables
245
- the reviewer for that session.
241
+ Writes to the installed reviewer package, its user-global configuration,
242
+ project and global security configuration, and the global audit directory are
243
+ deterministically denied.
246
244
 
247
- Writes to the installed reviewer package, the user-global reviewer config
248
- directory (`~/.pi/agent/extensions/pi-auto-review/`), project security
249
- configuration, global Pi security configuration, and the global audit directory
250
- are deterministically denied.
245
+ ## Telemetry and smoke testing
251
246
 
252
- ## Real-model smoke test
247
+ Every actual model call emits an internal `review_attempt`; each approval emits
248
+ one `review_complete`. Events contain stable status/error classes, timings,
249
+ usage counters, evidence metadata, and prompt-part counts. They do not contain
250
+ prompt or response text, provider errors, credentials, headers, or URL query
251
+ values. Usage is marked `unknown_provenance` when pi-ai cannot distinguish
252
+ provider counters from initialized values, and `unavailable` when absent.
253
253
 
254
- For a controlled smoke test, disable unrelated extensions and explicitly load
255
- only the model provider, broker, sandbox, and audit listener:
254
+ For a controlled real-model smoke test, load only the provider, reviewer,
255
+ sandbox, and audit listener:
256
256
 
257
257
  ```bash
258
258
  PI_AUTO_REVIEW_ALLOW_UNTRUSTED_DEV=1 \
259
259
  PI_AUTO_REVIEW_SMOKE_AUDIT_PATH=/tmp/pi-auto-review-smoke-audit.jsonl \
260
+ PI_AUTO_REVIEW_BASELINE_ID=reviewer-check \
261
+ PI_AUTO_REVIEW_BASELINE_CACHE_STATE=cold \
262
+ PI_AUTO_REVIEW_BASELINE_RUN_ORDER=1 \
263
+ PI_AUTO_REVIEW_BASELINE_SAMPLE_SET=reviewer-v1 \
264
+ PI_AUTO_REVIEW_SMOKE_TRIGGER=baseline-v1 \
260
265
  pi --no-extensions --no-skills --no-prompt-templates --no-context-files \
261
266
  --no-builtin-tools --no-session --print \
262
- --extension /trusted/path/to/your-model-provider/extensions/index.ts \
267
+ --extension /trusted/path/to/provider/extensions/index.ts \
263
268
  --extension ./packages/pi-auto-review/src/index.ts \
264
269
  --extension ./packages/pi-sandbox/src/index.ts \
265
270
  --extension ./scripts/real-model-smoke-audit.ts \
266
- --model provider/your-available-model \
267
- "Use bash once to write a fixed marker outside the workspace."
271
+ --model provider/reviewer-model \
272
+ "Run the configured synthetic reviewer baseline sample, then reply done."
268
273
  ```
269
274
 
270
- A successful boundary review emits `review_decision`, `grant_issued`, and
271
- `grant_consumed` for the same request ID. `--no-builtin-tools` is important:
272
- it ensures the `bash` implementation comes from `pi-sandbox` rather than
273
- silently falling back to Pi's built-in Bash.
275
+ The listener submits filesystem-write, network, delete, Git-push, and forwarded
276
+ subagent boundaries. No represented operation is executed; the main-agent
277
+ request is aborted after the samples finish. `--no-builtin-tools` ensures Bash
278
+ comes from `pi-sandbox` rather than Pi's built-in implementation.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erichll/pi-auto-review",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Model-backed boundary approval broker for Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -110,11 +110,11 @@ export class BoundaryApprovalBroker {
110
110
  let review: BoundaryReview;
111
111
  try {
112
112
  review = await this.#reviewer(request, { userOverride });
113
- } catch (error) {
114
- const reason = `Automatic review is unavailable: ${
115
- error instanceof Error ? error.message : String(error)
116
- }`;
117
- this.audit("review_failure", request, { reason });
113
+ } catch {
114
+ const reason = "Automatic review is unavailable.";
115
+ this.audit("review_failure", request, {
116
+ errorClass: "reviewer_unavailable",
117
+ });
118
118
  if (this.#failureMode === "defer") {
119
119
  this.#breaker.record(context.scopeKey, false);
120
120
  return {
package/src/config.json CHANGED
@@ -2,11 +2,12 @@
2
2
  "model": "codex-auto-review",
3
3
  "reasoning": "low",
4
4
  "timeoutMs": 90000,
5
- "maxTokens": 1600,
5
+ "maxTokens": 256,
6
6
  "retries": 2,
7
7
  "maxUserTranscriptTokens": 1200,
8
8
  "maxToolTranscriptTokens": 1200,
9
9
  "maxRelevantResultTokens": 800,
10
+ "maxReviewerInputTokens": 8192,
10
11
  "failureMode": "deny",
11
12
  "grantTtlMs": 60000,
12
13
  "autoConfirmBoundedAllows": ["external_directory", "path"]