# Codex 0.144.5 comparison and Pi adaptation

## Baseline and scope

This extension adapts the materially relevant behavior of OpenAI Codex CLI `0.144.5` Guardian/“Approve for me,” pinned to source commit `87db9bc18ba5bc82c1cb4e4381b44f693ee35623`. Pi has no native approval boundary or sandbox escalation object, so this extension is a gate on Pi's model-issued `tool_call` event.

Attribution is in [`../NOTICE`](../NOTICE). The policy in `src/prompt.ts` is a new compact adaptation of the reported risk vocabulary, authorization rules, and output contract.

## Behavior matrix

| Concern | Codex 0.144.5 | This Pi extension |
|---|---|---|
| Mode control | Client approval policy | Global `approveForMe.mode` setting |
| Reviewed boundary | Existing sandbox escalation/approval requests | Model-issued Pi tools not bypassed by the rules below |
| Allow effect | Allows one escalation/retry | This handler returns `undefined`; later Pi handlers still run |
| Sandbox | Workspace/read-only profiles remain enforcement | None added; Pi process permissions remain authoritative |
| Reviewer model | Guardian model selected by Codex catalog/provider logic | Fully-qualified `approveForMe.reviewer.model` resolved from current `ctx.modelRegistry` |
| Reviewer tools | Release session had read-only tool possibilities | No tools; decide only from supplied evidence |
| Deadline/retries | Nominal 90 seconds; selected retries | One 90-second deadline; up to three parse/provider attempts with 200/400 ms backoff |
| Approval condition | Parsed outcome `allow` | Parsed outcome `allow` only |
| Circuit breaker | Per parent turn | Per Pi run: 3 consecutive or 10 of latest 50 explicit denials |
| Review history | Guardian protocol and retained sessions | Sanitized Pi entries; no arguments, credentials, raw output, or rationale |

## Global configuration and gate

The global namespace contains `mode`, `reviewer`, and `alwaysAllowTools`. A missing `alwaysAllowTools` is `[]`; malformed configuration selects safe review behavior and leaves reviewed calls failed closed.

`full-access` bypasses this handler for every tool, including Bash. In `approve-for-me` mode, a call bypasses review only when either:

1. it is source-verified as Pi's genuine built-in `read`, `grep`, `find`, or `ls`; or
2. its exact case-sensitive name appears in `alwaysAllowTools` and the name is not `bash`.

The configurable list has no globs, patterns, source or package identity, argument policy, or provenance data. Entries are unique non-empty strings. Config validation rejects exact name `bash`, and the runtime gate retains the same hard guard for injected configurations.

The source-sensitive built-in check requires Pi's built-in source, `<builtin:name>` path, `temporary` scope, and `top-level` origin. A custom replacement named `read` is not a genuine built-in. Conversely, configured names bypass regardless of source metadata. Pi exposes one effective tool implementation per name, so a replacement that wins a name collision also inherits that configured exemption. This is an intentional consequence of matching Pi's routing interface.

Returning `undefined` is not a global approval token. Later extension handlers may block the call; an earlier block prevents later handlers from running. Pi has no run-last `tool_call` priority, so this extension reviews the arguments visible at its load-order position and a later handler may mutate them before execution.

## Planned action

The reviewer receives a sorted JSON object with the exact tool name, cwd, current source metadata, and arguments observed at this handler's load-order position. Bash calls also include a generic subprocess execution-scope note. Arbitrary custom tool names and arguments receive no semantic enrichment. The planned action must serialize without string truncation within an aggregate approximately 16,000-token cap. Truncated or aggregate-oversized actions fail closed before reviewer invocation with guidance to use a smaller command or split the action into smaller tool calls. Non-JSON values fail closed during request construction.

Every Pi session that loads the extension applies the same global configuration and gate. No cwd marker, session header, or package identity changes approval behavior.

## Transcript selection

The active branch is compacted to actual user text, visible assistant text, assistant tool calls, and tool results. After Pi compaction, selection also receives historical user messages from the full active branch and Pi's existing compaction or branch summary as labeled summary evidence. Hidden thinking, custom extension messages, and other synthetic context are excluded.

Selection uses the same separate approximate 10,000-token message and tool budgets with or without Pi compaction, approximate 2,000/1,000-token per-entry caps, summary retention, first/latest user anchors, newest-first recent non-user selection, at most 40 retained non-user entries, stable original numbering, and an omission marker. Unicode truncation is code-point safe.

Unlike Codex's reusable Guardian trunk/delta conversation, each review is stateless. That avoids hidden cross-review precedent and retained reviewer transcripts at the cost of resending compact current evidence.

## Fixed policy and parser

The fixed policy treats supplied artifacts as untrusted evidence. It defines low/medium/high/critical risk and unknown/low/medium/high authorization, and identifies credential probing, untrusted exfiltration, persistent security weakening, and broad destructive actions as deny categories.

The parser first attempts the whole output as JSON, then the span from the first `{` through the last `}`. It requires `outcome: "allow" | "deny"`, validates optional known fields, ignores unknown fields, and supplies defaults. A valid deny is not retried. Its concise rationale appears in Pi's ordinary blocked tool result but is not copied into the audit entry.

## Model call and failures

Each attempt re-finds the configured provider/model, checks reasoning support, and resolves auth. If the provider has an extension-registered `streamSimple` for the selected model's API, the reviewer awaits that stream's result; otherwise it uses `completeSimple`. The direct request has no tools, a 384-token output limit, no provider-internal retries, the configured reasoning level, and active cancellation under the shared deadline.

Missing model or auth, unsupported reasoning, timeout, cancellation, provider failure, malformed or empty output, output truncation, tool use, and unexpected aborts all fail closed. Only parse/provider failures retry.

The direct request does not enter Pi session messages or usage accounting and cannot recursively emit `tool_call`. It also does not inherit coding-agent provider request/response extension hooks. Matching extension-registered custom provider streams are invoked directly; other providers use Pi's compatibility completion path.

## Security and unavoidable Pi differences

This is a convenience reviewer, **not a sandbox**. Pi has no generic interception of interactive/RPC shell execution or arbitrary extension side effects. Extensions share the process and its OS permissions; a same-process extension can act without issuing a model tool call. OS/container policy remains the enforcement boundary.

Tool names are Pi's routing identity, not a security provenance identity. The configured name-collision behavior is therefore useful and simple but cannot distinguish two implementations competing for the same name.

Bypassing genuine built-in `read`, `grep`, `find`, and `ls` permits credential or other sensitive content to enter the primary model's context. Downstream reviewed use or exfiltration remains gated, but this extension does not prevent the initial read.

Codex's manual retry marker depends on privileged protocol semantics and exact denied-action identity that Pi cannot reproduce safely, so this adaptation does not expose an equivalent override.
