No items found.
Blog
Harness AI

When the Model Decides Instead of Writes | Harness Blog

Auditable Agent Judgment: Jev's Decision Primitive at Harness

TL;DR

Agents do more than generate - they continuously make judgments between reasoning and action. This article explores how typed, probabilistic decisions can become a first-class primitive for building agent loops that can be evaluated, governed, and trusted.

  • Today, agents make decisions by generating text or JSON and leaving software to infer what they chose. TypeSafe's Jev changes the model contract: the decision itself - a Choice, Score, or Noul with a probability - is the output. This is more than structured output. It exposes the ranking that normally disappears into generation and turns judgment into a computational primitive.
  • The hidden forks inside an agent loop - what to do next, whether evidence is sufficient, how risky an action is - can now be stored, evaluated, thresholded, governed, and audited.
  • Our Harness experiments apply this primitive to evals, routing, and action risk. The results show why decisions and outcomes must be measured separately: a faster judgment may be less accurate, and a cheaper route may produce a more expensive loop.

A different kind of model

The models used to build agents are typically designed to generate various forms of content, such as text, audio, video, and images. We have been able to create models that easily generate different types of content. However, agents don’t always produce content. They make decisions. For example, an agent can decide which document to open, which command to execute, or whether to take a given action based on the information it has. These are only a few examples of decisions agents can make. Like other agents, models that only generate text are reverse-engineered to make decisions. A prompt is typically used to solicit a decision. Often, the model generates text in paragraph-like format, and someone then manually extracts the decision from it. Usually, the model doesn’t really make the decisions. Reverse engineering is used to derive the decision from the model's generated text.

TypeSafe's Jev changes what a model output can be. It is their first System 1 model - a deliberate nod to the fast, intuitive mode of judgment described by Daniel Kahneman in Thinking, Fast and Slow. Jev is trained with RLCD (Reinforcement Learning for Calibrated Decisions), an objective designed to produce decisions whose probabilities are meaningful, rather than to optimize for human preference or a single verifiably correct answer. Give it a state and typed questions, and it returns typed answers - each paired with a probability - as a Choice, a Score, or a Noul. The decision is the model’s actual output, not a string scraped from prose, and it remains within the options you provide.

This isn't a change of format, although choosing does mean ranking. The model implicitly ranked options in order to select the next token; it dissolved that rank into what it generated, therefore, that decision was always there, but we couldn't access it. Making that ranking a type decision with a probability associated with it is a major shift and builds upon something new. For however long we have utilized these models, their responsibility was to state something, and it was our responsibility to formulate a decision from that.

It is practical because a well-calibrated 0.8 is correct about 80% of the time, on average, across all decisions. It is not correct to make any single decision with absolute certainty. With a numeric threshold set, a request can be rejected if the confidence is not high enough. RLCD trains for this, and a chat model that just gives an answer doesn't. Also, with TypeSafe models, all the questions in a given request are processed concurrently, and thousands of questions can be answered much faster and cheaper when compared to a chat model.

How the loop changes

In The Agent Loop Is the New OS, we argued that competence lives in the loop: observe, hypothesize, act, repeat, with tools kept few and composable. That still describes the work. It leaves out the choices between the steps.

Watch a model debug with a shell:

1. Observe:     ls src/                    → see the project structure
2. Hypothesize: "error likely in auth module"
3. Act:         grep -r "token" src/auth/
4. Observe:     see the grep output
5. Refine:      "ah, token expiry not handled"
6. Act:         cat src/auth/session.ts
7. Observe:     read the file
8. Fix:         edit the file
9. Verify:      npm test

Every grep and cat is in the transcript. Why auth, and not db, is not. After grep, why read instead of edit? Was there enough evidence to write?

Those answers live in one forward pass and never get logged. The tool call is in the transcript. The decision is not. That is acceptable with someone watching. It is not when the loop is unattended against production. You cannot eval, tune, or govern a judgment that was never written down.

System One is an interface for that missing step: ask the judgment, get a typed answer, apply policy in code, and keep the result with the trace.

TypeSafe exposes three question shapes, and almost every judgment in an agent loop is one of them:

•  Choice: pick one of a fixed set, and get back the pick, a distribution over the options, and a confidence

•  Score: a position on levels you define; it can land between two of them

•  Noul: yes or no as a probability, near 1, near 0, or near 0.5 when the model is torn

Ask one snap judgment per question. If what you want depends on reasoning, tools, consequences, and recovery, ask four questions and combine them into code. Ask them together when they share a state. The policy lives in code, not in a bigger prompt.

The loop we described last time:

while (task not complete) {    
    context   = observe(environment)
    plan      = reason(context, goal)
    action    = select_tool(plan)
    result    = execute(action)
    environment.update(result)
}

select_tool is the fork most systems log, and they log the tool, not the choice. Whether to act, whether evidence is enough, whether to ask, which model should even run: none of those has a line of its own.

while (task not complete) {
    context = observe(environment) 
    
    // System Two: hypotheses. A large model, thinking.
    candidates = reason(context, goal)
    
    // System One: small questions on the same state, one call
    state = { goal, context, candidates, proposed_action, stakes }
    answers = ask(state, [
        Choice  which_action
        Choice  hypothesis
        Noul    should_act_now
        Noul    should_ask_user
        Noul    enough_evidence
        Score   irreversibility
    ])

    action = policy(answers)
    record(decision_trace)
    result = execute(action)
    environment.update(result)
}

The decision is now something you can store. The model that proposes an edit is not the call that grades whether to run it. record(decision_trace) keeps what was asked, what came back, which policy fired, and what ran.

The agent is still stochastic. Ask twice, and the number can change. TypeSafe's claim is narrower than "no hallucination": the model cannot invent an option you did not list, and it cannot answer a Choice with a paragraph. That removes a class of failures we already see in generated JSON: malformed payloads, invented labels, prose you scrape for intent. A schema-valid {"department": "...", "confidence": 0.9} only means the parser succeeded. A Score can be well-formed and still call a production pipeline unused. Schema-validity is a type check. Whether the decision was good is something you measure.

You do not get the model's private reasoning. You get programmatic access to selected judgments inside the loop: store, compare, eval, threshold, and change the policy without retraining. Uncertainty stays. It just has a type, a value, and a place in the trace.

Same debug story, as forks:

At this point The question Shape Now visible
after ls where is the fault? Choice auth vs the rest, with a distribution
after the hypothesis grep, read, test, or ask? Choice why grep won
after grep is expiry the cause? Noul uncertain, so it read
before the edit enough evidence to write? Noul + Score write only if the evidence is strong and blast is low
after the edit did we fix it? Noul verify is a decision


We put this into three places at Harness.

Harness Evals

Evals were the natural first place to try this. `harness-evals` (the foundation layer of Harness AI Evals) is built around Metrics. Each Metric is a small object that encapsulates one scoring methodology, so GEval and rubric judges already live behind a common interface. A decision primitive is the same shape: a bounded question with a typed answer. Scoring a ticket's department is a Choice; its severity is a Score; whether it is an escalation is a Noul. The three primitives drop straight into the Metric interface, so we added ChoiceMetric, ScoreMetric, NoulMetric, and a DecisionCompositeMetric, backed by a TypeSafeDecisionProvider. They sit next to the existing judges and get called the same way.

The alternative is more awkward than it looks. LLM-as-judge is useful for open-ended work, but for a bounded question, it is slow, and a JSON schema that parses is too easily mistaken for a judgment.

We ran them against a JSON-schema judge on 18 hand-labeled support tickets, three dimensions, and 108 live calls. The judge was Claude Sonnet 4.5. (Routing, later, uses Sonnet 5 and Opus 5. Different models, different questions.)

Dimension Approach Accuracy Mean latency
department decision primitive 16/18 (88.9%) 185 ms
department LLM judge 14/18 (77.8%) 1,363 ms
severity decision primitive 14/18 (77.8%) 174 ms
severity LLM judge 15/18 (83.3%) 1,319 ms
is_escalation decision primitive 18/18 147 ms
is_escalation LLM judge 18/18 1,297 ms

Accuracy mixed: better on department, worse on severity, tied on escalation. Latency was consistent: seven to nine times faster, 147–185 ms against ~1.3 s. That is below TypeSafe's published multiples and still the difference between a check you can run on every turn and one you cannot.

The judge's "confidence" clustered on 0.85 / 0.9 / 0.95 / 1.0. TypeSafe's confidence comes from a distribution over the options. We did not measure calibration over a large population. A confidence field in JSON and a probability over choices are not the same thing.

Model Routing as a First-Class Decision

Model routing is one of the clearest examples of judgment inside an agent loop. Given the current state, should the next step use Sonnet or Opus? Normally, that choice is buried in a heuristic, a prompt, or the behavior of the loop itself. With System One, it becomes an explicit decision: typed questions produce bounded answers with probabilities, and versioned policy maps those answers to a model.

A document lookup should not require the same level of effort as an in-depth, multi-step analysis. In the LLM gateway, users can request an auto logical model. Before the gateway builds the model, it adds a route pin for the tool loop and falls back to the specified model if the judgment is not provided. System One makes the judgment calls based on its understanding of the model.

For version 1 (V1), the default, high, or low option was provided. Version 2 (V2) refined the questions, asked four questions of the same state, respectively, and provided code to map the answers. Based on the provided examples, if the model is set to high, and the example provided does not answer the question, V2 interprets that as an example of "reasoning demand cleared the threshold."

We ran V1 and V2 as matched arms on 12 curated AI Chat cases. Cheap maps to Sonnet 5, high to Opus 5:

Measure V1 (one holistic route) V2 (four signals + policy)
Outcome accuracy 10/12 (83.3%) 10/12 (83.3%)
SSE checks 12/12 12/12
Usage-budget pass 11/12 (91.7%) 9/12 (75.0%)
Agent cost $8.111 $8.226
Model mix (observations) 7 Sonnet / 6 Opus 8 Sonnet / 5 Opus


SSE checks: Transport-level checks that the routed request produced a valid Server-Sent Events stream, expected event structure, uninterrupted streaming, and proper completion. This verifies gateway behavior, not answer quality.
Usage-budget pass: Whether the complete agent run stayed within a predefined usage limit, such as tokens, turns, or model cost. This measures loop efficiency, not merely the cost of the routing decision.

Both completed 10 of 12. Counts can exceed 12 because a later turn can escalate. List pipelines stayed on Sonnet, then moved to Opus after "that did not help." V2 used Sonnet a little more often and still cost slightly more: one planning case burned 44 Opus turns. Routing to a cheaper model does not save money if the run gets longer. An earlier ten-case run sent all ten to Opus. The router fired; we still paid Opus rates.

A later gateway run on 10 read-only QA cases, billed model cost:

Metric Fixed Sonnet Fixed Opus Auto
Primary outcome passes 7/10 5/10 8/10
Quality pass rate 86.7% 88.3% 90.0%
Billed model cost $2.214 $4.552 $4.013
Agent turns 134 185 119
Tool calls 81 119 74

Auto passed more cases than either fixed model and cost 12% less than always-Opus. It still cost 81% more than always-Sonnet.

On the eight cases where at least one fixed arm passed, looking back, we would have used Sonnet whenever Sonnet was enough, and Opus only when Sonnet failed. That basket costs $2.349. Auto costs $2.955 on the same cases, about 26% extra from using Opus, or taking a longer path, when Sonnet would have been enough. 

The trace can now record what the router saw, what it decided, how confident it was, which policy applied, and which model ran. That makes routing independently observable and evaluable. System One’s lower cost and latency make this practical inside the loop - but the bigger change is that routing is now a first-class decision rather than hidden control flow.

Scoring a Destructive Call Before It Runs

We applied the same idea later in the path, before the MCP tool hits the backend. The change is in harness/mcp-server. pipeline.delete is destructive for every pipeline, because the static label has to assume the worst case.

We kept that label as a ceiling and added an optional riskFloor. A Score on already-fetched state (30-day executions) can only relax friction toward the floor for this instance. Miss, timeout, low confidence, no key: today's risk. Off unless explicitly enabled.

Three live, easy pipeline states: never-run → 0 at 148 ms, stale → 1 at ~250 ms, active-prod → 3 at 391 ms. Inside the 400 ms budget, with almost no slack on the slowest call. Confidence was 1.0 on all three, expected on obvious cases, and it means the confidence gate never fired. Rerunning those three would not tell us more. The next run has to be ambiguous pipelines, where a wrong Score would actually hurt.

We also score repo_rule update/delete from enforcement state, default-branch targeting, and recent commits. Typecheck and unit tests only so far, no live key. Building it found a real bug: harness_update was never on the scoring path, so a floor on an update would have been inert.

Fail-closed covers a missing score. The floor and ceiling are what we have against a well-formed, confidently wrong one.

The objects from these experiments are in the open repos: metrics in harness-evals, scoring in mcp-server, and routing telemetry in the gateway. The loop can emit decisions that the rest of Harness treats as data.

AgentTrace: The Trace That Can Be Audited

A tool log says what happened. A decision record can also say:

•  the question, and the state it was asked about

•  the answer, distribution, confidence

•  the policy version

•  what ran, or what was refused

•  which model was pinned

"The agent deleted a pipeline" versus "policy v3 saw Score 0.92 on this instance and allowed it." The second one you can audit. Over time, you can ask: Did we write below the evidence bar? Would a stricter bar still have finished the task? Which forks sat near 0.5: those are the places for a skill, more context, or a person.

The right tool at every step can still miss the bug. The right cheap route can still burn 44 turns. Decision evals sit next to outcome evals and cost.

Write-path scoring fails closed. Routing fails open. Same primitive, opposite default, because the surrounding code knows the stakes.

Toward an autonomous SDLC

Where this is heading at Harness is a completely autonomous SDLC. It's not about creating a smarter version of Think, Shape, Make, Verify, Ship, and Learn. It’s about setting up the software factory to allow agents to perform more of the work in the SDLC while still permitting humans to exercise control and judgment.

This can not be achieved by simply putting an individual behind a decision button. Judgment is only as good as the evidence it's considering and the things it is uncertain about. Also, what are the constraints that allowed the agent to act? You can't govern a judgment if you don't have visibility into the decision.

In terms of the architecture, the most important aspect of System One is the expression of judgment as an interface. How judgment is integrated determines the boundaries of permissibility and what actions are allowed. Is there sufficient evidence to act? What are the risks and consequences? Judgment is a statistical decision.

In a software system, code and policy define the hard boundaries of what is permissible; model judgment adjusts autonomy within them. At Harness, RBAC, OPA, freeze windows, gates, and approvals remain hard controls. For example, RBAC determines whether an agent may delete a pipeline at all, while a risk score determines whether that permitted action can proceed automatically, needs more evidence, or requires human approval. Strong evidence and low risk reduce friction; uncertainty and consequence increase it.

That gives risk-based autonomy something concrete to bind to. Harness already has the hard controls: RBAC, OPA, freeze windows, gates, approvals, and audit. Those stay hard. What changes is the friction inside those boundaries. A low-risk action backed by strong evidence can proceed; a consequential action on thin evidence can slow down, gather more evidence, or require a person.

The question stops being whether the agent is allowed to act. It becomes: which actions, backed by what evidence, at what risk, under which controls, and when should a person make the judgment instead?

We're still early, but eventually decisions will need to be expressed in a way that is explicit to humans. Maybe defining decisions in this manner is as important as the intelligence of the agents themselves. Can these decisions be expressed in computational form? Currently, we can do evaluations in under 200 ms. We can also express routing decisions with 83% holding accuracy. However, as expected, expressing decisions in this manner can be rather expensive, and routing decisions increased costs by 26%. Other expenses, like latency, remain outside the loop.

The pattern here is observer/control: hard boundaries (RBAC, OPA, gates) stay fixed, and System One adjusts the friction inside them based on evidence. The next primitive is to construct and parameterize a control policy and to write it down.

← Previous:
Next: →

Related Resources

Get Started

Get Started with Harness AI

Try the full platform free. No module restrictions, no credit card.

Sunil Gattupalle
AI Engineering Architect
Sunil is an Engineering Architect focused on building production-grade AI and data platforms at scale.
sunil-gattupalle
Sunil Gattupalle
Shubham Jindal
AI Software Engineering
Shubham Jindal is Director of AI at Harness, where he leads the company's AI strategy and the unified AI platform that powers products across the organization.
shubham-jindal-dir
Shubham Jindal
https://www.linkedin.com/in/shubham-jindal-67b69048/
Sanjay Nagaraj
SVP Global Engineering
Sanjay Nagaraj is SVP Global Engineering at Harness, where he leads the global engineering organization. He also serves as General Manager of the company's Application Security business, overseeing product management and strategy.
sanjay-nagaraj
Sanjay Nagaraj
https://www.linkedin.com/in/sanjaynagaraj/