jevscan

September 18, 2026 · View on GitHub

Typed onchain verdicts for EVM tokens. Paste a contract address, get ape / watch / avoid with calibrated probabilities, plus rug_risk, momentum, liquidity_health and fdv_stress scores. One System One decision loop, three interfaces: a library, a CLI built for pipelines, and an MCP server so your agents can use it too.

Robinhood Chain (4663) first-class, Base and everything DexScreener indexes as fallback.

$ jevscan 0x4ed4e862860bed51a9570b96d89af5e1b0efefed --chain base

$DEGEN  Degen  [base/uniswap]  \$0.004
liq \$2,514,000 · vol24 \$1,830,000 · fdv \$148,000,000 · age 540d · b/s 1.1

verdict: WATCH  p=0.472
rug_risk          ███░░░░░░░░░░░░░░░░░░░ 0.135
momentum          ███████████░░░░░░░░░░░ 0.512
liquidity_health  ██████████████████░░░░ 0.812
fdv_stress        ██████████░░░░░░░░░░░░ 0.464

jevscan-local-0.1 · 231ms · typed, no prose

Why

Software cannot act on "this token looks pretty risky tbh". It can act on {verdict: "avoid", p: 0.93}. Every trading bot, launch gate and portfolio script eventually reinvents a risk heuristic and hides it in a for-loop; jevscan pulls that decision out into the open, gives it the System One shape (state in, typed answers + probabilities out), and makes it pipeable.

The decision loop is honest about what it is: a deterministic, feature-based local engine by default, and the real TypeSafe jev endpoint the moment you export a key. Same questions, same output contract, zero code changes.

Install

git clone https://github.com/jevbook/jevscan
cd jevscan && npm install
npm link        # optional: makes `jevscan` available globally
npm test        # engine smoke test + one live scan

Node 18+ (uses global fetch). No API key required for the default engine.

CLI

jevscan <address> [--chain robinhood|base|ethereum|any] [--json]
jevscan <address> --assert ape [--min-p 0.6]     # exit 0 iff verdict matches
jevscan <a1> <a2> [...] --compare                # typed choice across tokens
cat addresses.txt | jevscan --stdin --json       # one JSON line per address
jevscan <address> --watch 60                     # rescan every 60s, log verdict changes

Exit codes are the whole point, grep-style:

codemeaning
0verdict ape, or --assert passed
1verdict watch
2verdict avoid
3no indexed liquidity anywhere
4bad input
5--assert failed

So a buy script becomes a one-liner gate:

jevscan $CA --assert ape --min-p 0.6 && ./buy.sh $CA

And a screening pipeline is just unix:

cat new_launches.txt | jevscan --stdin --json | jq -r 'select(.decision.answers[0].answer=="avoid") | .address'

Library

import { scanToken, compareTokens } from 'jevscan';

const scan = await scanToken('0x...', { chain: 'robinhood' });
// scan.decision.answers -> [{id:'scan_verdict', answer:'watch', distribution:{...}, probability:0.47}, ...]
// scan.features         -> liquidity, volume, fdv, pair age, buy/sell ratio, ...

const pick = await compareTokens(['0x...', '0x...', '0x...']);
// pick.answer -> {id:'best_token', answer:'$DEGEN', distribution:{'$DEGEN':0.61, '$OTHER':0.39}, ...}

MCP server

Give any MCP client typed onchain judgment:

claude mcp add jevscan -- node /path/to/jevscan/src/mcp.js

Tools: scan_token, compare_tokens, engine_info. Your agent stops guessing about tokens and starts quoting probabilities.

Using the real jev

export JEV_API_KEY=...            # TypeSafe System One key
export JEV_API_URL=...            # optional, defaults to api.typesafe.ai/v1/systemone

With a key set, the extracted features are serialized into a state string and the same five typed questions are asked of jev-latest. On any failure the local engine answers instead, and the output says so in decision.model. The output contract never changes.

Output contract

Every decision, local or remote, is the same shape:

{
  "model": "jevscan-local-0.1",
  "latency_ms": 1.8,
  "answers": [
    { "id": "scan_verdict", "type": "choice", "answer": "watch",
      "distribution": { "ape": 0.21, "watch": 0.47, "avoid": 0.32 }, "probability": 0.47 },
    { "id": "rug_risk", "type": "score", "answer": 0.135, "probability": 0.135 }
  ]
}

Limitations

  • Features come from DexScreener's public API: tokens without an indexed pair return a typed avoid with a note, not an error. Coverage on very new chains lags.
  • The local engine is a calibrated-looking heuristic, not a trained model. It is deterministic, inspectable (one file, src/engine.js) and deliberately conservative; it exists so the contract is usable today and swappable for real jev tomorrow.
  • None of this is financial advice. It is a typed opinion with a probability attached, which is already more than most financial advice.

Built for jevbook.dev, the typed social network. MIT.