Skip to main content

jev-cli

A small CLI and stdio MCP server for TypeSafe Jev. Send text or JSON state, ask typed questions, and receive machine-readable noul, choice, or score answers.

The jev command is useful when application code needs a fast classification or judgment instead of generated prose. The jev-mcp command exposes the same judgments to MCP hosts over stdio.

Unofficial: This is an independent community project. It is not affiliated with, maintained by, or endorsed by TypeSafe AI.

Features

  • Supports all three Jev primitives: noul, choice, and score
  • Sends multiple questions in one request with run
  • Accepts text, JSON, files, and stdin
  • Emits compact JSON by default
  • Can print only the primary value for shell scripts
  • Uses structured stderr errors and meaningful exit codes
  • Ships a stdio MCP server, jev-mcp, in the same installation

Requirements

  • uv
  • An API key for the provider you use. The official TypeSafe API is the default.

uv installs a compatible Python 3.13 or later interpreter when needed.

Install

Install jev-cli from PyPI with uv tool. This keeps the commands in an isolated environment and makes both jev and jev-mcp available on your PATH. There is no optional extra to select; the MCP server is part of the normal installation.

uv tool install jev-cli

Verify that the command is available:

jev --version

Expected output:

jev 0.6.0

Authentication

The official TypeSafe API is the default provider. The recommended approach for automation is the TYPESAFE_API_KEY environment variable. It takes precedence over the credential file.

export TYPESAFE_API_KEY='your-api-key'
jev auth status

For local use, enter the key at the hidden prompt. auth set does not accept the key as a command-line argument, which keeps it out of process arguments and shell history.

jev auth set
jev auth status
jev auth test

Jev is also available through Vercel AI Gateway and OpenRouter. Select a provider per command with --provider, or set JEV_PROVIDER for the process. Each provider uses its own API key and default model.

Provider Option API key environment variable Default model
TypeSafe official official TYPESAFE_API_KEY jev-latest
Vercel AI Gateway vercel AI_GATEWAY_API_KEY typesafe-ai/jev
OpenRouter openrouter OPENROUTER_API_KEY typesafe/jev-1.13
Jev-compatible proxy custom JEV_API_KEY JEV_MODEL or jev-latest

Store and test a provider-specific key without exposing it in shell history:

jev auth set --provider vercel
jev auth test --provider vercel

jev auth set --provider openrouter
jev auth test --provider openrouter

Run the same judgment through another provider:

jev noul \
  --provider openrouter \
  --question 'Does this message express urgency?' \
  --state 'Please restore service today.' \
  --value

Omitting --provider continues to use the official TypeSafe API. --model can override the provider's default model.

For a proxy that implements the native Jev request and response contract, select custom and configure its endpoint separately. This keeps proxy credentials isolated from the built-in providers.

export JEV_PROVIDER=custom
export JEV_ENDPOINT='https://proxy.example.com/v1/systemone'
export JEV_API_KEY='your-proxy-api-key'
export JEV_MODEL='jev-latest' # optional

jev noul -q 'Is this urgent?' -s 'Restore service today.' --value

--endpoint can replace JEV_ENDPOINT for one command. The CLI sends JEV_API_KEY to that endpoint as a bearer token, so use only a trusted HTTPS endpoint.

For non-interactive automation, piping the key to jev auth set remains supported.

auth status reports only whether a key is available. auth test sends a minimal request to Jev and verifies that the key is accepted. Neither command prints the key.

The fallback credential path follows XDG conventions:

  • $XDG_CONFIG_HOME/jev-cli/credentials.json when XDG_CONFIG_HOME is set
  • ~/.config/jev-cli/credentials.json otherwise

The credential directory is created with mode 0700; the file is written atomically with mode 0600.

Quick start

--question and --state also accept the short forms -q and -s. --value has no short form.

Install the bundled Agent Skill

jev-cli currently bundles the jev-cli skill. Install it for the current project or globally:

jev install-skills
jev install-skills --global

Use --claude to target Claude's skill directory instead:

jev install-skills --claude
jev install-skills --global --claude

The command prints JSON. It refreshes only copies it previously installed and refuses to overwrite an unmanaged skill directory.

Ask whether a message expresses urgency. --value prints only the resulting probability from 0 to 1.

jev noul \
  --question 'Does this message express urgency?' \
  --state 'Please restore service today.' \
  --value

Example output:

0.98

Without --value, the command returns the complete API response as JSON, including model and token usage.

jev noul \
  --question 'Does this message express urgency?' \
  --state 'Please restore service today.' \
  --pretty

Question types

Noul: yes/no probability

Use noul for one focused yes/no judgment. The value is the probability that the answer is yes.

jev noul \
  --question 'Does this message request a refund?' \
  --state 'The integration is broken, but I do not want a refund.' \
  --value

Choice: select one option

Use choice when the answer must be one of a known set. Each option uses KEY=DESCRIPTION syntax.

jev choice \
  --question 'Which team should handle this?' \
  --state 'The payment integration keeps failing.' \
  -o 'billing=Payment, charge, or refund issues' \
  -o 'technical=Bugs or integration failures' \
  -o 'other=None of these' \
  --pretty

Score: evaluate ordered levels

Use score for an ordered scale. Levels are numbered from zero in the order supplied.

jev score \
  --question 'How frustrated is the customer?' \
  --state 'This has failed for three days. Please help.' \
  -l 'Calm' \
  -l 'Concerned but civil' \
  -l 'Very angry' \
  --value

Input formats

Standard input

Omit the state or pass - to read it from stdin. This is useful for pipelines and avoids putting sensitive input in shell history.

printf '%s' 'Please resolve this today.' | \
  jev noul --question 'Does this message express urgency?' --value

File input

Prefix a path with @ to read its contents.

jev noul \
  --question 'Does this document mention security risks?' \
  --state @document.txt \
  --value

JSON state

Use --json-state to parse the state as JSON. Instructions can refer to named fields.

printf '%s' '{"message":"Please respond today"}' | \
  jev noul \
  --question 'Does `message` express urgency?' \
  --json-state \
  --value

Batch questions

Jev evaluates questions independently against the same state. Use run to send a complete System One request and avoid one API call per question.

Create request.json:

{
  "state": {
    "message": "The payment integration has failed for three days. Please fix it today."
  },
  "model": "jev-latest",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle `message`?",
      "criteria": {
        "billing": "Payment, charge, or refund issues",
        "technical": "Bugs or integration failures",
        "other": "None of these"
      }
    },
    "urgent": {
      "type": "noul",
      "instructions": "Does `message` express urgency?"
    }
  }
}

Send it in one request:

jev run request.json --pretty

A request can also be piped through stdin:

cat request.json | jev run - --pretty

MCP server

jev-mcp is a stdio MCP server installed alongside jev. It exposes four tools that map to the CLI commands:

Tool Purpose Required inputs
noul One yes/no judgment with a probability state, question
choice One selection from a typed option map state, question, options
score One evaluation against ordered levels state, question, levels
run A complete multi-question System One request request

choice requires at least two options and score requires at least two levels; a smaller request is rejected as a tool error before any provider call.

Every argument is described in the published tool schemas, so a host can construct a call without reading this page. run takes one complete System One request; its questions keys become the answer keys in the response:

{
  "request": {
    "state": {"message": "The invoice is wrong again and I want a refund."},
    "questions": {
      "urgent": {"type": "noul", "instructions": "Does this need a reply today?"},
      "team": {
        "type": "choice",
        "instructions": "Which team should own this?",
        "criteria": {"billing": "Invoice or payment problem", "support": "Product or account problem"}
      },
      "anger": {
        "type": "score",
        "instructions": "How frustrated is the sender?",
        "criteria": ["Calm", "Annoyed", "Angry"]
      }
    }
  }
}

Request members this client does not know are forwarded to the provider unchanged.

Every tool also accepts the optional provider, model, and endpoint arguments. Authentication, provider selection, model defaults, endpoint resolution, and response normalization are the same as for jev, including JEV_PROVIDER and the credential store, so no separate setup is required.

Add the server to an MCP host with a minimal stdio entry:

{
  "mcpServers": {
    "jev": {
      "command": "jev-mcp"
    }
  }
}

Pass provider configuration through the host's environment block when the default is not wanted:

{
  "mcpServers": {
    "jev": {
      "command": "jev-mcp",
      "env": {
        "JEV_PROVIDER": "openrouter",
        "OPENROUTER_API_KEY": "your-api-key"
      }
    }
  }
}

state is sent verbatim over MCP. Unlike the CLI, - does not read stdin and a leading @ does not read a file, because stdin carries the MCP protocol frames. Read a file in the host and pass its content as state.

Invalid input and provider failures are returned as MCP tool errors and never include the API key. stdout carries MCP protocol frames only; diagnostics go to stderr.

Output and automation

The default stdout is one JSON object. Logs and structured errors go to stderr, so stdout can be piped directly into another program.

Use --value with noul, choice, or score when a script needs only the primary answer:

if awk 'BEGIN { exit !(ARGV[1] >= 0.9) }' \
  "$(jev noul --question 'Is this urgent?' --state 'Restore service today.' --value)"; then
  echo urgent
fi

Use --model to select another model available to the account:

jev noul --question 'Is this urgent?' --state 'Restore service today.' \
  --model jev-latest \
  --pretty

Exit codes

Code Meaning
0 Success
1 Unexpected API response or other error
2 Invalid arguments or input
3 Missing or rejected authentication
4 Connection, rate-limit, or transient server error

An error is emitted as JSON on stderr:

{"ok": false, "error": "TypeSafe API key is not stored; run: jev auth set"}

Scope and limitations

The jev command is a thin client for focused System One judgments. It does not generate prose, perform arithmetic, compare dates, or replace application-level validation. Keep deterministic work in code and use Jev for semantic judgments.

The CLI sends the supplied state and questions to the selected provider. Do not submit data that your organization is not permitted to send to that service.

License

MIT

Release files for jev-cli 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jev-cli 0.6.0
File Size Uploaded
jev_cli-0.6.0.tar.gz 24.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jev-cli 0.6.0
File Interpreter ABI Platform
jev_cli-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 44.8 kB

Release files / jev_cli-0.6.0.tar.gz

Download URL jev_cli-0.6.0.tar.gz
Size 24.4 kB
Tags Source
SHA-256 checksum
How to use checksums
639f6852cc6b33ed0ba717443594544dbcc574f9dff0a04fc44b8478f82cdd11
BLAKE2b-256 checksum
How to use checksums
50f35f4b0aebd8059ff259db39991d3ee3c018ceabede9fc2b312e2fc6a43f44
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / jev_cli-0.6.0-py3-none-any.whl

Download URL jev_cli-0.6.0-py3-none-any.whl
Size 20.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c970f79c33a82577cbc22e3c3b7a6bc161c1c7c2064285e964d7ff878223be1c
BLAKE2b-256 checksum
How to use checksums
d1605c4601e9ab100c8cfd562434f2dab3ad81adc0638328c17eed4d496649c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.6.2

2 release files

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page