<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Olivia Mckelvey</title>
    <description>The latest articles on DEV Community by Olivia Mckelvey (@oliviamckelvey).</description>
    <link>https://dev.to/oliviamckelvey</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4140221%2F7b3564a8-e500-48bb-8917-5d5f15670cb3.jpg</url>
      <title>DEV Community: Olivia Mckelvey</title>
      <link>https://dev.to/oliviamckelvey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oliviamckelvey"/>
    <language>en</language>
    <item>
      <title>How three OSLabs engineers built a CLI to catch you overpaying Claude</title>
      <dc:creator>Olivia Mckelvey</dc:creator>
      <pubDate>Thu, 24 Sep 2026 02:45:22 +0000</pubDate>
      <link>https://dev.to/oliviamckelvey/how-three-oslabs-engineers-built-a-cli-to-catch-you-overpaying-claude-531e</link>
      <guid>https://dev.to/oliviamckelvey/how-three-oslabs-engineers-built-a-cli-to-catch-you-overpaying-claude-531e</guid>
      <description>&lt;p&gt;I’m one of three developers behind PennyWyze, an open-source CLI that audits which Claude tier (Opus, Sonnet, or Haiku) is the cheapest one that still passes your quality bar. You point it at your prompt and a handful of real examples you already know the right answer to, and it tells you, in real dollars, whether you’re overpaying.&lt;/p&gt;

&lt;h2&gt;
  
  
  How PennyWyze works
&lt;/h2&gt;

&lt;p&gt;You give it two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Your prompt&lt;/strong&gt; — the exact instructions you already send to Claude in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A golden dataset&lt;/strong&gt; — real inputs paired with the answer you already know is correct, one JSON object per line:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"input": "I was charged twice this month", "expected": "billing"}
{"input": "The app crashes on upload", "expected": "technical"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pennywyze audit &lt;span class="nt"&gt;--prompt&lt;/span&gt; prompt.md &lt;span class="nt"&gt;--dataset&lt;/span&gt; dataset.jsonl &lt;span class="nt"&gt;--pass-rate&lt;/span&gt; 90
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PennyWyze sends every example in your dataset to Opus, then Sonnet, then Haiku, using your real prompt over the real Anthropic API, and grades each answer against the one you said was correct. It prices every call from the token counts the API reports back, never an estimate. It prints a report showing each tier’s accuracy and projected monthly cost at your real volume, and names the cheapest tier that still cleared your bar. If a tier mathematically can’t recover, say it’s already missed more than your &lt;code&gt;--pass-rate&lt;/code&gt; allows with half the dataset still to go, PennyWyze stops calling that model immediately instead of burning your API budget to prove a foregone conclusion.&lt;/p&gt;

&lt;p&gt;Here’s a real run, exactly as it printed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ opus audited — 50 questions
✓ sonnet audited — 50 questions
✓ haiku audited — 50 questions
PENNYWYZE AUDIT REPORT
┌───────────────────────────┬────────────┬────────────────┐
│ MODEL                     │  ACCURACY  │ EST. COST / MO │
├───────────────────────────┼────────────┼────────────────┤
│ claude-opus-5             │ 49/50 PASS │   $205.94 / mo │
├───────────────────────────┼────────────┼────────────────┤
│ claude-sonnet-5           │ 48/50 PASS │    $77.30 / mo │
├───────────────────────────┼────────────┼────────────────┤
│ claude-haiku-4-5-20251001 │ 49/50 PASS │    $26.26 / mo │
└───────────────────────────┴────────────┴────────────────┘
VERDICT  Switch to claude-haiku-4-5-20251001 — save ~$179.68/mo.
ℹ Audit cost: $0.15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Opus and Haiku tied at 49/50. Sonnet didn’t just cost more than Haiku, it scored worse too: 48/50 for nearly three times the price. On this task, there’s no accuracy gradient to pay for at any tier above Haiku, and there was no way to know that without running the numbers. Fifteen cents to find out. This isn’t an “8x savings for a little accuracy” story. We got nothing at all for the extra $180 a month.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes it different
&lt;/h2&gt;

&lt;p&gt;Plenty of tools already rank which model is “best” in some general sense. PennyWyze tells you which model is cheapest for your prompt, graded against your own definition of correct. The verdict is only as generic as your dataset, and your dataset is built from your own real inputs.&lt;/p&gt;

&lt;p&gt;One real scope limit, worth stating here rather than leaving for the roadmap section: today’s grading is exact-match, which means PennyWyze works for tasks with one correct answer — classification, extraction, routing — not open-ended generation like drafting a reply or summarizing a document. Broader grading (an LLM-as-judge mode) is on the roadmap, not built yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the grading is stricter than you’d expect
&lt;/h2&gt;

&lt;p&gt;Both sides of a comparison get cleaned up before grading: surrounding quotes, code fences, capitalization, and trailing punctuation are stripped from both the model’s answer and your expected answer, then compared for exact equality, not “contains.” A model that answers "Billing" when you expected billing still passes; decoration doesn't count against it. But a model that answers "I think the answer is billing" fails, on purpose. If your production system needs a bare category name back and the model buries it in a sentence instead, that's a real compliance failure, not a grading technicality. PennyWyze is built to catch that gap between knowing the answer and following the instruction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pennywyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your own Anthropic API key in a &lt;code&gt;.env&lt;/code&gt; file (get one at &lt;a href="https://console.anthropic.com" rel="noopener noreferrer"&gt;the Anthropic Console&lt;/a&gt;), write a prompt and a golden dataset, and you're auditing against the real models in minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  New to how Claude’s pricing tiers work?
&lt;/h2&gt;

&lt;p&gt;Anthropic, like every major LLM provider, sells the same basic capability at multiple price points, based roughly on how much reasoning power sits behind the model. Opus is the most capable and the most expensive. Haiku is the fastest and cheapest. Sonnet sits in the middle. The prices aren’t small differences: multiples, not percentages, per token processed.&lt;/p&gt;

&lt;p&gt;Almost every team building on top of these APIs does the same thing: default every feature to the smartest tier, “just to be safe,” and never revisit it. That’s a reasonable instinct when you’re launching something for the first time. But most of what AI features do in production is narrower than “understand anything a human could say.” Sort a support ticket into a category. Extract a field from a form. Classify a message’s intent. Tasks like that rarely need the most expensive model in the lineup, just a model that’s reliably right, and the cheapest one that clears that bar is worth real money every month, at scale.&lt;/p&gt;

&lt;p&gt;Teams already believe this in theory. Checking it requires building a whole evaluation harness: a dataset, a grading method, a way to run the same task across multiple models and compare. Nobody wants to build that just to answer one cost question, so they don’t check. They just keep paying for Opus. PennyWyze is that evaluation harness, already built.&lt;/p&gt;




&lt;h2&gt;
  
  
  How this actually came together
&lt;/h2&gt;

&lt;p&gt;The short version of how we got here: the “we spotted a gap in the market and built a solution” story isn’t quite true. Every OSLabs team pitches eight or more product ideas before settling on three, and ours started as a conversation memory layer, my teammate Edward’s idea, to stop AI chat apps from re-sending their entire history on every message. We cared more about the theme underneath it, token efficiency, than that specific idea, which was lucky, because Mem0, Zep, and Letta (formerly MemGPT) were already solving conversation memory, and Anthropic had started shipping automatic context compaction natively. Every twist we tried hit the same wall: already built. We left one evening without an answer; Olivia came back the next day with a different one, auditing which model tier you actually need instead of defaulting to the priciest. By the time we wrote our final pitches, PennyWyze was one of them.&lt;br&gt;
I didn’t fully get the problem myself until I’d spent real time learning how AI is priced in production, not just how to use it, a few weeks of catching up that ended the first time we watched a real audit print the report above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to go deeper? (architecture, for the curious/technical)
&lt;/h2&gt;

&lt;p&gt;Everything above is what you need to use PennyWyze. Everything below is for anyone who wants to see under the hood, or is thinking about contributing.&lt;/p&gt;

&lt;p&gt;The whole audit loop is built around two small, swappable contracts instead of one monolithic pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ModelProvider&lt;/code&gt;&lt;/strong&gt; — anything that can take a prompt and a question and return an answer plus the tokens it cost. The real Anthropic provider implements this. Adding a new model provider — say, for a future non-Anthropic tier — means writing one new file that implements this interface, not touching the loop itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Scorer&lt;/code&gt;&lt;/strong&gt; — anything that can grade a model's answer against the expected one and return true or false. Our exact-match scorer is the only one that ships today, but the loop doesn't know or care how a Scorer makes its decision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more thing that’s useful if you’re contributing rather than just using PennyWyze: there’s a free, built-in fake provider behind a &lt;code&gt;--fake&lt;/code&gt; flag, which runs the identical pipeline against canned responses instead of the real API. It doesn't tell you anything about your own prompt's real cost or accuracy, so it's not a way to "try PennyWyze out." It's how we build and test the tool itself day to day without spending real API money on every change.&lt;/p&gt;

&lt;p&gt;The early-stopping math is one line: &lt;code&gt;allowedFailures = Math.floor(datasetLength * (1 - passBar))&lt;/code&gt;, computed once per audit and checked after every question. Cross that number and the run for that tier ends immediately, no more API spend on a tier that's already lost. Every cost figure comes from one formula, applied to real token counts from the API response: &lt;code&gt;(inputTokens × inputPrice + outputTokens × outputPrice) / 1,000,000&lt;/code&gt;. Anthropic quotes pricing per million tokens, and it's the one line in the whole codebase where forgetting that division would make every dollar figure wrong by six orders of magnitude, and nobody would notice until the invoice arrived.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some things that actually tripped us up
&lt;/h2&gt;

&lt;p&gt;Every project write-up says “we learned a lot,” and it’s usually too vague to mean anything. These four are pulled straight from our own commit history, not memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opus doesn’t always put the answer first
&lt;/h3&gt;

&lt;p&gt;When we first wired up the real Anthropic provider, we assumed the model’s text answer would be the first item in the API response’s content array, a reasonable assumption since for most models it is. Opus’s adaptive thinking broke it. The response can carry a thinking block before the text block, which meant we were occasionally grading an internal reasoning fragment as if it were the model's real answer. The fix was one line: search the response for whichever block has &lt;code&gt;type === "text"&lt;/code&gt; instead of assuming position zero. Getting there meant noticing our grading results looked subtly off specifically on Opus, and tracing that back to a response shape we hadn't accounted for.&lt;/p&gt;

&lt;h3&gt;
  
  
  A quoted answer with a period after it failed grading
&lt;/h3&gt;

&lt;p&gt;Our grading function strips code fences, then lowercases and strips trailing punctuation, then strips surrounding quotes, before comparing two strings for equality. Early on, that last step ran before the punctuation strip instead of after. A model answering "billing"., quoted, with a period after the closing quote, would only get its leading quote stripped, since the string's actual last character was a period, not a quote. That left a dangling quote mark stuck to the end of the string once punctuation was stripped, so it never matched the expected billing. A perfectly correct, slightly decorated answer failed for a reason that had nothing to do with correctness. The fix swapped the order: strip trailing punctuation first, so quote-stripping runs last against the string's real boundary. We added a regression test for that exact input so it can't quietly break again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Early stopping almost never stopped
&lt;/h3&gt;

&lt;p&gt;The whole point of early stopping is to stop paying for a model that’s already mathematically lost. The threshold is &lt;code&gt;datasetLength × (1 − passBar)&lt;/code&gt;, and it depends entirely on passBar being a fraction between 0 and 1. For one stretch of commits, it wasn't. &lt;code&gt;cli.ts&lt;/code&gt; was already converting your &lt;code&gt;--pass-rate&lt;/code&gt; flag from a percentage into a fraction before handing it off, and the audit loop divided it by 100 again on top of that. A 90% pass bar meant to allow a handful of misses out of fifty questions instead worked out to a pass bar so close to zero that a model would have to fail almost every question before the run would ever cut short. The feature was there, it just quietly couldn't trigger. It took a few commits across the same evening to notice the math didn't add up and settle on doing that one conversion exactly once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Would the same audit give us the same answer twice?
&lt;/h3&gt;

&lt;p&gt;This one worried us the most, because if the answer was no, the whole tool would be useless. Adaptive thinking means the same prompt can produce a different number of output tokens on different runs, even against the same model, which meant our cost projections could wobble between two audits of the exact same prompt and dataset. We didn’t want to ship something whose core promise, “here’s your cheapest passing tier,” might change if you ran it twice. So we ran the same real audit, against the real API, five consecutive times and compared every result. The dollar figures moved by a few percent run to run, exactly as expected from non-deterministic token counts. But the accuracy scores and the verdict itself, which tier to switch to, held identical across all five runs. That’s why we’re comfortable telling you PennyWyze’s verdict is something you can trust, not just something we hoped was true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we’re taking this next
&lt;/h2&gt;

&lt;p&gt;PennyWyze does one thing well today, and we’d rather ship that one thing solidly than half-ship five more. But there’s a real list of what’s next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cross-provider audits&lt;/strong&gt; — not built yet, but the plan is to run the same dataset against OpenAI, Google, and Grok models alongside Claude, so the verdict isn’t just “cheapest Claude tier” but “cheapest model, period.” Today, PennyWyze audits Claude only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM-as-judge grading&lt;/strong&gt; — exact match runs first as it does today, but a judge model would review everything exact match doesn’t pass and report how often it agrees with your own grading, for tasks where “correct” isn’t a single fixed string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pennywyze init&lt;/code&gt;&lt;/strong&gt; — a guided builder for your first golden dataset, for teams who know they want to audit something but don't have 20 labeled examples sitting around yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A GitHub Action&lt;/strong&gt; — re-run your audit in CI against a committed baseline, so a prompt change that quietly breaks your cheap tier gets caught before it ships.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus: structured JSON output and grading, a shareable HTML report, flexible dataset formats beyond JSONL, and prompt trimming — because the cheapest model is only half the savings; a leaner prompt is the other half.&lt;/p&gt;

&lt;p&gt;The full, current list lives in the &lt;a href="https://github.com/oslabs-beta/PennyWyze#roadmap" rel="noopener noreferrer"&gt;repo’s Roadmap&lt;/a&gt;, and every item on it is genuinely open for someone else to pick up.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to help build it
&lt;/h2&gt;

&lt;p&gt;PennyWyze is open source, and the two-contract design above is exactly why: most new features are one new file implementing ModelProvider or Scorer, not a change to the core loop. Fork &lt;a href="https://github.com/oslabs-beta/PennyWyze" rel="noopener noreferrer"&gt;the repo&lt;/a&gt;, branch, and open a PR against &lt;code&gt;main&lt;/code&gt; — the CONTRIBUTING guide in the repo walks through building from source and running the test suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet the team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Olivia McKelvey&lt;/li&gt;
&lt;li&gt;Edward Zgonc&lt;/li&gt;
&lt;li&gt;Maia Bard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don’t pay for wasted intelligence. Audit it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If any of this sounds like a problem you have too: &lt;code&gt;npm install -g pennywyze&lt;/code&gt;, point it at your own prompt and a handful of real examples, and see what it tells you.&lt;/p&gt;

&lt;p&gt;If you run it, I’d like to know: which prompt did you point it at, and what tier did it say you actually needed?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/oslabs-beta/PennyWyze" rel="noopener noreferrer"&gt;Explore PennyWyze on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PennyWyze — built at OSLabs&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>cli</category>
      <category>webdev</category>
    </item>
    <item>
      <title>We Built a CLI to Find Out If You’re Overpaying for Claude</title>
      <dc:creator>Olivia Mckelvey</dc:creator>
      <pubDate>Thu, 24 Sep 2026 02:35:56 +0000</pubDate>
      <link>https://dev.to/oliviamckelvey/we-built-a-cli-to-find-out-if-youre-overpaying-for-claude-1p26</link>
      <guid>https://dev.to/oliviamckelvey/we-built-a-cli-to-find-out-if-youre-overpaying-for-claude-1p26</guid>
      <description>&lt;p&gt;How three OSLabs engineers built PennyWyze—and almost built something completely different.&lt;/p&gt;

&lt;p&gt;Hi, I’m Maia. I’m one of three developers behind PennyWyze, an open-source CLI that audits which Claude tier—Opus, Sonnet, or Haiku—is the cheapest one that still passes your quality bar.&lt;/p&gt;

&lt;p&gt;You point it at your production prompt and a handful of real examples where you already know the correct answer.&lt;/p&gt;

&lt;p&gt;PennyWyze runs those examples against each Claude tier, measures accuracy, calculates the actual API cost, and tells you which tier clears your bar for the lowest cost.&lt;/p&gt;

&lt;p&gt;In other words: instead of assuming you need the most expensive model, you can test it.&lt;/p&gt;

&lt;p&gt;How PennyWyze Works&lt;/p&gt;

&lt;p&gt;You give it two things:&lt;/p&gt;

&lt;p&gt;Your prompt — the exact instructions you already send to Claude in production.&lt;/p&gt;

&lt;p&gt;A golden dataset — real inputs paired with the answer you already know is correct.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;{"input": "I was charged twice this month", "expected": "billing"}&lt;br&gt;
{"input": "The app crashes on upload", "expected": "technical"}&lt;/p&gt;

&lt;p&gt;Then run:&lt;/p&gt;

&lt;p&gt;pennywyze audit --prompt prompt.md --dataset dataset.jsonl --pass-rate 90&lt;/p&gt;

&lt;p&gt;PennyWyze sends every example to Opus, Sonnet, and Haiku using your real prompt and the real Anthropic API.&lt;/p&gt;

&lt;p&gt;It grades each response against your expected answer and calculates cost using the token counts returned by the API—not an estimate.&lt;/p&gt;

&lt;p&gt;It then produces a report showing each model's accuracy and projected monthly cost at your actual volume.&lt;/p&gt;

&lt;p&gt;A real audit&lt;/p&gt;

&lt;p&gt;Here's what one run looked like:&lt;/p&gt;

&lt;p&gt;✓ opus audited — 50 questions&lt;br&gt;
✓ sonnet audited — 50 questions&lt;br&gt;
✓ haiku audited — 50 questions&lt;/p&gt;

&lt;p&gt;PENNYWYZE AUDIT REPORT&lt;/p&gt;

&lt;p&gt;┌───────────────────────────┬────────────┬────────────────┐&lt;br&gt;
│ MODEL                     │  ACCURACY  │ EST. COST / MO │&lt;br&gt;
├───────────────────────────┼────────────┼────────────────┤&lt;br&gt;
│ claude-opus-5             │ 49/50 PASS │   $205.94 / mo │&lt;br&gt;
│ claude-sonnet-5           │ 48/50 PASS │    $77.30 / mo │&lt;br&gt;
│ claude-haiku-4-5-20251001 │ 49/50 PASS │    $26.26 / mo │&lt;br&gt;
└───────────────────────────┴────────────┴────────────────┘&lt;/p&gt;

&lt;p&gt;VERDICT  Switch to claude-haiku-4-5-20251001 — save ~$179.68/mo.&lt;br&gt;
ℹ Audit cost: $0.15&lt;/p&gt;

&lt;p&gt;Opus and Haiku tied at 49/50.&lt;/p&gt;

&lt;p&gt;Sonnet actually scored lower than both while costing nearly three times as much as Haiku.&lt;/p&gt;

&lt;p&gt;On this particular task, there wasn't an accuracy difference to justify the additional cost.&lt;/p&gt;

&lt;p&gt;And finding that out cost $0.15.&lt;/p&gt;

&lt;p&gt;Why We Built It&lt;/p&gt;

&lt;p&gt;There are already plenty of tools that try to answer which AI model is "best."&lt;/p&gt;

&lt;p&gt;That's not the question we wanted to answer.&lt;/p&gt;

&lt;p&gt;We wanted to answer:&lt;/p&gt;

&lt;p&gt;Which model is cheapest for my prompt while still being good enough for my application?&lt;/p&gt;

&lt;p&gt;Those are different questions.&lt;/p&gt;

&lt;p&gt;A model that performs well on a general benchmark isn't necessarily the cheapest model that will reliably handle your specific production task.&lt;/p&gt;

&lt;p&gt;PennyWyze uses your own examples to define what "correct" means.&lt;/p&gt;

&lt;p&gt;That makes the verdict specific to your application instead of based on a generic benchmark.&lt;/p&gt;

&lt;p&gt;The Problem With Always Using the Biggest Model&lt;/p&gt;

&lt;p&gt;When you're building an AI feature for the first time, defaulting to the most capable model makes sense.&lt;/p&gt;

&lt;p&gt;You want to know that your feature works.&lt;/p&gt;

&lt;p&gt;The problem is that it's easy to never revisit that decision.&lt;/p&gt;

&lt;p&gt;A lot of production AI work isn't open-ended reasoning. It's things like:&lt;/p&gt;

&lt;p&gt;Classifying support tickets&lt;/p&gt;

&lt;p&gt;Extracting fields&lt;/p&gt;

&lt;p&gt;Routing messages&lt;/p&gt;

&lt;p&gt;Detecting intent&lt;/p&gt;

&lt;p&gt;Categorizing requests&lt;/p&gt;

&lt;p&gt;For those tasks, you may not need the most expensive model.&lt;/p&gt;

&lt;p&gt;But checking requires building an evaluation harness: a dataset, a grading system, and a way to run the same task against multiple models.&lt;/p&gt;

&lt;p&gt;Most teams don't want to build all of that just to answer one cost question.&lt;/p&gt;

&lt;p&gt;So they don't check.&lt;/p&gt;

&lt;p&gt;PennyWyze is that evaluation harness.&lt;/p&gt;

&lt;p&gt;One Important Limitation&lt;/p&gt;

&lt;p&gt;PennyWyze currently uses exact-match grading.&lt;/p&gt;

&lt;p&gt;That means it works best for tasks where there is one correct answer:&lt;/p&gt;

&lt;p&gt;Classification&lt;/p&gt;

&lt;p&gt;Extraction&lt;/p&gt;

&lt;p&gt;Routing&lt;/p&gt;

&lt;p&gt;It isn't designed yet for open-ended generation such as drafting an email or summarizing a document.&lt;/p&gt;

&lt;p&gt;LLM-as-a-judge grading is on the roadmap.&lt;/p&gt;

&lt;p&gt;Why Our Grading Is Strict&lt;/p&gt;

&lt;p&gt;We wanted PennyWyze to catch a specific production problem: a model can technically know the right answer while still failing to follow the output format your application requires.&lt;/p&gt;

&lt;p&gt;Before grading, both the model response and expected answer are normalized.&lt;/p&gt;

&lt;p&gt;We remove things like:&lt;/p&gt;

&lt;p&gt;Surrounding quotes&lt;/p&gt;

&lt;p&gt;Code fences&lt;/p&gt;

&lt;p&gt;Capitalization differences&lt;/p&gt;

&lt;p&gt;Trailing punctuation&lt;/p&gt;

&lt;p&gt;Then we compare the results for exact equality.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;p&gt;Billing&lt;/p&gt;

&lt;p&gt;passes when the expected answer is:&lt;/p&gt;

&lt;p&gt;billing&lt;/p&gt;

&lt;p&gt;But:&lt;/p&gt;

&lt;p&gt;I think the answer is billing&lt;/p&gt;

&lt;p&gt;doesn't.&lt;/p&gt;

&lt;p&gt;That's intentional.&lt;/p&gt;

&lt;p&gt;If your application expects a bare category name and the model wraps it in a sentence, that's a real production failure—not something we want to hide with a fuzzy grading system.&lt;/p&gt;

&lt;p&gt;Getting Started&lt;/p&gt;

&lt;p&gt;Install PennyWyze globally:&lt;/p&gt;

&lt;p&gt;npm install -g pennywyze&lt;/p&gt;

&lt;p&gt;Then add your Anthropic API key to a .env file, create a prompt and golden dataset, and run your first audit.&lt;/p&gt;

&lt;p&gt;You can start testing against real models in minutes.&lt;/p&gt;

&lt;p&gt;The Part We Didn't Expect&lt;/p&gt;

&lt;p&gt;The interesting thing about PennyWyze is that it wasn't our original idea.&lt;/p&gt;

&lt;p&gt;Every OSLabs team pitches multiple product ideas before settling on a few.&lt;/p&gt;

&lt;p&gt;We initially started with a completely different problem: conversation memory.&lt;/p&gt;

&lt;p&gt;The idea was to stop AI chat applications from repeatedly sending their entire conversation history with every message.&lt;/p&gt;

&lt;p&gt;What we actually cared about was the broader problem underneath it:&lt;/p&gt;

&lt;p&gt;token efficiency.&lt;/p&gt;

&lt;p&gt;But as we explored the idea, we kept running into projects that were already solving the problems we were trying to solve. Mem0, Zep, and Letta were already working on conversation memory, and Anthropic had started shipping automatic context compaction.&lt;/p&gt;

&lt;p&gt;We eventually left one evening without an answer.&lt;/p&gt;

&lt;p&gt;The next day, Olivia came back with a different idea:&lt;/p&gt;

&lt;p&gt;Instead of trying to reduce tokens by changing how conversations were stored, what if we looked at which model you were using in the first place?&lt;/p&gt;

&lt;p&gt;That became PennyWyze.&lt;/p&gt;

&lt;p&gt;What We Actually Learned Building It&lt;/p&gt;

&lt;p&gt;The most useful lessons weren't the ones we expected to learn.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opus doesn't always put the answer first&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we first connected the real Anthropic provider, we assumed the model's text response would be the first item in the API response's content array.&lt;/p&gt;

&lt;p&gt;That assumption worked for most models.&lt;/p&gt;

&lt;p&gt;Then Opus's adaptive thinking broke it.&lt;/p&gt;

&lt;p&gt;The response can contain a thinking block before the text block, which meant we were sometimes grading an internal reasoning fragment instead of the actual answer.&lt;/p&gt;

&lt;p&gt;The fix was simple:&lt;/p&gt;

&lt;p&gt;Instead of assuming position zero, we search for the response block where:&lt;/p&gt;

&lt;p&gt;type === "text"&lt;/p&gt;

&lt;p&gt;The difficult part wasn't the fix.&lt;/p&gt;

&lt;p&gt;It was noticing that our results were subtly wrong specifically for Opus and tracing the problem back to the response structure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A quoted answer with a period failed grading&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our normalization logic removes code fences, lowercases the response, removes punctuation, and strips surrounding quotes.&lt;/p&gt;

&lt;p&gt;At one point, those operations happened in the wrong order.&lt;/p&gt;

&lt;p&gt;A response like:&lt;/p&gt;

&lt;p&gt;"billing".&lt;/p&gt;

&lt;p&gt;could leave a dangling quote after punctuation was removed.&lt;/p&gt;

&lt;p&gt;The answer was semantically correct, but our grader marked it wrong.&lt;/p&gt;

&lt;p&gt;We changed the order of operations and added a regression test for that exact case.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Early stopping almost never stopped&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PennyWyze can stop auditing a model once it mathematically cannot reach the requested pass rate.&lt;/p&gt;

&lt;p&gt;The basic calculation is:&lt;/p&gt;

&lt;p&gt;allowedFailures = floor(datasetLength × (1 - passBar))&lt;/p&gt;

&lt;p&gt;But at one point, we were converting the pass rate from a percentage to a fraction twice.&lt;/p&gt;

&lt;p&gt;A 90% pass rate was effectively being divided by 100 again.&lt;/p&gt;

&lt;p&gt;The feature existed.&lt;/p&gt;

&lt;p&gt;The feature just almost never triggered.&lt;/p&gt;

&lt;p&gt;It took several commits to notice that the math didn't add up and make sure the conversion happened exactly once.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Would the same audit give us the same answer twice?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This was probably the question that worried us most.&lt;/p&gt;

&lt;p&gt;Adaptive thinking means the same prompt can produce different output token counts between runs.&lt;/p&gt;

&lt;p&gt;That means the cost projection can move.&lt;/p&gt;

&lt;p&gt;We ran the same real audit against the real API five consecutive times.&lt;/p&gt;

&lt;p&gt;The dollar figures moved by a few percent, as expected from the variation in token counts.&lt;/p&gt;

&lt;p&gt;But the accuracy scores and the resulting model choice stayed the same across all five runs.&lt;/p&gt;

&lt;p&gt;That gave us confidence that PennyWyze's core result wasn't simply an artifact of one API run.&lt;/p&gt;

&lt;p&gt;Under the Hood&lt;/p&gt;

&lt;p&gt;For anyone interested in the architecture, the audit loop is built around two small, swappable contracts:&lt;/p&gt;

&lt;p&gt;ModelProvider&lt;/p&gt;

&lt;p&gt;Anything that can take a prompt and question and return an answer plus the tokens it cost.&lt;/p&gt;

&lt;p&gt;The real Anthropic provider implements this interface.&lt;/p&gt;

&lt;p&gt;Adding another provider means implementing the contract rather than rewriting the audit loop.&lt;/p&gt;

&lt;p&gt;Scorer&lt;/p&gt;

&lt;p&gt;Anything that can grade a model's answer against the expected answer and return true or false.&lt;/p&gt;

&lt;p&gt;Exact-match scoring is the only scorer currently included.&lt;/p&gt;

&lt;p&gt;But the audit loop doesn't need to know how the scorer makes its decision.&lt;/p&gt;

&lt;p&gt;That means adding a future LLM-as-a-judge scorer can happen without rewriting the core audit pipeline.&lt;/p&gt;

&lt;p&gt;We also built a fake provider behind a --fake flag.&lt;/p&gt;

&lt;p&gt;It runs the same pipeline using canned responses instead of the real API, which lets us develop and test without spending API money on every change.&lt;/p&gt;

&lt;p&gt;What's Next?&lt;/p&gt;

&lt;p&gt;PennyWyze currently audits Claude models.&lt;/p&gt;

&lt;p&gt;Some things we're exploring next:&lt;/p&gt;

&lt;p&gt;Cross-provider audits across OpenAI, Google, and Grok&lt;/p&gt;

&lt;p&gt;LLM-as-a-judge grading for open-ended tasks&lt;/p&gt;

&lt;p&gt;pennywyze init to help users build their first golden dataset&lt;/p&gt;

&lt;p&gt;A GitHub Action for running audits in CI&lt;/p&gt;

&lt;p&gt;Structured JSON output&lt;/p&gt;

&lt;p&gt;Shareable HTML reports&lt;/p&gt;

&lt;p&gt;More flexible dataset formats&lt;/p&gt;

&lt;p&gt;Prompt trimming&lt;/p&gt;

&lt;p&gt;The goal is to eventually look beyond model selection.&lt;/p&gt;

&lt;p&gt;The cheapest model is only half of the cost question.&lt;/p&gt;

&lt;p&gt;The other half is how much you ask it to process.&lt;/p&gt;

&lt;p&gt;If You Want to Try It&lt;/p&gt;

&lt;p&gt;PennyWyze is open source.&lt;/p&gt;

&lt;p&gt;npm install -g pennywyze&lt;/p&gt;

&lt;p&gt;Then point it at your own production prompt and a handful of examples where you know the correct answer.&lt;/p&gt;

&lt;p&gt;See what it tells you.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/oslabs-beta/PennyWyze" rel="noopener noreferrer"&gt;https://github.com/oslabs-beta/PennyWyze&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it, I'd genuinely like to know:&lt;/p&gt;

&lt;p&gt;What prompt did you audit, and what did PennyWyze tell you?&lt;/p&gt;

&lt;p&gt;PennyWyze was built at OSLabs.&lt;/p&gt;

&lt;h1&gt;
  
  
  codesmith-builds #opensource #ai #javascript #devtools #llm
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>opensource</category>
      <category>tools</category>
    </item>
  </channel>
</rss>
