pi-jev-guard

Jev validation guard for pi: on-demand tool + automatic provider gate. Dual backend: TypeSafe direct + OpenRouter.

Packages

Package details

extensionskill

Install pi-jev-guard from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-jev-guard
Package
pi-jev-guard
Version
0.7.2
Published
Sep 23, 2026
Downloads
1,869/mo · 1,869/wk
Author
alucard_24
License
unknown
Types
extension, skill
Size
273.9 KB
Dependencies
4 dependencies · 3 peers
Pi manifest JSON
{
  "skills": [
    "./skills"
  ],
  "extensions": [
    "./extensions/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-jev-guard

Verifica le risposte con TypeSafe Jev dentro pi: un solo motore di validazione, due interfacce.

  • A richiesta (default): tool jev_validate, comando /jev check, skill jev-review. Zero verifiche implicite, zero costi se non lo usi.
  • Domande tipate: tool jev_ask per giudizi calibrati definiti dal modello (noul/choice/score) invece di prosa.
  • Automatica: in automatic il gate copre il modello selezionato e ogni cambio modello, senza alias o registrazioni extra: trattiene la risposta, la verifica con Jev e pubblica solo l'output approvato (con rigenerazione privata su block). Stessa auth del provider: nessun login extra, funziona anche con Codex/OAuth.
  • Giudice output (solo automatic, fail-open): dopo ogni bash cerca secret nel testo e classifica i fallimenti, allegando un consiglio al risultato.
  • Verifica progetto (opt-in): footer deterministico da edit/write osservati e check autorizzati da override locale, manifest globale utente o profilo comune integrato; il modello può eseguire soltanto quegli id, mai shell arbitraria.

Installazione

cd pi-jev-guard
npm install
mkdir -p ~/.pi/agent
cp config/jev-config.example.json ~/.pi/agent/jev-config.json
pi install "$PWD"

Chiavi (a seconda del backend Jev scelto):

export OPENROUTER_API_KEY="sk-or-v1-..."   # backend openrouter (default)
export TYPESAFE_API_KEY="..."              # backend typesafe diretto

Uso normale (invariato)

Le nuove sessioni partono in on-demand: i modelli normali restano selezionabili e nessuna verifica parte da sola. /jev mode automatic|on-demand salva la scelta nella sessione, non nella config globale. La scelta sopravvive a /reload, riavvio e /resume; fork e /tree seguono lo stato del ramo. Credenziali e policy restano condivise.

Migrazione: il vecchio mode in jev-config.json non controlla più l'estensione (resta compatibile con i consumer standalone). Nelle sessioni senza uno stato salvato, riattiva automatic una volta se desiderato. JEV_MODE=automatic può impostare il valore iniziale in headless; una scelta già salvata nella sessione ha precedenza.

/jev check ./src/example.ts        # verifica singola di un file
/jev status                        # stato completo
/jev help                          # tutti i sottocomandi

In chat, l'LLM può chiamare jev_validate per controlli mirati.

Uso protetto

/model                          # scegli qualunque modello (o più modelli in sessioni diverse)
/jev mode automatic             # ogni risposta passa dal gate Jev
/jev off                        # gate disattivato, provider ripristinati

Nessun alias __jev, nessuna registrazione: il gate lavora sullo stesso oggetto provider e riusa la credenziale già configurata (env, stored, OAuth/SSO come Codex business plan). I vecchi alias delle versioni ≤ 0.6.x vengono normalizzati automaticamente ai modelli originali.

Backend e chiavi

Due backend, stessa policy e stesse regole:

Backend Endpoint Variabile Modello Timeout
openrouter (default) OpenRouter OPENROUTER_API_KEY typesafe/jev-1.13 4000 ms
typesafe SDK ufficiale @typesafe-ai/sdk → api.typesafe.ai TYPESAFE_API_KEY jev-1.13.0 1500 ms
auto sceglie il backend che ha una chiave (entrambe → OpenRouter) — — —
/jev backend                    # stato: backend, modello, chiavi rilevate
/jev backend typesafe           # cambia backend (salvato in jev-config.json)
/jev save-key typesafe          # salva la chiave del backend (file 600)
/jev save-key openrouter        # l'altra chiave resta dov'è
/jev key-file                   # dove viene cercata la chiave

Le chiavi stanno in file separati (jev-api-key.<backend>.txt accanto alla config), quindi i due backend possono coesistere. Precedenza: variabile d'ambiente → file del backend → file generico jev.apiKeyFile → percorso canonico. Vedi config/jev-config.example.json.

Qualunque modello: in automatic il gate segue la selezione — cambi modello con /model e ogni risposta resta coperta, senza passaggi di setup. Il catalogo resta quello di pi: nessun alias, nessun modulo extra nel picker.

Torna normale con /jev mode on-demand (o /jev off, che ripristina anche i metodi originali dei provider). Entrambe le scelte vivono nella sessione e sopravvivono a /reload e /resume.

L'installazione punta alla cartella: dopo un aggiornamento del codice basta /reload.

Headless/CI: JEV_MODE=automatic parte già col gate attivo sul modello usato.

Un hold [JEV — OUTPUT NON PUBBLICATO] interrompe intenzionalmente il turno: controlla /jev last. Non viene aggirato con un proseguimento automatico.

Verdetto incerto (review): il gate tenta prima una riparazione privata (automatic.repairOnReview, default true), poi applica la policy configurata: policy.onUncertain e policy.onUnavailable ("hold" default, oppure "pass"). Con "pass" il testo viene pubblicato con una nota di trasparenza sul verdetto.

Se un'altra estensione gestisce lo stesso provider (caso reale: pi-accounts con overlay auth su openai-codex), il gate NON ri-registra nulla: applica una patch in-place sull'oggetto provider live (stessa identità, stessa config del proprietario). Così i controlli di ownership altrui non vedono mai una "configuration changed" e non armano abort dei turni (This operation was aborted istantaneo). Quando il proprietario sostituisce l'oggetto, il nuovo viene patchato ex-novo agli hook (input, before_agent_start, turn_start, model_select, message_end); /jev off ripristina i metodi originali senza unregister (jev-overlay-reassert solo quando un oggetto nuovo viene patchato). Rete di sicurezza legacy: se un id __jev delle vecchie versioni sfugge nel payload, viene normalizzato al modello originale registrando jev-gate-bypass, perché quel turno non è passato dalla verifica. Le conferme per comandi di rete sospetti attendono invece una decisione esplicita; la normale sequenza tool → risposta successiva continua senza un nuovo prompt.

Come decide

Jev risponde a domande noul (probabilità 0–1 di "sì, c'è la falla"):

Regola Gate automatic On-demand
sql_injection ✓ ✓
unsafe_destructive_action ✓ ✓
requirement_conflict — (requisiti chat troppo vaghi) ✓ (requisiti espliciti)

Soglie preliminari calibrate live (docs/calibration-2026-09-19.md): p ≤ 0.20 pass · p ≥ 0.90 block · in mezzo review (trattenuto) · errori/timeout → unavailable (trattenuto). Mai approvazione su input troncato: un pass parziale diventa review dichiarata. I candidati lunghi sono verificati a chunk (copertura completa); i requisiti oltre 16k trattengono con nota.

In automatic è attiva anche una tool policy deterministica (costo zero): blocca comandi distruttivi (rm -rf /, fork bomb, mkfs, dd su device…) e scritture su path sensibili (.env, .ssh/, *.pem, node_modules/). In on-demand non blocca nulla. Sempre in automatic, i comandi con tool di rete (curl, scp, ssh…) passano un check semantico Jev (destructive/exfiltration/beyond_scope/impact): su flag chiede conferma in TUI, in headless solo avviso (fail-open).

Sempre in automatic, il giudice output esamina i risultati bash (1 chiamata Jev per output nuovo, con cache 120s): se trova un secret avvisa e dice di riferirsi al valore per nome; se è un errore, allega il consiglio per la classe (transient → riprova, code_bug → fixa il codice…). Non blocca mai; /jev output mostra l'ultimo verdetto.

Sempre in automatic, il grounding (opt-in, default spento) confronta le affermazioni sulla sessione — "ho letto il file", "i test passano", "ho eseguito X", "il guard riporta X" — con un registro evidenza costruito dai tool_result e dai fatti generati dal guard (footer di verifica, run jev_verify) (comandi, test, letture, modifiche; redatto, max 30 voci, solo sessione corrente). Due domande Jev strette: contraddizione con l'evidenza e affermazione non supportata. Senza evidenza non si giudica: "senza evidenza" non significa "falso". Una modifica riuscita invalida i test precedenti (stale). Tre modalità (/jev grounding off|warn|repair|hold): warn pubblica con nota, repair rigenera una volta, hold trattiene solo le contraddizioni ad alta confidenza. Fail-open: se il verificatore non risponde, il testo passa senza nota. /jev last mostra anche l'esito grounding (warned/repaired/held).

Verifica progetto deterministica (opt-in)

Il grounding è probabilistico; per compilazione, lint e test serve una prova deterministica. La verifica progetto conserva, solo nella sessione, edit/write riusciti e gli esiti osservati dei check. Il footer viene generato dall'estensione, non dal modello: un test non eseguito non può diventare “test passati”. Un report di “verifica” scritto dal modello non ha valore: il footer autorevole è solo quello del guard (marcato generata dal guard, non dal modello) e una guideline ai tool scoraggia le imitazioni.

Nuovi progetti: zero manifest locale

Una volta, in una sessione pi, abilita la modalità scelta:

/jev verification repair

Da quel momento ogni progetto usa questa precedenza:

  1. .pi/jev-verification.json locale, se presente;
  2. verification.globalManifestPath, se l'hai configurato nella config utente;
  3. profilo integrato common (default).

Il profilo common non legge comandi dal repository: abilita esclusivamente comandi fissi dell'estensione quando trova segnali convenzionali:

Rilevamento Check disponibili
package.json con script npm run typecheck, npm run lint, uno tra npm run test:unit, npm run test:ci, npm test
Cargo.toml cargo check, cargo test
go.mod go test ./...
*.sln / *.csproj (root o 2 livelli) dotnet build, dotnet test
configurazione pytest python -m pytest
repository Git git diff --check

Il profilo sceglie un solo ecosistema (Node → Rust → Go → .NET → Python) e aggiunge il check Git quando applicabile. I comandi sono bounded da verification.maxCommands (default 4) e timeout. Se nessun segnale è rilevato, non esegue nulla e il footer dichiara la limitazione.

Dopo un edit il modello può scegliere solo id già acquisiti:

/jev verify recommended      # check pertinenti non ancora freschi
/jev verify all              # tutti, fino a verification.maxCommands
/jev verify node-typecheck   # un id esplicito della policy corrente

Il tool LLM jev_verify ha lo stesso vincolo, richiede un progetto trusted e non accetta shell arbitraria. Footer/repair/hold operano in automatic; /jev verify è utilizzabile manualmente anche senza footer.

Override per progetti speciali

Per una pipeline specifica, aggiungi un manifest al progetto: prevale sempre sul profilo globale.

mkdir -p .pi
cp config/jev-verification.example.json .pi/jev-verification.json

Controllalo tu, poi acquisiscilo (e ripeti dopo ogni modifica manuale):

/jev verification reload

In alternativa puoi definire una policy comune per tutti i tuoi progetti nella config utente, purché esista davvero e sia sotto il tuo controllo:

{
  "verification": {
    "globalManifestPath": "~/.pi/agent/jev-verification.global.json",
    "defaultProfile": "common"
  }
}

Un globalManifestPath configurato ma assente o malformato non degrada silenziosamente al profilo integrato: la verifica segnala l'errore. Per disattivare il fallback integrato imposta "defaultProfile": "off". /jev verification e /jev status mostrano l'origine effettiva della policy.

Manifest e profilo sono acquisiti a inizio sessione, all'attivazione esplicita o con /jev verification reload. Se un manifest, un package.json o un file di configurazione che abilita il profilo cambia dopo l'acquisizione, nessun check parte fino al reload utente. In automatic, con tool policy e verifica attive, write/edit del modello su tali file sono bloccati; una modifica via shell viene comunque rilevata dal fingerprint. Questo evita che il modello trasformi uno script o un manifest in un nuovo comando autorizzato.

Modalità: warn aggiunge il footer; repair rigenera una volta con feedback che chiede jev_verify; hold trattiene dopo una failure concreta, o dopo il tentativo bounded se restano check mancanti. Nessun check pertinente non è un fallimento del codice e non produce hold. Le modifiche rilevate restano solo quelle di edit/write: una modifica shell non viene attribuita al modello.

Configurazione

~/.pi/agent/jev-config.json (o $JEV_CONFIG). Env: JEV_MODE, JEV_BACKEND (openrouter|typesafe|auto), JEV_MODEL. Vedi config/jev-config.example.json per tutti i campi.

Chiave Jev (ordine: env vince sul file): OPENROUTER_API_KEY o TYPESAFE_API_KEY, altrimenti jev.apiKeyFile (es. "~/.pi/agent/jev-api-key.txt", ~/ espanso, solo prima riga, permessi 600 consigliati). /jev status mostra la sorgente (env:VAR, file:<path>, o il motivo se assente) — mai il valore.

Per salvare la chiave stando dentro pi (senza passarla come argomento, che resterebbe in history e transcript):

/jev save-key   # chiede la chiave via dialogo, la scrive a 600, ricarica

Nota: il dialogo TUI potrebbe fare echo nel terminale; per massima paranoia usa la shell: umask 077 && cat > ~/.pi/agent/jev-api-key.txt.

I verdetti identici sono riusati per 120s (reviewCache, mai gli unavailable): retry e batch paralleli costano una sola chiamata. Gli input oltre i limiti sono marcati …[N chars elided] nel testo inviato a Jev, mai troncati in silenzio.

Retry solo su transienti (jev.retryTransients, default 1 retry): 429/5xx ed errori di connessione ritentano con backoff, timeout e auth mai — un rate-limit non diventa più subito hold. /jev last mostra l'ultimo verdetto del gate (esito, tentativi, controllo con p, backend, tempo).

Sviluppo

npm run typecheck
npm run test:unit            # mock, nessun costo
npm run test:integration
RUN_JEV_LIVE=1 npm run bench:jev   # corpus live (costa poco)
echo '{"requirements":"...","candidate":"..."}' | npm run jev-check

Limiti onesti

  • pass = "supera i controlli configurati", non "corretto". Compilazione e test restano necessari.
  • Il gate copre i turni che passano dal provider patchato in automatic; se un provider non è patchato (raro: sostituzione concorrente) il turno passa con una nota jev-guarded/diagnostica dichiarata.
  • Soglie calibrate su 20 casi (docs/calibration-2026-09-19.md): buone per iniziare, da rivalutare con corpus più ampio.
  • Jev è un giudice probabilistico, non un verificatore formale.
  • Il grounding controlla solo affermazioni verificabili sulla sessione (comandi, file, test, modifiche): niente fact-check di fatti esterni, e con contesti lunghi l'evidenza oltre budget viene elisa.
  • La verifica progetto dimostra solo i check dichiarati ed eseguiti dopo gli edit/write osservati; non è una prova formale di correttezza, non vede modifiche effettuate via shell e non sostituisce review umana.