YouMind
تسجيل الدخول

How to Build a Coding Agent That Costs 80% Less: Jev + Opus 5.5 (Full Architecture)

@cyrilXBT
الإنجليزية09 أكتوبر 2026
241K
200
25
11
306

ليرة تركية؛ د

This guide details a hybrid architecture for coding agents that uses Opus 5.5 for complex reasoning and Jev for routine decision-making tasks like context selection and error recovery, resulting in significant cost reductions.

Your coding agent is paying frontier prices for multiple choice questions.

Which notes should I load? Should this step go to the big model or a small one? The tool just failed. Retry, fix, or give up? Which tests should run first?

Every one of those is a question with four or five possible answers. And in most agent setups today, every one of them gets answered by the most expensive model you have, with thinking switched on, reading the whole context, writing a paragraph before it commits.

That's the leak.

This article shows you how to plug it. Opus 5.5 keeps the hard reasoning: planning, writing code, debugging. Jev takes the four decisions that happen on almost every step. Your harness prepares the options, checks the answers, and makes the final call.

In the worked example below, one feature session drops from $6.42 to $2.00. That's 69% cheaper, and every line of the math is in this article so you can check it against your own numbers.

This is written for anyone running a coding agent on real work: Claude Code, your own harness on the API, or anything in between. You don't need to rewrite your agent. Every piece in this article slots into an existing loop as a function call with a flag to switch it off. If you've read my Jev + Claude Code article, this is the upgraded version: same idea, a newer reasoning model, and four specific decisions instead of a general principle.

You'll need a Jev API key, an Anthropic API key, and about a week of your own agent logs to measure against.

Let's build it.

CyrilXBT - inline image

opus reasons jev decides.

The Problem: One Model Doing Two Jobs

Watch a coding agent work for ten minutes and you'll see it doing two very different kinds of work.

Job one is reasoning. Planning a feature. Writing a function. Reading a stack trace and figuring out why the date parser breaks on leap years. This work is open ended. The answer isn't on a list. You want the smartest model you can afford here, and Opus 5.5 is very good at it.

Job two is deciding. Picking the three project notes that matter out of forty. Deciding a rename can go to a cheap model. Choosing what to do after npm test times out. Picking which 12 test files to run before the full 1,400. These answers are on a list. The list is short. And your code can act on the answer directly.

Most agents run both jobs through the same model, because that's the default. The loop calls Opus, Opus thinks, Opus answers, the loop continues.

It works. It's also slow and expensive in a way that's easy to miss, because the decision calls don't look expensive one at a time. A single "which notes do I need" call is maybe a cent. But it happens on every step, and it carries the full context with it every time.

And there's a second cost that's even easier to miss: when the agent can't decide what to load, it loads everything. Every project note, every convention doc, every past decision, stuffed into every call. Opus 5.5 made cache reads cheap at $0.20 per million tokens, but "cheap times sixty steps times your whole notes folder" still adds up.

The Fix: Opus Reasons, Jev Decides, Your Harness Rules

Jev is the model from TypeSafe built for exactly job two. It doesn't write text. You give it context and typed questions with a fixed set of options, and it hands back a probability for every option. It answers in milliseconds, input costs $0.042 per million tokens, and output is free.

That makes the architecture simple to describe:

Opus 5.5 does the reasoning. Planning, code, debugging, anything where the answer isn't on a list.

Jev makes the small decisions. It picks from options your harness prepared.

Your harness stays in charge. It builds the option lists, reads the probabilities, applies thresholds, and falls back to Opus when Jev isn't sure.

That third line is the one people skip, and it's the one that makes the whole thing safe. Jev never invents an option. Jev never gets the final word on anything you can't undo. Your code decides what "sure enough" means.

Here's the helper everything else in this article is built on:

from dataclasses import dataclass

@dataclass

class Decision:

answer: str

prob: float

probs: dict

confident: bool

def jev_choice(context: str, question: str, options: list[str]):

Wire this to your Jev client: the TypeSafe SDK, Vercel AI Gateway,

or the LangChain package. It must return {option: probability}

for every option you passed in.

raise NotImplementedError

def decide(context: str, question: str, options: list[str], threshold: float):

probs = jev_choice(context, question, options)

answer = max(probs, key=probs.get)

return Decision(answer, probs[answer], probs, probs[answer] >= threshold)

Notice what's not in there: no question asking Jev how confident it is. You read the probability it returns. Asking any model "are you sure?" gets you a "yes" almost every time. The probability is the honest signal.

Now the four decisions.

CyrilXBT - inline image

The fourt decisions inside agent step

Decision 1: Pick the Relevant Project Notes Before Loading Context

This is the biggest single lever, and it's the one almost nobody has built.

Your agent has a notes folder. An AGENTS.md, architecture docs, conventions, past decisions, "never touch the billing module without a migration" warnings. Maybe 30,000 tokens of it. Most agents load all of it on every call, because nobody wants to be the one who left out the important note.

So instead of loading everything, you ask Jev a simple question about each note, all in parallel: does the agent need this note for this task?

First, split your notes into chunks by heading. Each section of AGENTS.md becomes its own chunk. Each architecture doc becomes one or more chunks.

import re

def chunk_notes(markdown: str, source: str):

parts = re.split(r"
(?=## )", markdown)

return [{"source": source, "text": p.strip()} for p in parts if p.strip()]

Then score every chunk against the current task:

from concurrent.futures import ThreadPoolExecutor

def pick_notes(task: str, notes: list[dict], keep: int = 6, floor: float = 0.55):

def score(note):

probs = jev_choice(

context=f"TASK:
{task}

NOTE ({note['source']}):
{note['text']}",

question="Would an engineer need this note to do the task correctly?",

options=["needed", "not_needed"],

)

return probs["needed"], note

with ThreadPoolExecutor(max_workers=16) as pool:

scored = sorted(pool.map(score, notes), key=lambda s: s[0], reverse=True)

picked = [n for p, n in scored[:keep] if p >= floor]

return picked or [n for _, n in scored[:2]]

Three details matter here.

Always load the non negotiables. Some notes should be in every call no matter what: security rules, "never force push," the one line that says which database is production. Tag those always and skip scoring them.

Keep a floor and a fallback. If nothing clears 0.55, you still load the top two. An agent with zero context is worse than one with slightly too much.

Log what got dropped. When the agent makes a mistake, the first thing you check is whether the note that would have prevented it was scored out. That log is how you tune keep and floor.

In the worked example, this one change takes the notes portion of each call from 30,000 tokens to 6,000. On its own, that cuts the session cost by about 24%.

Decision 2: Route Suitable Tasks to a Faster Worker

Not every step needs Opus.

Renaming a function across eight files doesn't. Adding a field to a form that already has nine fields just like it doesn't. Updating an import path doesn't. These are edits that follow a pattern already sitting in the codebase.

So before each step runs, Jev classifies the step, and your harness maps the class to a worker:

ROUTES = {

"rename_or_move": "fast",

"small_edit_following_existing_pattern": "fast",

"new_logic": "opus",

"debugging": "opus",

"design_decision": "opus",

}

def route(step: str, recent_diff: str):

d = decide(

context=f"STEP:
{step}

RECENT CHANGES:
{recent_diff}",

question="What kind of work is this step?",

options=list(ROUTES),

threshold=0.8,

)

if not d.confident:

return "opus"

return ROUTES[d.answer]

Look at how the options are written. They aren't "easy" and "hard," and they definitely aren't "can a small model handle this?" They're concrete kinds of work that your code can map to an action. That's the rule for every Jev question: every option has to be something your harness knows how to act on.

And notice the default. Below 0.8, the step goes to Opus. Routing mistakes only go in one direction here: a hard task sent to the fast worker costs you a failed step and a retry, while an easy task sent to Opus just costs a little extra. So when in doubt, send it up.

For the fast worker I use Haiku 4.5 at $1 per million input tokens and $5 per million output. In the worked example, 12 of the 36 real work steps go to it.

Decision 3: Choose a Recovery Path When a Tool Fails

Tools fail constantly. Tests time out. A file path is wrong. A package isn't installed. A shell command hits a permission error. A linter complains about something unrelated.

Most agents handle this in the most expensive way possible: they hand the whole error back to the big model and let it think about what to do. Sometimes that's right. Often the answer is obvious, and Opus spends 1,500 tokens rediscovering that ENOENT means the file isn't there.

Worse, agents get stuck in loops. Retry, fail, retry, fail, each time paying for a full reasoning step.

So you give the failure to Jev with a fixed set of recovery paths:

from collections import deque

def tail(text: str, n: int = 4000):

return "".join(deque(text, maxlen=n)) # last n characters of the error

def recover(tool: str, command: str, error: str, attempt: int):

if attempt >= 3:

return "stop_and_report"

d = decide(

context=f"TOOL: {tool}
COMMAND: {command}
ATTEMPT: {attempt}
ERROR:
{tail(error)}",

question="What is the best next move after this failure?",

options=RECOVERY,

threshold=0.8,

)

return d.answer if d.confident else "escalate_to_opus"

text
1RECOVERY = [
2 "retry_unchanged", # flaky network or timeout
3 "retry_after_install", # missing package or tool
4 "fix_path_and_retry", # wrong file path or cwd
5 "switch_tool", # this tool can't do it, another can
6 "escalate_to_opus", # needs real debugging
7 "stop_and_report", # needs a human
8]

The hard cap on attempts lives in code, not in the model. No model, however cheap, should be allowed to retry forever.

Each recovery path maps to a small function in your harness. retry_after_install reads the missing package from the error with a regex and installs it. fix_path_and_retry checks the paths that exist and suggests the closest match. Only escalate_to_opus spends real money, and it only fires when the failure actually needs thinking.

In the worked example, this removes 6 wasted retry steps from the session.

Decision 4: Run Focused Checks Before the Full Test Suite

This one saves time more than money, and time is what makes an agent feel fast.

After every change, most agents run the whole test suite. If your suite takes four minutes, your agent spends four minutes waiting after every edit, and then reads through hundreds of lines of output looking for the one failure that matters.

The fix is the same pattern as the notes: score each test file against the diff, run the most relevant ones first, and only run the full suite when the focused checks pass.

text
1def pick_tests(diff: str, test_files: list[str], keep: int = 12):
2 def score(path):
3 probs = jev_choice(
4 context=f"DIFF:\n{diff[:12000]}\n\nTEST FILE: {path}",
5 question="Could this change break tests in this file?",
6 options=["likely", "unlikely"],
7 )
8 return probs["likely"], path
9
10 with ThreadPoolExecutor(max_workers=16) as pool:
11 scored = sorted(pool.map(score, test_files), key=lambda s: s[0], reverse=True)
12 return [p for _, p in scored[:keep]]
13
14def check(diff: str, test_files: list[str]):
15 focused = pick_tests(diff, test_files)
16 if not run_tests(focused):
17 return False # fail fast, fix before anything else
18 return run_tests(test_files) # full suite still gates the commit

Read that last line twice. The full suite still runs before anything gets committed. Focused checks are an early warning, not a replacement. You catch most breaks in seconds instead of minutes, and you never ship something the full suite would have caught.

Add the cheap checks first too: type check and lint on the changed files only. They take a second and catch a surprising share of mistakes before any test runs.

Putting It Together: The Harness Loop

Here's how the four decisions sit inside one step of the loop:

def run_step(task: str, step: str, state):

1. context: load only the notes this step needs

notes = state.always_notes + pick_notes(step, state.notes)

2. routing: pick the worker for this step

worker = state.workers[route(step, state.recent_diff())]

result = worker.run(step, notes=notes, history=state.history)

3. recovery: handle any tool failures in this step

for failure in result.failures:

action = recover(failure.tool, failure.command, failure.error, failure.attempt)

state.apply_recovery(action, failure)

4. checks: focused tests first, full suite before commit

if result.diff:

state.log_check(check(result.diff, state.test_files))

And here's the Opus side: it's just your normal Opus 5.5 call. Put your stable context first (system prompt, tool definitions, the "always" notes) so it stays cached across steps, and put the step specific material last.

import os

import anthropic

client = anthropic.Anthropic()

OPUS = os.environ["OPUS_MODEL"] # your Opus 5.5 model id

def opus_step(system: str, notes: list[dict], history: list, step: str):

notes_text = "

".join(n["text"] for n in notes)

return client.messages.create(

model=OPUS,

max_tokens=8000,

system=[{"type": "text", "text": system, "cache_control": {"type": "ephemeral"}}],

messages=history + [{"role": "user", "content": f"NOTES:
{notes_text}

STEP:
{step}"}],

)

Nothing exotic. The savings come from what you stop sending to it, not from a clever prompt.

One Step, Traced

Here's what a single step looks like in the log once all four decisions are live. The task: add rate limiting to the public signup endpoint. This trace is illustrative, but it's the shape you'll see in your own logs.

step 14 "add a per IP rate limit to POST /signup"

[notes] scored 41 chunks in parallel

kept: api/middleware.md (0.94), conventions/errors.md (0.88),

infra/redis.md (0.81), decisions/2025_auth.md (0.62)

dropped: 37 chunks, including billing, email templates, CI

[route] new_logic (0.91) → opus

[opus] plans the change, writes middleware + config + handler edit

[tool] npm test FAILED "Cannot find module 'bottleneck'"

[recover] retry_after_install (0.97) → npm install, rerun

[checks] typecheck changed files: pass

focused tests (12 of 1,388): pass

full suite: pass

Read it from top to bottom and count how many of those lines used to be a full Opus call. Picking notes: one big call, or no picking at all and 30,000 tokens of notes loaded blind. Routing: nothing, every step went to Opus. The missing package: a full reasoning step to work out that a missing module means "install the module." Choosing tests: nothing, the full suite on every edit.

Now only one line in that trace is Opus, and it's the line that actually needed a frontier model: planning and writing the rate limiter.

That's the whole idea in one picture. The expensive model spends its time on the part of the job only it can do.

The Worked Example: Where the 69% Comes From

Here's the full math for one feature session: 60 agent steps plus the 6 wasted retries a typical agent racks up along the way. All prices are the current public list prices.

Before: Opus 5.5 does everything

Every step loads 70,000 tokens of context: 15,000 for the system prompt and tools, 30,000 for the full notes folder, and 25,000 for the conversation so far. I assume 80% of that is a cache hit. Every step produces about 1,500 output tokens, because thinking is always on in Opus 5.5.

cache reads: 56,000 × $0.20/M = $0.0112

fresh input: 14,000 × $4.00/M = $0.0560

output: 1,500 × $20.00/M = $0.0300

per step = $0.0972

66 steps × $0.0972 = $6.42

After: the decision layer

Context drops to 46,000 tokens per step, because Jev picks 6,000 tokens of notes instead of loading all 30,000. The 24 pure decision steps move to Jev. The 6 retry loops disappear. And 12 of the remaining 36 work steps go to Haiku 4.5.

Opus 5.5: 24 steps × $0.0742 = $1.78

Haiku 4.5: 12 steps × $0.0169 = $0.20

Jev: 102 calls × 5,000 tokens

× $0.042/M, output free = $0.02

total = $2.00

From $6.42 to $2.00. That's 68.8% cheaper for the same feature.

CyrilXBT - inline image

set the threshold by what a wrong answer costs

And here's how much each lever contributes, stacked in order:

notes selection only $4.89 23.7% saved

  • decisions moved to Jev $3.13 51.2% saved
  • recovery paths $2.69 58.1% saved
  • routing to a fast worker $2.00 68.8% saved

Two honest notes about this math.

First, these are modeled numbers built on explicit assumptions, not a measurement of your stack. Your context size, cache hit rate and decision count will be different. The point of showing every line is so you can swap in your own numbers. Once you've measured your real before and after, use your number, not mine.

Second, look at where the money actually goes. Jev's 102 calls cost two cents in total. The savings don't come from Jev being cheap per call. They come from everything that stops happening once Jev makes the decision: bloated context, full reasoning steps for multiple choice questions, retry loops, and big model calls on rename jobs.

Why Not Just Use Haiku for the Decisions?

Fair question. Haiku 4.5 is cheap and fast. Why add a new model at all?

Three reasons.

It still writes. Haiku answers in text. You have to prompt it to answer with one of your options, then parse the answer, then handle the times it adds an explanation, picks something that isn't on the list, or wraps the answer in a sentence. Jev returns a probability for every option you passed in. There's nothing to parse and nothing off the list.

You get the full distribution, not just an answer. When Jev says needed: 0.52, not_needed: 0.48, you know it's a coin flip and your harness can escalate. When a text model says "needed," you have no idea whether it was sure. Thresholds only work when you can see the probabilities.

The cost math is different. Jev's output is free and its input is $0.042 per million tokens. Scoring 41 note chunks every step means 41 small calls per step. With Jev that's a fraction of a cent. With any text model, even a cheap one, that's 41 generations with their own output cost and latency.

Use Haiku for small edits, where it actually has to write code. Use Jev for picking from lists. Use Opus for thinking. Each model does the job it's built for.

How to Roll It Out Without Breaking Anything

Don't flip all four decisions on at once. Here's the order I'd use.

Week 1: shadow mode. Keep your current agent exactly as it is. For every decision it makes, also ask Jev the same question and log both answers plus Jev's probability. Don't act on Jev's answer at all.

text
1def shadow(decision_name, context, question, options, current_answer):
2 probs = jev_choice(context, question, options)
3 jev_answer = max(probs, key=probs.get)
4 log_row(
5 decision=decision_name,
6 current=current_answer,
7 jev=jev_answer,
8 prob=probs[jev_answer],
9 agree=(jev_answer == current_answer),
10 )

Week 2: read the disagreements. Look only at the rows where Jev and your current agent disagreed. Sort them by Jev's probability. You'll usually find a clean line: above some probability, Jev is right about as often as Opus. That line is your threshold. Those disagreement rows also become your test set, built for free out of your real traffic.

Week 3: switch on notes selection. It's the biggest lever and the easiest to undo, since a missed note shows up fast in your logs.

Week 4: switch on recovery and tests. Both have hard caps and fallbacks in code, so the worst case is falling back to what you do today.

Last: routing. Routing mistakes are the most visible to users, because a hard task sent to the fast worker produces bad code. Turn it on last, with a conservative threshold, and watch the fail rate on fast worker steps.

Put every decision behind an on/off flag so you can undo it in one line.

Setting Thresholds by Risk

One threshold for everything is a mistake. Set them by what happens when the answer is wrong.

CyrilXBT - inline image

One feature session, same result $6.42 to $2.00

Low stakes, easy to undo: 0.55 to 0.65. Picking notes. Ordering tests. A wrong answer costs a bit of context or a few seconds.

Medium stakes: 0.8. Routing and recovery. A wrong answer costs a failed step, which your harness catches.

High stakes, hard to undo: 0.9 or never. Deleting files. Force pushing. Touching production config. Running a migration. My honest advice: don't let any model make these calls alone. Route them to a human, or at minimum to Opus with a confirmation step.

Anything below the threshold goes up the ladder: to Opus if it needs reasoning, to a human if it needs judgment.

Where This Doesn't Help

This architecture is not a magic multiplier on every workload.

Pure generation workloads barely change. If your agent spends most of its time writing large amounts of new code from a clear spec, there aren't many decisions to move. You'll still get the notes selection savings, but not much else.

Tiny projects don't need it. If your whole notes folder is 2,000 tokens and your suite runs in eight seconds, the overhead of building this isn't worth it yet.

Jev isn't great at making the final call alone. It's excellent at noticing things and picking from a short list. It's not the model you want deciding "is this pull request ready to merge?" as a single question. Break big questions into small ones, score each, and combine the results in your own code with your own weights.

If you already have labelled data for a fixed question, a small model you host yourself can beat Jev on price. Jev shines when the questions keep changing and you don't have training data, which describes most coding agents.

The Mistakes I'd Avoid

Letting the model write the option list. The whole architecture depends on options your code can act on. If a model generates the options, you're back to parsing free text.

Asking Jev if it's confident. Read the probability instead. A self report is almost always "yes."

No fallback. Every Jev decision needs a path for "not sure," and that path is Opus or a human, never a guess.

Retry limits in the prompt instead of in code. A model told "only retry 3 times" will occasionally retry 30 times. Code doesn't.

Dropping the full test suite. Focused checks speed you up. The full suite keeps you honest. Keep both.

Measuring nothing. If you don't log cost per session before you start, you'll never know whether you saved 20% or 70%. Pull your usage for a week of normal work first. It takes ten minutes and it's the only number that matters.

What to Do This Week

Here's the whole thing as a checklist:

  1. Log one week of agent sessions: steps, tokens, cost, failures.
  2. Find the decisions hiding in your loop: notes, routing, recovery, tests.
  3. Write each one as a question with a fixed list of options.
  4. Run Jev in shadow mode next to your current agent for a week.
  5. Set thresholds from the disagreement log, by risk.
  6. Switch on notes selection first, then recovery and tests, then routing.
  7. Compare cost per session before and after. That's your number.

Opus 5.5 is the best reasoning model I've used for code. The mistake is making it do everything else too.

Let it think. Let Jev decide. Let your code rule.

If this was useful, follow @cyrilXBT. I break down how to build with the newest AI models every week, with the real numbers.

Bookmark this so you have it when you start building.

بنقرة واحدة حفظ

استخدم YouMind للقراءة العميقة للمقالات سريعة الانتشار بتقنية الذكاء الاصطناعي

احفظ المصدر، واطرح أسئلة مركزة، ولخص الحجة، وحوّل المقالة واسعة الانتشار إلى ملاحظات قابلة لإعادة الاستخدام في مساحة عمل واحدة تعمل بالذكاء الاصطناعي.

اكتشف YouMind
للمبدعين

حول Markdown إلى مقالة 𝕏 نظيفة

عندما تنشر كتاباتك الطويلة، فإن الصور والجداول وكتل التعليمات البرمجية تجعل تنسيق 𝕏 مؤلمًا. YouMind يحول مسودة Markdown كاملة إلى مقالة نظيفة وجاهزة للنشر 𝕏.

حاول Markdown إلى 𝕏

المزيد من الأنماط لفك التشفير

المقالات الفيروسية الأخيرة

استكشاف المزيد من المقالات الفيروسية