pi-jev-command-guard

September 20, 2026 · View on GitHub

English | 简体中文

A Pi coding agent extension that reviews bash and powershell tool calls with TypeSafe JEV before execution.

It provides a Codex/Claude Code-style command approval gate:

  • confidently low-risk commands run automatically;
  • risky, ambiguous, or low-confidence commands require human approval, with an option to remember a trusted command prefix;
  • clearly malicious or catastrophic commands are blocked;
  • API failures and malformed responses fail closed.

How it works

The extension registers a Pi tool_call hook. Before a shell command executes:

  1. Small deterministic rules identify commands that must always be reviewed locally, such as sudo, recursive forced deletion, disk utilities, forced pushes, and downloaded scripts piped into a shell.
  2. Other commands are sent to JEV as one structured choice question with three possible answers: allow, ask, or deny.
  3. Code applies an additional confidence gate. JEV may auto-allow a command only when:
    • the selected choice is allow;
    • confidence is at least 0.75;
    • ask probability is below 0.25;
    • deny probability is below 0.10.
  4. ask opens Pi's native selection dialog. The user can allow the command once, permanently allow its two-word prefix, or reject it.
  5. deny blocks the command immediately.

If the API key is missing, the request fails, or JEV returns an invalid response, the extension routes to human approval when an interactive UI is available. Without an interactive UI, it blocks the command.

JEV request

The extension calls:

POST https://api.typesafe.ai/v1/systemone
Authorization: Bearer $TYPESAFE_API_KEY
Content-Type: application/json

The request uses jev-latest and a body shaped like this:

{
  "state": {
    "command": "git push origin main",
    "shell": "bash",
    "working_directory": "/path/to/project",
    "latest_user_message": "Commit locally, but do not push.",
    "assistant_text_before_tool_call": "I will create a local commit.",
    "project_trusted": true,
    "interactive_ui_available": true
  },
  "model": "jev-latest",
  "questions": {
    "command_policy": {
      "type": "choice",
      "instructions": "Choose the safest execution policy for this coding-agent command before it runs...",
      "criteria": {
        "allow": "Low-risk and normally reversible or read-only...",
        "ask": "Needs explicit human confirmation...",
        "deny": "Clearly malicious, unrelated to a legitimate coding task..."
      }
    }
  }
}

The complete question text is defined in src/reviewer.ts.

Context sent to TypeSafe

FieldSourceLimitPurpose
commandPi shell tool inputFull commandThe action being reviewed
shellPi tool namebash or powershellShell semantics
working_directoryctx.cwdFull pathTarget scope and project context
latest_user_messageCurrent session branch4,000 charactersUser intent and explicit boundaries
assistant_text_before_tool_callCurrent assistant message1,000 charactersStated purpose of the command
project_trustedctx.isProjectTrusted()BooleanWhether Pi trusts project-local resources
interactive_ui_availablectx.hasUIBooleanWhether uncertainty can be routed to a person

Only text before the matching tool call is taken from the assistant message. Model thinking is never included.

Context not sent

The extension does not send:

  • the API key as part of state;
  • environment variables;
  • model thinking or reasoning;
  • images;
  • tool results or terminal output;
  • file contents or diffs;
  • the complete conversation history.

The API key is used only in the Authorization header. However, the full command, current path, latest user message, and selected assistant text are sent to TypeSafe. Avoid putting secrets directly in commands or messages.

Installation

Global extension

Clone into Pi's global extensions directory so every project can use it:

git clone https://github.com/JasonHZS/pi-jev-command-guard.git \
  ~/.pi/agent/extensions/pi-jev-command-guard
cd ~/.pi/agent/extensions/pi-jev-command-guard
npm install

Restart Pi. The startup resource list should include:

[Extensions]
  pi-jev-command-guard

Pi package installation

Pi can also install the Git repository as a package:

pi install git:github.com/JasonHZS/pi-jev-command-guard

Configuration

The extension reads the TypeSafe API key from the local TYPESAFE_API_KEY environment variable when Pi starts. The key is used only in the HTTP Authorization header and is never added to JEV state, logged, or persisted by the extension.

If the variable is unavailable, shell commands require manual approval in interactive sessions and are blocked in non-interactive sessions.

Trusted command prefixes can be configured in config.json at the package root:

{
  "allowedCommandPrefixes": [
    "git commit",
    "git push"
  ]
}

The file is re-read before every command, so manual edits apply immediately. Prefixes use word-boundary matching: git push matches git push origin main, but not git pushy. A compound command bypasses JEV only when every top-level command has an allowed prefix. Pipes, redirections, command substitutions, subshells, and unsupported shell syntax remain subject to JEV review.

Approval UI

An ask decision uses Pi's native selection dialog:

⚠️ Command approval required

Command
  $ git push origin main

Review
  Recommendation  Ask for approval
  Confidence      45%
  Probability     Ask 64% · Allow 36% · Deny 0%
  Source          JEV

Choose how to handle this command.

→ Allow once
  Always allow “git push”
  Reject

Local safeguards

The local rules currently escalate representative forms of:

  • sudo;
  • rm -rf / rm -fr;
  • mkfs, fdisk, and parted;
  • dd involving /dev/;
  • shutdown and reboot commands;
  • git reset --hard, forced git clean, and forced pushes;
  • curl or wget piped into a shell;
  • broad root/home chmod or chown operations.

These rules always produce ask; they never silently allow execution and do not require a JEV request.

Development

Requirements:

  • Node.js 22 or newer;
  • Pi 0.85.0 or newer.

Install dependencies and run checks:

npm install
npm test
npm run typecheck

The test suite covers local destructive-command escalation, confidence thresholds, API failure behavior, session-context extraction, thinking exclusion, request-state construction, allowed-prefix matching and persistence, and the approval prompt.

Limitations

  • A semantic classifier can make mistakes. The local rules and confidence gates reduce risk but do not provide a complete sandbox.
  • JEV primarily trains on English. Other languages are accepted but may have lower accuracy.
  • Commands assembled indirectly by scripts or aliases may not reveal their full effect in the visible command text.
  • Prefix allowlisting is intentionally lexical rather than semantic. Review a prefix carefully before saving it; arguments under that prefix are trusted except when unsupported shell composition forces a JEV review.
  • Extensions run with the same system permissions as Pi. Review third-party changes before updating.

License

MIT