Skip to content
Back to Blog

Jev Alternatives in 2026: Decision Models and a TypeScript SDK That Lets You Switch

New to decision models? Start with What is a decision model?

Try it online (sign-in required): System One demos

The short list (October 2026)

No rankings here. Each option gets a "best for" line instead.

Hosted models (the vendor trains and hosts it; you call its API)

  • Jev: POST /v1/systemone, text-only input. Best for: the reference implementation of the Choice / Score / Noul format. system-one.dev offers the Jev model from TypeSafe.
  • OpenAI Decisions API: POST /v1/decisions, currently only gpt-6-luna, in public beta, accepts text and images. Best for: teams already on OpenAI that need image inputs.
  • Microsoft-Decision-1: deployed in Microsoft Foundry. Microsoft says it is post-trained from Qwen3.5-9B. Best for: teams on Azure that want the model in their own Foundry resource. See Microsoft-Decision-1.
  • Clef / Clef Flash: follows the POST /v1/systemone format and reads on system-one.dev: text and images. Best for: multimodal inputs. system-one.dev offers Clef and Clef Flash.

Open weights and open re-implementations (run the model on your own hardware)

  • Clef open weights: Clef and Clef Flash weights are published on Hugging Face. Best for: keeping data on your own infrastructure.
  • EdgeJev (Apache-2.0): packages open re-implementations (laya, kev, NanoJev, PlayJev and others) into a convert → quantize → deploy flow that runs offline on CPU and serves POST /v1/systemone locally. The project says "data never leaves the machine". Best for: offline experiments.
  • Standalone re-implementations such as jev-clone also exist. All of them state they are not affiliated with Jev's developer.

SDK layer (not a model; sits between your code and the services above)

  • System One SDK (this site): define Choice / Score / Noul questions in TypeScript and connect to different model services through adapters. Best for: comparing or switching models without rewriting question definitions.

Open-source SDK ≠ self-hostable model. System One open-sources the SDK; it doesn't ship downloadable model weights.

Why lock-in happens: request format, question definitions, thresholds

The lock-in risk usually isn't which API you call. It's that your question definitions get written in one vendor's request format. The official docs show two different shapes:

| | Jev / Microsoft-Decision-1 / Clef | OpenAI Decisions API | | --- | --- | --- | | Input field | state (string or JSON) | input (string, or a user message with text and images) | | Questions | questions is an object keyed by your question IDs | questions is an array; each question has a name | | Yes/no | type: "noul" | type: "predicate" | | Options and levels | both in criteria (object for Choice, ordered array for Score) | Choice in choices: [{ value, description }], Score in levels: [{ label, description }] |

On top of that, confidence is computed differently by each provider, so a threshold tuned on Jev can't be reused as-is on Clef or GPT-6 Luna Decisions.

To stay free to switch, guard three things:

  1. Question definitions: questions, options and rubric levels live in your code, not scattered across a vendor console or request bodies.
  2. Thresholds and business rules: policies like "below this score, send to a person" belong to your application and must be revalidated when you switch.
  3. The call layer: switching models should only change the adapter and credentials.

Every vendor also publishes self-reported "best" results, and those claims can't be checked against each other. Being able to compare several backends on your own labelled data is the real benefit of not being locked in.

Write once, switch backends with the System One SDK

This code is the dev team's example (examples/decision-articles/02-swappable-provider.ts). Questions, the rubric and the action threshold all live in this one file. Switching backends only swaps the adapter and credentials:

  • hosted: the System One hosted API (@system-one-ai/adapter-system-one). system-one.dev offers Jev, Clef Flash and Clef; get exact model IDs from GET /v1/models.
  • The other ProviderKind values use the other adapters imported in the file, each with that service's own credentials.
ts/**
 * Article 2 — Keep the problem definition in your code so the provider is swappable.
 *
 * The SDK is an open-source TypeScript toolkit. Questions, rubrics, and
 * action thresholds live in this file. Only the adapter / credentials change.
 *
 * Adapters this repository actually depends on:
 *   - @system-one-ai/adapter-system-one  → System One hosted API or TypeSafe HTTP
 *   - @system-one-ai/adapter-openrouter  → OpenRouter Decisions
 *   - @system-one-ai/adapter-cloudflare  → Cloudflare REST (needs accountId)
 *
 * `@system-one-ai/adapter-vercel` is mentioned in docs but is not a dependency
 * of this repo, so this file does not import it.
 *
 * Hosted credits apply only to POST /v1/systemone. TypeSafe, OpenRouter, and
 * Cloudflare bill on their own accounts. Adapter support is not the hosted
 * model catalog — use GET /v1/models for what this site currently hosts.
 */
import { createSystemOne, choice, score, booleanQuestion } from '@system-one-ai/core';
import type { EvaluationClient } from '@system-one-ai/core';
import { systemOneAdapter } from '@system-one-ai/adapter-system-one';
import { openRouterAdapter } from '@system-one-ai/adapter-openrouter';
import { cloudflareAdapter } from '@system-one-ai/adapter-cloudflare';
import { createFetchTransport } from '@system-one-ai/transport-fetch';

/** Application-owned problem definition. Do not move these labels into the provider dashboard. */
export const reviewQuestions = {
  team: choice('Choose the team that should review this message.', {
    billing: 'Payments and refunds',
    support: 'Technical issues',
    review: 'More information or a person is required',
  }),
  completeness: score('How completely does the draft reply address the message?', [
    'Does not address the message',
    'Partially addresses the message',
    'Fully addresses the message',
  ]),
};

/** Application-owned policy. Unknown or missing scores are unresolved, not a pass. */
export const REVIEW_IF_SCORE_BELOW = 1.5;

export type ProviderKind = 'hosted' | 'typesafe' | 'openrouter' | 'cloudflare';

export function createProviderClient(kind: ProviderKind): EvaluationClient {
  const transport = createFetchTransport();
  if (kind === 'hosted') {
    const apiKey = process.env.SYSTEM_ONE_API_KEY;
    const baseURL = process.env.SYSTEM_ONE_BASE_URL;
    const model = process.env.SYSTEM_ONE_MODEL;
    if (!apiKey || !baseURL || !model) {
      throw new Error('Hosted client needs SYSTEM_ONE_API_KEY, SYSTEM_ONE_BASE_URL, SYSTEM_ONE_MODEL.');
    }
    return createSystemOne({
      apiKey, baseURL, model, adapter: systemOneAdapter, transport, maxRetries: 0, timeoutMs: 30_000,
    });
  }
  if (kind === 'typesafe') {
    const apiKey = process.env.TYPESAFE_API_KEY;
    const model = process.env.TYPESAFE_MODEL;
    if (!apiKey || !model) throw new Error('TypeSafe client needs TYPESAFE_API_KEY and TYPESAFE_MODEL.');
    return createSystemOne({
      apiKey,
      baseURL: 'https://api.typesafe.ai/v1',
      model,
      adapter: systemOneAdapter,
      transport,
      maxRetries: 0,
      timeoutMs: 30_000,
    });
  }
  if (kind === 'openrouter') {
    const apiKey = process.env.OPENROUTER_API_KEY;
    const model = process.env.OPENROUTER_MODEL;
    if (!apiKey || !model) throw new Error('OpenRouter client needs OPENROUTER_API_KEY and OPENROUTER_MODEL.');
    return createSystemOne({
      apiKey, model, adapter: openRouterAdapter, transport, maxRetries: 0, timeoutMs: 30_000,
    });
  }
  const apiKey = process.env.CLOUDFLARE_API_TOKEN;
  const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
  const model = process.env.CLOUDFLARE_MODEL;
  if (!apiKey || !accountId || !model) {
    throw new Error('Cloudflare REST client needs CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_MODEL.');
  }
  return createSystemOne({
    apiKey,
    model,
    adapter: cloudflareAdapter({ accountId }),
    transport,
    maxRetries: 0,
    timeoutMs: 30_000,
  });
}

export type ReviewNext = 'revise_draft' | 'keep_draft' | 'needs_review';

export function applyReviewPolicy(completeness: number | null | undefined): ReviewNext {
  if (completeness == null || Number.isNaN(completeness)) {
    return 'needs_review';
  }
  return completeness < REVIEW_IF_SCORE_BELOW ? 'revise_draft' : 'keep_draft';
}

export async function reviewDraft(
  client: EvaluationClient,
  input: { message: string; draft: string },
) {
  const result = await client.evaluate({
    state: { message: input.message, answer: input.draft },
    questions: reviewQuestions,
  });
  return {
    team: result.answers.team.choice,
    completeness: result.answers.completeness.score,
    next: applyReviewPolicy(result.answers.completeness.score),
    model: result.model,
  };
}

async function main() {
  const kind = (process.env.EXAMPLE_PROVIDER ?? 'hosted') as ProviderKind;
  const allowed: ProviderKind[] = ['hosted', 'typesafe', 'openrouter', 'cloudflare'];
  if (!allowed.includes(kind)) {
    throw new Error(`EXAMPLE_PROVIDER must be one of ${allowed.join(', ')}.`);
  }
  const decision = await reviewDraft(createProviderClient(kind), {
    message: 'I was charged twice for the same order.',
    draft: 'Please send your order number so we can review both charges.',
  });
  console.log(JSON.stringify(decision, null, 2));
}

if (process.argv[1] && import.meta.url.endsWith(process.argv[1].split(/[\\/]/).pop() ?? '')) {
  main().catch((error: unknown) => {
    console.error(error instanceof Error ? error.message : error);
    process.exitCode = 1;
  });
}

What to notice (all from the example's comments and README):

  • The application owns the questions. The comment on reviewQuestions says not to move these labels into a provider dashboard.
  • The application owns the threshold. REVIEW_IF_SCORE_BELOW = 1.5 is app policy. applyReviewPolicy() has three outcomes: a missing (undefined/null) or NaN score returns needs_review; a score under 1.5 returns revise_draft; anything else returns keep_draft. Missing or unknown scores count as unresolved, never as a pass.
  • Billing is separate. System One credits only apply to the System One hosted API (POST /v1/systemone). Third-party services bill on their own accounts.
  • Adapter support isn't the hosted catalog. For what this site hosts right now, use GET /v1/models. A full model ID selects a model, but it can't pin a model version.
  • @system-one-ai/adapter-vercel appears in the docs but isn't a dependency of this repo, so the example doesn't import it.

Choose a backend with EXAMPLE_PROVIDER and provide that service's own credentials. Those calls don't use System One credits.

The @system-one-ai/core npm readme also notes that requests can carry images, but only adapters that declare supportsImages: true accept them. Other adapters throw an error instead of silently downgrading the image to text.

Self-hosting checklist

To keep data inside your network you need a model you can run yourself, not just an open-source SDK. The options we could verify are the Clef open weights and open re-implementations such as EdgeJev. Check:

  • Data residency: EdgeJev says inference makes no network requests, has no telemetry, and state and questions never leave the machine (project claim). For hosted services, read each vendor's terms: OpenAI's docs mention ZDR for eligible customers, and Jev's docs say customer requests aren't used for training.
  • Accuracy and calibration: the only numbers for open re-implementations are self-reported. EdgeJev publishes its own results in its README along with the test conditions. jev-clone's README says existing public re-implementations open-source the "interface shape" but none has been evaluated for calibration (project claim). Test on your own labelled data.
  • Language: The Jev docs say Jev's primary training language is English. Test non-English content whichever option you choose.
  • Latency: every published latency figure, from projects or vendors, is self-measured. We haven't measured any.
  • Ops cost: conversion, quantization, deployment, monitoring and upgrades are your job. For example, EdgeJev's conversion step needs torch and a network connection to download weights before it can run offline.
  • SDK connection: EdgeJev serves POST /v1/systemone, the same path the System One hosted API uses ({baseURL}/systemone). Whether the System One SDK connects to such a self-hosted server directly hasn't been verified, and we make no promise.

How to choose: a simple order

  1. Can data leave your network? If not, look at open weights or re-implementations and budget time to validate calibration yourself.
  2. Do you need images? Per the official docs, Jev is text-only; the OpenAI Decisions API and Clef accept images.
  3. Do you want to try several? Use an SDK layer and compare them on one set of question definitions.
  4. Whatever you choose: keep questions and thresholds in your code, and revalidate thresholds on the same labelled data after any switch.

No latency or accuracy columns: vendors and projects only publish self-measured numbers, and we haven't measured any.

Related reading

Comparison table (checked 2026-10-11)

OptionTypeHostingInputsFormat and question typesProbabilitiesPublic price
Jev (TypeSafe)Source: TypeSafe: Models · Verified 2026-10-11Hosted modelHosted (TypeSafe API); self-host: not publishedText only: strings, JSON objects, text arraysSource: TypeSafe: Models · Verified 2026-10-11POST /v1/systemone; Choice / Score / NoulSource: TypeSafe: System One · Verified 2026-10-11Yes: Choice/Score probabilities + confidence; Noul P(yes)Source: TypeSafe: Confidence · Verified 2026-10-11$0.042 per 1M input tokens, output freeSource: TypeSafe: Models · Verified 2026-10-11
OpenAI Decisions APISource: OpenAI: Decisions · Verified 2026-10-11Hosted modelHosted, public beta, gpt-6-luna only; self-host: not publishedText, images, or both (inline base64)POST /v1/decisions; predicate / choice / score (OpenAI's own format)Yes: predicate probability; choice/score probabilities + confidence$0.10 per 1M input tokens, no output chargeSource: OpenAI: Decisions · Verified 2026-10-11
Microsoft-Decision-1Source: Microsoft launch blog · Verified 2026-10-11Hosted modelHosted in Microsoft Foundry; self-host: not publishedText or JSON stateSource: Microsoft Learn · Verified 2026-10-11{Foundry endpoint}/providers/microsoft/v1/systemone; noul / choice / score (state + questions + criteria)Yes: noul probability; per-option and per-level probabilities$0.042 per 1M input tokens, output freeSource: Microsoft launch blog · Verified 2026-10-11
Clef / Clef FlashHosted model + open weightsHosted; weights on Hugging Faceon system-one.dev: text and imagesFollows `POST /v1/systemone`; noul / choice / score, up to 64 questions per requestYes: noul probability; choice per-option probabilities + confidence; score per-levelOn system-one.dev: Clef Flash 3 credits, Clef 6 credits per block per question
EdgeJev (open re-implementation)Source: EdgeJev README · Verified 2026-10-11Open re-implementationSelf-hosted, offline on local CPU, Apache-2.0; not affiliated with TypeSafeDepends on the chosen backend (project claim)Local POST /v1/systemone; choice / score / noulYes: example returns probabilities + confidence (project claim)No API fees when run locally; you pay for hardware and ops
System One SDK (this site)Source: npm @system-one-ai/core · Verified 2026-10-11SDK layerOpen-source SDK; system-one.dev offers Jev, Clef Flash and Clef; no downloadable weightsSource: System One docs · Verified 2026-10-11Depends on the connected service; images only on adapters declaring supportsImageschoice / score / booleanQuestion defined in codeSource: System One SDK docs · Verified 2026-10-11Yes: Choice probabilities + confidence, Score adds a legend, Noul P(true)Source: System One primitives · Verified 2026-10-11SDK is MIT-licensed. Hosted API: prepaid credits, see pricing; third parties bill separatelySource: System One pricing · Verified 2026-10-11

Frequently asked questions

Is there an open-source Jev alternative?
Two kinds: open weights, such as Clef and Clef Flash, and community re-implementations, such as EdgeJev and jev-clone. The community projects aren't affiliated with Jev's developer and their accuracy and calibration numbers are self-reported, so validate them on your own data.
Can I run it offline, with data never leaving my network?
Yes, but you need a model you can run yourself: downloaded open weights or a local server like EdgeJev (which says it runs fully offline). System One open-sources the TypeScript SDK, not a downloadable model, and whether the SDK can connect to a self-hosted server hasn't been verified.
Are open models accurate?
There's no neutral, shared benchmark yet. Projects and vendors publish self-measured numbers with different test sets, conditions and metrics, so they can't be compared directly. Compare candidates on your own labelled samples with the same question definitions.
Can I keep my thresholds when I switch models?
We don't recommend it. Confidence is calculated differently by each provider. Revalidate thresholds on the same labelled data after switching.
Which services can the System One SDK connect to?
The [SDK docs](https://docs.system-one.dev/en/docs/sdk) list four public adapters, including `@system-one-ai/adapter-system-one` (the System One hosted API). The docs note these are SDK integration options, not a list of what this site hosts and not official integrations. The example above uses three of them. For hosted models, check `GET /v1/models`.
How do prices compare?
See the table for public list prices. The System One hosted API uses prepaid credits: every 4KB is one block, and anything under 4KB still counts as one; cost = blocks × questions × the model's price per block. The [pricing page](https://system-one.dev/en/pricing) lists the credit packs, all one-time purchases with no auto-renewal. New accounts get 100 free credits on sign-up. Third-party services you call through the SDK bill you on their own accounts.