pi-jev-guard
Jev validation guard for pi: on-demand tool + automatic provider gate. Dual backend: TypeSafe direct + OpenRouter.
Package details
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.4.0- Published
- Sep 22, 2026
- Downloads
- 1,744/mo · 1,744/wk
- Author
- alucard_24
- License
- unknown
- Types
- extension, skill
- Size
- 221.6 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, skilljev-review. Zero verifiche implicite, zero costi se non lo usi. - Domande tipate: tool
jev_askper giudizi calibrati definiti dal modello (noul/choice/score) invece di prosa. - Automatica: gemello guarded
<modello>__jevdentro lo stesso provider, che trattiene la risposta, la verifica con Jev e pubblica solo l'output approvato (con rigenerazione privata sublock). Stessa auth del provider: nessun login extra, funziona anche con Codex/OAuth. - Giudice output (solo
automatic, fail-open): dopo ognibashcerca secret nel testo e classifica i fallimenti, allegando un consiglio al risultato.
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, policy e catalogo dei twin restano condivisi.
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
/jev upstream deepseek deepseek-flash # crea deepseek/deepseek-flash__jev
/jev upstream openai-codex gpt-5.6-terra # aggiunge openai-codex/gpt-5.6-terra__jev
/jev twins # elenca attivi e salvati
/jev untwin openai-codex gpt-5.6-terra # rimuove uno solo
/jev mode automatic # seleziona il primario + attiva enforcement
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.
Più twin insieme: ogni /jev upstream aggiunge un modello guarded, senza
rimuovere i precedenti. I twin vengono registrati anche all'avvio (i modelli
dinamici come Codex sono letti dal models-store), quando gli originali sono disponibili.
Il primario salvato è il target di auto-selezione e revert; un twin già selezionato
nella sessione viene mantenuto al reload, anche se non è il primario.
Nessun login extra: i twin vivono nello stesso provider e riusano la credenziale già configurata (env, stored, OAuth/SSO come Codex business plan). I modelli originali restano intatti e selezionabili.
I twin salvati vengono registrati prima del ripristino del modello anche in
on-demand: registrazione e attivazione del gate sono indipendenti. Il suffisso
__jev è locale e non viene inviato al provider; anche la cronologia viene
normalizzata sull'identità originale senza perdere firme o metadati di continuazione.
Torna normale con /jev mode on-demand, che seleziona anche il modello originale.
In automatic, selezionare un modello non protetto lo fa ritornare
subito al twin (enforcement a livello selezione).
/jev upstream senza argomenti ripristina tutti i twin salvati, /jev untwin P M
ne rimuove uno solo, /jev off li rimuove tutti
(e salva on-demand nella sessione, selezionando l'originale prima di rimuovere il routing).
/jev off conserva il catalogo salvato: al reload gli alias tornano disponibili,
ma il gate rimane disattivato.
Se filtri i modelli con enabledModels, usa i glob invece delle voci esplicite,
così i twin futuri non restano nascosti:
"enabledModels": ["openai-codex/*__jev", "deepseek/*__jev", "...altri pattern..."]
Dopo aver aggiunto un twin serve /reload (lo scope è risolto all'avvio della sessione).
/jev upstream avvisa subito quando il twin appena creato è fuori dal picker.
L'installazione punta alla cartella: dopo un aggiornamento del codice basta /reload.
Headless/CI: JEV_MODE=automatic JEV_AUTO_UPSTREAM=provider/model crea e attiva
il guarded nelle sessioni senza uno stato Jev salvato.
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. I twin restano visibili nel registry per le letture altrui
(jev-overlay-reassert solo quando un oggetto nuovo viene patchato).
In più, rete di sicurezza: se un id __jev sfugge comunque nel payload, il
gate toglie il suffisso registrando jev-gate-bypass e avvisando in TUI,
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" — con un registro evidenza costruito dai tool_result
(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).
Configurazione
~/.pi/agent/jev-config.json (o $JEV_CONFIG). Env: JEV_MODE, JEV_BACKEND
(openrouter|typesafe|auto), JEV_MODEL, JEV_AUTO_UPSTREAM.
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 solo il twin
__jevselezionato; inautomaticla selezione di altri modelli viene rifiutata con revert al twin. (/jev offripristina il provider originale intatto.) - 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.