npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

jev-kit

v0.1.30

Published

An agent-first CLI for TypeSafe Jev decisions.

Readme

jev-kit

npm License: MIT

Agent-first CLI for TypeSafe Jev — for Cursor, Claude Code, Codex, Pi, and subagents.

Pipe logs, diffs, or files in. Ask Noul, Choice, or Score questions. Get official JSON on stdout. The agent (or jq) decides what to do next.

  COMMAND 2>&1  ──►  jev-kit  ──►  TypeSafe Jev  ──►  JSON  ──►  agent / jq

Yes: pipes · mixed questions in one call · probabilities preserved · System One via @typesafe-ai/sdk

No: chat model · review/validate commands · running Choice labels as shell · replacing tests or lint


Quickstart

Node 22+ · a TypeSafe API key from console.typesafe.ai/keys

npm install -g jev-kit

Set your API key. Use either option:

Option 1: save the key to ~/.jev-kit/config.json. The command checks the key, then saves it.

jev-kit set-key

Option 2: set the key in your terminal. This takes precedence over a saved key.

export TYPESAFE_API_KEY="your-key"

Check the setup. This prints the version, Node, key source, model, and API URL, then checks the key with TypeSafe:

jev-kit doctor

Then:

jev-kit --help
jev-kit --version

How an agent uses it

  1. Run a normal shell command (test, diff, cat file).
  2. Pipe output into jev-kit with --noul, --choice, or --score flags.
  3. Read stdout JSON; use stderr only if something failed locally.
  4. Route with your skill rules or jq — never eval an answer label.
git diff 2>&1 |
  jev-kit \
    --noul unrelated_changes \
      "Does this diff contain unrelated changes?" \
    --choice risk \
      "What is the highest review risk?" \
      --option behavior "Behavior may be wrong." \
      --option security "Auth, secrets, or trust boundaries changed." \
      --option compatibility "Public or persisted interface changed." \
      --option low "No material risk visible."
git diff 2>&1 |
  jev-kit ... |
  jq '.answers.risk.choice, .answers.unrelated_changes.noul'
Use jev-kit for bounded judgments over shell evidence. Read jev-kit --help first. Do not pass a model. The user sets JEV_KIT_MODEL; otherwise the model is jev-latest. Tests, lint, thresholds, and edits stay outside Jev. One narrow question per name; batch over the same state in one call. Preserve JSON and probabilities; use jq. Never execute Choice labels as shell. Failed tests/lint always mean revise.

Mental model

STATE + QUESTIONS → RESPONSE

| Part | Meaning | | --- | --- | | State | Evidence Jev inspects (pipe, --state, file, JSON, attachments) | | Question | Named Noul, Choice, or Score | | Response | answers.NAME in official JSON |

Model: JEV_KIT_MODEL (non-empty after trim) → jev-latest

Locked CLI

API schema · SDK · Noul · Choice · Score

TypeSafe does not publish a jev-kit CLI. This is the public interface:

COMMAND 2>&1 | jev-kit QUESTION...

jev-kit [STATE] QUESTION...

STATE:
  --state TEXT
  --state-file PATH
  --state-json JSON
  --attach NAME PATH              Repeatable. PATH is a file, or - for the pipe (once)

QUESTION:
  --noul NAME INSTRUCTIONS
    [--true-when TEXT]
    [--false-when TEXT]

  --choice NAME INSTRUCTIONS
    --option NAME DESCRIPTION     Repeatable

  --score NAME INSTRUCTIONS
    --level DESCRIPTION           Repeatable, ordered

Vocabulary

| Term | Meaning | | --- | --- | | State | Complete evidence every question evaluates | | State source | Exactly one of: pipe, --state, --state-file, --state-json | | Attachment | One exact text file, or the pipe with -, under attachments.NAME (with --state only) | | Question name | Key under answers in the response | | Policy | Caller-owned thresholds and routing |

Grammar rules

  1. Put state and attachments before the first primitive.
  2. Each new --noul, --choice, or --score starts the next question.
  3. Child flags belong only to their active primitive.
  4. Multi-word values are one quoted shell argument.
  5. Unique question names; Choice/Score need at least two criteria.
  6. All questions share one state and one SDK request.
  7. stdout is success JSON only; help and errors use stderr.
  8. Empty piped, literal, or file state fails before any API call.
  9. The pipe is read only when no state flag is given, or by one --attach NAME -.

Command patterns

| Goal | Pattern | | --- | --- | | Judge command output | COMMAND 2>&1 \| jev-kit QUESTIONS... | | Judge short text | jev-kit --state "..." QUESTIONS... | | Judge one text file | jev-kit --state-file PATH QUESTIONS... | | Judge structured data | jev-kit --state-json '{...}' QUESTIONS... | | Compare exact files | jev-kit --state "task" --attach NAME PATH... QUESTIONS... | | Pin a model | Set JEV_KIT_MODEL; unset uses jev-latest | | Ask several questions | Several primitive blocks in one invocation | | Read one answer | jq '.answers.NAME' on stdout |

flowchart TB
    G["Global flags"] --> Q1["Question 1"]
    Q1 --> Q2["Question 2"]
    Q2 --> QN["Question N"]
    QN --> R["One SDK request"]
    R --> O["One JSON response"]

State examples

Official state

Piped state

jev-kit follows the Unix rule of grep, cat, and diff: an explicit input wins, and - means the pipe.

| Command | State sent | | --- | --- | | npm test 2>&1 \| jev-kit --noul … | "<npm test output>" | | npm test 2>&1 \| jev-kit --state "Task" --noul … | "Task" (pipe ignored) | | npm test 2>&1 \| jev-kit --state "Task" --attach tests - --noul … | {"task":"Task","attachments":{"tests":"<npm test output>"}} | | rg -l expiry src \| while read -r f; do jev-kit --state "Task" --attach file "$f" --noul …; done | {"task":"Task","attachments":{"file":"<text of $f>"}} per file |

npm test 2>&1 | jev-kit --state "Task: fix session expiry handling." --attach tests - --noul failed 'Does `attachments.tests` show a failing test?'

< file and heredocs act like a pipe. With a state flag and no -, jev-kit never reads stdin, so it never waits on an open pipe and never consumes a loop's input. A file literally named - is ./-.

Literal state

jev-kit \
  --state "The customer was charged twice and requests a refund." \
  --noul refund_requested \
    "Does the customer request a refund?"

File state

jev-kit \
  --state-file bug-report.txt \
  --score bug_severity \
    "How severe is the reported issue?" \
    --level "Cosmetic; no impact to functionality" \
    --level "Broken or degraded feature, but workaround exists" \
    --level "Blocking issue; no workaround exists"

Example file contents:

The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.

JSON state

jev-kit \
  --state-json '{
    "ticket": {
      "subject": "Duplicate charge",
      "messages": [
        {"from": "customer", "text": "I was charged twice for order A-104. Please refund the duplicate."},
        {"from": "support", "text": "We are checking the charges."}
      ]
    },
    "order": {
      "id": "A-104",
      "charges": [
        {"amount_usd": 49, "status": "captured"},
        {"amount_usd": 49, "status": "captured"}
      ]
    },
    "refund_policy": "Duplicate charges are eligible for a refund."
  }' \
  --noul refund_requested \
    'Does `ticket.messages[0].text` request a refund?' \
  --noul policy_supports_refund \
    'Does `refund_policy` support the refund requested in `ticket.messages[0].text`, given `order.charges`?'

Attachments

--attach loads exact UTF-8 text files into object state. See State and citation check.

jev-kit \
  --state "Task: fix refresh-token rotation after session expiry." \
  --attach file src/auth/refresh.ts \
  --noul relevant 'Is `attachments.file` materially relevant to `task`?'

Assembled state shape:

{
  "task": "Task: fix refresh-token rotation after session expiry.",
  "attachments": {
    "file": "…file contents…"
  }
}

To rank several files, make one call per file and sort in the shell:

for f in src/auth/session.ts src/auth/refresh.ts src/http/cookies.ts tests/auth/refresh.test.ts; do
  jev-kit \
    --state "Task: fix refresh-token rotation after session expiry." \
    --attach file "$f" \
    --noul relevant 'Is `attachments.file` materially relevant to `task`?' |
    jq -r --arg f "$f" '"\(.answers.relevant.noul)\t\($f)"' &
done | sort -rn

Tip: One file per call keeps each request small and free of other files. Unrelated text in the state lowers accuracy (Jev 1.13 jaggedness), and one request holds at most 32k tokens of state (Models). This follows the official one-question-per-candidate pattern in Re-ranking. Attach several files to one call only when a question must compare them, such as a diff and its test output.

Folder, glob, and path-regex collection are deferred; see architect.md.

Question examples

Primitives overview

Noul

Probability of yes, 0–1 at answers.NAME.noul. Optional --true-when / --false-when.

printf '%s\n' "The customer was charged twice and wants their money back." |
  jev-kit \
    --noul refund_requested \
      "Does the customer request a refund?" \
      --true-when "The customer asks for money or credit back." \
      --false-when "The customer does not request a refund or credit."

Choice

jev-kit \
  --state "The checkout test hangs in CI. Diagnose it; do not change code." \
  --choice skill \
    "Which skill best matches the request?" \
    --option diagnosing_bugs "Investigate without automatically implementing a fix." \
    --option tdd "Implement behavior test-first." \
    --option code_review "Review an existing change." \
    --option none "No listed skill fits."

Returns choice, full probabilities, and confidence.

Score

jev-kit \
  --state-file compiler-output.txt \
  --score actionability \
    "How actionable is this compiler output?" \
    --level "No useful diagnostic evidence." \
    --level "Names an affected area." \
    --level "Shows a useful location or symptom." \
    --level "Directly identifies the likely cause."

Returns weighted score, per-level probabilities, legend, and confidence.

Mixed primitives

jev-kit \
  --state-file resume.txt \
  --score technical_depth \
    "How deep is the demonstrated technical experience?" \
    --level "Basic familiarity." \
    --level "Independent implementation." \
    --level "Deep production ownership." \
  --noul mentorship \
    "Does the candidate demonstrate mentoring experience?" \
  --choice primary_profile \
    "Which profile is the strongest match?" \
    --option frontend "Primarily frontend engineering." \
    --option backend "Primarily backend engineering." \
    --option full_stack "Substantial frontend and backend ownership." \
    --option other "None is a strong match."

Response

API response · Confidence

jev-kit prints the official SDK result without a workflow wrapper:

{
  "model": "jev-1.13.0",
  "answers": {
    "refund_requested": {
      "type": "noul",
      "noul": 0.99
    },
    "department": {
      "type": "choice",
      "choice": "billing",
      "probabilities": {
        "billing": 0.96,
        "technical": 0.03,
        "other": 0.01
      },
      "confidence": 0.94
    },
    "frustration": {
      "type": "score",
      "score": 1.6,
      "legend": {
        "0": "Calm",
        "1": "Frustrated",
        "2": "Very angry"
      },
      "probabilities": {
        "0": 0.05,
        "1": 0.3,
        "2": 0.65
      },
      "confidence": 0.78
    }
  },
  "usage": {
    "input_tokens": 312,
    "output_tokens": 48
  }
}

| Path | Meaning | | --- | --- | | .answers.NAME | Typed answer for question NAME | | .answers.NAME.noul | Probability of yes | | .answers.NAME.choice | Highest-probability Choice label | | .answers.NAME.probabilities | Full Choice or Score distribution | | .answers.NAME.score | Probability-weighted Score | | .answers.NAME.confidence | Choice/Score certainty from distribution |

Agent quality gates

LLM guardrails · Composite scoring

Final-answer grounding: exact user request + draft answer + inspected evidence → send, revise, inspect more, abstain, or escalate.

Code-change handoff: deterministic checks first, then request + diff + check output + changed source. Failed checks always mean revise.

flowchart TB
    W["Agent work"] --> D["Deterministic checks"]
    D -->|fail| R["Revise"]
    D -->|pass| C["Code semantic gate"]
    C -->|pass| F["Final answer grounding"]
    C -->|revise| R
    C -->|escalate| H["Human review"]
    F -->|send| U["User"]
    F -->|revise| R
    F -->|inspect more| W
    F -->|escalate| H

Configuration

| Setting | Source | | --- | --- | | API key | TYPESAFE_API_KEY if set, otherwise the key saved by jev-kit set-key. There is no key flag. | | Saved key | $XDG_CONFIG_HOME/jev-kit/config.json when set, otherwise ~/.jev-kit/config.json, mode 0600 | | Model | JEV_KIT_MODEL when non-empty after trim, otherwise jev-latest |

There is no model flag. Pin a version by setting JEV_KIT_MODEL=jev-1.13.0. TYPESAFE_DEFAULT_MODEL is not read.

Logs

One JSON line per run in ~/.jev-kit/logs/. See docs/LOGGING.md.

CI

Pushes and pull requests to main and develop run GitHub Actions on Node 22 and 24:

npm ci → lint → typecheck → npm run test:coverage → npm pack → install the tarball → jev-kit --version, --help

npm run test:coverage compiles with tsc, then runs node:test against dist/ under c8. Those tests do not use TYPESAFE_API_KEY and do not call the TypeSafe API. They also fail when --help names a flag outside the locked interface, or README.md, architect.md stops naming one. On a pull request, CI warns without failing when src/ changes and test/ does not. Publish stays manual — see RELEASE.md.

Dependabot opens weekly PRs against develop for outdated npm and GitHub Actions dependencies; each still goes through the CI checks above before merge.

Errors

No success JSON on stdout; one diagnostic on stderr; non-zero exit; no API call when local validation fails.

jev-kit: E_INPUT: attachment "tests" is empty

| Exit | Code | Meaning | | --- | --- | --- | | 0 | — | Success JSON on stdout | | 2 | E_USAGE | Invalid flags or question grammar | | 3 | E_INPUT | Empty, missing, binary, or oversized state or attachment | | 4 | E_CONFIG | No API key (run jev-kit set-key), set-key could not save a key, or TypeSafe rejected the key in set-key or doctor | | 5 | E_API | TypeSafe API or network failure | | 70 | E_INTERNAL | Unexpected failure |

See architect.md.

Report a bug

jev-kit doctor

Open an issue at github.com/nikheal25/jev-kit/issues. Paste the doctor output, the command you ran, its stderr, and its exit code. Report security problems through SECURITY.md instead.