Skip to content

Quickstart

The samples on this site share a small support-desk domain: a Ticket, a few Engineers, and three handlers. Nothing in it is specific to jevlish.

The shared domain
support.ts
// Shared domain for the samples. The site imports these files as text, so
// each sample shows exactly the code that typechecks against the library.
export interface Ticket {
id: string;
status: "open" | "closed";
subject: string;
body: string;
}
export interface Engineer {
name: string;
expertise: string[];
recentWork: string;
}
export const ticket: Ticket = {
id: "T-1",
status: "open",
subject: "Export broken",
body: "Every PDF export fails with a spinner that never finishes. We cannot send invoices to clients this week.",
};
export const tickets: Ticket[] = [
ticket,
{
id: "T-2",
status: "open",
subject: "Logo blurry",
body: "The logo looks slightly blurry on my retina display. Everything works fine otherwise.",
},
{
id: "T-3",
status: "closed",
subject: "Login down",
body: "Nobody on our team can log in since this morning; every attempt returns a 500 error.",
},
];
export const engineers: Engineer[] = [
{ name: "Ada", expertise: ["billing", "payments"], recentWork: "Migrated invoicing to the new billing API." },
{ name: "Grace", expertise: ["exports", "PDF rendering"], recentWork: "Rewrote the PDF export worker queue." },
{ name: "Linus", expertise: ["auth", "SSO", "sessions"], recentWork: "Shipped SAML single sign-on." },
];
export const escalate = (t: Ticket) => `escalated ${t.id}`;
export const leave = (t: Ticket) => `left ${t.id}`;
export const review = (t: Ticket) => `queued ${t.id} for review`;
hero-decision.ts
import { given, means } from "jevlish";
import { escalate, leave, review, ticket, type Ticket } from "./support.js";
const blocked = means<Ticket>("the customer cannot complete their task")
.excluding("they can finish the task despite the inconvenience");
const isOpen = (ticket: Ticket) => ticket.status === "open";
const decision = await given(ticket)
.seenAs((t) => ({ subject: t.subject, body: t.body }))
.when(blocked)
.and(isOpen)
.do(escalate)
.otherwise(leave)
.whenUncertain(review);
decision.branch; // "do" | "otherwise" | "uncertain"

Line by line:

  • means<Ticket>("...") defines a meaning: a proposition the model judges about a ticket. .excluding("...") draws the boundary from the outside. It becomes the Noul’s criteria.false, so “search is slow but works” does not count as blocked.
  • given(ticket) names the subject. Everything after it is about that one ticket.
  • .seenAs((t) => ({ subject, body })) is what the model sees. Code predicates and handlers still receive the whole Ticket.
  • .when(blocked) states the condition. .and((t) => t.status === "open") refines it with a code predicate. If the predicate is false, the conjunction is false and no request is sent.
  • .do(escalate).otherwise(leave).whenUncertain(review) gives all three outcomes a handler. Without .whenUncertain() the branch cannot run, and awaiting it rejects.
  • await runs it. decision.branch names the handler that ran; decision.result is what it returned; decision.judgment.evidence is every request and answer behind it.
hero-queue.ts
import { from, scale } from "jevlish";
import { tickets, type Ticket } from "./support.js";
const disruption = scale<Ticket>("how much this disrupts the customer's work")
.from("Work continues; the problem is cosmetic")
.to("The task cannot be completed");
const isOpen = (ticket: Ticket) => ticket.status === "open";
const queue = await from(tickets)
.where(isOpen)
.and("the message reports a failure in the product")
.rankedBy(disruption, "highest first")
.take(10);
queue.accepted; // passed both checks, highest score first
queue.uncertain; // missed the threshold on the Noul or the score
queue.rejected; // resolved false
  • scale<Ticket>("...").from(low).to(high) defines a scale: ordered situations, two to ten of them. The model returns a position along them, not a yes or no.
  • from(tickets) names the collection. .where(...) and .and(...) filter it with the same three kinds of condition given accepts: a code predicate, a string, or a meaning.
  • .rankedBy(disruption, "highest first") sends the filter and Score question together for each ticket not rejected by code, then sorts accepted tickets locally. .take(10) limits the returned list; it does not reduce how many tickets are judged.
  • The result has three buckets. Every ticket lands in exactly one. uncertain is not a soft reject: it is the tickets the policy would not decide, kept where you can see them.

Replace await with .plan() on either expression and nothing is sent. The plan lists the requests that would go out, the state the model would see, and how many subjects code alone settled. See Running and planning.

The Support desk example uses this same domain in a complete pipeline, with commands to plan, run, trace, and measure it against labeled fixtures.