---
name: pi-guardian
description: Diagnose Pi Guardian when tool calls are unexpectedly blocked or allowed, Guardian Reviews fail or time out, settings seem ineffective, Child Agents or Advisors behave differently, or reviews cost too much.
license: MIT
disable-model-invocation: true
---

# Pi Guardian

Use this sequence for a live Guardian problem:

1. Run `/guardian status`. Record the state, each setting and its source, the review counts (allowed, rejected, failed, overrides, argument drift), total cost, and the last failure. Treat unknown cost as unknown, not zero. Expand the newest `pi-guardian-review` entries in the transcript for the tool, scores, rationale, failure, model, and duration of each Guardian Review. Allowed reviews are hidden from the transcript, and low- and medium-risk reviews carry no rationale, unless `verbose` is on; turn it on (`/guardian set verbose true`) while diagnosing, then off again.
2. If the state is `disabled` and calls run unreviewed, Guardian is off: it is disabled by default, so check `enabled` and its source, and turn it on with `/guardian on` at the intended scope (`--global`, `--project`, or the session by default). A disabled Guardian enforces nothing, not even `deny` Tool Policies or Command Rules. If the state is `error`, read the message: invalid `guardian` settings in the global or trusted-project `settings.json`, an invalid session override, or an unreadable session. Correct it; until then every call except the built-in `read`, `grep`, `find`, and `ls` is a Review Failure, including calls the defaults would allow. A `commands` (Command Rule) prefix must be literal words starting with a bare program name (not `./gradlew` or `NAME=value`), and its value `allow`, `review`, `deny`, or `null`.
3. If a call was blocked without a Guardian Review, check its Tool Policy and, for `bash`, `terminal_start`, or `powershell`, the Command Rules. A `deny` Tool Policy, or a `deny` Command Rule matching any segment of such a command (even under `tools.bash: allow`), blocks without a model call. A `deny` rule also matches after wrappers such as `time`, `env`, or `sudo`, and when a command holds a here-document, comment, `$'…'` string, line continuation, or substitution, it may deny a command that only mentions the denied one; `tools.bash: allow` ignores `review` rules. Resolution order: `tools.<name>` setting, then the built-in default (read-only tools and the Context Management tools `context_notes`, `context_history`, and `context_rollover`, pi-advisor's `advisor_report`, and Pi Secret's `secret_ask`, `secret_list`, and `secret_forget`, allowed; `edit`/`write` allowed except for Sensitive Paths; `bash` allowed only for Safe Commands), then the tool's `readOnlyHint` annotation (unless it also declares `openWorldHint`), then review. `web_fetch` is reviewed by default because a URL can carry data out; allow it with `/guardian tool web_fetch allow` only if that is acceptable. Change one entry with `/guardian tool <name> <allow|review|deny|default|inherit>` at the intended scope (`--global`, `--project`, or the session by default).
4. If a `bash` command you consider safe is reviewed, it is not a Safe Command. Pipelines and lists joined by `|`, `&&`, `||`, or `;` are Safe Commands only when every segment is one; redirection, substitutions, variables, globs, `~`, quotes left open, newlines, or a segment whose program is outside the built-in list or your `allow` Command Rules send it to review, and so does any segment matching a `review` Command Rule (the Reviewed Call names the rule). A `cd` segment is safe only with one literal operand naming an existing workspace directory that is no Sensitive Path and holds no nested git repository, judged from the working directory and every earlier `cd` target, outside pipelines, with an absolute operand while `CDPATH` is set, and when no other call of a parallel batch or `codemode` script could change it first; Pi must run bash or `sh` (`shellPath`) without `shellCommandPrefix`, and `BASH_ENV`, `ENV`, `BASHOPTS`, `SHELLOPTS`, exported `BASH_FUNC_*` functions, and non-absolute `GIT_*` variables must be unset. A built-in `git` is reviewed while a variable such as `GIT_DIR`, `GIT_WORK_TREE`, `GIT_CONFIG_GLOBAL`, or `GIT_CONFIG_COUNT` is set, or after a `cd` only an `allow` rule permits; nothing is a Safe Command while `PATH` has a relative or empty entry. Check the environment Pi was started with. Add an `allow` Command Rule with `/guardian command git describe allow`; a prefix matches a segment's leading words and the rest of the segment must still be literal. Do not allow script runners such as `npm test`: they run workspace code without review.
5. If an edit is reviewed, the review entry's Reviewed Call says why: its path is a Sensitive Path, or a `tools` setting sends `edit` or `write` to review. The reason lists every Sensitive Path rule that matched and where a symlink resolves: outside the workspace root after resolving `~`, `..`, and symlinks (everything, when the workspace root is the home directory or an ancestor of it); a persistence or credential location under the home directory such as `.bashrc`, `.ssh`, `.config`, `~/bin`, or `.local/bin`, or the same dotfile name anywhere in the workspace; inside `.git`, `.pi`, `.agents`, `.claude`, `.husky`, `.github/workflows`, `.vscode`, `.idea`, or a `.env*` file; `.yarnrc.yml` or `.pnpmfile.cjs`; a context file such as `AGENTS.md`; a resource Pi loaded (extensions only when outside the workspace); a file with more than one hard link; or under Pi's agent directory or session directory.
6. For Review Failures, read the failure: no model resolves (set `model` to `provider/id` or select a session model), no credentials for that model, a provider error, a timeout (`reviewTimeoutMs`), malformed output (the model did not return exactly one assessment JSON, even after one corrective retry; choose a stronger model or raise `thinkingLevel`), or a call too large to review in full (choose a model with a larger context window; Guardian never shortens the Reviewed Call). With UI, Guardian asks whether to allow once; without UI it blocks. A failed Escalation Pass after a would-be Rejection is not a Review Failure: the first pass's Rejection stands, and the entry is marked `escalation failed, first pass stands` with the escalation failure (check `escalationModel`, its credentials, and its context window). With `classifierModel` set, a Review Failure whose failure says the Escalation Pass failed came from a classifier First Pass that was unsure, named no Risk Category, or failed: fix the escalation failure, and for a failing classifier read `classification.failure` (no such classifier or no credentials, such as an unset `TYPESAFE_API_KEY`; a call too large for it; a provider error; an invalid answer; or its fixed 10 s deadline).
7. For a Rejection you disagree with, first check whether it was escalated: a first-pass Rejection is rechecked by the Escalation Pass (`escalationModel` at `escalationThinkingLevel`), and stands when that pass agrees or fails (its `escalation` record says which: `assessed` or `failed` with the failure). A wrong Rejection the escalation agreed with usually needs a stronger escalation model or more thinking, not a stronger first pass; one whose escalation failed needs that failure fixed. Then check its Risk Category: `high` and `critical` need one of `data_egress`, `credential_access`, `destruction`, `persistence`, `sensitive_path`, `safety_weakening`, `remote_code`, `unreviewed_execution`, or `security_policy` (offered only with a Security Policy or `deny` Command Rule) that concretely applies; one still without a category after the corrective retry was decided as `medium` and marked `downgraded`. Then check the rationale against Trusted Evidence: only messages the user typed, context files from the global agent directory or a trusted project, recorded User Overrides, and Approved Delegations establish User Authorization. Evidence is reasoning-blind: the Guardian sees user messages and the agent's tool calls, never the agent's text, so an agent's explanation cannot authorize anything, and a bare "yes" may not identify what it approves. Tool calls, Skill bodies, messages an extension sent, an untrusted project's context files, and a Child Agent's task that is not an Approved Delegation cannot. Tell the agent in your own message that you authorize the exact action, naming it (the file, command, or destination), add rules to the Security Policy (`/guardian policy`), or set `onDeny` to `ask` to allow once interactively.
8. If the agent stopped after Rejections, the Rejection Streak reached `maxConsecutiveRejections` (default 3; 0 disables). Blocked Review Failures count too. Guardian then blocks every call until the next prompt or a message the user types while the agent runs (in a Child Agent, also a Coordination Message from its direct parent), so the turn ends at the latest with the next response's calls.
9. If a Child Agent or Advisor behaves differently, check `/guardian status` in that session for `follows root`: Child Agents and Advisors (also an Advisor observing a Child Agent) follow the root session's effective settings while the root runs Guardian in the same process, keep its last settings after the root ends, and use their own settings only if they never reached it. Their user messages come from another agent and are untrusted unless they are an Approved Delegation: a task or `agent_message` that the parent's Guardian allowed with at least `medium` User Authorization (or the parent's user allowed once), matched exactly, reaching this agent (`delegationRecipient` in the parent's review entry), and received as the same kind (task or Coordination Message). A delegation an `allow` Tool Policy let through stays untrusted, so keep `subagent` and `agent_message` reviewed if Child Agents should act on their tasks. The root user's typed messages are Trusted Evidence for their calls while the root runs Guardian in the same process. They have no UI, so Review Failures block.
10. If `/guardian status` reports argument drift, an extension loaded after Guardian changed the call's arguments after review. Load Guardian last. Loading it last also matters for extension messages: one that a later extension's `input` handler rewrites looks typed by the user, and so trusted.
11. If reviews cost too much, compare the total review cost with the session cost. Allow more read-only tools or Command Rules, lower `evidenceBudgetTokens`, choose a cheaper `model`, or lower `thinkingLevel`. Count escalated reviews in `/guardian status`, by trigger: without a classifier, Escalation Passes run only for would-be Rejections, so many of them mean the first pass rejects too often or the escalation model is expensive. A classifier First Pass (`classifierModel`, such as `typesafe/jev-latest`) is far cheaper and faster than any language model; many `uncertain` escalations mean `escalationThreshold` is low for that classifier, and many `failed` ones mean it is unavailable or too small for the calls (check `classification.failure`). Raise the threshold only as far as you accept the classifier's doubt deciding. With `model` unset, reviews use the session model; a small, fast model such as `anthropic/claude-haiku-4-5` with `thinkingLevel` `off` is usually far cheaper and faster. Check the review entries' token usage: if cache reads stay near the system prompt's size across reviews, report it, since evidence is meant to keep a shared prefix.

Finish when `/guardian status` shows the intended settings and the problematic call is allowed, reviewed, or blocked as its Tool Policy and Decision Table say. If a model or provider remains unavailable, report the exact failure instead of disabling Guardian.
