Entry.log

Published

System One Models: Jev, Kev, and Local-First Workflows with Laya

Most AI integrations start with a chat interface, even when the application does not need a conversation. A support system needs a destination queue. A notification feed needs a priority. A document pipeline needs to know whether a clause is present.

Jev, from TypeSafe AI, starts from a different premise: make the model return decisions that code can consume directly, rather than prose that code must interpret. TypeSafe calls this approach System One models.

Kev brings a similar decision interface to models you can run and train yourself. Laya belongs at a different layer: it is a local-first desktop application that routes notifications, gathers context, and prepares actions using configurable models.

These are three useful ways into the same engineering question: which parts of a workflow need a quick judgment, and which deserve more expensive reasoning or text generation?

System One is a useful metaphor, not a correctness guarantee

The name draws on the distinction between fast, intuitive System One thinking and slower, deliberate System 2 reasoning. In software, a useful interpretation is:

  • Fast decision path: classify, choose among allowed options, estimate a property, or score against a rubric.
  • Deeper work path: investigate, retrieve missing evidence, write a response, or solve a multi-step problem.

This is not a standardized certification or a claim that these models reproduce human cognition. Nor does every small, fast language model become a System One model simply by running without reasoning tokens.

The important change is the interface. Instead of asking for a paragraph explaining what to do, you define the possible decisions in advance and compose them in ordinary code.

Jev: structured decisions as the model output

Jev accepts a shared state and typed questions. Its three primitives are:

PrimitiveUse it forReturned information
NoulWhether a statement is trueA value from 0 to 1 representing probability of yes
ChoiceSelecting among named alternativesSelected option, probabilities, and confidence
ScoreRating against ordered criteriaExpected level index, distribution, and confidence

Questions are evaluated independently against the same state. A question cannot rely on the answer to another question in the same request. If a second decision depends on the first, make that dependency explicit in code or in a later call.

TypeSafe describes Jev as producing these decisions in parallel rather than generating an answer token by token. Its launch report advertises 70–500 ms end-to-end responses, but those are vendor measurements under particular workloads and network conditions, not a latency guarantee for your application.

The same care applies to the claim that Jev cannot hallucinate. Constraining outputs prevents an invented category or malformed answer structure. It does not prevent a valid category from being the wrong category. Type safety and factual correctness are different properties.

Example: route a support ticket with Jev

With TypeSafe API access, install the TypeSafe Python SDK:

pip install typesafe-sdk

Set TYPESAFE_API_KEY in your environment. The client reads it automatically and uses the hosted Jev service by default.

from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

client = TypeSafeClient()

response = client.system_one(
    state={
        "message": "I was charged twice for the same order. Please help.",
        "account_plan": "standard",
        "service_unavailable": False,
    },
    questions={
        "team": Choice(
            instructions="Which team should own the primary request?",
            criteria={
                "billing": "Charges, invoices, and payment corrections",
                "technical": "Broken product functionality or integrations",
                "sales": "Pricing questions and purchasing plans",
                "other": "Insufficient evidence or none of these teams",
            },
        ),
        "outage": Noul(
            instructions="Does the supplied state report unavailable service?"
        ),
        "urgency": Score(
            instructions="Rate urgency using the reported operational impact.",
            criteria=[
                "Routine request with no reported service interruption",
                "Work is impaired but a workaround exists",
                "Service is unavailable with no workaround",
            ],
        ),
    },
)

team = response.answers["team"]
selected_probability = team.probabilities[team.choice]

# Illustrative policy: validate the threshold on your own labeled tickets.
if team.choice == "other" or selected_probability < 0.90:
    destination = "manual-triage"
else:
    destination = team.choice

print({
    "destination": destination,
    "outage_probability": response.answers["outage"].noul,
    "urgency_score": response.answers["urgency"].score,
})

The model handles the fuzzy interpretation. Code owns the routing policy. This example selects a destination; it does not issue a refund or send a customer reply.

A Score is an expected zero-based level index, so a result such as 1.4 can be meaningful. It is not necessarily one of the integer levels. Likewise, confidence is not interchangeable with the selected option’s probability or with a measured accuracy rate.

Kev: the local decision-model alternative

Kev exposes a Jev-compatible System One API and publishes model weights, training recipes, and evaluations. It is a separate project, not an official local edition of Jev or evidence of identical internals.

The current family is based on Qwen3.5 and Qwen3.8. Rather than writing a free-form response, its decision head scores the supplied options. Smaller checkpoints use adapters; the 27B release uses full fine-tuned weights. The project reports that Jev outputs were not used for training.

For local experimentation, start with the hardware you actually have:

ModelPractical starting point from the project documentation
Kev-0.8BSmallest footprint; documented for a 4 GB GPU or Apple Silicon, with lower accuracy
Kev-4BRecommended general starting point; documented Mac measurements use 32 GB unified memory
Kev-9BMore GPU memory; the README reports about 17 GB of GPU memory and lists larger Mac support as expected rather than measured
Kev-27BAround 51 GB of weights and roughly 66 GB resident with serving buffers; an 80 GB GPU is the documented target

Those are project-reported configurations, not universal minimum requirements. Loading, context length, precision, and concurrency all affect memory. A local model also has a real cost in occupied hardware, energy, and maintenance.

Start a local server

The documented setup requires Python 3.12 or 3.13 and uv. Run these in a directory where you keep development projects:

git clone https://github.com/jaredpalmer/kev.git
cd kev
uv sync --extra serve
uv run --extra serve python -m kev.serve \
  --run jaredpalmer/kev-4b@v1.0 --port 8009

The first run downloads the checkpoint and base model. The server supports GPU execution and automatically uses MLX on Apple Silicon. The weight revision above pins the model; pin the repository revision and dependencies too when turning an experiment into a reproducible deployment.

In the Python example, replace the client construction with:

client = TypeSafeClient(
    api_key="local",
    base_url="http://127.0.0.1:8009",
    model="kev-latest",
)

The question definitions can stay the same. The model answers will not necessarily match Jev, so evaluate the replacement before reusing production thresholds. Kev binds to loopback by default; if you expose it beyond the machine, configure authentication and an appropriate network boundary.

Measure the right kind of speed

Kev’s README reports Kev-4B at around 721 ms for five questions about a short new text on a 32 GB Apple M5, dropping to 136 ms when the state is cached. These are project measurements, not results from this article.

They illustrate a useful distinction: repeated questions about the same document are a different workload from processing a stream of new documents. Benchmark both, including cold starts, network overhead, concurrency, and p95 latency.

The accepted context limit also differs from the validated useful context. The current server accepts states up to 65,536 tokens, while the project validates the smaller models to 8,192 tokens under its stated accuracy criterion. Fitting a document into memory does not prove the model will interpret all of it reliably.

Laya: apply the pattern to daily work

Laya is an application, not another decision-model family. It combines integrations, local storage, model calls, search, and action cards. Its pipeline separates a fast Router from more capable stages such as Stager, Chat, and Coherence.

That makes it a practical example of the fast-path/deep-work split, even when its router is an ordinary local LLM rather than a specialized System One model.

For example, a failed-build notification might first be classified as an engineering event with high priority. Later stages can gather the linked pull request and discussion, prepare a summary, and offer an action. Writing that summary is a text-generation job; choosing its initial queue is a decision job.

Set up a local-first notification workflow

  1. Install a desktop build from the Laya releases. The documentation lists Node.js 18+ for its local n8n integration gateway; release builds bundle the Python engine.
  2. Start a model in Ollama or LM Studio, choosing an instruction model that fits your memory and supports the output capabilities the pipeline needs.
  3. In Settings → Models → Local Providers, add Ollama at http://localhost:11434 or LM Studio at http://localhost:1234, then use Test Connection.
  4. Assign a small, fast model to Router and a more capable model to drafting and synthesis. For local inference throughout, check every active role and any per-space overrides, including Chat and Coherence.
  5. Connect one source initially, such as GitHub notifications. Use filters to remove predictable bot noise before invoking a model.
  6. Review the resulting cards and correct priority or persona assignments. Inspect the audit log for failed stages and actual latency before adding more sources.

For sensitive-source handling, Laya documents tier3_processing: local_only. Local model inference avoids sending the model input to a cloud inference provider, but connected Gmail, Slack, or GitHub accounts still communicate with those services. Optional cloud coding agents introduce their own data paths too. Local-first is not the same thing as offline.

Laya’s documented providers include Ollama, LM Studio, and OpenAI-compatible model servers. Kev’s System One endpoint is not an OpenAI chat endpoint. Plugging its URL into Laya is not a documented drop-in integration. Using Kev as a specialized router would require an adapter and changes to the routing contract; it could not replace stages that need to generate drafts.

Three workloads where this approach fits

1. Support triage before response generation

Ask independent questions about ownership, service interruption, and missing information. Route the clear cases, collect evidence for ambiguous ones, and use a generative model only when a reply is needed.

If a ticket contains both a billing issue and a product bug, separate yes/no questions may represent it better than forcing a single category. The output schema should reflect the business problem rather than hide its ambiguity.

2. Document checks before a deeper review

Given a contract excerpt, ask whether it contains an explicit renewal clause and classify the termination conditions among predefined options. Use code for date arithmetic and monetary calculations. Escalate missing or conflicting evidence instead of treating a fluent interpretation as proof.

This is a fit for decision models when the needed evidence is in the supplied state. It is not a replacement for retrieval over documents the model has never received.

3. Notification prioritization with local drafting

Use Laya to aggregate events, filter known noise, and separate quick classification from context gathering and drafting. Begin with one source and a small set of priority rules. Evaluate whether the system surfaces important events without flooding the feed before enabling additional automation.

How to use them well

Ask atomic questions. “Is service unavailable?” is more testable than “What should we do about this customer?” Combine independent answers in code, where policy changes can be reviewed.

Supply decisive context. Include the relevant policy, known account facts, and timestamps. Compute exact facts yourself. Do not expect a model to infer an unstated refund rule or reliably subtract dates.

Leave room for uncertainty. Include an other or insufficient_evidence option when appropriate, and retain a fallback path. A forced choice always produces a winner, even when none of the choices is justified.

Validate calibration on your workload. A fitted calibration temperature does not guarantee reliability on another language, document type, or customer population. For Italian tickets, build an Italian evaluation set. Measure accuracy, Brier score, and how much traffic can be automated at an acceptable error rate.

Do not confuse probability with confidence. In Kev’s documented Choice interface, confidence rescales the maximum probability relative to uniform guessing. With three choices and a top probability of 0.8, confidence is 0.7. Neither number is automatically an 80% or 70% success rate on your own traffic.

Tune thresholds to error costs. Misrouting a newsletter and missing an outage do not have the same cost. The 0.90 threshold above is an example, not a recommendation for every task. Test false positives and false negatives separately, and choose thresholds on validation data rather than your final test set.

Fine-tune only after establishing a baseline. Kev supports training on labeled requests. First improve category definitions and state quality; then separate training, calibration, and evaluation data. Split by customer, document, or time where needed to avoid near-duplicate leakage. Compare the tuned checkpoint against the original on untouched examples.

Which one should you choose?

NeedStarting point
Typed decisions without operating model infrastructureJev through the TypeSafe API
A self-hosted decision service with your own weights and evaluationKev
A ready-made desktop workflow for notifications, context, and draftsLaya with local or selected cloud models
Long-form writing or open-ended multi-step investigationA generative or reasoning model, potentially downstream of a decision layer

The useful idea here is not that every application needs a new class of model. It is that many AI workflows become easier to understand when decisions and generation stop sharing the same interface. Let a fast model interpret the fuzzy parts, let code express policy, and reserve deeper work for the cases that actually need it.

Sources and further reading