omp packages

@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

crooycom Published 17 days ago MIT ~297 downloads/mo

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.

Did it work for you?

Result

One report per person. A new report replaces your old one.

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 guard tool (allow action) — 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 on clears them; nothing persists across sessions — a /new, /resume, or /tree fork 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: false in .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 on typesafe, openrouter, cloudflare-workers-ai, vercel-ai-gateway, opencode) and/or a raw API key in TYPESAFE_AI_API_KEY (or TYPESAFE_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:

  1. 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 /login OAuth, models.json — anything pi accepts. The model id (model: jev-latest by default) is matched against the provider's classifier catalog, aliases included (openrouter's ~typesafe/jev-latest, cloudflare's typesafe/jev, …).
  2. 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

License

MIT