<?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: Oskar</title>
    <description>The latest articles on DEV Community by Oskar (@osquarski).</description>
    <link>https://dev.to/osquarski</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%2F3856857%2F86e413a0-7706-4237-9f3e-ca0edafdd0e4.jpeg</url>
      <title>DEV Community: Oskar</title>
      <link>https://dev.to/osquarski</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/osquarski"/>
    <language>en</language>
    <item>
      <title>Tokenminning (for people who write openai.chat.completions.create)</title>
      <dc:creator>Oskar</dc:creator>
      <pubDate>Fri, 19 Jun 2026 17:49:24 +0000</pubDate>
      <link>https://dev.to/osquarski/tokenminning-for-people-who-write-openaichatcompletionscreate-43b7</link>
      <guid>https://dev.to/osquarski/tokenminning-for-people-who-write-openaichatcompletionscreate-43b7</guid>
      <description>&lt;p&gt;Your team shipped the agent. The demo was magic. Then finance asked why one engineer's coding assistant burned &lt;strong&gt;$40k in a month&lt;/strong&gt; while the feature backlog looked the same.&lt;/p&gt;

&lt;p&gt;Welcome to the hangover after &lt;strong&gt;tokenmaxxing&lt;/strong&gt; — the habit of maximizing raw LLM usage, often celebrated on internal leaderboards, without tying token spend to shipped outcomes.&lt;/p&gt;

&lt;p&gt;The counter-move has a name: &lt;strong&gt;tokenminning&lt;/strong&gt;. Journalists call it &lt;a href="https://www.nytimes.com/2026/06/18/technology/ai-token-minimizing.html" rel="noopener noreferrer"&gt;&lt;em&gt;token minimizing&lt;/em&gt;&lt;/a&gt;. Engineering teams call it &lt;strong&gt;tokenminning&lt;/strong&gt; when they formalize it — metering, model routing, context hygiene, hard budgets, and CI enforcement.&lt;/p&gt;

&lt;p&gt;This is the developer's cut. Philosophy lives in the &lt;a href="https://tokenminning.ai/manifesto" rel="noopener noreferrer"&gt;Manifesto&lt;/a&gt;. Law lives in the &lt;a href="https://tokenminning.ai/constitution" rel="noopener noreferrer"&gt;Constitution&lt;/a&gt;. This post is what you ship &lt;strong&gt;before Friday&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;token&lt;/strong&gt; is a billable unit (~word fragment). Providers charge for &lt;strong&gt;input&lt;/strong&gt; and &lt;strong&gt;output&lt;/strong&gt; separately.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;agent loops&lt;/strong&gt;, input usually dominates — full history and tool dumps are re-sent every turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokenminning&lt;/strong&gt; = same output quality, minimum viable token spend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order matters:&lt;/strong&gt; meter → prompt hygiene → model routing → caching → context hygiene → caps.&lt;/li&gt;
&lt;li&gt;Soft guidance produces soft budgets. Hard ceilings belong in code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Tokenmaxxing vs tokenminning (for people who write &lt;code&gt;openai.chat.completions.create&lt;/code&gt;)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Tokenmaxxing&lt;/th&gt;
&lt;th&gt;Tokenminning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Goal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Maximize token volume&lt;/td&gt;
&lt;td&gt;Maximize value per token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model choice&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frontier default&lt;/td&gt;
&lt;td&gt;Cheapest model that passes your quality bar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Grow by accretion&lt;/td&gt;
&lt;td&gt;Versioned, schema-enforced, audited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run until done&lt;/td&gt;
&lt;td&gt;Session budget + graceful degradation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Measurement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Who used the most AI?"&lt;/td&gt;
&lt;td&gt;USD per feature, user, session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enforcement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Slack reminders&lt;/td&gt;
&lt;td&gt;CI gates, runtime caps, immutable ledgers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Meta, Uber, Walmart, and Amazon all reversed course in 2026 — caps, limits, leaderboard removals. Uber burned through its projected &lt;strong&gt;annual&lt;/strong&gt; AI budget in &lt;strong&gt;four months&lt;/strong&gt;. The NYT &lt;a href="https://tokenminning.ai/press/new-york-times" rel="noopener noreferrer"&gt;documented the shift&lt;/a&gt;. Your invoice is not a personal failure. It is a missing constraint layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why your bill exploded (three bugs in production, not one)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Hardcoded frontier models
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tokenmaxxing&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// every request, regardless of task&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Classification, extraction, and JSON transforms rarely need frontier tiers. Teams report &lt;strong&gt;60–90% savings&lt;/strong&gt; from &lt;a href="https://tokenminning.ai/practice/model-routing" rel="noopener noreferrer"&gt;model routing&lt;/a&gt; alone — &lt;em&gt;after&lt;/em&gt; they benchmark on real traffic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tokenminning&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;capability&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classify-intent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// router maps capability → cheapest model passing SLA&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Agent loops with unbounded context
&lt;/h3&gt;

&lt;p&gt;A chat turn might cost hundreds of tokens. An agent that retains full tool payloads, never summarizes state, and re-sends everything each step can cost &lt;strong&gt;tens of thousands&lt;/strong&gt; per session. Per-token prices look flat; &lt;strong&gt;context inflation&lt;/strong&gt; makes total tokens per request grow 10×. See &lt;a href="https://tokenminning.ai/what-is/context-inflation" rel="noopener noreferrer"&gt;what is context inflation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Prompts treated as Google Docs
&lt;/h3&gt;

&lt;p&gt;Every token in a system prompt is billed on &lt;strong&gt;every request&lt;/strong&gt;. A prompt that grows 200 tokens sounds free. At 10M requests/month, it is a line item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# scaffolding waste (delete these)
"You are a helpful assistant."
"Take a deep breath and think step by step."
// TODO: update this when we switch models
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace prose formatting rules with schema enforcement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response_format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json_schema"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"json_schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"summary_response"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxLength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Schema outputs validate in CI. Vibes do not. Full guide: &lt;a href="https://tokenminning.ai/practice/prompt-hygiene" rel="noopener noreferrer"&gt;prompt hygiene&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The optimization sequence (do not skip steps)
&lt;/h2&gt;

&lt;p&gt;From &lt;a href="https://tokenminning.ai/practice/where-to-start" rel="noopener noreferrer"&gt;Where to start&lt;/a&gt; on tokenminning.ai:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;th&gt;Typical impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Metering + attribution&lt;/td&gt;
&lt;td&gt;Prerequisite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Prompt hygiene&lt;/td&gt;
&lt;td&gt;~20–25% on high-volume templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Model routing&lt;/td&gt;
&lt;td&gt;60–95% depending on task mix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Prompt caching&lt;/td&gt;
&lt;td&gt;41–80% on stable prefixes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Context hygiene&lt;/td&gt;
&lt;td&gt;40–60% in agentic workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Output control + RAG discipline&lt;/td&gt;
&lt;td&gt;15–40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Semantic caching&lt;/td&gt;
&lt;td&gt;Eliminates inference on cache hits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Anti-pattern:&lt;/strong&gt; optimizing prompts before metering. You cannot prove savings or find the real bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anti-pattern:&lt;/strong&gt; trimming &lt;code&gt;max_tokens&lt;/code&gt; on output when input is 80% of spend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start this week: five PRs that actually move the needle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PR 1 — Log input and output tokens separately
&lt;/h3&gt;

&lt;p&gt;Before changing anything, answer: &lt;em&gt;"What did this user action cost, in USD, when it completed?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Minimum viable instrumentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ledger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;document-analysis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prompt_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;outputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completion_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;priceResolver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUsd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implement &lt;a href="https://tokenminning.ai/constitution/article-i" rel="noopener noreferrer"&gt;Article I: immutable metering&lt;/a&gt; before you optimize prompts.&lt;/p&gt;

&lt;h3&gt;
  
  
  PR 2 — Audit top 10 templates for scaffolding
&lt;/h3&gt;

&lt;p&gt;Pull highest-volume or highest-cost prompts. Remove signal-free tokens. Diff token counts before/after. Target &lt;strong&gt;20–25%&lt;/strong&gt; on bloated templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  PR 3 — Add &lt;code&gt;max_tokens&lt;/code&gt; to every bounded task
&lt;/h3&gt;

&lt;p&gt;If the answer shape is known, cap it in the API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// not a paragraph essay for a boolean classification&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PR 4 — Stable prefix for caching
&lt;/h3&gt;

&lt;p&gt;Static system prompts and tool definitions go &lt;strong&gt;first&lt;/strong&gt;. Dynamic user content goes &lt;strong&gt;after&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;STABLE_SYSTEM_PROMPT&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// cacheable prefix&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamicUserInput&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable provider prefix caching. Guide: &lt;a href="https://tokenminning.ai/practice/prompt-caching" rel="noopener noreferrer"&gt;prompt caching&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  PR 5 — Session budgets with graceful degradation
&lt;/h3&gt;

&lt;p&gt;Hard ceilings are architecture, not suggestions. From &lt;a href="https://tokenminning.ai/constitution/article-iv" rel="noopener noreferrer"&gt;Article IV&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;usr_123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;document-analysis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tokenBudget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;usdCeiling&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// at 90% budget: inject wrap-up directive&lt;/span&gt;
&lt;span class="c1"&gt;// at 100%: return best partial with status `completed_degraded`&lt;/span&gt;
&lt;span class="c1"&gt;// never: abort mid-sentence with a raw 429&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No budget, no session. No "internal testing" exceptions in prod.&lt;/p&gt;




&lt;h2&gt;
  
  
  Model routing: cascade, don't default upward
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → small model
            ↓ quality check passes → return
            ↓ fails → mid-tier model
                        ↓ passes → return (log escalation)
                        ↓ fails → frontier (log justification)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every frontier call needs an auditable reason:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complexity classifier score above threshold&lt;/li&gt;
&lt;li&gt;Cheaper model failed quality checks (logged)&lt;/li&gt;
&lt;li&gt;User explicitly chose a billed "high quality" tier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not acceptable: developer preference, "the prompt is long," no routing layer at all.&lt;/p&gt;

&lt;p&gt;Benchmark on &lt;strong&gt;your&lt;/strong&gt; data — 1,000 real inputs, parallel runs, compare quality × cost × latency. Blog post savings are not your savings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What tokenminning is not
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stripping required instructions to shave counts (noise removal ≠ signal removal)&lt;/li&gt;
&lt;li&gt;Using the smallest model for everything without benchmarks&lt;/li&gt;
&lt;li&gt;Fragile micro-edits that save 12 tokens and break edge cases&lt;/li&gt;
&lt;li&gt;Asking engineers to "write shorter prompts" without infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tokenminning is building systems where token bloat &lt;strong&gt;physically cannot deploy&lt;/strong&gt; and every inference call maps to a ledger.&lt;/p&gt;

&lt;p&gt;What is the most expensive inference call pattern in your stack right now — and do you actually know its USD cost per session?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>llm</category>
    </item>
    <item>
      <title>Launching @ai-billing package for Vercel AI SDK</title>
      <dc:creator>Oskar</dc:creator>
      <pubDate>Tue, 16 Jun 2026 17:44:48 +0000</pubDate>
      <link>https://dev.to/osquarski/launching-ai-billing-package-for-vercel-ai-sdk-4pfj</link>
      <guid>https://dev.to/osquarski/launching-ai-billing-package-for-vercel-ai-sdk-4pfj</guid>
      <description>&lt;h2&gt;
  
  
  Problem worth solving
&lt;/h2&gt;

&lt;p&gt;If you are building an AI-powered product, you’ve likely run into the "billing wall." Unlike traditional SaaS, AI products are often billed per inference, token, or request. Building a robust metering and billing system that handles real-time usage data, balances, and provider integrations is a major distraction from your core product.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;pnpm add @ai-billing/openai&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/narevai/ai-billing" rel="noopener noreferrer"&gt;@ai-billing&lt;/a&gt; is an npm package designed to handle the heavy lifting of usage-based billing in &lt;a href="https://github.com/vercel/ai" rel="noopener noreferrer"&gt;Vercel AI SDK&lt;/a&gt;. It does two things:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Adds cost in dollars to your provider
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8lxav0e7ms05hjs1f7fs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8lxav0e7ms05hjs1f7fs.png" alt=" " width="780" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. (optionally) Sends usage events to billing providers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf98evr92derkacwlied.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf98evr92derkacwlied.png" alt=" " width="736" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works?
&lt;/h2&gt;

&lt;p&gt;The package acts as a middleware for your usage telemetry. Instead of writing custom logic for every provider, you use a unified interface to track consumption and sync it with your chosen billing platform.&lt;/p&gt;

&lt;p&gt;When working on it, we prioritized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;being provider agnostic&lt;/strong&gt;: Easily switch or add billing providers as your needs scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;having ready-to-use templates&lt;/strong&gt;: We’ve provided full-stack examples for popular combinations like OpenRouter + Polar or OpenAI + Stripe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;thinking of the developer experience&lt;/strong&gt;: Less time configuring APIs, more time building features.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic example - adding cost to OpenAI calls
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;UIMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;convertToModelMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;generateText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;wrapLanguageModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createOpenAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ai-sdk/openai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createOpenAIMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ai-billing/openai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;consoleDestination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createObjectPriceResolver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ModelPricing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ai-billing/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createOpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// eslint-disable-next-line turbo/no-undeclared-env-vars&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customPricingMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ModelPricing&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;promptTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.25&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;completionTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputCacheReadTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.125&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;promptTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;completionTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;priceResolver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createObjectPriceResolver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customPricingMap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;billingMiddleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createOpenAIMiddleware&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;destinations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;consoleDestination&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;priceResolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;priceResolver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIMessage&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-gen-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;What is the capital of Sweden?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wrapLanguageModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;billingMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wrappedModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convertToModelMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generate Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Full-stack projects built with @ai-billing
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Demo Link&lt;/th&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Deploy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chatbot (OpenRouter + Polar)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://chatbot-with-billing-polar-three.vercel.app/" rel="noopener noreferrer"&gt;View Demo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/narevai/chatbot-with-billing-polar" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fnarevai%2Fai-billing%2Ftree%2Fmain%2Fexamples%2Fchatbot-with-billing-polar" rel="noopener noreferrer"&gt;Deploy with Vercel&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chatbot (OpenAI + Polar)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://chatbot-openai-with-billing-polar.vercel.app/" rel="noopener noreferrer"&gt;View Demo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/narevai/chatbot-openai-with-billing-polar" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fnarevai%2Fchatbot-openai-with-billing-polar&amp;amp;env=AUTH_SECRET,OPENAI_API_KEY,POSTGRES_URL,POLAR_ACCESS_TOKEN,POLAR_SERVER,NAREV_API_KEY&amp;amp;envDefaults=%7B%22POLAR_SERVER%22%3A%22sandbox%22%7D" rel="noopener noreferrer"&gt;Deploy with Vercel&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chatbot (Stripe)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://chatbot-with-billing-stripe.vercel.app/" rel="noopener noreferrer"&gt;View Demo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/narevai/chatbot-with-billing-stripe" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fnarevai%2Fchatbot-with-billing-polar&amp;amp;env=AUTH_SECRET,AI_GATEWAY_API_KEY,POSTGRES_URL,POLAR_ACCESS_TOKEN,POLAR_SERVER&amp;amp;envDefaults=%7B%22POLAR_SERVER%22%3A%22sandbox%22%7D" rel="noopener noreferrer"&gt;Deploy with Vercel&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  One more time, repo link
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/narevai/ai-billing" rel="noopener noreferrer"&gt;https://github.com/narevai/ai-billing&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>FinOps X 2026 recap: the great token panic</title>
      <dc:creator>Oskar</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:25:27 +0000</pubDate>
      <link>https://dev.to/osquarski/finops-x-2026-recap-the-great-token-panic-40l0</link>
      <guid>https://dev.to/osquarski/finops-x-2026-recap-the-great-token-panic-40l0</guid>
      <description>&lt;p&gt;If you were following the FinOps X 2026 conference that just wrapped up in San Diego (June 8–11, 2026), you probably noticed a massive shift. The discipline has officially outgrown its cloud-cost-management origins. While the expo floor had the usual vendor announcements, the real story for those of us building AI products was what the keynotes dubbed: "The Great Token Panic."&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://www.gartner.com/en/newsroom/press-releases/2026-05-19-gartner-forecasts-worldwide-ai-spending-to-grow-47-percent-in-2026" rel="noopener noreferrer"&gt;Gartner forecasting $2.59 trillion in AI spending in 2026&lt;/a&gt;, the era of treating AI costs as an unattributed R&amp;amp;D expense is over. Here are the core takeaways from the event and why they matter for engineering teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Arrival of Token Economics
&lt;/h2&gt;

&lt;p&gt;For the last decade, FinOps was about CPU hours, memory, and reserved instances. Now, the atomic unit of technology spend is the token.&lt;br&gt;
Because reasoning and agentic workloads consume 5 to 30 times more tokens per task than simple chat interactions, enterprise consumption is swamping the gradual decline in per-token list prices. AI token costs are variable, hard to forecast, and prone to rapid volatility. Recognizing this, the Linux Foundation and FinOps Foundation used the event to launch the Tokenomics Foundation. It's a massive industry effort uniting hyperscalers and enterprises to establish open standards for AI cost management and billing data.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Agentic FinOps and Moving Beyond Dashboards
&lt;/h2&gt;

&lt;p&gt;We are officially moving past static dashboards and natural-language wrappers on billing exports. The conference floor was dominated by the concept of "Agentic FinOps" - autonomous systems that don't just report on costs, but actively investigate and orchestrate remediation.&lt;br&gt;
Instead of analysts manually digging through blast radiuses, the next generation of tooling uses AI to continuously scan Kubernetes clusters, cloud environments, and AI service consumption to automatically route root-cause analysis straight into engineering workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. FinOps Scopes: Expanding the Definition
&lt;/h2&gt;

&lt;p&gt;The State of FinOps 2026 report made it clear: 90% of teams now manage SaaS costs or plan to within the year. The FinOps umbrella is expanding to cover private clouds, data platforms, software licensing, and, crucially, multi-model AI endpoints.&lt;br&gt;
Optimization efforts fail without accurate allocation. If you can't attribute the cost of an Anthropic or OpenAI API call to a specific product feature or user, you can't optimize it. Teams are shifting to virtual tagging and strict governance frameworks to isolate these costs before they scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Widespread Adoption of&amp;nbsp;FOCUS
&lt;/h2&gt;

&lt;p&gt;The FinOps Open Cost and Usage Specification (FOCUS) continues to gain traction as the universal billing format. As organizations juggle multiple AI providers, standardizing billing data into a universal schema is the only way to maintain portability. If your infrastructure emits FOCUS-compliant data, you can seamlessly integrate new ecosystem tools without having to rebuild your underlying data pipeline.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>infrastructure</category>
      <category>llm</category>
      <category>news</category>
    </item>
    <item>
      <title>How we cut our Dagster Cloud bill by 60% by collapsing our dbt assets</title>
      <dc:creator>Oskar</dc:creator>
      <pubDate>Mon, 15 Jun 2026 05:17:03 +0000</pubDate>
      <link>https://dev.to/osquarski/how-we-cut-our-dagster-cloud-bill-by-60-by-collapsing-our-dbt-assets-2</link>
      <guid>https://dev.to/osquarski/how-we-cut-our-dagster-cloud-bill-by-60-by-collapsing-our-dbt-assets-2</guid>
      <description>&lt;p&gt;If your team is using Dagster Cloud's Solo or Starter tiers, &lt;a href="https://support.dagster.io/articles/3171123463-dagster-solo-and-starter-pricing-updates-may-2026" rel="noopener noreferrer"&gt;the May 2026 pricing update probably gave you a bit of a shock&lt;/a&gt;. By removing the monthly credit allowance and charging for each step-executed asset materialization, workspaces that used to cost $10–$100 a month suddenly spiked into the hundreds or even over a thousand dollars.&lt;/p&gt;

&lt;p&gt;At Narev, we love the developer experience of Dagster, but our 24/7 schedule was driving up our bill to the point where self-hosting Airflow was starting to look attractive.&lt;/p&gt;

&lt;p&gt;Before jumping ship, we audited our setup and found a massive quick win: we were paying Dagster to coordinate a graph that dbt already understood. Here is how we fixed it and cut our orchestration bill by 60%.&lt;/p&gt;

&lt;h2&gt;
  
  
  The culprit: &lt;code&gt;@dbt_assets&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The standard &lt;a href="https://docs.dagster.io/integrations/libraries/dbt" rel="noopener noreferrer"&gt;dagster-dbt&lt;/a&gt; component is beautiful. You use &lt;code&gt;@dbt_assets&lt;/code&gt;, and Dagster maps every single dbt model and seed into an individual node in your Dagster UI.&lt;/p&gt;

&lt;p&gt;But under the new pricing model, every asset materialization has a cost (around $0.035 to $0.040 per credit). If you have a couple hundred dbt models running on an hourly or daily partition, you are burning credits just to have Dagster say, "Yep, dbt built this view."&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: One asset, One command
&lt;/h2&gt;

&lt;p&gt;We decided to collapse our entire dbt project into a single plain @asset that just shells out to dbt. Same dbt logic, same data, but far fewer orchestration steps.&lt;br&gt;
Here is what our refactored asset looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dagster&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AssetExecutionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dagster_dbt&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DbtCliResource&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;etl.defs.partitions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;daily_partition&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;etl.defs.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DeploymentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_deployment_type&lt;/span&gt;

&lt;span class="nd"&gt;@asset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;partitions_def&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;daily_partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transformers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dw_load&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dw_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AssetExecutionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dbt_resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbtCliResource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;time_window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_time_window&lt;/span&gt;
    &lt;span class="n"&gt;deployment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_deployment_type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;dbt_target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;deployment&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;DeploymentType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PROD&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;dbt_vars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time_window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time_window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dbt_target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--vars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbt_vars&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="c1"&gt;# The crucial part:
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dbt_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_successful&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dbt build failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All models updated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The gotcha: Drop the context
&lt;/h2&gt;

&lt;p&gt;If you try this, there is one massive trap you need to avoid. Do not pass &lt;code&gt;context=context&lt;/code&gt; to &lt;code&gt;dbt_resource.cli()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you do &lt;code&gt;result = dbt_resource.cli(args, context=context).wait()&lt;/code&gt;, the dagster-dbt package will still emit individual materialization events behind the scenes for every single model. You will end up paying for per-model orchestration without getting the per-model UI benefits.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;.wait()&lt;/code&gt; instead of &lt;code&gt;.stream()&lt;/code&gt; and dropping the context ensures you only pay for one materialization per partition per run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trade-offs
&lt;/h2&gt;

&lt;p&gt;This optimization isn't entirely free. By hiding dbt's complexity from Dagster, you are giving up a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No per-model UI lineage&lt;/strong&gt;: You won't see individual staging models in the Dagster graph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coarser alerting&lt;/strong&gt;: If a single model fails, the entire dw_transform asset goes red. You'll have to check the dbt logs to see exactly which model broke.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For us, this was a no-brainer. We rely on dbt docs and our warehouse for deep lineage anyway, and we only need Dagster to know: "Extract done → Load done → Transform done."&lt;/p&gt;

&lt;p&gt;If you want to see exactly how this changes downstream asset dependencies and how to wire up your jobs with this new pattern, I wrote a full breakdown on our blog (along with a drop-in Cursor prompt to automate the refactor for your workspace).&lt;/p&gt;

&lt;p&gt;Read the full guide &lt;a href="https://www.narev.ai/blog/lower-dagster-bill" rel="noopener noreferrer"&gt;on the Narev blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>devops</category>
      <category>database</category>
    </item>
    <item>
      <title>It's time to get familiar with what FinOps for AI is</title>
      <dc:creator>Oskar</dc:creator>
      <pubDate>Sun, 31 May 2026 17:05:10 +0000</pubDate>
      <link>https://dev.to/osquarski/its-time-to-get-familiar-with-what-finops-for-ai-is-49lk</link>
      <guid>https://dev.to/osquarski/its-time-to-get-familiar-with-what-finops-for-ai-is-49lk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;No Generative AI was used in writing this article. If you enjoyed reading it, please let me know. It helps me dedicate more time to things that resonate with my readers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It took Uber 4 months to burn the entire AI budget for 2026. The cost if AI, the ROI and the question of AI investment have entered the picture.&lt;/p&gt;

&lt;p&gt;Uber’s COO, Andrew MacDonald, said &lt;a href="https://youtu.be/y_mQ6xLcKyc?si=qcqDSlEwOV3AShmu&amp;amp;t=1720%5D" rel="noopener noreferrer"&gt;in his recent interview&lt;/a&gt; that the costs became “harder to justify” because the link between spending on AI tokens and creating more useful features “was not there”.&lt;/p&gt;

&lt;h2&gt;
  
  
  It started with all you can eat subscriptions.
&lt;/h2&gt;

&lt;p&gt;Since the early days of tech, we’ve been conditioned to expect all you can eat subscriptions. For a month, you could watch Netflix non-stop, for 24 hours, 7 days a week and you’d still pay the same price as if you watched only one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s a great deal!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In fact, such a good deal, that we see it everywhere. On Netflix, on Amazon Prime, pretty much all the software.&lt;/p&gt;

&lt;h2&gt;
  
  
  The magic of zero marginal cost (in digital goods)
&lt;/h2&gt;

&lt;p&gt;In traditional businesses, selling one more unit of physical product costs the company an extra unit of resources.&lt;/p&gt;

&lt;p&gt;Each flower bouquet of 5 roses sold requires 10 roses. Selling 100 bouquets will require 100 bouquets x 5 roses = 500 roses. This is called marginal cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But that’s not the case in the digital world!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once Netflix pays the massive upfront cost to produce Stranger Things ($30 million an episode), it costs them exactly the same amount of money whether 10 people watch it or 100 million people watch it. As long as they get enough subscriber to cover the initial investment, every new subscriber after that is 100% pure profit. This is a zero marginal cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Large Language Models are more like a flower shop
&lt;/h2&gt;

&lt;p&gt;The cost of generating tokens requires significant amount of energy. This makes token generation expensive.&lt;/p&gt;

&lt;p&gt;This week news cycle brought us a story about an anonymous company accidentally burning through $500M of tokens.&lt;/p&gt;

&lt;p&gt;This very nature of LLMs requires that all-you-can-eat subscriptions have to be subsidized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is it a good thing?
&lt;/h2&gt;

&lt;p&gt;Ultimately, it’s about the unit economics.&lt;/p&gt;

&lt;p&gt;We went through a very similar pain with a shift to cloud computing. The solution was to not abandon AWS completely due to spiraling bills.&lt;/p&gt;

&lt;p&gt;Instead we built dashboards, tracked usage, and an entire discipline was born: FinOps.&lt;/p&gt;

&lt;p&gt;When the costs are real, the value has to be real too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where would you start?
&lt;/h2&gt;

&lt;p&gt;I'll leave you with the &lt;a href="https://www.narev.ai/guides/finops-for-ai" rel="noopener noreferrer"&gt;FinOps for AI framework from Narev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>news</category>
    </item>
    <item>
      <title>It was never easier to make software. It was never harder to make good software</title>
      <dc:creator>Oskar</dc:creator>
      <pubDate>Sun, 31 May 2026 11:23:21 +0000</pubDate>
      <link>https://dev.to/osquarski/it-was-never-easier-to-make-software-it-was-never-harder-to-make-good-software-cfe</link>
      <guid>https://dev.to/osquarski/it-was-never-easier-to-make-software-it-was-never-harder-to-make-good-software-cfe</guid>
      <description></description>
      <category>discuss</category>
      <category>programming</category>
      <category>software</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
