jev
Jev is TypeSafe's decision model: it picks one option from a list and says how sure it is.
With the Claude Code plugin, ship-check can ask it three things about a review's findings:
- harm: does this finding do real harm (money, data, a side effect done twice or sent wrong, security, legal, a crash, stuck work, or the change not doing its job)? Jev can make a finding real harm. It can never clear one the review named, and an answer below its confidence floor, or any failure, leaves the call to the rules.
- priority: for the list of smaller findings, which to recommend fixing now.
- proof: for a small fix the user picked, the least proof it needs (the repo's checks only, a unit test, a test against the real database or service, or a browser test). A real-harm fix always gets the full proof.
Without the judge, the rules make each call as written. Nothing here is needed to use first-pass.
What leaves the machine
For each finding asked about: its scenario, its worst case, who meets it and, for proof,
the fix in one line, after secrets, emails and phone numbers are blanked. They go to
TypeSafe's API (https://api.typesafe.ai/v1/systemone) with the key. TypeSafe charges per
word sent; check the current price on its models page (https://docs.typesafe.ai/models)
before telling the user a number. Its data terms: https://docs.typesafe.ai/legal.
1. Where it stands
For the current folder, and for one repo of each group the user keeps apart (two companies with separate accounts):
node "${CLAUDE_SKILL_DIR}/../../scripts/cli.mjs" jev status <repo>
It prints on or off, why, where the key comes from (a variable name and a file, never the key) and the config file's path.
2. What the user wants
From what they typed (nothing: show the status and ask; "off" or "on": do that), or ask in one message:
- Do they have a Jev API key? If not, say where one comes from (TypeSafe's console, https://console.typesafe.ai/keys) and stop.
- Where is it set? The name of the variable that holds it, and whether it is in the environment or in an env file (the file's path; it must be one git ignores). Never ask for the key itself; if one is pasted, don't repeat it, and say it should be rotated.
- For which repos? One key for everything, or a key per group of repos when they belong to separate accounts (then every group is named, and a repo no entry names has the judge off).
3. Write the config
The config file is the path jev status printed (first-pass/jev.json in the Claude Code
config folder, ~/.claude unless CLAUDE_CONFIG_DIR says otherwise). Read it first if it
exists and change only what the user asked:
One key for everything:
json{ "keys": [{ "env": "TYPESAFE_API_KEY" }] }
A key per account:
json{ "keys": [ { "env": "COMPANY_A_TYPESAFE_API_KEY", "file": "/abs/path/company-a/.env.local", "repos": ["/abs/path/company-a", "/abs/path/company-a-site"] }, { "env": "COMPANY_B_TYPESAFE_API_KEY", "repos": ["/abs/path/company-b"] } ] }
env: the variable's name. It is read from the environment first, then fromfile.file: optional, an env file holdingNAME=value.repos: absolute paths. The deepest one that holds the folder wins, and a checkout of a named repo elsewhere (a worktree, a clean checkout in the temp folder) counts as that repo, even inside a folder named for another key. An entry withoutreposcovers every folder, and is allowed only as the only entry: with separate accounts, a folder no entry names has the judge off, never another account's key.- With separate accounts, name each repo's own folder. Never name a folder that also holds another account's repos (the main folder above them all, say): a named folder covers every folder inside it, new repos included, so a repo cloned there later would get that key.
"off": trueswitches the judge off everywhere and keeps the rest."model"pins a version (defaultjev-latest); pin one when you have tuned against it."url": only to send somewhere other than TypeSafe's endpoint (https, or this machine for a test server);jev statusthen shows it. Leave it out otherwise, and remove one the user did not ask for.- Before writing a
filepath, check git ignores it:git -C <its repo> check-ignore -q <file>. If it is not ignored, say so and don't use it.
4. Check it works
Run jev status <repo> again for each group, then once per key:
node "${CLAUDE_SKILL_DIR}/../../scripts/cli.mjs" jev test <repo>
It sends one made-up finding (no code, no customer data) and prints Jev's pick and how sure it was. A refused key or no answer prints why.
5. Report
Jev judge: <on for <repos> (key from <NAME>, in the environment | in <file>) | off, <why>>, one line per key Verified: jev test → <Jev's pick and confidence, or the error>, one line per key Config: <the file, and what changed>


