Skip to content
MrJev

Jevalyn

Rails-native decision layer with typed results, guardrails, a router and test helpers.

View on GitHub →

Hands-on review

Decisions as classes, validated when the app boots, with a confidence threshold and a mock mode that never opens a connection.

Good for

  • Rails apps that want judgments as reviewable classes, not scattered calls
  • A per-decision confidence threshold with `certain?` on the result
  • Tests that cannot reach the network, with stubs per question

Watch out for

  • The default state for a model is `as_json` — every column, unless you override it
  • Three commits, 0.1.0, one author, published two days ago
  • A guardrail is only as good as the criteria you write for it

Tested Sep 21, 2026 at 0567d10169be · Ruby 3.3 in Docker; its 167 specs, and live decisions against the real API

How we reviewed this: we installed the gem from the repository in Docker on Ruby 3.3, ran its 167 specs, and defined the README’s own triage decision to run live against the real API, including a stricter threshold on a deliberately meaningless input.

What it does

A decision is a class. The questions are declared, typed and validated when the class body runs:

class SupportTriage < Jevalyn::Decision
  question :urgent,     type: :noul,   instructions: "Does this convey urgency?",
           criteria: { true: "Explicitly time-sensitive", false: "No urgency expressed" }
  question :department, type: :choice, instructions: "Which team should handle this?",
           criteria: { billing: "Payments, invoicing, refunds", technical: "Bugs, outages", sales: "Pricing, upgrades" }
  question :severity,   type: :score,  instructions: "How severe is this issue?",
           criteria: ["trivial", "minor", "major", "critical"]
  confidence_threshold 0.75
end

Ours, live, on a refund complaint:

urgent:     0.9
department: :billing
severity:   1.96
certain?:   true

Put the same class on a meaningless input with confidence_threshold: 0.99 and certain? comes back false while the answers still arrive — so the branch is yours to write, with the model’s hesitancy in a boolean rather than buried in a float. uncertain_questions names which ones fell short.

Declaring questions in a class body has a second effect worth naming: a rubric with eleven score levels, or a choice with no criteria, fails when the application boots rather than at the first request on a Friday. Generators (rails g jevalyn:decision, :guardrail, :install) put them where a Rails developer expects.

The parts beyond decisions

Guardrails are a decision narrowed to “should this be allowed through”, which is the shape most people want when they wire a model into an agent or a job.

The router picks a handler the same way, and background evaluation hands the call to Active Job so a controller does not wait on it.

Testing is the part we would copy. TypeSafe has no sandbox key, so mock_mode is local: with it on, the client never opens a connection. Requiring jevalyn/testing/rspec turns it on for the suite, resets stubs between examples, and lets you stub per question. A suite that cannot accidentally spend money is the right default for this kind of library.

What leaves your app

Anything you pass: a string, a hash, an array of messages, or an Active Record model. For a model the default is as_json, which the README itself flags — “every column, wasteful in tokens and careless with data that did not need to leave the building” — and recommends defining #jevalyn_state to send the fields the decision actually needs.

We like that the warning is in the documentation rather than in a reviewer’s write-up. Take it seriously: a Ticket with a customer_notes column will ship it with everything else if you do not.

Maintenance

Created 20 September, three commits, one author, MIT, published as jevalyn 0.1.0, CI green, 167 specs passing. The documentation is longer than the code, which at this age is usually a warning sign and here is not: everything documented that we tried, worked, including the threshold override and the uncertainty reporting.

Verdict

If you are adding judgment calls to a Rails app and expect them to outlive the sprint, this is the shape to use: named classes, typed questions, validation at boot, a threshold you can tighten per call, and tests that cannot reach the network. It asks for more ceremony than Hunch and gives you more structure in return; which is right depends on whether the decision is a one-liner in a validation or a thing your team will argue about later.

Override jevalyn_state before you point it at a model, and treat 0.1.0 as 0.1.0.

For the lighter Ruby option see Hunch; for the same idea in TypeScript, Advocaat.

See how it compares with other tools in Best Jev tools, tested hands-on.

Review updated Sep 21, 2026. Numbers quoted from the project are its author's own; we don't publish our own measurements of Jev.

More in Libraries & Integrations

agentrun

★ 423▲ 13

Parcha-ai/agentrun

A workflow DSL for agents with a Jev package for the steps that are decisions rather than generation.

TypeScript

switch

★ 420▲ 170

osolmaz/switch

TypeScript framework for decision-model harnesses: your program offers a short list of next steps and the model picks one at a time until it can answer, with chess, wikirace and rubric-judge examples run on Jev.

TypeScript

Ten Levels of Jev

★ 264▲ 10

disler/ten-levels-of-jev

Thirty worked uses arranged in ten levels, from one if statement to an agent that reaches for Jev itself, with a video walkthrough.

TypeScriptReviewed

Get new Jev projects every week

New Jev releases, pricing changes, and the best new projects, once a week. No spam; unsubscribe anytime.

Powered by Buttondown. See our privacy policy.