@crooycom/pi-jev-guard1.0.1
Jev classifier as a pre-execution guard rail on every mutating tool call (bash, write, edit) — batched lens, hard block with reason, session allows, breaker failover
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-jev-guard
A pi extension where jev (the cheap typesafe model) is a pre-execution guard rail on
every mutating tool call — bash, write, edit — with a read gating extension on the
roadmap (design validated: docs/superpowers/specs/2026-09-28-read-gating-design.md).
Before a call runs, one batched jev call scores it against a question lens (rich context:
task frame + recent calls + outputs); any flag ≥ its threshold hard-blocks the call
with a deterministic reason fed back to the agent.
"Jev decides if it's safe to run, the LLM does the work."
How it works
flowchart TD
A["Agent wants to run a tool call"]
A --> B{"Mutating?"}
B -->|"no (read, grep, ls…)"| C["Read gating (roadmap)¹"]
C -->|"within workspace"| D["Pass — one-liner into window"]
C -->|"sensitive or outside workspace"| E["Jev consent check / 4-question lens"]
E -->|"user asked for it (consent)"| D
E -->|"unsolicited (no consent)"| F["Block with reason²"]
B -->|"yes (bash, write, edit)"| G{"Checkpoint due?<br>interval · first-in-turn · after-block"}
G -->|"no"| H["Execute unchecked (counted)"]
G -->|"yes — call is HELD"| I["Batched jev call<br>battery lens · 0.7/0.8 thresholds"]
I -->|"any flag ≥ t"| J["Hard block"]
J -->|"notify²"| K["Agent sees: flagged rule +<br>confidence + guard-allow hint"]
K -->|"guard allow → retry"| A
I -->|"all flags < t"| L["Execute — appended to window buffer"]
I -->|"failure ×retries"| M["Fail-closed: block 'guard unavailable'"]
M -->|"consecutive or rolling trip"| N["DEGRADED<br>notify-only + catastrophic floor"]
N -->|"probe call after 60s cooldown"| O["Probe jev call"]
O -->|"2 consecutive successes"| P["Auto-recovery → armed"]
O -->|"failure"| N
style C fill:#e8e8ff,stroke:#666,stroke-dasharray:8 4
style E fill:#e8e8ff,stroke:#666,stroke-dasharray:8 4
style F fill:#e8e8ff,stroke:#666,stroke-dasharray:8 4
style N fill:#fff3cd,stroke:#856404
style J fill:#f8d7da,stroke:#721c24
style M fill:#f8d7da,stroke:#721c24
¹ Read gating is designed (docs/superpowers/specs/2026-09-28-read-gating-design.md)
and validated (6/6 dangerous caught, 0/6 false blocks) — implementation on the roadmap.
Within-workspace reads: always OK. Known-sensitive paths (~/.ssh/*, **/.env*, /etc/*):
trigger a jev consent check with chat context.
² On block, the user gets a ctx.ui.notify warning with the flagged question + confidence.
- Block = deny before execution; the block reason in the chat names the rule +
confidence + its definition, and tells the agent it can skip that rule for this
session via the
guardtool (allowaction) — no sticky hint panel. - Session allows:
guard allow <rule>(model tool or/guard allow <rule>) removes that one rule from the checkpoint for the rest of the session; allowed rules are not even sent to jev. Invalid/unknown rule ids are rejected against the battery./guard onclears them; nothing persists across sessions — a/new,/resume, or/treefork starts a fresh guard (allows and breaker state reset). - Window buffer: last 12 tool-call entries (mutating rich, read-only one-liners, block events appended) — the evidence jev judges against.
- Lenses (
battery-v2): bash → 8 gate questions (destructive / out-of-workspace / remote-code-exec / credential-exposure / supply-chain / privilege-escalation / force-mutation / unguarded-expansion); write & edit → the 20-question code battery (security sinks + correctness + maintainability) + 2 filesystem gate questions. - Commands:
/guard off(session-only, audited) ·/guard on(re-arm, clears allows) ·/guard status(state, counters, allowed rules) ·/guard allow <rule>. Future:/guard contained(sandbox mode, restricts reads/writes to workspace). - Breaker: 3 consecutive or 5-of-8 rolling jev failures → degraded (calls pass, catastrophic floor still hard-blocks); auto-recovery via real-call probes.
- Read gating (roadmap): gating read-only tool calls via a 4-question jev lens
(
r_sensitive_path,r_out_of_workspace,r_exfiltration,r_lacks_consent). Within-workspace reads pass free; known-sensitive paths (~/.ssh/*,**/.env*,/etc/*) trigger a jev consent check. Validated: 6/6 dangerous caught, 0/6 false blocks on a 12-case testbench. Design:read-gating-design.md. - Persistent disable:
enabled: falsein.pi/guard.yaml.
Configuration as data
(This section describes the repo's own reference config — the same files any project
can place in its .pi/ to override the global defaults.)
| Path | Role |
|---|---|
.pi/guard.yaml |
gate knobs: interval, budgets, timeout, tools, thresholds, breaker, provider, debug, show_status |
.pi/guard-battery.yaml |
checklist: routing, 28 questions, thresholds, preambles, scope rules |
Validation
testbench/ — 28 labeled mutating-tool cases (15 benign / 13 dangerous), question-set
configs, scorer: npm run testbench. Acceptance: ≥ 12/13 catch, ≤ 1/15 false-blocks,
3-pass variance protocol. routed-final: 13/13 / 0 FP.
testbench-read/ — 13 labeled read-gating cases (6 benign / 7 dangerous), 4-question
read lens, scorer: npm run testbench-read. Acceptance: ≥ 6/7 catch, ≤ 1/6 false-blocks.
Current: 7/7 / 0 FP.
Design/spec: docs/superpowers/specs/2026-09-22-jev-guard-design.md (mutating gate),
docs/superpowers/specs/2026-09-28-read-gating-design.md (read gating). Research
notes in docs/research/.
Running & verifying
npm install
npm run check # tsc --noEmit (strict)
npm test # 48 tests, jev transport mocked
npm run testbench # live jev testbench: mutating tools
npm run testbench-read # live jev testbench: read gating (roadmap)
node scripts/demo-live.mts # end-to-end demo: allow / block / fail-closed
Env: a Jev classifier credential — /login on any catalog provider, or
TYPESAFE_AI_API_KEY (or TYPESAFE_API_KEY) / OPENROUTER_API_KEY for the direct
fallback. /reload picks up config + code changes; the guard re-arms on every
session transition (/new, /resume, /tree forks included).
Requirements
- pi ≥ 1.0
- A Jev classifier credential: a
/login-backed provider (pi 1.0 serves Jev classifiers ontypesafe,openrouter,cloudflare-workers-ai,vercel-ai-gateway,opencode) and/or a raw API key inTYPESAFE_AI_API_KEY(orTYPESAFE_API_KEY) /OPENROUTER_API_KEY(see Providers) - Node ≥ 22 (for the test suite; the extension itself runs inside pi)
Providers
The gate reaches Jev through one or more providers, tried in order with automatic
failover. Configure with provider: in .pi/guard.yaml (a single name or a list):
provider: [typesafe, openrouter] # ordered preference; failover on failure
Each provider resolves through the first transport that can serve it:
- pi 1.0 classifier runtime (default) — the guard calls
ctx.modelRegistry.classify()on the provider's Jev classifier model. Auth is resolved by pi at request time: env keys, stored/loginOAuth,models.json— anything pi accepts. The model id (model: jev-latestby default) is matched against the provider's classifier catalog, aliases included (openrouter's~typesafe/jev-latest, cloudflare'stypesafe/jev, …). - Direct TypeSafe-SDK fallback — when the provider has no classifier in pi's catalog, the guard calls the SystemOne API directly with an env key.
| provider | pi catalog | direct fallback key |
|---|---|---|
typesafe |
jev-latest (TYPESAFE_API_KEY or /login) |
TYPESAFE_AI_API_KEY (or TYPESAFE_API_KEY) |
openrouter |
typesafe/jev-1.13, ~typesafe/jev-latest |
OPENROUTER_API_KEY |
opencode |
jev-1.13, jev-1.13-free |
— |
cloudflare-workers-ai |
typesafe/jev |
— |
vercel-ai-gateway |
typesafe-ai/jev |
— |
provider: [typesafe, openrouter] keeps the guard armed if TypeSafe is down — it
only falls to fail-closed when every provider fails. Providers with neither a
pi-catalog credential nor an env key are skipped; if none resolve, the guard loads
OFF with a loud config error naming the fix. A single-provider config is fine; the
default is [typesafe].
Install
The repo is a pi package: the root package.json carries a pi manifest
(extensions/./extension/jev-guard), so pi handles discovery, dependencies, and
loading — no manual file copying.
Local checkout (works today): clone, install deps once, then let pi install the
package from the resolved path (no copy — edits in the checkout are live after
/reload):
git clone https://tangled.org/did:plc:zbh2vqomyj6bcpnzesehriwv pi-jev-guard
cd pi-jev-guard && npm install
pi install /path/to/pi-jev-guard # add --local to scope it to one project
From npm / git (once published):
pi install npm:@crooycom/pi-jev-guard
pi install git:tangled.org/did:plc:zbh2vqomyj6bcpnzesehriwv
Start (or /reload) pi — the statusline shows jev-guard: guard: armed (defaults).
Projects without their own .pi/guard.yaml run on built-in defaults + the embedded
battery. Pick a project to tune it: copy .pi/guard.yaml + .pi/guard-battery.yaml
from this repo into the project's .pi/ and edit (per-project thresholds, interval,
floor patterns, breaker settings).
Try without installing — one invocation, nothing written to settings:
pi -e /path/to/pi-jev-guard
Extension development — load the extension file directly:
pi -e /path/to/pi-jev-guard/extension/jev-guard/index.ts
pi list shows the installed package, pi remove uninstalls, pi config toggles
resources. If an older manual copy exists in ~/.pi/agent/extensions/jev-guard/, delete
it before installing the package — two instances would each gate every call.
Repository layout
| Path | What |
|---|---|
extension/jev-guard/ |
the extension source (index wiring + engine, window, verdict, jev, breaker, config, session allows, embedded default battery) |
.pi/guard.yaml, .pi/guard-battery.yaml |
runtime config + question battery (data, edit freely) |
testbench/ |
labeled mutating-tool testbench: 29 cases, question-set configs, scorer |
testbench-read/ |
labeled read-gating testbench: 13 cases, 4-question read lens, scorer |
test/ |
unit tests (node:test, jev transport mocked) |
scripts/ |
demo-live.mts: end-to-end allow / block / fail-closed demo |
docs/superpowers/specs/ |
design specs: mutating gate + read gating |
docs/research/ |
research notes: pi mechanics, pi-auto-review mining, spike, battery, semantics, breaker policy, golden report |